[installd] Support creating oat dir hierarchy for inherit install.

This is to support the Package Manager change in
commit 767b1214ba6e5640380827d2f32ddb85271d938c. Details can be found
there.

Bug: 258223472
Test: -
  1. Install a base APK using `adb install`.
  2. Check the files in the oat dir and their inodes.
  3. Install a split APK using `adb install -p` (inherit install).
  4. Verify that the existing files are there in the oat dir at the
     destination and their inodes are unchanged.
Flag: android.content.pm.alternative_for_dexopt_cleanup
Change-Id: I97f8e2be418a9375b84e2b872dc17d5bee0406d9
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 051c999..b4ad289 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -3291,7 +3291,7 @@
 
     const char* oat_dir = getCStr(outputPath);
     const char* instruction_set = instructionSet.c_str();
-    if (oat_dir != nullptr && !createOatDir(packageName, oat_dir, instruction_set).isOk()) {
+    if (oat_dir != nullptr && !createOatDirs(packageName, oat_dir, {instruction_set}).isOk()) {
         // Can't create oat dir - let dexopt use cache dir.
         oat_dir = nullptr;
     }
@@ -3499,17 +3499,15 @@
     return res;
 }
 
-binder::Status InstalldNativeService::createOatDir(const std::string& packageName,
-                                                   const std::string& oatDir,
-                                                   const std::string& instructionSet) {
+binder::Status InstalldNativeService::createOatDirs(const std::string& packageName,
+                                                    const std::string& oatDir,
+                                                    const std::vector<std::string>& oatSubDirs) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     CHECK_ARGUMENT_PATH(oatDir);
     LOCK_PACKAGE();
 
     const char* oat_dir = oatDir.c_str();
-    const char* instruction_set = instructionSet.c_str();
-    char oat_instr_dir[PKG_PATH_MAX];
 
     if (validate_apk_path(oat_dir)) {
         return error("Invalid path " + oatDir);
@@ -3520,9 +3518,22 @@
     if (selinux_android_restorecon(oat_dir, 0)) {
         return error("Failed to restorecon " + oatDir);
     }
-    snprintf(oat_instr_dir, PKG_PATH_MAX, "%s/%s", oat_dir, instruction_set);
-    if (fs_prepare_dir(oat_instr_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
-        return error(StringPrintf("Failed to prepare %s", oat_instr_dir));
+    for (const std::string& sub_dir : oatSubDirs) {
+        // Create the given sub-directory as well as any nonexistent parent directories.
+        std::filesystem::path current_path(oat_dir);
+        std::filesystem::path sub_path(sub_dir);
+        if (sub_path.is_absolute()) {
+            return error("Invalid oat sub directory " + sub_dir);
+        }
+        for (const std::filesystem::path& component : sub_path) {
+            current_path /= component;
+            std::string path_str = current_path.string();
+            CHECK_ARGUMENT_PATH(path_str);
+            if (fs_prepare_dir(path_str.c_str(), S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM,
+                               AID_INSTALL)) {
+                return error(StringPrintf("Failed to prepare %s", path_str.c_str()));
+            }
+        }
     }
     return ok();
 }
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index b13d6d7..5c140fe 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -170,8 +170,8 @@
             int32_t flags);
     binder::Status linkNativeLibraryDirectory(const std::optional<std::string>& uuid,
             const std::string& packageName, const std::string& nativeLibPath32, int32_t userId);
-    binder::Status createOatDir(const std::string& packageName, const std::string& oatDir,
-                                const std::string& instructionSet);
+    binder::Status createOatDirs(const std::string& packageName, const std::string& oatDir,
+                                 const std::vector<std::string>& oatSubDirs);
     binder::Status linkFile(const std::string& packageName, const std::string& relativePath,
                             const std::string& fromBase, const std::string& toBase);
     binder::Status moveAb(const std::string& packageName, const std::string& apkPath,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 8a2f113..64f662d 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -90,8 +90,8 @@
     void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes, int flags);
     void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
             @utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId);
-    void createOatDir(@utf8InCpp String packageName, @utf8InCpp String oatDir,
-            @utf8InCpp String instructionSet);
+    void createOatDirs(@utf8InCpp String packageName, @utf8InCpp String oatDir,
+            in @utf8InCpp List<String> oatSubDirs);
     void linkFile(@utf8InCpp String packageName, @utf8InCpp String relativePath,
             @utf8InCpp String fromBase, @utf8InCpp String toBase);
     void moveAb(@utf8InCpp String packageName, @utf8InCpp String apkPath,
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index e89543e..5b1d8b1 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -775,7 +775,7 @@
 
 TEST_F(DexoptTest, DexoptPrimaryPublicCreateOatDir) {
     LOG(INFO) << "DexoptPrimaryPublic";
-    ASSERT_BINDER_SUCCESS(service_->createOatDir(package_name_, app_oat_dir_, kRuntimeIsa));
+    ASSERT_BINDER_SUCCESS(service_->createOatDirs(package_name_, app_oat_dir_, {kRuntimeIsa}));
     CompilePrimaryDexOk("verify",
                         DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
                         app_oat_dir_.c_str(),