Merge "[installd] Extend profile operations to take the profile name"
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 950c9a0..e4f8f04 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -107,10 +107,6 @@
 
 constexpr const char* kDump = "android.permission.DUMP";
 
-// TODO(calin): We can stop hardcoding this here once the PM passes the profile
-// name for all profile related operations.
-constexpr const char* kPrimaryProfileName = "primary.prof";
-
 static binder::Status ok() {
     return binder::Status::ok();
 }
@@ -389,14 +385,6 @@
         return false;
     }
 
-    const std::string profile_file = create_current_profile_path(userId, packageName,
-            kPrimaryProfileName, /*is_secondary_dex*/false);
-    // read-write only for the app user.
-    if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
-        PLOG(ERROR) << "Failed to prepare " << profile_file;
-        return false;
-    }
-
     const std::string ref_profile_path =
             create_primary_reference_profile_package_dir_path(packageName);
 
@@ -545,16 +533,17 @@
 }
 
 
-binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName) {
+binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName,
+        const std::string& profileName) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     binder::Status res = ok();
-    if (!clear_primary_reference_profile(packageName, kPrimaryProfileName)) {
+    if (!clear_primary_reference_profile(packageName, profileName)) {
         res = error("Failed to clear reference profile for " + packageName);
     }
-    if (!clear_primary_current_profiles(packageName, kPrimaryProfileName)) {
+    if (!clear_primary_current_profiles(packageName, profileName)) {
         res = error("Failed to clear current profiles for " + packageName);
     }
     return res;
@@ -604,11 +593,6 @@
                 res = error("Failed to delete contents of " + path);
             }
         }
-        if (!only_cache) {
-            if (!clear_primary_current_profile(packageName, kPrimaryProfileName, userId)) {
-                res = error("Failed to clear current profile for " + packageName);
-            }
-        }
     }
     return res;
 }
@@ -1856,37 +1840,34 @@
 // Dumps the contents of a profile file, using pkgname's dex files for pretty
 // printing the result.
 binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
-        const std::string& codePaths, bool* _aidl_return) {
+        const std::string& profileName, const std::string& codePath, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    const char* pkgname = packageName.c_str();
-    const char* code_paths = codePaths.c_str();
-
-    *_aidl_return = dump_profiles(uid, pkgname, code_paths);
+    *_aidl_return = dump_profiles(uid, packageName, profileName, codePath);
     return ok();
 }
 
 // Copy the contents of a system profile over the data profile.
 binder::Status InstalldNativeService::copySystemProfile(const std::string& systemProfile,
-        int32_t packageUid, const std::string& packageName, bool* _aidl_return) {
+        int32_t packageUid, const std::string& packageName, const std::string& profileName,
+        bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
-    *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName,
-            kPrimaryProfileName);
+    *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName, profileName);
     return ok();
 }
 
 // TODO: Consider returning error codes.
 binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
-        bool* _aidl_return) {
+        const std::string& profileName, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    *_aidl_return = analyze_primary_profiles(uid, packageName, kPrimaryProfileName);
+    *_aidl_return = analyze_primary_profiles(uid, packageName, profileName);
     return ok();
 }
 
@@ -1918,7 +1899,8 @@
         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>& seInfo, bool downgrade, int32_t targetSdkVersion,
+        const std::unique_ptr<std::string>& profileName) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     if (packageName && *packageName != "*") {
@@ -1934,10 +1916,10 @@
     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;
     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, kPrimaryProfileName);
+            downgrade, targetSdkVersion, profile_name);
     return res ? error(res, "Failed to dexopt") : ok();
 }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 7bd9c21..ce5c1a0 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -85,22 +85,24 @@
             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);
+            int32_t targetSdkVersion, const std::unique_ptr<std::string>& profileName);
 
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
-    binder::Status mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return);
+    binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
+            const std::string& profileName, bool* _aidl_return);
     binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
