[installd] Pass .dm files to dexopt

(cherry picked from commit cc3b8aeff19f39afb8d4f2c198ee6cd2ec132d22)

Test: installd_otapreopt_test installd_dexopt_test
Bug: 30934496
Merged-In: I3cb5b3f96205688203a134023492d8ff80524ab6
Change-Id: I3cb5b3f96205688203a134023492d8ff80524ab6
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index ebf09c0..c52255a 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1877,13 +1877,18 @@
     return ok();
 }
 
+static const char* getCStr(const std::unique_ptr<std::string>& data,
+        const char* default_value = nullptr) {
+    return data == nullptr ? default_value : data->c_str();
+}
 binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
         const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
         int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
         const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
         const std::unique_ptr<std::string>& classLoaderContext,
         const std::unique_ptr<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
-        const std::unique_ptr<std::string>& profileName) {
+        const std::unique_ptr<std::string>& profileName,
+        const std::unique_ptr<std::string>& dexMetadataPath) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     if (packageName && *packageName != "*") {
@@ -1892,17 +1897,18 @@
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
-    const char* pkgname = packageName ? packageName->c_str() : "*";
+    const char* pkgname = getCStr(packageName, "*");
     const char* instruction_set = instructionSet.c_str();
-    const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
+    const char* oat_dir = getCStr(outputPath);
     const char* compiler_filter = compilerFilter.c_str();
-    const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
-    const char* class_loader_context = classLoaderContext ? classLoaderContext->c_str() : nullptr;
-    const char* se_info = seInfo ? seInfo->c_str() : nullptr;
-    const char* profile_name = profileName ? profileName->c_str() : nullptr;
+    const char* volume_uuid = getCStr(uuid);
+    const char* class_loader_context = getCStr(classLoaderContext);
+    const char* se_info = getCStr(seInfo);
+    const char* profile_name = getCStr(profileName);
+    const char* dm_path = getCStr(dexMetadataPath);
     int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
             oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
-            downgrade, targetSdkVersion, profile_name);
+            downgrade, targetSdkVersion, profile_name, dm_path);
     return res ? error(res, "Failed to dexopt") : ok();
 }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 4650901..e40b74e 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -85,7 +85,8 @@
             const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
             const std::unique_ptr<std::string>& classLoaderContext,
             const std::unique_ptr<std::string>& seInfo, bool downgrade,
-            int32_t targetSdkVersion, const std::unique_ptr<std::string>& profileName);
+            int32_t targetSdkVersion, const std::unique_ptr<std::string>& profileName,
+            const std::unique_ptr<std::string>& dexMetadataPath);
 
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 626944e..1106734 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -52,7 +52,8 @@
             @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
             @nullable @utf8InCpp String sharedLibraries,
             @nullable @utf8InCpp String seInfo, boolean downgrade, int targetSdkVersion,
-            @nullable @utf8InCpp String profileName);
+            @nullable @utf8InCpp String profileName,
+            @nullable @utf8InCpp String dexMetadataPath);
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 9c9567e..1139ebc 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -223,7 +223,8 @@
         const char* input_file_name, const char* output_file_name, int swap_fd,
         const char* instruction_set, const char* compiler_filter,
         bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
-        const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks) {
+        const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
+        int dex_metadata_fd) {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -420,6 +421,7 @@
         sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
     }
 
+    std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
 
     ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
 
@@ -450,7 +452,8 @@
                      + (disable_cdex ? 1 : 0)
                      + (generate_minidebug_info ? 1 : 0)
                      + (target_sdk_version != 0 ? 2 : 0)
-                     + (enable_hidden_api_checks ? 2 : 0)];
+                     + (enable_hidden_api_checks ? 2 : 0)
+                     + (dex_metadata_fd > -1 ? 1 : 0)];
     int i = 0;
     argv[i++] = dex2oat_bin;
     argv[i++] = zip_fd_arg;
@@ -529,6 +532,9 @@
         argv[i++] = "-Xhidden-api-checks";
     }
 
+    if (dex_metadata_fd > -1) {
+        argv[i++] = dex_metadata_fd_arg.c_str();
+    }
     // Do not add after dex2oat_flags, they should override others for debugging.
     argv[i] = NULL;
 
@@ -1846,7 +1852,8 @@
 int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
-        bool downgrade, int target_sdk_version, const char* profile_name) {
+        bool downgrade, int target_sdk_version, const char* profile_name,
+        const char* dex_metadata_path) {
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
     if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
@@ -1937,6 +1944,14 @@
     Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
             pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex);
 
+    unique_fd dex_metadata_fd;
+    if (dex_metadata_path != nullptr) {
+        dex_metadata_fd.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW)));
+        if (dex_metadata_fd.get() < 0) {
+            PLOG(ERROR) << "Failed to open dex metadata file " << dex_metadata_path;
+        }
+    }
+
     ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path);
 
     pid_t pid = fork();
@@ -1966,7 +1981,8 @@
                     reference_profile_fd.get(),
                     class_loader_context,
                     target_sdk_version,
-                    enable_hidden_api_checks);
+                    enable_hidden_api_checks,
+                    dex_metadata_fd.get());
         _exit(68);   /* only get here on exec failure */
     } else {
         int res = wait_child(pid);
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 93cf545..ae1412e 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -105,7 +105,8 @@
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
-        bool downgrade, int target_sdk_version, const char* profile_name);
+        bool downgrade, int target_sdk_version, const char* profile_name,
+        const char* dexMetadataPath);
 
 bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
         const char *apk_path, const char *instruction_set);
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index c163f2c..b3e87f2 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -580,7 +580,8 @@
                       parameters_.se_info,
                       parameters_.downgrade,
                       parameters_.target_sdk_version,
