Add copy system profile functionality
Test: Flash preopted speed-profile maps.
Test: Confirm ref profile exists.
Test: Close maps, recompile with speed-profile, test the profile was used.
Test: Launch maps, do some stuff until cur profile exists.
Test: Re-compile with speed-profile and confirm cur merged over ref correctly.
Bug: 38032017
Change-Id: I19c8009ad61213bdcb52f010329eb459ca82f92b
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 19dfb87..eac2564 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1779,6 +1779,16 @@
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) {
+ 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);
+ return ok();
+}
+
// TODO: Consider returning error codes.
binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
bool* _aidl_return) {
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 200fc77..a94223c 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -91,6 +91,8 @@
binder::Status mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return);
binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
const std::string& codePaths, 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);
binder::Status destroyAppProfiles(const std::string& packageName);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 6b99c1d..efcae4f 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -57,6 +57,8 @@
boolean mergeProfiles(int uid, @utf8InCpp String packageName);
boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String codePaths);
+ boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
+ @utf8InCpp String packageName);
void clearAppProfiles(@utf8InCpp String packageName);
void destroyAppProfiles(@utf8InCpp String packageName);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index bb499e6..dd66b81 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -847,6 +847,66 @@
return true;
}
+bool copy_system_profile(const std::string& system_profile,
+ uid_t packageUid, const std::string& data_profile_location) {
+ unique_fd in_fd(open(system_profile.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+ unique_fd out_fd(open_reference_profile(packageUid,
+ data_profile_location,
+ /*read_write*/ true,
+ /*secondary*/ false));
+ if (in_fd.get() < 0) {
+ PLOG(WARNING) << "Could not open profile " << system_profile;
+ return false;
+ }
+ if (out_fd.get() < 0) {
+ PLOG(WARNING) << "Could not open profile " << data_profile_location;
+ return false;
+ }
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ drop_capabilities(packageUid);
+
+ if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
+ if (errno != EWOULDBLOCK) {
+ PLOG(WARNING) << "Error locking profile " << data_profile_location;
+ }
+ // This implies that the app owning this profile is running
+ // (and has acquired the lock).
+ //
+ // The app never acquires the lock for the reference profiles of primary apks.
+ // Only dex2oat from installd will do that. Since installd is single threaded
+ // we should not see this case. Nevertheless be prepared for it.
+ PLOG(WARNING) << "Failed to flock " << data_profile_location;
+ return false;
+ }
+
+ bool truncated = ftruncate(out_fd.get(), 0) == 0;
+ if (!truncated) {
+ PLOG(WARNING) << "Could not truncate " << data_profile_location;
+ }
+
+ // Copy over data.
+ static constexpr size_t kBufferSize = 4 * 1024;
+ char buffer[kBufferSize];
+ while (true) {
+ ssize_t bytes = read(in_fd.get(), buffer, kBufferSize);
+ if (bytes == 0) {
+ break;
+ }
+ write(out_fd.get(), buffer, bytes);
+ }
+ if (flock(out_fd.get(), LOCK_UN) != 0) {
+ PLOG(WARNING) << "Error unlocking profile " << data_profile_location;
+ }
+ exit(0);
+ }
+ /* parent */
+ int return_code = wait_child(pid);
+ return return_code == 0;
+}
+
static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) {
// A standard dalvik-cache entry. Replace ".dex" with `new_ext`.
if (EndsWith(oat_path, ".dex")) {
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index cb8aaeb..d171ee5 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -50,6 +50,10 @@
bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
+bool copy_system_profile(const std::string& system_profile,
+ uid_t packageUid,
+ const std::string& data_profile_location);
+
bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
bool reconcile_secondary_dex_file(const std::string& dex_path,