-            const std::string& codePaths, bool* _aidl_return);
+            const std::string& profileName, const std::string& codePath, bool* _aidl_return);
     binder::Status copySystemProfile(const std::string& systemProfile,
-            int32_t uid, const std::string& packageName, bool* _aidl_return);
-    binder::Status clearAppProfiles(const std::string& packageName);
+            int32_t uid, const std::string& packageName, const std::string& profileName,
+            bool* _aidl_return);
+    binder::Status clearAppProfiles(const std::string& packageName, const std::string& profileName);
     binder::Status destroyAppProfiles(const std::string& packageName);
 
     binder::Status createProfileSnapshot(int32_t appId, const std::string& packageName,
-            const std::string& codePath, bool* _aidl_return);
+            const std::string& profileName, bool* _aidl_return);
     binder::Status destroyProfileSnapshot(const std::string& packageName,
-            const std::string& codePath);
+            const std::string& profileName);
 
     binder::Status idmap(const std::string& targetApkPath, const std::string& overlayApkPath,
             int32_t uid);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index ba7efd0..d457a2a 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -51,20 +51,22 @@
             @nullable @utf8InCpp String outputPath, int dexFlags,
             @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
             @nullable @utf8InCpp String sharedLibraries,
-            @nullable @utf8InCpp String seInfo, boolean downgrade, int targetSdkVersion);
+            @nullable @utf8InCpp String seInfo, boolean downgrade, int targetSdkVersion,
+            @nullable @utf8InCpp String profileName);
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
-    boolean mergeProfiles(int uid, @utf8InCpp String packageName);
-    boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String codePaths);
+    boolean mergeProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String profileName);
+    boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String  profileName,
+            @utf8InCpp String codePath);
     boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
-            @utf8InCpp String packageName);
-    void clearAppProfiles(@utf8InCpp String packageName);
+            @utf8InCpp String packageName, @utf8InCpp String profileName);
+    void clearAppProfiles(@utf8InCpp String packageName, @utf8InCpp String profileName);
     void destroyAppProfiles(@utf8InCpp String packageName);
 
     boolean createProfileSnapshot(int appId, @utf8InCpp String packageName,
-            @utf8InCpp String codePath);
-    void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String codePath);
+            @utf8InCpp String profileName);
+    void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String profileName);
 
     void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
     void removeIdmap(@utf8InCpp String overlayApkPath);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 0c836e8..0549a46 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -876,13 +876,14 @@
     exit(68);   /* only get here on exec failure */
 }
 
-bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths) {
+bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
+        const std::string& code_path) {
     std::vector<unique_fd> profile_fds;
     unique_fd reference_profile_fd;
-    std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname.c_str());
+    std::string out_file_name = StringPrintf("/data/misc/profman/%s-%s.txt",
+        pkgname.c_str(), profile_name.c_str());
 
-    // TODO(calin): get the profile name as a parameter.
-    open_profile_files(uid, pkgname, "primary.prof", /*is_secondary_dex*/false,
+    open_profile_files(uid, pkgname, profile_name, /*is_secondary_dex*/false,
             &profile_fds, &reference_profile_fd);
 
     const bool has_reference_profile = (reference_profile_fd.get() != -1);
@@ -896,22 +897,20 @@
     unique_fd output_fd(open(out_file_name.c_str(),
             O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0644));
     if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
-        ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str());
+        LOG(ERROR) << "installd cannot chmod file for dump_profile" << out_file_name;
         return false;
     }
-    std::vector<std::string> code_full_paths = base::Split(code_paths, ";");
+
     std::vector<std::string> dex_locations;
     std::vector<unique_fd> apk_fds;
