Installd: don't generate app image without reference profile

Use app images only if we are compiling profile-guided
and reference profile exists.

Fixed test logic to use a dm_file so that the profile is actually
opened by dexopt.cpp.

Test: adb install xxx.apk & check if app image file exists
Bug: 112860306
Change-Id: I50375a9d9213ee1e7b1fffbdd69c8510f509e008
Signed-off-by: liulvping <liulvping@xiaomi.com>
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index a5cc0df..214c665 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -2117,14 +2117,20 @@
     // Create a swap file if necessary.
     unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
 
-    // Create the app image file if needed.
-    Dex2oatFileWrapper image_fd = maybe_open_app_image(
-            out_oat_path, generate_app_image, is_public, uid, is_secondary_dex);
-
     // Open the reference profile if needed.
     Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
             pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex);
 
+    if (reference_profile_fd.get() == -1) {
+        // We don't create an app image without reference profile since there is no speedup from
+        // loading it in that case and instead will be a small overhead.
+        generate_app_image = false;
+    }
+
+    // Create the app image file if needed.
+    Dex2oatFileWrapper image_fd = maybe_open_app_image(
+            out_oat_path, generate_app_image, 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)));
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index aa79fdc..bd45005 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -89,6 +89,8 @@
         "libinstalld",
         "liblog",
         "liblogwrap",
+        "libziparchive",
+        "libz",
     ],
     test_config: "installd_dexopt_test.xml",
 }
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index fa2b0d9..13fd067 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -41,6 +41,7 @@
 #include "globals.h"
 #include "tests/test_utils.h"
 #include "utils.h"
+#include "ziparchive/zip_writer.h"
 
 using android::base::ReadFully;
 using android::base::unique_fd;
@@ -195,6 +196,7 @@
     std::unique_ptr<std::string> volume_uuid_;
     std::string package_name_;
     std::string apk_path_;
+    std::string empty_dm_file_;
     std::string app_apk_dir_;
     std::string app_private_dir_ce_;
     std::string app_private_dir_de_;
@@ -260,6 +262,26 @@
                                                  << " : " << error_msg;
         }
 
+        // Create an empty dm file.
+        empty_dm_file_ = apk_path_ + ".dm";
+        {
+            int fd = open(empty_dm_file_.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+            if (fd < 0) {
+                return ::testing::AssertionFailure() << "Could not open " << empty_dm_file_;
+            }
+            FILE* file = fdopen(fd, "wb");
+            if (file == nullptr) {
+                return ::testing::AssertionFailure() << "Null file for " << empty_dm_file_
+                         << " fd=" << fd;
+            }
+            ZipWriter writer(file);
+            // Add vdex to zip.
+            writer.StartEntry("primary.prof", ZipWriter::kCompress);
+            writer.FinishEntry();
+            writer.Finish();
+            close(fd);
+          }
+
         // Create the app user data.
         status = service_->createAppData(
                 volume_uuid_,
@@ -479,7 +501,7 @@
         bool prof_result;
         ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
                 package_name_, kTestUserId, kTestAppId, *profile_name_ptr, apk_path_,
-                /*dex_metadata*/ nullptr, &prof_result));
+                dm_path_ptr, &prof_result));
         ASSERT_TRUE(prof_result);
 
         binder::Status result = service_->dexopt(apk_path_,
@@ -645,7 +667,9 @@
                         DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_GENERATE_APP_IMAGE,
                         app_oat_dir_.c_str(),
                         kTestAppGid,
-                        DEX2OAT_FROM_SCRATCH);
+                        DEX2OAT_FROM_SCRATCH,
+                        /*binder_result=*/nullptr,
+                        empty_dm_file_.c_str());
 }
 
 TEST_F(DexoptTest, DexoptPrimaryProfilePublic) {
@@ -655,7 +679,9 @@
                                 DEXOPT_GENERATE_APP_IMAGE,
                         app_oat_dir_.c_str(),
                         kTestAppGid,
-                        DEX2OAT_FROM_SCRATCH);
+                        DEX2OAT_FROM_SCRATCH,
+                        /*binder_result=*/nullptr,
+                        empty_dm_file_.c_str());
 }
 
 TEST_F(DexoptTest, DexoptPrimaryBackgroundOk) {
@@ -665,7 +691,9 @@
                                 DEXOPT_GENERATE_APP_IMAGE,
                         app_oat_dir_.c_str(),
                         kTestAppGid,
-                        DEX2OAT_FROM_SCRATCH);
+                        DEX2OAT_FROM_SCRATCH,
+                        /*binder_result=*/nullptr,
+                        empty_dm_file_.c_str());
 }
 
 TEST_F(DexoptTest, ResolveStartupConstStrings) {
@@ -684,7 +712,9 @@
                                 DEXOPT_GENERATE_APP_IMAGE,
                         app_oat_dir_.c_str(),
                         kTestAppGid,
-                        DEX2OAT_FROM_SCRATCH);
+                        DEX2OAT_FROM_SCRATCH,
+                        /*binder_result=*/nullptr,
+                        empty_dm_file_.c_str());
     run_cmd_and_process_output(
             "oatdump --header-only --oat-file=" + odex,
             [&](const std::string& line) {
@@ -701,7 +731,9 @@
                                 DEXOPT_GENERATE_APP_IMAGE,
                         app_oat_dir_.c_str(),
                         kTestAppGid,
-                        DEX2OAT_FROM_SCRATCH);
+                        DEX2OAT_FROM_SCRATCH,
+                        /*binder_result=*/nullptr,
+                        empty_dm_file_.c_str());
     run_cmd_and_process_output(
             "oatdump --header-only --oat-file=" + odex,
             [&](const std::string& line) {