-                      parameters_.profile_name);
+                      parameters_.profile_name,
+                      parameters_.dex_metadata_path);
     }
 
     int RunPreopt() {
diff --git a/cmds/installd/otapreopt_parameters.cpp b/cmds/installd/otapreopt_parameters.cpp
index b8e6310..5b5f522 100644
--- a/cmds/installd/otapreopt_parameters.cpp
+++ b/cmds/installd/otapreopt_parameters.cpp
@@ -228,6 +228,7 @@
         case 3: num_args_expected = 12; break;
         case 4: num_args_expected = 13; break;
         case 5: num_args_expected = 14; break;
+        case 6: num_args_expected = 15; break;
         default:
             LOG(ERROR) << "Don't know how to read arguments for version " << version;
             return false;
@@ -330,6 +331,9 @@
                 profile_name = ParseNull(param);
                 break;
 
+            case 14:
+                 dex_metadata_path = ParseNull(param);
+
             default:
                 CHECK(false) << "Should not get here. Did you call ReadArguments "
                         << "with the right expectation?";
diff --git a/cmds/installd/otapreopt_parameters.h b/cmds/installd/otapreopt_parameters.h
index eb5dd85..0f3bb8c 100644
--- a/cmds/installd/otapreopt_parameters.h
+++ b/cmds/installd/otapreopt_parameters.h
@@ -45,6 +45,7 @@
     bool downgrade;
     int target_sdk_version;
     const char* profile_name;
+    const char* dex_metadata_path;
 
     std::string target_slot;
 
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 052fcfc..ea52c0e 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -263,6 +263,7 @@
         bool downgrade = false;
         int32_t target_sdk_version = 0;  // default
         std::unique_ptr<std::string> profile_name_ptr = nullptr;
+        std::unique_ptr<std::string> dm_path_ptr = nullptr;
 
         binder::Status result = service_->dexopt(path,
                                                  uid,
@@ -277,7 +278,8 @@
                                                  se_info_ptr,
                                                  downgrade,
                                                  target_sdk_version,
-                                                 profile_name_ptr);
+                                                 profile_name_ptr,
+                                                 dm_path_ptr);
         ASSERT_EQ(should_binder_call_succeed, result.isOk());
         int expected_access = should_dex_be_compiled ? 0 : -1;
         std::string odex = GetSecondaryDexArtifact(path, "odex");
@@ -331,9 +333,10 @@
                              const char* oat_dir,
                              int32_t uid,
                              int32_t dexopt_needed,
+                             const char* dm_path = nullptr,
                              bool downgrade = false) {
         return CompilePrimaryDex(
-                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, true);
+                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, true);
     }
 
     void CompilePrimaryDexFail(std::string compiler_filter,
@@ -341,9 +344,10 @@
                                const char* oat_dir,
                                int32_t uid,
                                int32_t dexopt_needed,
+                               const char* dm_path = nullptr,
                                bool downgrade = false) {
         return CompilePrimaryDex(
-                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, false);
+                compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, dm_path, downgrade, false);
     }
 
     void CompilePrimaryDex(std::string compiler_filter,
@@ -351,6 +355,7 @@
                            const char* oat_dir,
                            int32_t uid,
                            int32_t dexopt_needed,
+                           const char* dm_path,
                            bool downgrade,
                            bool should_binder_call_succeed) {
         std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
@@ -360,6 +365,10 @@
         std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
         int32_t target_sdk_version = 0;  // default
         std::unique_ptr<std::string> profile_name_ptr(new std::string("primary.prof"));
+        std::unique_ptr<std::string> dm_path_ptr = nullptr;
+        if (dm_path != nullptr) {
+            dm_path_ptr.reset(new std::string(dm_path));
+        }
 
         bool prof_result;
         binder::Status prof_binder_result = service_->prepareAppProfile(
@@ -382,7 +391,8 @@
                                                  se_info_ptr,
                                                  downgrade,
                                                  target_sdk_version,
-                                                 profile_name_ptr);
+                                                 profile_name_ptr,
+                                                 dm_path_ptr);
         ASSERT_EQ(should_binder_call_succeed, result.isOk());
 
         if (!should_binder_call_succeed) {
diff --git a/cmds/installd/tests/installd_otapreopt_test.cpp b/cmds/installd/tests/installd_otapreopt_test.cpp
index 3bcc362..1e8ae42 100644
--- a/cmds/installd/tests/installd_otapreopt_test.cpp
+++ b/cmds/installd/tests/installd_otapreopt_test.cpp
@@ -85,6 +85,11 @@
         } else {
             ASSERT_STREQ(params.profile_name, "primary.prof");
         }
+        if (version > 5) {
+            ASSERT_STREQ(params.dex_metadata_path, ParseNull(args[i++]));
+        } else {
+            ASSERT_STREQ(params.dex_metadata_path, nullptr);
+        }
     }
 
     const char* getVersionCStr(uint32_t version) {
@@ -94,6 +99,7 @@
             case 3: return "3";
             case 4: return "4";
             case 5: return "5";
+            case 6: return "6";
         }
         return nullptr;
     }
@@ -129,6 +135,9 @@
         if (version > 4) {
             args.push_back("split_a.prof");  // profile_name
         }
+        if (version > 5) {
+            args.push_back("dex_metadata.dm");  // dex_metadata_path
+        }
         args.push_back(nullptr);  // we have to end with null.
         return args;
     }
@@ -165,6 +174,10 @@
     VerifyReadArguments(5, true);
 }
 
+TEST_F(OTAPreoptTest, ReadArgumentsV6) {
+    VerifyReadArguments(6, true);
+}
+
 TEST_F(OTAPreoptTest, ReadArgumentsFailToManyArgs) {
     OTAPreoptParameters params;
     std::vector<const char*> args = getArgs(5, true);