Loading cmds/installd/dexopt.cpp +12 −2 Original line number Diff line number Diff line Loading @@ -1290,7 +1290,7 @@ unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) { // Opens the reference profiles if needed. // Note that the reference profile might not exist so it's OK if the fd will be -1. Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname, const std::string& dex_path, const std::string& profile_name, bool profile_guided, const std::string& dex_path, const char* profile_name, bool profile_guided, bool is_public, int uid, bool is_secondary_dex) { // Public apps should not be compiled with profile information ever. Same goes for the special // package '*' used for the system server. Loading @@ -1299,7 +1299,17 @@ Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname, } // Open reference profile in read only mode as dex2oat does not get write permissions. const std::string location = is_secondary_dex ? dex_path : profile_name; std::string location; if (is_secondary_dex) { location = dex_path; } else { if (profile_name == nullptr) { // This path is taken for system server re-compilation lunched from ZygoteInit. return Dex2oatFileWrapper(); } else { location = profile_name; } } unique_fd ufd = open_reference_profile(uid, pkgname, location, /*read_write*/false, is_secondary_dex); const auto& cleanup = [pkgname, location, is_secondary_dex]() { Loading cmds/installd/tests/installd_dexopt_test.cpp +185 −9 Original line number Diff line number Diff line Loading @@ -159,6 +159,7 @@ protected: std::string app_private_dir_ce_; std::string app_private_dir_de_; std::string se_info_; std::string app_oat_dir_; int64_t ce_data_inode_; Loading Loading @@ -199,9 +200,9 @@ protected: void create_mock_app() { // Create the oat dir. std::string app_oat_dir = app_apk_dir_ + "/oat"; app_oat_dir_ = app_apk_dir_ + "/oat"; mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755); service_->createOatDir(app_oat_dir, kRuntimeIsa); service_->createOatDir(app_oat_dir_, kRuntimeIsa); // Copy the primary apk. apk_path_ = app_apk_dir_ + "/base.jar"; Loading Loading @@ -261,14 +262,8 @@ protected: 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")); std::unique_ptr<std::string> profile_name_ptr = nullptr; 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, Loading Loading @@ -330,6 +325,106 @@ protected: ASSERT_EQ(gid, st.st_gid); ASSERT_EQ(mode, st.st_mode); } void CompilePrimaryDexOk(std::string compiler_filter, int32_t dex_flags, const char* oat_dir, int32_t uid, int32_t dexopt_needed, bool downgrade = false) { return CompilePrimaryDex( compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, true); } void CompilePrimaryDexFail(std::string compiler_filter, int32_t dex_flags, const char* oat_dir, int32_t uid, int32_t dexopt_needed, bool downgrade = false) { return CompilePrimaryDex( compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, false); } void CompilePrimaryDex(std::string compiler_filter, int32_t dex_flags, const char* oat_dir, int32_t uid, int32_t dexopt_needed, bool downgrade, bool should_binder_call_succeed) { std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_)); std::unique_ptr<std::string> out_path( oat_dir == nullptr ? nullptr : new std::string(oat_dir)); std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&")); 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")); 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(apk_path_, uid, package_name_ptr, kRuntimeIsa, dexopt_needed, out_path, dex_flags, compiler_filter, volume_uuid_, class_loader_context_ptr, se_info_ptr, downgrade, target_sdk_version, profile_name_ptr); ASSERT_EQ(should_binder_call_succeed, result.isOk()); if (!should_binder_call_succeed) { return; } // 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 vdex = GetPrimaryDexArtifact(oat_dir, apk_path_, "vdex"); std::string art = GetPrimaryDexArtifact(oat_dir, apk_path_, "art"); mode_t mode = S_IFREG | (compiler_filter == "speed-profile" ? 0640 : 0644); CheckFileAccess(odex, kSystemUid, uid, mode); CheckFileAccess(vdex, kSystemUid, uid, mode); CheckFileAccess(odex, kSystemUid, uid, mode); // empty profiles do not generate an image. // todo: add tests with non-empty profiles. struct stat st; ASSERT_EQ(-1, stat(art.c_str(), &st)); } std::string GetPrimaryDexArtifact(const char* oat_dir, const std::string& dex_path, const std::string& type) { if (oat_dir == nullptr) { std::string path = dex_path; for (auto it = path.begin() + 1; it < path.end(); ++it) { if (*it == '/') { *it = '@'; } } return android_data_dir + DALVIK_CACHE + '/' + kRuntimeIsa + "/" + path + "@classes.dex"; } else { std::string::size_type name_end = dex_path.rfind('.'); std::string::size_type name_start = dex_path.rfind('/'); return std::string(oat_dir) + "/" + kRuntimeIsa + "/" + dex_path.substr(name_start + 1, name_end - name_start) + type; } } }; Loading Loading @@ -376,6 +471,87 @@ TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) { /*binder_ok*/ false, /*compile_ok*/ false, kSystemUid); } TEST_F(DexoptTest, DexoptPrimaryPublic) { LOG(INFO) << "DexoptPrimaryPublic"; CompilePrimaryDexOk("verify", DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) { LOG(INFO) << "DexoptPrimaryProfileNonPublic"; CompilePrimaryDexOk("speed-profile", DEXOPT_BOOTCOMPLETE, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryProfilePublic) { LOG(INFO) << "DexoptPrimaryProfilePublic"; CompilePrimaryDexOk("verify", DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryBackgroundOk) { LOG(INFO) << "DexoptPrimaryBackgroundOk"; CompilePrimaryDexOk("speed-profile", DEXOPT_IDLE_BACKGROUND_JOB, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) { LOG(INFO) << "DexoptPrimaryFailedInvalidFilter"; CompilePrimaryDexFail("awesome-filter", DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } class PrimaryDexReCompilationTest : public DexoptTest { public: virtual void SetUp() { DexoptTest::SetUp(); CompilePrimaryDexOk("verify", DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); std::string odex = GetSecondaryDexArtifact(apk_path_, "odex"); std::string vdex = GetSecondaryDexArtifact(apk_path_, "vdex"); first_compilation_odex_fd_.reset(open(odex.c_str(), O_RDONLY)); first_compilation_vdex_fd_.reset(open(vdex.c_str(), O_RDONLY)); } virtual void TearDown() { first_compilation_odex_fd_.reset(-1); first_compilation_vdex_fd_.reset(-1); DexoptTest::TearDown(); } protected: unique_fd first_compilation_odex_fd_; unique_fd first_compilation_vdex_fd_; }; TEST_F(PrimaryDexReCompilationTest, DexoptPrimaryUpdateInPlaceVdex) { LOG(INFO) << "DexoptPrimaryUpdateInPlaceVdex"; CompilePrimaryDexOk("verify", DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FOR_BOOT_IMAGE); } class ReconcileTest : public DexoptTest { virtual void SetUp() { Loading Loading
cmds/installd/dexopt.cpp +12 −2 Original line number Diff line number Diff line Loading @@ -1290,7 +1290,7 @@ unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) { // Opens the reference profiles if needed. // Note that the reference profile might not exist so it's OK if the fd will be -1. Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname, const std::string& dex_path, const std::string& profile_name, bool profile_guided, const std::string& dex_path, const char* profile_name, bool profile_guided, bool is_public, int uid, bool is_secondary_dex) { // Public apps should not be compiled with profile information ever. Same goes for the special // package '*' used for the system server. Loading @@ -1299,7 +1299,17 @@ Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname, } // Open reference profile in read only mode as dex2oat does not get write permissions. const std::string location = is_secondary_dex ? dex_path : profile_name; std::string location; if (is_secondary_dex) { location = dex_path; } else { if (profile_name == nullptr) { // This path is taken for system server re-compilation lunched from ZygoteInit. return Dex2oatFileWrapper(); } else { location = profile_name; } } unique_fd ufd = open_reference_profile(uid, pkgname, location, /*read_write*/false, is_secondary_dex); const auto& cleanup = [pkgname, location, is_secondary_dex]() { Loading
cmds/installd/tests/installd_dexopt_test.cpp +185 −9 Original line number Diff line number Diff line Loading @@ -159,6 +159,7 @@ protected: std::string app_private_dir_ce_; std::string app_private_dir_de_; std::string se_info_; std::string app_oat_dir_; int64_t ce_data_inode_; Loading Loading @@ -199,9 +200,9 @@ protected: void create_mock_app() { // Create the oat dir. std::string app_oat_dir = app_apk_dir_ + "/oat"; app_oat_dir_ = app_apk_dir_ + "/oat"; mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755); service_->createOatDir(app_oat_dir, kRuntimeIsa); service_->createOatDir(app_oat_dir_, kRuntimeIsa); // Copy the primary apk. apk_path_ = app_apk_dir_ + "/base.jar"; Loading Loading @@ -261,14 +262,8 @@ protected: 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")); std::unique_ptr<std::string> profile_name_ptr = nullptr; 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, Loading Loading @@ -330,6 +325,106 @@ protected: ASSERT_EQ(gid, st.st_gid); ASSERT_EQ(mode, st.st_mode); } void CompilePrimaryDexOk(std::string compiler_filter, int32_t dex_flags, const char* oat_dir, int32_t uid, int32_t dexopt_needed, bool downgrade = false) { return CompilePrimaryDex( compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, true); } void CompilePrimaryDexFail(std::string compiler_filter, int32_t dex_flags, const char* oat_dir, int32_t uid, int32_t dexopt_needed, bool downgrade = false) { return CompilePrimaryDex( compiler_filter, dex_flags, oat_dir, uid, dexopt_needed, downgrade, false); } void CompilePrimaryDex(std::string compiler_filter, int32_t dex_flags, const char* oat_dir, int32_t uid, int32_t dexopt_needed, bool downgrade, bool should_binder_call_succeed) { std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_)); std::unique_ptr<std::string> out_path( oat_dir == nullptr ? nullptr : new std::string(oat_dir)); std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&")); 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")); 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(apk_path_, uid, package_name_ptr, kRuntimeIsa, dexopt_needed, out_path, dex_flags, compiler_filter, volume_uuid_, class_loader_context_ptr, se_info_ptr, downgrade, target_sdk_version, profile_name_ptr); ASSERT_EQ(should_binder_call_succeed, result.isOk()); if (!should_binder_call_succeed) { return; } // 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 vdex = GetPrimaryDexArtifact(oat_dir, apk_path_, "vdex"); std::string art = GetPrimaryDexArtifact(oat_dir, apk_path_, "art"); mode_t mode = S_IFREG | (compiler_filter == "speed-profile" ? 0640 : 0644); CheckFileAccess(odex, kSystemUid, uid, mode); CheckFileAccess(vdex, kSystemUid, uid, mode); CheckFileAccess(odex, kSystemUid, uid, mode); // empty profiles do not generate an image. // todo: add tests with non-empty profiles. struct stat st; ASSERT_EQ(-1, stat(art.c_str(), &st)); } std::string GetPrimaryDexArtifact(const char* oat_dir, const std::string& dex_path, const std::string& type) { if (oat_dir == nullptr) { std::string path = dex_path; for (auto it = path.begin() + 1; it < path.end(); ++it) { if (*it == '/') { *it = '@'; } } return android_data_dir + DALVIK_CACHE + '/' + kRuntimeIsa + "/" + path + "@classes.dex"; } else { std::string::size_type name_end = dex_path.rfind('.'); std::string::size_type name_start = dex_path.rfind('/'); return std::string(oat_dir) + "/" + kRuntimeIsa + "/" + dex_path.substr(name_start + 1, name_end - name_start) + type; } } }; Loading Loading @@ -376,6 +471,87 @@ TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) { /*binder_ok*/ false, /*compile_ok*/ false, kSystemUid); } TEST_F(DexoptTest, DexoptPrimaryPublic) { LOG(INFO) << "DexoptPrimaryPublic"; CompilePrimaryDexOk("verify", DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) { LOG(INFO) << "DexoptPrimaryProfileNonPublic"; CompilePrimaryDexOk("speed-profile", DEXOPT_BOOTCOMPLETE, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryProfilePublic) { LOG(INFO) << "DexoptPrimaryProfilePublic"; CompilePrimaryDexOk("verify", DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryBackgroundOk) { LOG(INFO) << "DexoptPrimaryBackgroundOk"; CompilePrimaryDexOk("speed-profile", DEXOPT_IDLE_BACKGROUND_JOB, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) { LOG(INFO) << "DexoptPrimaryFailedInvalidFilter"; CompilePrimaryDexFail("awesome-filter", DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); } class PrimaryDexReCompilationTest : public DexoptTest { public: virtual void SetUp() { DexoptTest::SetUp(); CompilePrimaryDexOk("verify", DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FROM_SCRATCH); std::string odex = GetSecondaryDexArtifact(apk_path_, "odex"); std::string vdex = GetSecondaryDexArtifact(apk_path_, "vdex"); first_compilation_odex_fd_.reset(open(odex.c_str(), O_RDONLY)); first_compilation_vdex_fd_.reset(open(vdex.c_str(), O_RDONLY)); } virtual void TearDown() { first_compilation_odex_fd_.reset(-1); first_compilation_vdex_fd_.reset(-1); DexoptTest::TearDown(); } protected: unique_fd first_compilation_odex_fd_; unique_fd first_compilation_vdex_fd_; }; TEST_F(PrimaryDexReCompilationTest, DexoptPrimaryUpdateInPlaceVdex) { LOG(INFO) << "DexoptPrimaryUpdateInPlaceVdex"; CompilePrimaryDexOk("verify", DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC, app_oat_dir_.c_str(), kTestAppGid, DEX2OAT_FOR_BOOT_IMAGE); } class ReconcileTest : public DexoptTest { virtual void SetUp() { Loading