Return the freed bytes from deleteOdex API
This will help quantify the number of bytes we free for
telemetry purposes.
Test: installd_tests
Bug: 187458876
Change-Id: I29f7974977a58decf784bda443715f8b11fdf7c1
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 9dbafcd..a176df9 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -2654,7 +2654,8 @@
}
binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
- const std::string& instructionSet, const std::optional<std::string>& outputPath) {
+ const std::string& instructionSet, const std::optional<std::string>& outputPath,
+ int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PATH(apkPath);
CHECK_ARGUMENT_PATH(outputPath);
@@ -2664,8 +2665,8 @@
const char* instruction_set = instructionSet.c_str();
const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
- bool res = delete_odex(apk_path, instruction_set, oat_dir);
- return res ? ok() : error();
+ *_aidl_return = delete_odex(apk_path, instruction_set, oat_dir);
+ return *_aidl_return == -1 ? error() : ok();
}
// This kernel feature is experimental.
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 2aa36f6..3127be6 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -147,7 +147,7 @@
binder::Status moveAb(const std::string& apkPath, const std::string& instructionSet,
const std::string& outputPath);
binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
- const std::optional<std::string>& outputPath);
+ const std::optional<std::string>& outputPath, int64_t* _aidl_return);
binder::Status installApkVerity(const std::string& filePath,
android::base::unique_fd verityInput, int32_t contentSize);
binder::Status assertFsverityRootHashMatches(const std::string& filePath,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index aa2c1f4..816e508 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -93,7 +93,7 @@
@utf8InCpp String toBase);
void moveAb(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
@utf8InCpp String outputPath);
- void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
+ long deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
@nullable @utf8InCpp String outputPath);
void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput,
int contentSize);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index c9e8398..15f0c5b 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -2252,38 +2252,52 @@
return success;
}
-bool delete_odex(const char* apk_path, const char* instruction_set, const char* oat_dir) {
+int64_t delete_odex(const char* apk_path, const char* instruction_set, const char* oat_dir) {
// Delete the oat/odex file.
char out_path[PKG_PATH_MAX];
if (!create_oat_out_path(apk_path, instruction_set, oat_dir,
/*is_secondary_dex*/false, out_path)) {
- return false;
+ LOG(ERROR) << "Cannot create apk path for " << apk_path;
+ return -1;
}
// In case of a permission failure report the issue. Otherwise just print a warning.
- auto unlink_and_check = [](const char* path) -> bool {
- int result = unlink(path);
- if (result != 0) {
- if (errno == EACCES || errno == EPERM) {
- PLOG(ERROR) << "Could not unlink " << path;
- return false;
+ auto unlink_and_check = [](const char* path) -> int64_t {
+ struct stat file_stat;
+ if (stat(path, &file_stat) != 0) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "Could not stat " << path;
+ return -1;
}
- PLOG(WARNING) << "Could not unlink " << path;
+ return 0;
}
- return true;
+
+ if (unlink(path) != 0) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "Could not unlink " << path;
+ return -1;
+ }
+ }
+ return static_cast<int64_t>(file_stat.st_size);
};
// Delete the oat/odex file.
- bool return_value_oat = unlink_and_check(out_path);
+ int64_t return_value_oat = unlink_and_check(out_path);
// Derive and delete the app image.
- bool return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
+ int64_t return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
// Derive and delete the vdex file.
- bool return_value_vdex = unlink_and_check(create_vdex_filename(out_path).c_str());
+ int64_t return_value_vdex = unlink_and_check(create_vdex_filename(out_path).c_str());
- // Report success.
- return return_value_oat && return_value_art && return_value_vdex;
+ // Report result
+ if (return_value_oat == -1
+ || return_value_art == -1
+ || return_value_vdex == -1) {
+ return -1;
+ }
+
+ return return_value_oat + return_value_art + return_value_vdex;
}
static bool is_absolute_path(const std::string& path) {
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index cdeadf1..5a637b1 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -109,7 +109,8 @@
const std::string& code_path,
const std::optional<std::string>& dex_metadata);
-bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
+// Returns the total bytes that were freed, or -1 in case of errors.
+int64_t delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
bool reconcile_secondary_dex_file(const std::string& dex_path,
const std::string& pkgname, int uid, const std::vector<std::string>& isas,
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 2ee06fa..7e7e513 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -518,7 +518,8 @@
// Check the access to the compiler output.
// - speed-profile artifacts are not world-wide readable.
// - files are owned by the system uid.
- std::string odex = GetPrimaryDexArtifact(oat_dir, apk_path_, "odex");
+ std::string odex = GetPrimaryDexArtifact(oat_dir, apk_path_,
+ oat_dir == nullptr ? "dex" : "odex");
std::string vdex = GetPrimaryDexArtifact(oat_dir, apk_path_, "vdex");
std::string art = GetPrimaryDexArtifact(oat_dir, apk_path_, "art");
@@ -546,7 +547,7 @@
}
}
return android_data_dir + DALVIK_CACHE + '/' + kRuntimeIsa + "/" + path
- + "@classes.dex";
+ + "@classes." + type;
} else {
std::string::size_type name_end = dex_path.rfind('.');
std::string::size_type name_start = dex_path.rfind('/');
@@ -554,6 +555,53 @@
dex_path.substr(name_start + 1, name_end - name_start) + type;
}
}
+
+ int64_t GetSize(const std::string& path) {
+ struct stat file_stat;
+ if (stat(path.c_str(), &file_stat) == 0) {
+ return static_cast<int64_t>(file_stat.st_size);
+ }
+ PLOG(ERROR) << "Cannot stat path: " << path;
+ return -1;
+ }
+
+ void TestDeleteOdex(bool in_dalvik_cache) {
+ const char* oat_dir = in_dalvik_cache ? nullptr : app_oat_dir_.c_str();
+ CompilePrimaryDexOk(
+ "speed-profile",
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_PUBLIC
+ | DEXOPT_GENERATE_APP_IMAGE,
+ oat_dir,
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH,
+ /*binder_result=*/nullptr,
+ empty_dm_file_.c_str());
+
+
+ int64_t odex_size = GetSize(GetPrimaryDexArtifact(oat_dir, apk_path_,
+ in_dalvik_cache ? "dex" : "odex"));
+ int64_t vdex_size = GetSize(GetPrimaryDexArtifact(oat_dir, apk_path_, "vdex"));
+ int64_t art_size = GetSize(GetPrimaryDexArtifact(oat_dir, apk_path_, "art"));
+
+ LOG(ERROR) << "test odex " << odex_size;
+ LOG(ERROR) << "test vdex_size " << vdex_size;
+ LOG(ERROR) << "test art_size " << art_size;
+ int64_t expected_bytes_freed = odex_size + vdex_size + art_size;
+
+ int64_t bytes_freed;
+ binder::Status result = service_->deleteOdex(
+ apk_path_,
+ kRuntimeIsa,
+ in_dalvik_cache ? std::nullopt : std::make_optional<std::string>(app_oat_dir_.c_str()),
+ &bytes_freed);
+ ASSERT_TRUE(result.isOk()) << result.toString8().c_str();
+
+ ASSERT_GE(odex_size, 0);
+ ASSERT_GE(vdex_size, 0);
+ ASSERT_GE(art_size, 0);
+
+ ASSERT_EQ(expected_bytes_freed, bytes_freed);
+ }
};
@@ -702,6 +750,16 @@
empty_dm_file_.c_str());
}
+TEST_F(DexoptTest, DeleteDexoptArtifactsData) {
+ LOG(INFO) << "DeleteDexoptArtifactsData";
+ TestDeleteOdex(/*in_dalvik_cache=*/ false);
+}
+
+TEST_F(DexoptTest, DeleteDexoptArtifactsDalvikCache) {
+ LOG(INFO) << "DeleteDexoptArtifactsDalvikCache";
+ TestDeleteOdex(/*in_dalvik_cache=*/ true);
+}
+
TEST_F(DexoptTest, ResolveStartupConstStrings) {
LOG(INFO) << "DexoptDex2oatResolveStartupStrings";
const std::string property = "persist.device_config.runtime.dex2oat_resolve_startup_strings";