Convert vold_prepare_subdirs to C++

Minimize overhead in boot by replacing shell script invoked multiple
times with a C++ program invoked once.

Bug: 67901036
Test: create user, run adb shell ls -laZ /data/misc_ce/10; delete user
    and check logs.
Change-Id: I886cfd6505cca1f5b5902f2071e13f48e612214d
diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp
index 646a032..5f59d35 100644
--- a/Ext4Crypt.cpp
+++ b/Ext4Crypt.cpp
@@ -41,6 +41,8 @@
 
 #include <private/android_filesystem_config.h>
 
+#include "android/os/IVold.h"
+
 #include "cryptfs.h"
 
 #define EMULATED_USES_SELINUX 0
@@ -61,10 +63,6 @@
 using android::vold::kEmptyAuthentication;
 using android::vold::KeyBuffer;
 
-// NOTE: keep in sync with StorageManager
-static constexpr int FLAG_STORAGE_DE = 1 << 0;
-static constexpr int FLAG_STORAGE_CE = 1 << 1;
-
 namespace {
 
 const std::string device_key_dir = std::string() + DATA_MNT_POINT + e4crypt_unencrypted_folder;
@@ -73,6 +71,7 @@
 
 const std::string user_key_dir = std::string() + DATA_MNT_POINT + "/misc/vold/user_keys";
 const std::string user_key_temp = user_key_dir + "/temp";
+const std::string prepare_subdirs_path = "/system/bin/vold_prepare_subdirs";
 
 bool s_global_de_initialized = false;
 
@@ -379,7 +378,7 @@
     // We can only safely prepare DE storage here, since CE keys are probably
     // entangled with user credentials.  The framework will always prepare CE
     // storage once CE keys are installed.
-    if (!e4crypt_prepare_user_storage("", 0, 0, FLAG_STORAGE_DE)) {
+    if (!e4crypt_prepare_user_storage("", 0, 0, android::os::IVold::STORAGE_FLAG_DE)) {
         LOG(ERROR) << "Failed to prepare user 0 storage";
         return false;
     }
@@ -594,13 +593,12 @@
     return true;
 }
 
-static bool prepare_subdirs(const std::string& action, const std::string& dirtype,
-                            const std::string& volume_uuid, userid_t user_id,
-                            const std::string& path) {
-    if (0 != android::vold::ForkExecvp(std::vector<std::string>{"/system/bin/vold_prepare_subdirs",
-                                                                action, dirtype, volume_uuid,
-                                                                std::to_string(user_id), path})) {
-        LOG(ERROR) << "vold_prepare_subdirs failed on: " << path;
+static bool prepare_subdirs(const std::string& action, const std::string& volume_uuid,
+                            userid_t user_id, int flags) {
+    if (0 != android::vold::ForkExecvp(
+                 std::vector<std::string>{prepare_subdirs_path, action, volume_uuid,
+                                          std::to_string(user_id), std::to_string(flags)})) {
+        LOG(ERROR) << "vold_prepare_subdirs failed";
         return false;
     }
     return true;
@@ -611,7 +609,7 @@
     LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_empty(volume_uuid)
                << ", user " << user_id << ", serial " << serial << ", flags " << flags;
 
-    if (flags & FLAG_STORAGE_DE) {
+    if (flags & android::os::IVold::STORAGE_FLAG_DE) {
         // DE_sys key
         auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id);
         auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
@@ -644,14 +642,9 @@
             }
             if (!ensure_policy(de_raw_ref, user_de_path)) return false;
         }
-
-        if (volume_uuid.empty()) {
-            if (!prepare_subdirs("prepare", "misc_de", volume_uuid, user_id, misc_de_path))
-                return false;
-        }
     }
 
-    if (flags & FLAG_STORAGE_CE) {
+    if (flags & android::os::IVold::STORAGE_FLAG_CE) {
         // CE_n key
         auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
         auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
@@ -678,8 +671,6 @@
         }
 
         if (volume_uuid.empty()) {
-            if (!prepare_subdirs("prepare", "misc_ce", volume_uuid, user_id, misc_ce_path))
-                return false;
             // Now that credentials have been installed, we can run restorecon
             // over these paths
             // NOTE: these paths need to be kept in sync with libselinux
@@ -687,6 +678,7 @@
             android::vold::RestoreconRecursive(misc_ce_path);
         }
     }
+    if (!prepare_subdirs("prepare", volume_uuid, user_id, flags)) return false;
 
     return true;
 }
@@ -696,7 +688,9 @@
                << ", user " << user_id << ", flags " << flags;
     bool res = true;
 
-    if (flags & FLAG_STORAGE_CE) {
+    res &= prepare_subdirs("destroy", volume_uuid, user_id, flags);
+
+    if (flags & android::os::IVold::STORAGE_FLAG_CE) {
         // CE_n key
         auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
         auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
@@ -706,13 +700,12 @@
         res &= destroy_dir(media_ce_path);
         res &= destroy_dir(user_ce_path);
         if (volume_uuid.empty()) {
-            res &= prepare_subdirs("destroy", "misc_ce", volume_uuid, user_id, misc_ce_path);
             res &= destroy_dir(system_ce_path);
             res &= destroy_dir(misc_ce_path);
         }
     }
 
-    if (flags & FLAG_STORAGE_DE) {
+    if (flags & android::os::IVold::STORAGE_FLAG_DE) {
         // DE_sys key
         auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id);
         auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
@@ -725,7 +718,6 @@
 
         res &= destroy_dir(user_de_path);
         if (volume_uuid.empty()) {
-            res &= prepare_subdirs("destroy", "misc_de", volume_uuid, user_id, misc_de_path);
             res &= destroy_dir(system_legacy_path);
 #if MANAGE_MISC_DIRS
             res &= destroy_dir(misc_legacy_path);