-    for (const std::string& code_full_path : code_full_paths) {
-        const char* full_path = code_full_path.c_str();
-        unique_fd apk_fd(open(full_path, O_RDONLY | O_NOFOLLOW));
-        if (apk_fd == -1) {
-            ALOGE("installd cannot open '%s'\n", full_path);
-            return false;
-        }
-        dex_locations.push_back(get_location_from_path(full_path));
-        apk_fds.push_back(std::move(apk_fd));
+    unique_fd apk_fd(open(code_path.c_str(), O_RDONLY | O_NOFOLLOW));
+    if (apk_fd == -1) {
+        PLOG(ERROR) << "installd cannot open " << code_path.c_str();
+        return false;
     }
+    dex_locations.push_back(get_location_from_path(code_path.c_str()));
+    apk_fds.push_back(std::move(apk_fd));
+
 
     pid_t pid = fork();
     if (pid == 0) {
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 29312d2..b96351b 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -63,7 +63,10 @@
 bool create_profile_snapshot(int32_t app_id, const std::string& package,
         const std::string& profile_name);
 
-bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
+bool dump_profiles(int32_t uid,
+                   const std::string& pkgname,
+                   const std::string& profile_name,
+                   const std::string& code_path);
 
 bool copy_system_profile(const std::string& system_profile,
                          uid_t packageUid,
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 3e5e832..74dca72 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -181,6 +181,7 @@
         const char* se_info;
         bool downgrade;
         int target_sdk_version;
+        const char* profile_name;
     };
 
     bool ReadSystemProperties() {
@@ -363,6 +364,8 @@
                 return ReadArgumentsV3(argc, argv);
             case 4:
                 return ReadArgumentsV4(argc, argv);
+            case 5:
+                return ReadArgumentsV5(argc, argv);
 
             default:
                 LOG(ERROR) << "Unsupported version " << version;
@@ -449,6 +452,9 @@
         // conservative and may force some classes to verify at runtime.
         package_parameters_.target_sdk_version = 0;
 
+        // Set the profile name to the primary apk profile.
+        package_parameters_.profile_name = "primary.prof";
+
         if (param_index != 11) {
             LOG(ERROR) << "Not enough parameters";
             return false;
@@ -536,6 +542,9 @@
         // conservative and may force some classes to verify at runtime.
         package_parameters_.target_sdk_version = 0;
 
+        // Set the profile name to the primary apk profile.
+        package_parameters_.profile_name = "primary.prof";
+
         if (param_index != 12) {
             LOG(ERROR) << "Not enough parameters";
             return false;
@@ -623,6 +632,9 @@
             }
         }
 
+        // Set the profile name to the primary apk profile.
+        package_parameters_.profile_name = "primary.prof";
+
         if (param_index != 13) {
             LOG(ERROR) << "Not enough parameters";
             return false;
@@ -631,6 +643,99 @@
         return true;
     }
 
+    // TODO: this pattern does not scale and result in a lot of code duplication.
+    // Either find a better pattern or refactor the code to eliminate the duplication.
+    bool ReadArgumentsV5(int argc ATTRIBUTE_UNUSED, char** argv) {
+        size_t dexopt_index = 3;
+
+        // Check for "dexopt".
+        if (argv[dexopt_index] == nullptr) {
+            LOG(ERROR) << "Missing parameters";
+            return false;
+        }
+        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
+            LOG(ERROR) << "Expected \"dexopt\"";
+            return false;
+        }
+
+        size_t param_index = 0;
+        for (;; ++param_index) {
+            const char* param = argv[dexopt_index + 1 + param_index];
+            if (param == nullptr) {
+                break;
+            }
+
+            switch (param_index) {
+                case 0:
+                    package_parameters_.apk_path = param;
+                    break;
+
+                case 1:
+                    package_parameters_.uid = atoi(param);
+                    break;
+
+                case 2:
+                    package_parameters_.pkgName = param;
+                    break;
+
+                case 3:
+                    package_parameters_.instruction_set = param;
+                    break;
+
+                case 4:
+                    package_parameters_.dexopt_needed = atoi(param);
+                    break;
+
+                case 5:
+                    package_parameters_.oat_dir = param;
+                    break;
+
+                case 6:
+                    package_parameters_.dexopt_flags = atoi(param);
+                    break;
+
+                case 7:
+                    package_parameters_.compiler_filter = param;
+                    break;
+
+                case 8:
+                    package_parameters_.volume_uuid = ParseNull(param);
+                    break;
+
+                case 9:
+                    package_parameters_.shared_libraries = ParseNull(param);
+                    break;
+
+                case 10:
+                    package_parameters_.se_info = ParseNull(param);
+                    break;
+
+                case 11:
+                    package_parameters_.downgrade = ParseBool(param);
+                    break;
+
+                case 12:
+                    package_parameters_.target_sdk_version = atoi(param);
+                    break;
+
+                case 13:
+                    package_parameters_.profile_name = ParseNull(param);
+                    break;
+
+                default:
+                    LOG(ERROR) << "Too many arguments, got " << param;
+                    return false;
+            }
+        }
+
+        if (param_index != 14) {
+            LOG(ERROR) << "Not enough parameters";
+            return false;
+        }
+
+        return true;
+    }
+
     static int ReplaceMask(int input, int old_mask, int new_mask) {
         return (input & old_mask) != 0 ? new_mask : 0;
     }
@@ -738,6 +843,9 @@
         // conservative and may force some classes to verify at runtime.
         package_parameters_.target_sdk_version = 0;
 
+        // Set the profile name to the primary apk profile.
+        package_parameters_.profile_name = "primary.prof";
+
         return true;
     }
 
@@ -1028,7 +1136,7 @@
                       package_parameters_.se_info,
                       package_parameters_.downgrade,
                       package_parameters_.target_sdk_version,
-                      "primary.prof");
+                      package_parameters_.profile_name);
     }
 
     int RunPreopt() {
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 4d6d234..8113542 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -259,7 +259,14 @@
         std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
         bool downgrade = false;
         int32_t target_sdk_version = 0;  // default
+        std::unique_ptr<std::string> profile_name_ptr(new std::string("primary.prof"));
 
+        bool prof_result;
+        binder::Status prof_binder_result = service_->prepareAppProfile(
+                package_name_, kTestUserId, kTestAppId, *profile_name_ptr, /*code path*/ "base.apk",
+                /*dex_metadata*/ nullptr, &prof_result);
+        ASSERT_TRUE(prof_binder_result.isOk());
+        ASSERT_TRUE(prof_result);
         binder::Status result = service_->dexopt(path,
                                                  uid,
                                                  package_name_ptr,
@@ -272,7 +279,8 @@
                                                  class_loader_context_ptr,
                                                  se_info_ptr,
                                                  downgrade,
-                                                 target_sdk_version);
+                                                 target_sdk_version,
+                                                 profile_name_ptr);
         ASSERT_EQ(should_binder_call_succeed, result.isOk());
         int expected_access = should_dex_be_compiled ? 0 : -1;
         std::string odex = GetSecondaryDexArtifact(path, "odex");
