Create DE_n and CE_n APEX data directories.

This creates an apexdata directory under /data/misc_de/<user> and
/data/misc_ce/<user>, and also creates a directory under that for
every APEX that is installed.

See go/apex-data-directories.

APEXes are discovered by scanning the /apex directory. It may be better
to delegate this process to a library, but it is proposed to defer that
change to a future CL.

Bug: 141148175
Test: Built and flashed, checked directories were created.
Change-Id: I95a060b4f42241c91da25a779e61a8f85ca1914c
diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp
index a620edd..2fb95d2 100644
--- a/vold_prepare_subdirs.cpp
+++ b/vold_prepare_subdirs.cpp
@@ -120,6 +120,31 @@
     }
 }
 
+static bool prepare_apex_subdirs(struct selabel_handle* sehandle, const std::string& path) {
+    if (!prepare_dir(sehandle, 0700, 0, 0, path + "/apexdata")) return false;
+
+    auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/apex"), closedir);
+    if (!dirp) {
+        PLOG(ERROR) << "Unable to open apex directory";
+        return false;
+    }
+    struct dirent* entry;
+    while ((entry = readdir(dirp.get())) != nullptr) {
+        if (entry->d_type != DT_DIR) continue;
+
+        const char* name = entry->d_name;
+        // skip any starting with "."
+        if (name[0] == '.') continue;
+
+        if (strchr(name, '@') != NULL) continue;
+
+        if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, path + "/apexdata/" + name)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int flags) {
     struct selabel_handle* sehandle = selinux_android_file_context_handle();
 
@@ -129,6 +154,8 @@
             if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/vold")) return false;
             if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/storaged")) return false;
             if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/rollback")) return false;
+            // TODO: Return false if this returns false once sure this should succeed.
+            prepare_apex_subdirs(sehandle, misc_de_path);
 
             auto vendor_de_path = android::vold::BuildDataVendorDePath(user_id);
             if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, vendor_de_path + "/fpdata")) {
@@ -144,6 +171,8 @@
             if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/vold")) return false;
             if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/storaged")) return false;
             if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/rollback")) return false;
+            // TODO: Return false if this returns false once sure this should succeed.
+            prepare_apex_subdirs(sehandle, misc_ce_path);
 
             auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
             if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, system_ce_path + "/backup")) {