diff options
author | 2022-11-08 13:17:50 +0000 | |
---|---|---|
committer | 2022-11-11 15:10:59 +0000 | |
commit | bfd155dcf0a8f77cb3f7eb26fc237e644117ce3f (patch) | |
tree | bd1195d0c0580ad6863d91bd68f26bd6498b381f | |
parent | 548c910df68afc83a508921c34666f4c1ce78302 (diff) |
Always pass --dm-fd to dex2oat and change reason to "install-dm".
Bug: 255944781
Test: atest ArtServiceTests
Test: m test-art-host-gtest-art_artd_tests
Ignore-AOSP-First: ART Services.
Change-Id: Ibb8ffd6da39186cb571dbd9e59847bc2161ebd15
16 files changed, 339 insertions, 229 deletions
diff --git a/artd/artd.cc b/artd/artd.cc index 32c89c3532..2e86b38b53 100644 --- a/artd/artd.cc +++ b/artd/artd.cc @@ -74,6 +74,7 @@ namespace artd { namespace { using ::aidl::com::android::server::art::ArtifactsPath; +using ::aidl::com::android::server::art::DexMetadataPath; using ::aidl::com::android::server::art::DexoptOptions; using ::aidl::com::android::server::art::DexoptResult; using ::aidl::com::android::server::art::DexoptTrigger; @@ -550,6 +551,13 @@ ndk::ScopedAStatus Artd::getDexFileVisibility(const std::string& in_dexFile, return ScopedAStatus::ok(); } +ndk::ScopedAStatus Artd::getDmFileVisibility(const DexMetadataPath& in_dmFile, + FileVisibility* _aidl_return) { + std::string dm_path = OR_RETURN_FATAL(BuildDexMetadataPath(in_dmFile)); + *_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(dm_path)); + return ScopedAStatus::ok(); +} + ndk::ScopedAStatus Artd::mergeProfiles(const std::vector<ProfilePath>& in_profiles, const std::optional<ProfilePath>& in_referenceProfile, OutputProfile* in_outputProfile, @@ -691,6 +699,7 @@ ndk::ScopedAStatus Artd::dexopt( const std::string& in_compilerFilter, const std::optional<ProfilePath>& in_profile, const std::optional<VdexPath>& in_inputVdex, + const std::optional<DexMetadataPath>& in_dmFile, PriorityClass in_priorityClass, const DexoptOptions& in_dexoptOptions, const std::shared_ptr<IArtdCancellationSignal>& in_cancellationSignal, @@ -783,18 +792,20 @@ ndk::ScopedAStatus Artd::dexopt( std::unique_ptr<File> input_vdex_file = nullptr; if (in_inputVdex.has_value()) { - if (in_inputVdex->getTag() == VdexPath::dexMetadataPath) { - std::string input_vdex_path = OR_RETURN_FATAL(BuildDexMetadataPath(in_inputVdex.value())); - input_vdex_file = OR_RETURN_NON_FATAL(OpenFileForReading(input_vdex_path)); - args.Add("--dm-fd=%d", input_vdex_file->Fd()); - } else { - std::string input_vdex_path = OR_RETURN_FATAL(BuildVdexPath(in_inputVdex.value())); - input_vdex_file = OR_RETURN_NON_FATAL(OpenFileForReading(input_vdex_path)); - args.Add("--input-vdex-fd=%d", input_vdex_file->Fd()); - } + std::string input_vdex_path = OR_RETURN_FATAL(BuildVdexPath(in_inputVdex.value())); + input_vdex_file = OR_RETURN_NON_FATAL(OpenFileForReading(input_vdex_path)); + args.Add("--input-vdex-fd=%d", input_vdex_file->Fd()); fd_logger.Add(*input_vdex_file); } + std::unique_ptr<File> dm_file = nullptr; + if (in_dmFile.has_value()) { + std::string dm_path = OR_RETURN_FATAL(BuildDexMetadataPath(in_dmFile.value())); + dm_file = OR_RETURN_NON_FATAL(OpenFileForReading(dm_path)); + args.Add("--dm-fd=%d", dm_file->Fd()); + fd_logger.Add(*dm_file); + } + std::unique_ptr<File> profile_file = nullptr; if (profile_path.has_value()) { profile_file = OR_RETURN_NON_FATAL(OpenFileForReading(profile_path.value())); diff --git a/artd/artd.h b/artd/artd.h index 1230ee8ba8..b729c78c60 100644 --- a/artd/artd.h +++ b/artd/artd.h @@ -120,6 +120,10 @@ class Artd : public aidl::com::android::server::art::BnArtd { const std::string& in_dexFile, aidl::com::android::server::art::FileVisibility* _aidl_return) override; + ndk::ScopedAStatus getDmFileVisibility( + const aidl::com::android::server::art::DexMetadataPath& in_dmFile, + aidl::com::android::server::art::FileVisibility* _aidl_return) override; + ndk::ScopedAStatus getDexoptNeeded( const std::string& in_dexFile, const std::string& in_instructionSet, @@ -136,6 +140,7 @@ class Artd : public aidl::com::android::server::art::BnArtd { const std::string& in_compilerFilter, const std::optional<aidl::com::android::server::art::ProfilePath>& in_profile, const std::optional<aidl::com::android::server::art::VdexPath>& in_inputVdex, + const std::optional<aidl::com::android::server::art::DexMetadataPath>& in_dmFile, aidl::com::android::server::art::PriorityClass in_priorityClass, const aidl::com::android::server::art::DexoptOptions& in_dexoptOptions, const std::shared_ptr<aidl::com::android::server::art::IArtdCancellationSignal>& diff --git a/artd/artd_test.cc b/artd/artd_test.cc index 68d23db615..a2ba7f5113 100644 --- a/artd/artd_test.cc +++ b/artd/artd_test.cc @@ -299,6 +299,8 @@ class ArtdTest : public CommonArtTest { PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "primary"}, .id = "12345"}; profile_path_ = tmp_profile_path; + vdex_path_ = artifacts_path_; + dm_path_ = DexMetadataPath{.dexPath = dex_file_}; std::filesystem::create_directories( std::filesystem::path(OR_FATAL(BuildFinalProfilePath(tmp_profile_path))).parent_path()); } @@ -311,7 +313,7 @@ class ArtdTest : public CommonArtTest { void RunDexopt(binder_exception_t expected_status = EX_NONE, Matcher<DexoptResult> aidl_return_matcher = Field(&DexoptResult::cancelled, false), std::shared_ptr<IArtdCancellationSignal> cancellation_signal = nullptr) { - InitDexoptInputFiles(); + InitFilesBeforeDexopt(); if (cancellation_signal == nullptr) { ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk()); } @@ -323,6 +325,7 @@ class ArtdTest : public CommonArtTest { compiler_filter_, profile_path_, vdex_path_, + dm_path_, priority_class_, dexopt_options_, cancellation_signal, @@ -360,23 +363,32 @@ class ArtdTest : public CommonArtTest { std::optional<std::string> class_loader_context_; std::string compiler_filter_; std::optional<VdexPath> vdex_path_; + std::optional<DexMetadataPath> dm_path_; PriorityClass priority_class_ = PriorityClass::BACKGROUND; DexoptOptions dexopt_options_; std::optional<ProfilePath> profile_path_; private: - void InitDexoptInputFiles() { + void InitFilesBeforeDexopt() { + // Required files. CreateFile(dex_file_); + + // Optional files. if (vdex_path_.has_value()) { - if (vdex_path_->getTag() == VdexPath::dexMetadataPath) { - CreateFile(OR_FATAL(BuildDexMetadataPath(vdex_path_.value()))); - } else { - CreateFile(OR_FATAL(BuildVdexPath(vdex_path_.value()))); - } + CreateFile(OR_FATAL(BuildVdexPath(vdex_path_.value())), "old_vdex"); + } + if (dm_path_.has_value()) { + CreateFile(OR_FATAL(BuildDexMetadataPath(dm_path_.value()))); } if (profile_path_.has_value()) { CreateFile(OR_FATAL(BuildProfileOrDmPath(profile_path_.value()))); } + + // Files to be replaced. + std::string oat_path = OR_FATAL(BuildOatPath(artifacts_path_)); + CreateFile(oat_path, "old_oat"); + CreateFile(OatPathToVdexPath(oat_path), "old_vdex"); + CreateFile(OatPathToArtPath(oat_path), "old_art"); } }; @@ -485,16 +497,18 @@ TEST_F(ArtdTest, dexopt) { WhenSplitBy( "--", AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")), - AllOf(Contains(art_root_ + "/bin/dex2oat32"), - Contains(Flag("--zip-fd=", FdOf(dex_file_))), - Contains(Flag("--zip-location=", dex_file_)), - Contains(Flag("--oat-location=", scratch_path_ + "/a/oat/arm64/b.odex")), - Contains(Flag("--instruction-set=", "arm64")), - Contains(Flag("--compiler-filter=", "speed")), - Contains( - Flag("--profile-file-fd=", - FdOf(android_data_ + - "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"))))), + AllOf( + Contains(art_root_ + "/bin/dex2oat32"), + Contains(Flag("--zip-fd=", FdOf(dex_file_))), + Contains(Flag("--zip-location=", dex_file_)), + Contains(Flag("--oat-location=", scratch_path_ + "/a/oat/arm64/b.odex")), + Contains(Flag("--instruction-set=", "arm64")), + Contains(Flag("--compiler-filter=", "speed")), + Contains(Flag("--profile-file-fd=", + FdOf(android_data_ + + "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"))), + Contains(Flag("--input-vdex-fd=", FdOf(scratch_path_ + "/a/oat/arm64/b.vdex"))), + Contains(Flag("--dm-fd=", FdOf(scratch_path_ + "/a/b.dm"))))), _, _)) .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")), @@ -542,47 +556,23 @@ TEST_F(ArtdTest, dexoptClassLoaderContextNull) { RunDexopt(); } -TEST_F(ArtdTest, dexoptNoInputVdex) { +TEST_F(ArtdTest, dexoptNoOptionalInputFiles) { + profile_path_ = std::nullopt; + vdex_path_ = std::nullopt; + dm_path_ = std::nullopt; + EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(WhenSplitBy("--", _, - AllOf(Not(Contains(Flag("--dm-fd=", _))), - Not(Contains(Flag("--input-vdex-fd=", _))))), + AllOf(Not(Contains(Flag("--profile-file-fd=", _))), + Not(Contains(Flag("--input-vdex-fd=", _))), + Not(Contains(Flag("--dm-fd=", _))))), _, _)) .WillOnce(Return(0)); RunDexopt(); } -TEST_F(ArtdTest, dexoptInputVdex) { - vdex_path_ = artifacts_path_; - EXPECT_CALL(*mock_exec_utils_, - DoExecAndReturnCode( - WhenSplitBy("--", - _, - AllOf(Not(Contains(Flag("--dm-fd=", _))), - Contains(Flag("--input-vdex-fd=", - FdOf(scratch_path_ + "/a/oat/arm64/b.vdex"))))), - _, - _)) - .WillOnce(Return(0)); - RunDexopt(); -} - -TEST_F(ArtdTest, dexoptInputVdexDm) { - vdex_path_ = DexMetadataPath{.dexPath = dex_file_}; - EXPECT_CALL(*mock_exec_utils_, - DoExecAndReturnCode( - WhenSplitBy("--", - _, - AllOf(Contains(Flag("--dm-fd=", FdOf(scratch_path_ + "/a/b.dm"))), - Not(Contains(Flag("--input-vdex-fd=", _))))), - _, - _)) - .WillOnce(Return(0)); - RunDexopt(); -} - TEST_F(ArtdTest, dexoptPriorityClassBoot) { priority_class_ = PriorityClass::BOOT; EXPECT_CALL(*mock_exec_utils_, @@ -873,15 +863,15 @@ TEST_F(ArtdTest, dexoptAllResourceControlBackground) { TEST_F(ArtdTest, dexoptFailed) { dexopt_options_.generateAppImage = true; EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)) - .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")), - WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")), - WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")), + .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")), + WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")), + WithArg<0>(WriteToFdFlag("--app-image-fd=", "new_art")), Return(1))); RunDexopt(EX_SERVICE_SPECIFIC); - EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.odex")); - EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.vdex")); - EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.art")); + CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat"); + CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex"); + CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art"); } TEST_F(ArtdTest, dexoptCancelledBeforeDex2oat) { @@ -902,8 +892,9 @@ TEST_F(ArtdTest, dexoptCancelledBeforeDex2oat) { RunDexopt(EX_NONE, Field(&DexoptResult::cancelled, true), cancellation_signal); - EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.odex")); - EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.vdex")); + CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat"); + CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex"); + CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art"); } TEST_F(ArtdTest, dexoptCancelledDuringDex2oat) { @@ -948,8 +939,9 @@ TEST_F(ArtdTest, dexoptCancelledDuringDex2oat) { t.join(); // Step 6. - EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.odex")); - EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.vdex")); + CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat"); + CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex"); + CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art"); } TEST_F(ArtdTest, dexoptCancelledAfterDex2oat) { @@ -959,11 +951,13 @@ TEST_F(ArtdTest, dexoptCancelledAfterDex2oat) { constexpr pid_t kPid = 123; EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)) - .WillOnce([&](auto, const ExecCallbacks& callbacks, auto) { - callbacks.on_start(kPid); - callbacks.on_end(kPid); - return 0; - }); + .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")), + WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")), + [&](auto, const ExecCallbacks& callbacks, auto) { + callbacks.on_start(kPid); + callbacks.on_end(kPid); + return 0; + })); EXPECT_CALL(mock_kill_, Call).Times(0); RunDexopt(EX_NONE, Field(&DexoptResult::cancelled, false), cancellation_signal); @@ -971,8 +965,9 @@ TEST_F(ArtdTest, dexoptCancelledAfterDex2oat) { // This signal should be ignored. cancellation_signal->cancel(); - EXPECT_TRUE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.odex")); - EXPECT_TRUE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.vdex")); + CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "new_oat"); + CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "new_vdex"); + EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.art")); } TEST_F(ArtdTest, isProfileUsable) { @@ -1158,128 +1153,138 @@ TEST_F(ArtdTest, deleteProfileFailed) { EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk()); } -TEST_F(ArtdTest, getProfileVisibilityOtherReadable) { - std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value())); - CreateFile(profile_file); - std::filesystem::permissions( - profile_file, std::filesystem::perms::others_read, std::filesystem::perm_options::add); - - FileVisibility result; - ASSERT_TRUE(artd_->getProfileVisibility(profile_path_.value(), &result).isOk()); - EXPECT_EQ(result, FileVisibility::OTHER_READABLE); -} +class ArtdGetVisibilityTest : public ArtdTest { + protected: + template <typename PathType> + using Method = ndk::ScopedAStatus (Artd::*)(const PathType&, FileVisibility*); + + template <typename PathType> + void TestGetVisibilityOtherReadable(Method<PathType> method, + const PathType& input, + const std::string& path) { + CreateFile(path); + std::filesystem::permissions( + path, std::filesystem::perms::others_read, std::filesystem::perm_options::add); + + FileVisibility result; + ASSERT_TRUE(((*artd_).*method)(input, &result).isOk()); + EXPECT_EQ(result, FileVisibility::OTHER_READABLE); + } -TEST_F(ArtdTest, getProfileVisibilityNotOtherReadable) { - std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value())); - CreateFile(profile_file); - std::filesystem::permissions( - profile_file, std::filesystem::perms::others_read, std::filesystem::perm_options::remove); + template <typename PathType> + void TestGetVisibilityNotOtherReadable(Method<PathType> method, + const PathType& input, + const std::string& path) { + CreateFile(path); + std::filesystem::permissions( + path, std::filesystem::perms::others_read, std::filesystem::perm_options::remove); + + FileVisibility result; + ASSERT_TRUE(((*artd_).*method)(input, &result).isOk()); + EXPECT_EQ(result, FileVisibility::NOT_OTHER_READABLE); + } - FileVisibility result; - ASSERT_TRUE(artd_->getProfileVisibility(profile_path_.value(), &result).isOk()); - EXPECT_EQ(result, FileVisibility::NOT_OTHER_READABLE); -} + template <typename PathType> + void TestGetVisibilityNotFound(Method<PathType> method, const PathType& input) { + FileVisibility result; + ASSERT_TRUE(((*artd_).*method)(input, &result).isOk()); + EXPECT_EQ(result, FileVisibility::NOT_FOUND); + } -TEST_F(ArtdTest, getProfileVisibilityNotFound) { - FileVisibility result; - ASSERT_TRUE(artd_->getProfileVisibility(profile_path_.value(), &result).isOk()); - EXPECT_EQ(result, FileVisibility::NOT_FOUND); -} + template <typename PathType> + void TestGetVisibilityPermissionDenied(Method<PathType> method, + const PathType& input, + const std::string& path) { + CreateFile(path); -TEST_F(ArtdTest, getProfileVisibilityPermissionDenied) { - std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value())); - CreateFile(profile_file); + auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(path).parent_path()); + auto scoped_unroot = ScopedUnroot(); - auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(profile_file).parent_path()); - auto scoped_unroot = ScopedUnroot(); + FileVisibility result; + ndk::ScopedAStatus status = ((*artd_).*method)(input, &result); + EXPECT_FALSE(status.isOk()); + EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC); + EXPECT_THAT(status.getMessage(), HasSubstr("Failed to get status of")); + } +}; - FileVisibility result; - ndk::ScopedAStatus status = artd_->getProfileVisibility(profile_path_.value(), &result); - EXPECT_FALSE(status.isOk()); - EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC); - EXPECT_THAT(status.getMessage(), - ContainsRegex(R"re(Failed to get status of .*primary\.prof\.12345\.tmp)re")); +TEST_F(ArtdGetVisibilityTest, getProfileVisibilityOtherReadable) { + TestGetVisibilityOtherReadable(&Artd::getProfileVisibility, + profile_path_.value(), + OR_FATAL(BuildProfileOrDmPath(profile_path_.value()))); } -TEST_F(ArtdTest, getArtifactsVisibilityOtherReadable) { - std::string oat_file = OR_FATAL(BuildOatPath(artifacts_path_)); - CreateFile(oat_file); - std::filesystem::permissions( - oat_file, std::filesystem::perms::others_read, std::filesystem::perm_options::add); - - FileVisibility result; - ASSERT_TRUE(artd_->getArtifactsVisibility(artifacts_path_, &result).isOk()); - EXPECT_EQ(result, FileVisibility::OTHER_READABLE); +TEST_F(ArtdGetVisibilityTest, getProfileVisibilityNotOtherReadable) { + TestGetVisibilityNotOtherReadable(&Artd::getProfileVisibility, + profile_path_.value(), + OR_FATAL(BuildProfileOrDmPath(profile_path_.value()))); } -TEST_F(ArtdTest, getArtifactsVisibilityNotOtherReadable) { - std::string oat_file = OR_FATAL(BuildOatPath(artifacts_path_)); - CreateFile(oat_file); - std::filesystem::permissions( - oat_file, std::filesystem::perms::others_read, std::filesystem::perm_options::remove); +TEST_F(ArtdGetVisibilityTest, getProfileVisibilityNotFound) { + TestGetVisibilityNotFound(&Artd::getProfileVisibility, profile_path_.value()); +} - FileVisibility result; - ASSERT_TRUE(artd_->getArtifactsVisibility(artifacts_path_, &result).isOk()); - EXPECT_EQ(result, FileVisibility::NOT_OTHER_READABLE); +TEST_F(ArtdGetVisibilityTest, getProfileVisibilityPermissionDenied) { + TestGetVisibilityPermissionDenied(&Artd::getProfileVisibility, + profile_path_.value(), + OR_FATAL(BuildProfileOrDmPath(profile_path_.value()))); } -TEST_F(ArtdTest, getArtifactsVisibilityNotFound) { - FileVisibility result; - ASSERT_TRUE(artd_->getArtifactsVisibility(artifacts_path_, &result).isOk()); - EXPECT_EQ(result, FileVisibility::NOT_FOUND); +TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityOtherReadable) { + TestGetVisibilityOtherReadable( + &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_))); } -TEST_F(ArtdTest, getArtifactsVisibilityPermissionDenied) { - std::string oat_file = OR_FATAL(BuildOatPath(artifacts_path_)); - CreateFile(oat_file); +TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotOtherReadable) { + TestGetVisibilityNotOtherReadable( + &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_))); +} - auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(oat_file).parent_path()); - auto scoped_unroot = ScopedUnroot(); +TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotFound) { + TestGetVisibilityNotFound(&Artd::getArtifactsVisibility, artifacts_path_); +} - FileVisibility result; - ndk::ScopedAStatus status = artd_->getArtifactsVisibility(artifacts_path_, &result); - EXPECT_FALSE(status.isOk()); - EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC); - EXPECT_THAT(status.getMessage(), ContainsRegex(R"re(Failed to get status of .*b\.odex)re")); +TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityPermissionDenied) { + TestGetVisibilityPermissionDenied( + &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_))); } -TEST_F(ArtdTest, getDexFileVisibilityOtherReadable) { - CreateFile(dex_file_); - std::filesystem::permissions( - dex_file_, std::filesystem::perms::others_read, std::filesystem::perm_options::add); +TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityOtherReadable) { + TestGetVisibilityOtherReadable(&Artd::getDexFileVisibility, dex_file_, dex_file_); +} - FileVisibility result; - ASSERT_TRUE(artd_->getDexFileVisibility(dex_file_, &result).isOk()); - EXPECT_EQ(result, FileVisibility::OTHER_READABLE); +TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityNotOtherReadable) { + TestGetVisibilityNotOtherReadable(&Artd::getDexFileVisibility, dex_file_, dex_file_); } -TEST_F(ArtdTest, getDexFileVisibilityNotOtherReadable) { - CreateFile(dex_file_); - std::filesystem::permissions( - dex_file_, std::filesystem::perms::others_read, std::filesystem::perm_options::remove); +TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityNotFound) { + TestGetVisibilityNotFound(&Artd::getDexFileVisibility, dex_file_); +} - FileVisibility result; - ASSERT_TRUE(artd_->getDexFileVisibility(dex_file_, &result).isOk()); - EXPECT_EQ(result, FileVisibility::NOT_OTHER_READABLE); +TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityPermissionDenied) { + TestGetVisibilityPermissionDenied(&Artd::getDexFileVisibility, dex_file_, dex_file_); } -TEST_F(ArtdTest, getDexFileVisibilityNotFound) { - FileVisibility result; - ASSERT_TRUE(artd_->getDexFileVisibility(dex_file_, &result).isOk()); - EXPECT_EQ(result, FileVisibility::NOT_FOUND); +TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityOtherReadable) { + TestGetVisibilityOtherReadable(&Artd::getDmFileVisibility, + dm_path_.value(), + OR_FATAL(BuildDexMetadataPath(dm_path_.value()))); } -TEST_F(ArtdTest, getDexFileVisibilityPermissionDenied) { - CreateFile(dex_file_); +TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityNotOtherReadable) { + TestGetVisibilityNotOtherReadable(&Artd::getDmFileVisibility, + dm_path_.value(), + OR_FATAL(BuildDexMetadataPath(dm_path_.value()))); +} - auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(dex_file_).parent_path()); - auto scoped_unroot = ScopedUnroot(); +TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityNotFound) { + TestGetVisibilityNotFound(&Artd::getDmFileVisibility, dm_path_.value()); +} - FileVisibility result; - ndk::ScopedAStatus status = artd_->getDexFileVisibility(dex_file_, &result); - EXPECT_FALSE(status.isOk()); - EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC); - EXPECT_THAT(status.getMessage(), ContainsRegex(R"re(Failed to get status of .*/a/b\.apk)re")); +TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityPermissionDenied) { + TestGetVisibilityPermissionDenied(&Artd::getDmFileVisibility, + dm_path_.value(), + OR_FATAL(BuildDexMetadataPath(dm_path_.value()))); } TEST_F(ArtdTest, mergeProfiles) { diff --git a/artd/binder/com/android/server/art/IArtd.aidl b/artd/binder/com/android/server/art/IArtd.aidl index d575adfdb3..19c1d66c1b 100644 --- a/artd/binder/com/android/server/art/IArtd.aidl +++ b/artd/binder/com/android/server/art/IArtd.aidl @@ -110,6 +110,14 @@ interface IArtd { com.android.server.art.FileVisibility getDexFileVisibility(@utf8InCpp String dexFile); /** + * Returns the visibility of the DM file. + * + * Throws fatal and non-fatal errors. + */ + com.android.server.art.FileVisibility getDmFileVisibility( + in com.android.server.art.DexMetadataPath dmFile); + + /** * Returns true if dexopt is needed. `dexoptTrigger` is a bit field that consists of values * defined in `com.android.server.art.DexoptTrigger`. * @@ -131,6 +139,7 @@ interface IArtd { @nullable @utf8InCpp String classLoaderContext, @utf8InCpp String compilerFilter, in @nullable com.android.server.art.ProfilePath profile, in @nullable com.android.server.art.VdexPath inputVdex, + in @nullable com.android.server.art.DexMetadataPath dmFile, com.android.server.art.PriorityClass priorityClass, in com.android.server.art.DexoptOptions dexoptOptions, in com.android.server.art.IArtdCancellationSignal cancellationSignal); diff --git a/artd/binder/com/android/server/art/VdexPath.aidl b/artd/binder/com/android/server/art/VdexPath.aidl index ec23a0ea54..6112e7a490 100644 --- a/artd/binder/com/android/server/art/VdexPath.aidl +++ b/artd/binder/com/android/server/art/VdexPath.aidl @@ -24,6 +24,4 @@ package com.android.server.art; union VdexPath { /** Represents a VDEX file as part of the artifacts. */ com.android.server.art.ArtifactsPath artifactsPath; - /** Represents a VDEX file in a dex metadata file. */ - com.android.server.art.DexMetadataPath dexMetadataPath; } diff --git a/artd/path_utils.cc b/artd/path_utils.cc index 8dcc1e9607..295b023923 100644 --- a/artd/path_utils.cc +++ b/artd/path_utils.cc @@ -210,11 +210,6 @@ Result<std::string> BuildDexMetadataPath(const DexMetadataPath& dex_metadata_pat return ReplaceFileExtension(dex_metadata_path.dexPath, "dm"); } -Result<std::string> BuildDexMetadataPath(const VdexPath& vdex_path) { - DCHECK(vdex_path.getTag() == VdexPath::dexMetadataPath); - return BuildDexMetadataPath(vdex_path.get<VdexPath::dexMetadataPath>()); -} - Result<std::string> BuildProfileOrDmPath(const ProfilePath& profile_path) { switch (profile_path.getTag()) { case ProfilePath::primaryRefProfilePath: diff --git a/artd/path_utils.h b/artd/path_utils.h index bfbbd80664..0cc017ea83 100644 --- a/artd/path_utils.h +++ b/artd/path_utils.h @@ -70,9 +70,6 @@ android::base::Result<std::string> BuildTmpProfilePath( android::base::Result<std::string> BuildDexMetadataPath( const aidl::com::android::server::art::DexMetadataPath& dex_metadata_path); -android::base::Result<std::string> BuildDexMetadataPath( - const aidl::com::android::server::art::VdexPath& vdex_path); - android::base::Result<std::string> BuildProfileOrDmPath( const aidl::com::android::server::art::ProfilePath& profile_path); diff --git a/artd/path_utils_test.cc b/artd/path_utils_test.cc index 508d8c2b73..b0e1a257a0 100644 --- a/artd/path_utils_test.cc +++ b/artd/path_utils_test.cc @@ -241,11 +241,6 @@ TEST_F(PathUtilsTest, BuildDexMetadataPath) { EXPECT_THAT(BuildDexMetadataPath(DexMetadataPath{.dexPath = "/a/b.apk"}), HasValue("/a/b.dm")); } -TEST_F(PathUtilsTest, BuildDexMetadataPathForVdex) { - EXPECT_THAT(BuildDexMetadataPath(VdexPath(DexMetadataPath{.dexPath = "/a/b.apk"})), - HasValue("/a/b.dm")); -} - TEST_F(PathUtilsTest, BuildProfilePath) { EXPECT_THAT(BuildProfileOrDmPath(PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "primary"}), diff --git a/libartservice/service/java/com/android/server/art/DexOptimizer.java b/libartservice/service/java/com/android/server/art/DexOptimizer.java index 8cfe8ad506..356d74beec 100644 --- a/libartservice/service/java/com/android/server/art/DexOptimizer.java +++ b/libartservice/service/java/com/android/server/art/DexOptimizer.java @@ -148,13 +148,13 @@ public abstract class DexOptimizer<DexInfoType extends DetailedDexInfo> { long wallTimeMs = 0; long cpuTimeMs = 0; try { - DexoptTarget target = DexoptTarget.builder() + var target = DexoptTarget.<DexInfoType>builder() .setDexInfo(dexInfo) .setIsa(abi.isa()) .setIsInDalvikCache(isInDalvikCache()) .setCompilerFilter(compilerFilter) .build(); - GetDexoptNeededOptions options = + var options = GetDexoptNeededOptions.builder() .setProfileMerged(profileMerged) .setFlags(mParams.getFlags()) @@ -346,7 +346,7 @@ public abstract class DexOptimizer<DexInfoType extends DetailedDexInfo> { } @NonNull - GetDexoptNeededResult getDexoptNeeded(@NonNull DexoptTarget target, + GetDexoptNeededResult getDexoptNeeded(@NonNull DexoptTarget<DexInfoType> target, @NonNull GetDexoptNeededOptions options) throws RemoteException { int dexoptTrigger = getDexoptTrigger(target, options); @@ -362,8 +362,8 @@ public abstract class DexOptimizer<DexInfoType extends DetailedDexInfo> { return result; } - int getDexoptTrigger(@NonNull DexoptTarget target, @NonNull GetDexoptNeededOptions options) - throws RemoteException { + int getDexoptTrigger(@NonNull DexoptTarget<DexInfoType> target, + @NonNull GetDexoptNeededOptions options) throws RemoteException { if ((options.flags() & ArtFlags.FLAG_FORCE) != 0) { return DexoptTrigger.COMPILER_FILTER_IS_BETTER | DexoptTrigger.COMPILER_FILTER_IS_SAME | DexoptTrigger.COMPILER_FILTER_IS_WORSE @@ -396,8 +396,8 @@ public abstract class DexOptimizer<DexInfoType extends DetailedDexInfo> { return dexoptTrigger; } - private DexoptResult dexoptFile(@NonNull DexoptTarget target, @Nullable ProfilePath profile, - @NonNull GetDexoptNeededResult getDexoptNeededResult, + private DexoptResult dexoptFile(@NonNull DexoptTarget<DexInfoType> target, + @Nullable ProfilePath profile, @NonNull GetDexoptNeededResult getDexoptNeededResult, @NonNull PermissionSettings permissionSettings, @PriorityClass int priorityClass, @NonNull DexoptOptions dexoptOptions, IArtdCancellationSignal artdCancellationSignal) throws RemoteException { @@ -407,9 +407,25 @@ public abstract class DexOptimizer<DexInfoType extends DetailedDexInfo> { VdexPath inputVdex = getInputVdex(getDexoptNeededResult, target.dexInfo().dexPath(), target.isa()); + DexMetadataPath dmFile = getDmFile(target.dexInfo()); + if (dmFile != null + && ReasonMapping.REASONS_FOR_INSTALL.contains(dexoptOptions.compilationReason)) { + // If the DM file is passed to dex2oat, then add the "-dm" suffix to the reason (e.g., + // "install-dm"). + // Note that this only applies to reasons for app install because the goal is to give + // Play a signal that a DM file is downloaded at install time. We actually pass the DM + // file regardless of the compilation reason, but we don't append a suffix when the + // compilation reason is not a reason for app install. + // Also note that the "-dm" suffix does NOT imply anything in the DM file being used by + // dex2oat. dex2oat may ignore some contents of the DM file when appropriate. The + // compilation reason can still be "install-dm" even if dex2oat left all contents of the + // DM file unused or an empty DM file is passed to dex2oat. + dexoptOptions.compilationReason = dexoptOptions.compilationReason + "-dm"; + } + return mInjector.getArtd().dexopt(outputArtifacts, target.dexInfo().dexPath(), target.isa(), target.dexInfo().classLoaderContext(), target.compilerFilter(), profile, inputVdex, - priorityClass, dexoptOptions, artdCancellationSignal); + dmFile, priorityClass, dexoptOptions, artdCancellationSignal); } @Nullable @@ -426,7 +442,8 @@ public abstract class DexOptimizer<DexInfoType extends DetailedDexInfo> { return VdexPath.artifactsPath( AidlUtils.buildArtifactsPath(dexPath, isa, false /* isInDalvikCache */)); case ArtifactsLocation.DM: - return VdexPath.dexMetadataPath(AidlUtils.buildDexMetadataPath(dexPath)); + // The DM file is passed to dex2oat as a separate flag whenever it exists. + return null; default: // This should never happen as the value is got from artd. throw new IllegalStateException( @@ -434,6 +451,22 @@ public abstract class DexOptimizer<DexInfoType extends DetailedDexInfo> { } } + @Nullable + private DexMetadataPath getDmFile(@NonNull DexInfoType dexInfo) throws RemoteException { + DexMetadataPath path = buildDmPath(dexInfo); + if (path == null) { + return null; + } + try { + if (mInjector.getArtd().getDmFileVisibility(path) != FileVisibility.NOT_FOUND) { + return path; + } + } catch (ServiceSpecificException e) { + Log.e(TAG, "Failed to check DM file for " + dexInfo.dexPath(), e); + } + return null; + } + private boolean commitProfileChanges(@NonNull TmpProfilePath profile) throws RemoteException { try { mInjector.getArtd().commitTmpProfile(profile); @@ -525,24 +558,30 @@ public abstract class DexOptimizer<DexInfoType extends DetailedDexInfo> { /** Returns the paths to the current profiles of the given dex file. */ @NonNull protected abstract List<ProfilePath> getCurProfiles(@NonNull DexInfoType dexInfo); + /** + * Returns the path to the DM file that should be passed to dex2oat, or null if no DM file + * should be passed. + */ + @Nullable protected abstract DexMetadataPath buildDmPath(@NonNull DexInfoType dexInfo); + @AutoValue - abstract static class DexoptTarget { - abstract @NonNull DetailedDexInfo dexInfo(); + abstract static class DexoptTarget<DexInfoType extends DetailedDexInfo> { + abstract @NonNull DexInfoType dexInfo(); abstract @NonNull String isa(); abstract boolean isInDalvikCache(); abstract @NonNull String compilerFilter(); - static Builder builder() { - return new AutoValue_DexOptimizer_DexoptTarget.Builder(); + static <DexInfoType extends DetailedDexInfo> Builder<DexInfoType> builder() { + return new AutoValue_DexOptimizer_DexoptTarget.Builder<DexInfoType>(); } @AutoValue.Builder - abstract static class Builder { - abstract Builder setDexInfo(@NonNull DetailedDexInfo value); + abstract static class Builder<DexInfoType extends DetailedDexInfo> { + abstract Builder setDexInfo(@NonNull DexInfoType value); abstract Builder setIsa(@NonNull String value); abstract Builder setIsInDalvikCache(boolean value); abstract Builder setCompilerFilter(@NonNull String value); - abstract DexoptTarget build(); + abstract DexoptTarget<DexInfoType> build(); } } diff --git a/libartservice/service/java/com/android/server/art/PrimaryDexOptimizer.java b/libartservice/service/java/com/android/server/art/PrimaryDexOptimizer.java index 032f2aedc7..ee36b08dd1 100644 --- a/libartservice/service/java/com/android/server/art/PrimaryDexOptimizer.java +++ b/libartservice/service/java/com/android/server/art/PrimaryDexOptimizer.java @@ -206,6 +206,12 @@ public class PrimaryDexOptimizer extends DexOptimizer<DetailedPrimaryDexInfo> { return profiles; } + @Override + @Nullable + protected DexMetadataPath buildDmPath(@NonNull DetailedPrimaryDexInfo dexInfo) { + return AidlUtils.buildDexMetadataPath(dexInfo.dexPath()); + } + private boolean isSharedLibrary() { // TODO(b/242688548): Package manager should provide a better API for this. return !TextUtils.isEmpty(mPkg.getSdkLibraryName()) diff --git a/libartservice/service/java/com/android/server/art/ReasonMapping.java b/libartservice/service/java/com/android/server/art/ReasonMapping.java index 88a330c2fe..08140ad304 100644 --- a/libartservice/service/java/com/android/server/art/ReasonMapping.java +++ b/libartservice/service/java/com/android/server/art/ReasonMapping.java @@ -27,6 +27,8 @@ import com.android.server.art.model.ArtFlags; import dalvik.system.DexFile; +import java.util.Set; + /** * Maps a compilation reason to a compiler filter and a priority class. * @@ -57,6 +59,11 @@ public class ReasonMapping { public static final String REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = "install-bulk-secondary-downgraded"; + /** @hide */ + public static final Set<String> REASONS_FOR_INSTALL = Set.of(REASON_INSTALL, + REASON_INSTALL_FAST, REASON_INSTALL_BULK, REASON_INSTALL_BULK_SECONDARY, + REASON_INSTALL_BULK_DOWNGRADED, REASON_INSTALL_BULK_SECONDARY_DOWNGRADED); + /** * Loads the compiler filter from the system property for the given reason and checks for * validity. diff --git a/libartservice/service/java/com/android/server/art/SecondaryDexOptimizer.java b/libartservice/service/java/com/android/server/art/SecondaryDexOptimizer.java index 95b9ddba0f..73987fe864 100644 --- a/libartservice/service/java/com/android/server/art/SecondaryDexOptimizer.java +++ b/libartservice/service/java/com/android/server/art/SecondaryDexOptimizer.java @@ -135,6 +135,12 @@ public class SecondaryDexOptimizer extends DexOptimizer<DetailedSecondaryDexInfo return List.of(AidlUtils.buildProfilePathForSecondaryCur(dexInfo.dexPath())); } + @Override + @Nullable + protected DexMetadataPath buildDmPath(@NonNull DetailedSecondaryDexInfo dexInfo) { + return null; + } + private int getUid(@NonNull DetailedSecondaryDexInfo dexInfo) { return dexInfo.userHandle().getUid(mPkgState.getAppId()); } diff --git a/libartservice/service/java/com/android/server/art/model/OptimizationStatus.java b/libartservice/service/java/com/android/server/art/model/OptimizationStatus.java index 2fdf1ce184..4abf4c3e78 100644 --- a/libartservice/service/java/com/android/server/art/model/OptimizationStatus.java +++ b/libartservice/service/java/com/android/server/art/model/OptimizationStatus.java @@ -109,6 +109,17 @@ public abstract class OptimizationStatus { * <li>{@code "unknown"}: if the reason is empty or the optimized artifacts do not exist. * <li>{@code "error"}: if an unexpected error occurs. * </ul> + * + * Note that this value can differ from the requested compilation reason passed to {@link + * OptimizeParams.Builder}. Specifically, if the requested reason is for app install (e.g., + * "install"), and a DM file is passed to {@code dex2oat}, a "-dm" suffix will be appended + * to the actual reason (e.g., "install-dm"). Other compilation reasons remain unchanged + * even if a DM file is passed to {@code dex2oat}. + * + * Also note that the "-dm" suffix does <b>not</b> imply anything in the DM file being used + * by {@code dex2oat}. The compilation reason can still be "install-dm" even if {@code + * dex2oat} left all contents of the DM file unused or an empty DM file is passed to + * {@code dex2oat}. */ public abstract @NonNull String getCompilationReason(); diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java index 407fd61cc7..bff34ee8ef 100644 --- a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java +++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java @@ -209,6 +209,7 @@ public class PrimaryDexOptimizerParameterizedTest extends PrimaryDexOptimizerTes dexoptOptions.hiddenApiPolicyEnabled = mParams.mExpectedIsHiddenApiPolicyEnabled; when(mArtd.createCancellationSignal()).thenReturn(mock(IArtdCancellationSignal.class)); + when(mArtd.getDmFileVisibility(any())).thenReturn(FileVisibility.NOT_FOUND); // The first one is normal. doReturn(dexoptIsNeeded()) @@ -222,8 +223,8 @@ public class PrimaryDexOptimizerParameterizedTest extends PrimaryDexOptimizerTes mParams.mExpectedIsInDalvikCache, permissionSettings)), eq("/data/app/foo/base.apk"), eq("arm64"), eq("PCL[]"), eq(mParams.mExpectedCompilerFilter), isNull() /* profile */, - isNull() /* inputVdex */, eq(PriorityClass.INTERACTIVE), - deepEq(dexoptOptions), any()); + isNull() /* inputVdex */, isNull() /* dmFile */, + eq(PriorityClass.INTERACTIVE), deepEq(dexoptOptions), any()); // The second one fails on `dexopt`. doReturn(dexoptIsNeeded()) @@ -236,8 +237,8 @@ public class PrimaryDexOptimizerParameterizedTest extends PrimaryDexOptimizerTes mParams.mExpectedIsInDalvikCache, permissionSettings)), eq("/data/app/foo/base.apk"), eq("arm"), eq("PCL[]"), eq(mParams.mExpectedCompilerFilter), isNull() /* profile */, - isNull() /* inputVdex */, eq(PriorityClass.INTERACTIVE), - deepEq(dexoptOptions), any()); + isNull() /* inputVdex */, isNull() /* dmFile */, + eq(PriorityClass.INTERACTIVE), deepEq(dexoptOptions), any()); // The third one doesn't need dexopt. doReturn(dexoptIsNotNeeded()) @@ -257,8 +258,8 @@ public class PrimaryDexOptimizerParameterizedTest extends PrimaryDexOptimizerTes mParams.mExpectedIsInDalvikCache, permissionSettings)), eq("/data/app/foo/split_0.apk"), eq("arm"), eq("PCL[base.apk]"), eq(mParams.mExpectedCompilerFilter), isNull() /* profile */, - isNull() /* inputVdex */, eq(PriorityClass.INTERACTIVE), - deepEq(dexoptOptions), any()); + isNull() /* inputVdex */, isNull() /* dmFile */, + eq(PriorityClass.INTERACTIVE), deepEq(dexoptOptions), any()); assertThat(mPrimaryDexOptimizer.dexopt()) .comparingElementsUsing(TestingUtils.<DexContainerFileOptimizeResult>deepEquality()) diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java index 5b9264de0f..ff74e15120 100644 --- a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java +++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java @@ -73,6 +73,7 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME, "primary"); private final ProfilePath mPrebuiltProfile = AidlUtils.buildProfilePathForPrebuilt(mDexPath); private final ProfilePath mDmProfile = AidlUtils.buildProfilePathForDm(mDexPath); + private final DexMetadataPath mDmFile = AidlUtils.buildDexMetadataPath(mDexPath); private final OutputProfile mPublicOutputProfile = AidlUtils.buildOutputProfileForPrimary( PKG_NAME, "primary", Process.SYSTEM_UID, SHARED_GID, true /* isOtherReadable */); private final OutputProfile mPrivateOutputProfile = AidlUtils.buildOutputProfileForPrimary( @@ -106,13 +107,16 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { lenient().when(mArtd.isProfileUsable(any(), any())).thenReturn(false); lenient().when(mArtd.copyAndRewriteProfile(any(), any(), any())).thenReturn(false); + // By default, no DM file exists. + lenient().when(mArtd.getDmFileVisibility(any())).thenReturn(FileVisibility.NOT_FOUND); + // Dexopt is by default needed and successful. lenient() .when(mArtd.getDexoptNeeded(any(), any(), any(), any(), anyInt())) .thenReturn(dexoptIsNeeded()); lenient() - .when(mArtd.dexopt( - any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), any())) + .when(mArtd.dexopt(any(), any(), any(), any(), any(), any(), any(), any(), anyInt(), + any(), any())) .thenReturn(mDexoptResult); lenient() @@ -133,8 +137,8 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { .getDexoptNeeded(eq(mDexPath), eq("arm64"), any(), any(), anyInt()); doReturn(mDexoptResult) .when(mArtd) - .dexopt(any(), eq(mDexPath), eq("arm64"), any(), any(), any(), isNull(), anyInt(), - any(), any()); + .dexopt(any(), eq(mDexPath), eq("arm64"), any(), any(), any(), isNull(), any(), + anyInt(), any(), any()); // ArtifactsPath, isInDalvikCache=true. doReturn(dexoptIsNeeded(ArtifactsLocation.DALVIK_CACHE)) @@ -145,7 +149,7 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { .dexopt(any(), eq(mDexPath), eq("arm"), any(), any(), any(), deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPath( mDexPath, "arm", true /* isInDalvikCache */))), - anyInt(), any(), any()); + any(), anyInt(), any(), any()); // ArtifactsPath, isInDalvikCache=false. doReturn(dexoptIsNeeded(ArtifactsLocation.NEXT_TO_DEX)) @@ -156,7 +160,7 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { .dexopt(any(), eq(mSplit0DexPath), eq("arm64"), any(), any(), any(), deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPath( mSplit0DexPath, "arm64", false /* isInDalvikCache */))), - anyInt(), any(), any()); + any(), anyInt(), any(), any()); // DexMetadataPath. doReturn(dexoptIsNeeded(ArtifactsLocation.DM)) @@ -164,15 +168,34 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { .getDexoptNeeded(eq(mSplit0DexPath), eq("arm"), any(), any(), anyInt()); doReturn(mDexoptResult) .when(mArtd) - .dexopt(any(), eq(mSplit0DexPath), eq("arm"), any(), any(), any(), - deepEq(VdexPath.dexMetadataPath( - AidlUtils.buildDexMetadataPath(mSplit0DexPath))), + .dexopt(any(), eq(mSplit0DexPath), eq("arm"), any(), any(), any(), isNull(), any(), anyInt(), any(), any()); mPrimaryDexOptimizer.dexopt(); } @Test + public void testDexoptDm() throws Exception { + lenient() + .when(mArtd.getDmFileVisibility(deepEq(mDmFile))) + .thenReturn(FileVisibility.OTHER_READABLE); + + mPrimaryDexOptimizer.dexopt(); + + verify(mArtd, times(2)) + .dexopt(any(), eq(mDexPath), any(), any(), any(), any(), any(), deepEq(mDmFile), + anyInt(), + argThat(dexoptOptions + -> dexoptOptions.compilationReason.equals("install-dm")), + any()); + verify(mArtd, times(2)) + .dexopt(any(), eq(mSplit0DexPath), any(), any(), any(), any(), any(), isNull(), + anyInt(), + argThat(dexoptOptions -> dexoptOptions.compilationReason.equals("install")), + any()); + } + + @Test public void testDexoptUsesRefProfile() throws Exception { makeProfileUsable(mRefProfile); when(mArtd.getProfileVisibility(deepEq(mRefProfile))) @@ -342,8 +365,8 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { makeProfileNotUsable(mPrebuiltProfile); makeProfileUsable(mDmProfile); - when(mArtd.dexopt(any(), eq(mDexPath), any(), any(), any(), any(), any(), anyInt(), any(), - any())) + when(mArtd.dexopt(any(), eq(mDexPath), any(), any(), any(), any(), any(), any(), anyInt(), + any(), any())) .thenThrow(ServiceSpecificException.class); mPrimaryDexOptimizer.dexopt(); @@ -448,7 +471,7 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { true /* cancelled */, 200 /* wallTimeMs */, 200 /* cpuTimeMs */); }) .when(mArtd) - .dexopt(any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), + .dexopt(any(), any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), same(artdCancellationSignal)); // The result should only contain one element: the result of the first file with @@ -462,7 +485,8 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { // It shouldn't continue after being cancelled on the first file. verify(mArtd, times(1)).createCancellationSignal(); verify(mArtd, times(1)) - .dexopt(any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), any()); + .dexopt(any(), any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), + any()); } @Test @@ -481,7 +505,7 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { true /* cancelled */, 200 /* wallTimeMs */, 200 /* cpuTimeMs */); }) .when(mArtd) - .dexopt(any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), + .dexopt(any(), any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), same(artdCancellationSignal)); doAnswer(invocation -> { dexoptCancelled.release(); @@ -507,7 +531,8 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { // It shouldn't continue after being cancelled on the first file. verify(mArtd, times(1)).createCancellationSignal(); verify(mArtd, times(1)) - .dexopt(any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), any()); + .dexopt(any(), any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), + any()); } private void checkDexoptWithPublicProfile( @@ -515,8 +540,8 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { artd.dexopt( argThat(artifacts -> artifacts.permissionSettings.fileFsPermission.isOtherReadable == true), - eq(dexPath), eq(isa), any(), eq("speed-profile"), deepEq(profile), any(), anyInt(), - argThat(dexoptOptions -> dexoptOptions.generateAppImage == true), any()); + eq(dexPath), eq(isa), any(), eq("speed-profile"), deepEq(profile), any(), any(), + anyInt(), argThat(dexoptOptions -> dexoptOptions.generateAppImage == true), any()); } private void checkDexoptWithPrivateProfile( @@ -524,8 +549,8 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { artd.dexopt( argThat(artifacts -> artifacts.permissionSettings.fileFsPermission.isOtherReadable == false), - eq(dexPath), eq(isa), any(), eq("speed-profile"), deepEq(profile), any(), anyInt(), - argThat(dexoptOptions -> dexoptOptions.generateAppImage == true), any()); + eq(dexPath), eq(isa), any(), eq("speed-profile"), deepEq(profile), any(), any(), + anyInt(), argThat(dexoptOptions -> dexoptOptions.generateAppImage == true), any()); } private void checkDexoptWithNoProfile( @@ -533,7 +558,7 @@ public class PrimaryDexOptimizerTest extends PrimaryDexOptimizerTestBase { artd.dexopt( argThat(artifacts -> artifacts.permissionSettings.fileFsPermission.isOtherReadable == true), - eq(dexPath), eq(isa), any(), eq(compilerFilter), isNull(), any(), anyInt(), + eq(dexPath), eq(isa), any(), eq(compilerFilter), isNull(), any(), any(), anyInt(), argThat(dexoptOptions -> dexoptOptions.generateAppImage == false), any()); } diff --git a/libartservice/service/javatests/com/android/server/art/SecondaryDexOptimizerTest.java b/libartservice/service/javatests/com/android/server/art/SecondaryDexOptimizerTest.java index 7b967e4e11..4e9a7f1f94 100644 --- a/libartservice/service/javatests/com/android/server/art/SecondaryDexOptimizerTest.java +++ b/libartservice/service/javatests/com/android/server/art/SecondaryDexOptimizerTest.java @@ -145,8 +145,8 @@ public class SecondaryDexOptimizerTest { .when(mArtd.getDexoptNeeded(any(), any(), any(), any(), anyInt())) .thenReturn(dexoptIsNeeded()); lenient() - .when(mArtd.dexopt( - any(), any(), any(), any(), any(), any(), any(), anyInt(), any(), any())) + .when(mArtd.dexopt(any(), any(), any(), any(), any(), any(), any(), any(), anyInt(), + any(), any())) .thenReturn(createDexoptResult()); lenient() @@ -316,7 +316,7 @@ public class SecondaryDexOptimizerTest { OutputArtifacts outputArtifacts = AidlUtils.buildOutputArtifacts( dexPath, isa, false /* isInDalvikCache */, permissionSettings); artd.dexopt(deepEq(outputArtifacts), eq(dexPath), eq(isa), eq(classLoaderContext), - eq("speed-profile"), deepEq(profile), any(), anyInt(), + eq("speed-profile"), deepEq(profile), any(), isNull() /* dmFile */, anyInt(), argThat(dexoptOptions -> dexoptOptions.generateAppImage == false), any()); } @@ -326,7 +326,7 @@ public class SecondaryDexOptimizerTest { OutputArtifacts outputArtifacts = AidlUtils.buildOutputArtifacts( dexPath, isa, false /* isInDalvikCache */, permissionSettings); artd.dexopt(deepEq(outputArtifacts), eq(dexPath), eq(isa), eq(classLoaderContext), - eq(compilerFilter), isNull(), any(), anyInt(), + eq(compilerFilter), isNull(), any(), isNull() /* dmFile */, anyInt(), argThat(dexoptOptions -> dexoptOptions.generateAppImage == false), any()); } |