@@ -498,10 +506,12 @@
         ASSERT_TRUE(WIFEXITED(wait_child(pid)));
     }
 
-    void mergePackageProfiles(const std::string& package_name, bool expected_result) {
+    void mergePackageProfiles(const std::string& package_name,
+                              const std::string& code_path,
+                              bool expected_result) {
         bool result;
         binder::Status binder_result = service_->mergeProfiles(
-                kTestAppUid, package_name, &result);
+                kTestAppUid, package_name, code_path, &result);
         ASSERT_TRUE(binder_result.isOk());
         ASSERT_EQ(expected_result, result);
 
@@ -628,7 +638,7 @@
     LOG(INFO) << "ProfileMergeOk";
 
     SetupProfiles(/*setup_ref*/ true);
-    mergePackageProfiles(package_name_, /*expected_result*/ true);
+    mergePackageProfiles(package_name_, "primary.prof", /*expected_result*/ true);
 }
 
 // The reference profile is created on the fly. We need to be able to
@@ -637,14 +647,14 @@
     LOG(INFO) << "ProfileMergeOkNoReference";
 
     SetupProfiles(/*setup_ref*/ false);
-    mergePackageProfiles(package_name_, /*expected_result*/ true);
+    mergePackageProfiles(package_name_, "primary.prof", /*expected_result*/ true);
 }
 
 TEST_F(ProfileTest, ProfileMergeFailWrongPackage) {
     LOG(INFO) << "ProfileMergeFailWrongPackage";
 
     SetupProfiles(/*setup_ref*/ true);
-    mergePackageProfiles("not.there", /*expected_result*/ false);
+    mergePackageProfiles("not.there", "primary.prof", /*expected_result*/ false);
 }
 
 TEST_F(ProfileTest, ProfileDirOk) {
@@ -657,7 +667,6 @@
     std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_);
 
     CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
-    CheckFileAccess(cur_profile_file, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
     CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
 }
 
@@ -689,7 +698,6 @@
 
     // Check the file access.
     CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
-    CheckFileAccess(cur_profile_file, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
     CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
 }