diff options
author | 2020-04-02 10:50:35 +0100 | |
---|---|---|
committer | 2020-04-03 13:40:14 +0100 | |
commit | d1f73515701bc64b3a23727b3973da6906f1b167 (patch) | |
tree | 59d789c42edd402ae799caa748939b61aeb00be7 | |
parent | bda163d9c8313f0b92046abda5ffb1216af1e808 (diff) |
dex2oat: add --updatable-bcp-packages-file argument.
Add a command line argument specifying a file that contains
the list of updatable boot class path packages.
Test: Updated module_exclusion_test
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: aosp_taimen-userdebug boots.
Bug: 151314205
Change-Id: Ic6a66ad7e565a9b9b344cc467cb1ed550ab41b3f
-rw-r--r-- | build/Android.gtest.mk | 7 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 62 | ||||
-rw-r--r-- | dex2oat/dex2oat_options.cc | 3 | ||||
-rw-r--r-- | dex2oat/dex2oat_options.def | 1 | ||||
-rw-r--r-- | runtime/aot_class_linker.cc | 44 | ||||
-rw-r--r-- | runtime/aot_class_linker.h | 8 | ||||
-rw-r--r-- | runtime/class_linker.cc | 35 | ||||
-rw-r--r-- | runtime/class_linker.h | 2 | ||||
-rw-r--r-- | runtime/module_exclusion_test.cc | 65 |
9 files changed, 197 insertions, 30 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index b3cac26374..f5c989202b 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -315,6 +315,11 @@ ART_GTEST_dex2oat_image_test_TARGET_DEPS := \ $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \ $(TESTING_ART_APEX) # For dex2oatd. +ART_GTEST_module_exclusion_test_HOST_DEPS := \ + $(ART_GTEST_dex2oat_image_test_HOST_DEPS) +ART_GTEST_module_exclusion_test_TARGET_DEPS := \ + $(ART_GTEST_dex2oat_image_test_TARGET_DEPS) + # TODO: document why this is needed. ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_DEFAULT_64) $(HOST_CORE_IMAGE_DEFAULT_32) @@ -742,6 +747,8 @@ ART_GTEST_dex2oat_test_TARGET_DEPS := ART_GTEST_dex2oat_image_test_DEX_DEPS := ART_GTEST_dex2oat_image_test_HOST_DEPS := ART_GTEST_dex2oat_image_test_TARGET_DEPS := +ART_GTEST_module_exclusion_test_HOST_DEPS := +ART_GTEST_module_exclusion_test_TARGET_DEPS := ART_GTEST_object_test_DEX_DEPS := ART_GTEST_proxy_test_DEX_DEPS := ART_GTEST_reflection_test_DEX_DEPS := diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index cb49bfe127..8713886518 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -41,6 +41,7 @@ #include "android-base/stringprintf.h" #include "android-base/strings.h" +#include "aot_class_linker.h" #include "arch/instruction_set_features.h" #include "art_method-inl.h" #include "base/callee_save_type.h" @@ -491,9 +492,14 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(" for dex files in --class-loader-context. Their order must be the same as"); UsageError(" dex files in flattened class loader context."); UsageError(""); - UsageError(" --dirty-image-objects=<directory-path>: list of known dirty objects in the image."); + UsageError(" --dirty-image-objects=<file-path>: list of known dirty objects in the image."); UsageError(" The image writer will group them together."); UsageError(""); + UsageError(" --updatable-bcp-packages-file=<file-path>: file with a list of updatable"); + UsageError(" boot class path packages. Classes in these packages and sub-packages"); + UsageError(" shall not be resolved during app compilation to avoid AOT assumptions"); + UsageError(" being invalidated after applying updates to these components."); + UsageError(""); UsageError(" --compact-dex-level=none|fast: None avoids generating compact dex, fast"); UsageError(" generates compact dex with low compile time. If speed-profile is specified as"); UsageError(" the compiler filter and the profile is not empty, the default compact dex"); @@ -793,6 +799,7 @@ class Dex2Oat final { image_storage_mode_(ImageHeader::kStorageModeUncompressed), passes_to_run_filename_(nullptr), dirty_image_objects_filename_(nullptr), + updatable_bcp_packages_filename_(nullptr), is_host_(false), elf_writers_(), oat_writers_(), @@ -1066,6 +1073,10 @@ class Dex2Oat final { } } + if ((IsBootImage() || IsBootImageExtension()) && updatable_bcp_packages_filename_ != nullptr) { + Usage("Do not specify --updatable-bcp-packages-file for boot image compilation."); + } + if (!cpu_set_.empty()) { SetCpuAffinity(cpu_set_); } @@ -1324,6 +1335,7 @@ class Dex2Oat final { AssignIfExists(args, M::NoInlineFrom, &no_inline_from_string_); AssignIfExists(args, M::ClasspathDir, &classpath_dir_); AssignIfExists(args, M::DirtyImageObjects, &dirty_image_objects_filename_); + AssignIfExists(args, M::UpdatableBcpPackagesFile, &updatable_bcp_packages_filename_); AssignIfExists(args, M::ImageFormat, &image_storage_mode_); AssignIfExists(args, M::CompilationReason, &compilation_reason_); AssignTrueIfExists(args, M::CheckLinkageConditions, &check_linkage_conditions_); @@ -1879,6 +1891,11 @@ class Dex2Oat final { class_loader_context_->EncodeContextForOatFile(classpath_dir_, stored_class_loader_context_.get()); key_value_store_->Put(OatHeader::kClassPathKey, class_path_key); + + // Prepare exclusion list for updatable boot class path packages. + if (!PrepareUpdatableBcpPackages()) { + return dex2oat::ReturnCode::kOther; + } } // Now that we have finalized key_value_store_, start writing the .rodata section. @@ -2613,6 +2630,48 @@ class Dex2Oat final { return true; } + bool PrepareUpdatableBcpPackages() { + DCHECK(!IsBootImage() && !IsBootImageExtension()); + AotClassLinker* aot_class_linker = down_cast<AotClassLinker*>(runtime_->GetClassLinker()); + if (updatable_bcp_packages_filename_ != nullptr) { + std::unique_ptr<std::vector<std::string>> updatable_bcp_packages = + ReadCommentedInputFromFile<std::vector<std::string>>(updatable_bcp_packages_filename_, + nullptr); // No post-processing. + if (updatable_bcp_packages == nullptr) { + LOG(ERROR) << "Failed to load updatable boot class path packages from '" + << updatable_bcp_packages_filename_ << "'"; + return false; + } + return aot_class_linker->SetUpdatableBootClassPackages(*updatable_bcp_packages); + } else { + // Use the default list based on updatable packages for Android 11. + return aot_class_linker->SetUpdatableBootClassPackages({ + // Reserved conscrypt packages (includes sub-packages under these paths). + // "android.net.ssl", // Covered by android.net below. + "com.android.org.conscrypt", + // Reserved updatable-media package (includes sub-packages under this path). + "android.media", + // Reserved framework-mediaprovider package (includes sub-packages under this path). + "android.provider", + // Reserved framework-statsd packages (includes sub-packages under these paths). + "android.app", + "android.os", + "android.util", + // Reserved framework-permission packages (includes sub-packages under this path). + "android.permission", + // "android.app.role", // Covered by android.app above. + // Reserved framework-sdkextensions package (includes sub-packages under this path). + // "android.os.ext", // Covered by android.os above. + // Reserved framework-wifi packages (includes sub-packages under these paths). + "android.hardware.wifi", + // "android.net.wifi", // Covered by android.net below. + "android.x.net.wifi", + // Reserved framework-tethering package (includes sub-packages under this path). + "android.net", + }); + } + } + void PruneNonExistentDexFiles() { DCHECK_EQ(dex_filenames_.size(), dex_locations_.size()); size_t kept = 0u; @@ -2985,6 +3044,7 @@ class Dex2Oat final { ImageHeader::StorageMode image_storage_mode_; const char* passes_to_run_filename_; const char* dirty_image_objects_filename_; + const char* updatable_bcp_packages_filename_; std::unique_ptr<HashSet<std::string>> dirty_image_objects_; std::unique_ptr<std::vector<std::string>> passes_to_run_; bool is_host_; diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc index ea72d54e26..d282c3b1b8 100644 --- a/dex2oat/dex2oat_options.cc +++ b/dex2oat/dex2oat_options.cc @@ -131,6 +131,9 @@ static void AddImageMappings(Builder& builder) { .Define("--dirty-image-objects=_") .WithType<std::string>() .IntoKey(M::DirtyImageObjects) + .Define("--updatable-bcp-packages-file=_") + .WithType<std::string>() + .IntoKey(M::UpdatableBcpPackagesFile) .Define("--image-format=_") .WithType<ImageHeader::StorageMode>() .WithValueMap({{"lz4", ImageHeader::kStorageModeLZ4}, diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def index e324e8bd20..805a13ee82 100644 --- a/dex2oat/dex2oat_options.def +++ b/dex2oat/dex2oat_options.def @@ -89,6 +89,7 @@ DEX2OAT_OPTIONS_KEY (std::string, ClassLoaderContext) DEX2OAT_OPTIONS_KEY (std::string, ClassLoaderContextFds) DEX2OAT_OPTIONS_KEY (std::string, StoredClassLoaderContext) DEX2OAT_OPTIONS_KEY (std::string, DirtyImageObjects) +DEX2OAT_OPTIONS_KEY (std::string, UpdatableBcpPackagesFile) DEX2OAT_OPTIONS_KEY (std::vector<std::string>, RuntimeOptions) DEX2OAT_OPTIONS_KEY (std::string, CompilationReason) DEX2OAT_OPTIONS_KEY (Unit, CheckLinkageConditions) diff --git a/runtime/aot_class_linker.cc b/runtime/aot_class_linker.cc index 77faa2d2b9..6625b8dbd2 100644 --- a/runtime/aot_class_linker.cc +++ b/runtime/aot_class_linker.cc @@ -196,4 +196,48 @@ bool AotClassLinker::CanReferenceInBootImageExtension(ObjPtr<mirror::Class> klas return true; } +bool AotClassLinker::SetUpdatableBootClassPackages(const std::vector<std::string>& packages) { + DCHECK(updatable_boot_class_path_descriptor_prefixes_.empty()); + // Transform package names to descriptor prefixes. + std::vector<std::string> prefixes; + prefixes.reserve(packages.size()); + for (const std::string& package : packages) { + if (package.empty() || package.find('/') != std::string::npos) { + LOG(ERROR) << "Invalid package name: " << package; + return false; + } + std::string prefix = 'L' + package + '/'; + std::replace(prefix.begin(), prefix.end(), '.', '/'); + prefixes.push_back(std::move(prefix)); + } + // Sort and remove unnecessary prefixes. + std::sort(prefixes.begin(), prefixes.end()); + std::string last_prefix; + auto end_it = std::remove_if( + prefixes.begin(), + prefixes.end(), + [&last_prefix](const std::string& s) { + if (!last_prefix.empty() && StartsWith(s, last_prefix)) { + return true; + } else { + last_prefix = s; + return false; + } + }); + prefixes.resize(std::distance(prefixes.begin(), end_it)); + prefixes.shrink_to_fit(); + updatable_boot_class_path_descriptor_prefixes_.swap(prefixes); + return true; +} + +bool AotClassLinker::IsUpdatableBootClassPathDescriptor(const char* descriptor) { + std::string_view descriptor_sv(descriptor); + for (const std::string& prefix : updatable_boot_class_path_descriptor_prefixes_) { + if (StartsWith(descriptor_sv, prefix)) { + return true; + } + } + return false; +} + } // namespace art diff --git a/runtime/aot_class_linker.h b/runtime/aot_class_linker.h index 2b50c46b8c..76984bda99 100644 --- a/runtime/aot_class_linker.h +++ b/runtime/aot_class_linker.h @@ -35,6 +35,8 @@ class AotClassLinker : public ClassLinker { static bool CanReferenceInBootImageExtension(ObjPtr<mirror::Class> klass, gc::Heap* heap) REQUIRES_SHARED(Locks::mutator_lock_); + bool SetUpdatableBootClassPackages(const std::vector<std::string>& packages); + protected: // Overridden version of PerformClassVerification allows skipping verification if the class was // previously verified but unloaded. @@ -59,7 +61,13 @@ class AotClassLinker : public ClassLinker { override REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_); + + bool IsUpdatableBootClassPathDescriptor(const char* descriptor) override; + + private: + std::vector<std::string> updatable_boot_class_path_descriptor_prefixes_; }; + } // namespace art #endif // ART_RUNTIME_AOT_CLASS_LINKER_H_ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 284f19ff3b..daabf01cb7 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3147,33 +3147,6 @@ ObjPtr<mirror::Class> ClassLinker::FindClass(Thread* self, return result_ptr; } -static bool IsReservedBootClassPathDescriptor(const char* descriptor) { - std::string_view descriptor_sv(descriptor); - return - // Reserved conscrypt packages (includes sub-packages under these paths). - // StartsWith(descriptor_sv, "Landroid/net/ssl/") || // Covered by android.net below. - StartsWith(descriptor_sv, "Lcom/android/org/conscrypt/") || - // Reserved updatable-media package (includes sub-packages under this path). - StartsWith(descriptor_sv, "Landroid/media/") || - // Reserved framework-mediaprovider package (includes sub-packages under this path). - StartsWith(descriptor_sv, "Landroid/provider/") || - // Reserved framework-statsd packages (includes sub-packages under these paths). - StartsWith(descriptor_sv, "Landroid/app/") || - StartsWith(descriptor_sv, "Landroid/os/") || - StartsWith(descriptor_sv, "Landroid/util/") || - // Reserved framework-permission packages (includes sub-packages under this path). - StartsWith(descriptor_sv, "Landroid/permission/") || - // StartsWith(descriptor_sv, "Landroid/app/role/") || // Covered by android.app above. - // Reserved framework-sdkextensions package (includes sub-packages under this path). - // StartsWith(descriptor_sv, "Landroid/os/ext/") || // Covered by android.os above. - // Reserved framework-wifi packages (includes sub-packages under these paths). - StartsWith(descriptor_sv, "Landroid/hardware/wifi/") || - // StartsWith(descriptor_sv, "Landroid/net/wifi/") || // Covered by android.net below. - StartsWith(descriptor_sv, "Landroid/x/net/wifi/") || - // Reserved framework-tethering package (includes sub-packages under this path). - StartsWith(descriptor_sv, "Landroid/net/"); -} - // Helper for maintaining DefineClass counting. We need to notify callbacks when we start/end a // define-class and how many recursive DefineClasses we are at in order to allow for doing things // like pausing class definition. @@ -3251,7 +3224,7 @@ ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self, // with these modules as these classes could be resolved differently during execution. if (class_loader != nullptr && Runtime::Current()->IsAotCompiler() && - IsReservedBootClassPathDescriptor(descriptor)) { + IsUpdatableBootClassPathDescriptor(descriptor)) { ObjPtr<mirror::Throwable> pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); @@ -9861,6 +9834,12 @@ ObjPtr<mirror::IfTable> ClassLinker::AllocIfTable(Thread* self, size_t ifcount) ifcount * mirror::IfTable::kMax))); } +bool ClassLinker::IsUpdatableBootClassPathDescriptor(const char* descriptor ATTRIBUTE_UNUSED) { + // Should not be called on ClassLinker, only on AotClassLinker that overrides this. + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); +} + // Instantiate ClassLinker::ResolveMethod. template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>( uint32_t method_idx, diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 998f7392ce..4731203fad 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -829,6 +829,8 @@ class ClassLinker { return true; } + virtual bool IsUpdatableBootClassPathDescriptor(const char* descriptor); + private: class LinkInterfaceMethodsHelper; class VisiblyInitializedCallback; diff --git a/runtime/module_exclusion_test.cc b/runtime/module_exclusion_test.cc index 67b79d45db..1f5f87ef2b 100644 --- a/runtime/module_exclusion_test.cc +++ b/runtime/module_exclusion_test.cc @@ -16,6 +16,8 @@ #include "common_compiler_test.h" +#include "aot_class_linker.h" +#include "base/casts.h" #include "class_linker-inl.h" #include "handle.h" #include "handle_scope-inl.h" @@ -71,7 +73,15 @@ class ModuleExclusionTest : public CommonCompilerTest { } } - private: + protected: + void SetUpRuntimeOptions(RuntimeOptions* options) override { + CommonCompilerTest::SetUpRuntimeOptions(options); + + // Set up the image location to be used by StartDex2OatCommandLine(). + // Using a prebuilt image also makes the test run faster. + options->push_back(std::make_pair("-Ximage:" + GetImageLocation(), nullptr)); + } + std::string GetModuleFileName() const { std::vector<std::string> filename = GetLibCoreDexFileNames({ module_ }); CHECK_EQ(filename.size(), 1u); @@ -124,7 +134,60 @@ class ConscryptExclusionTest : public ModuleExclusionTest { }; TEST_F(ConscryptExclusionTest, Test) { + Runtime* runtime = Runtime::Current(); + ASSERT_TRUE(runtime->IsAotCompiler()); + AotClassLinker* aot_class_linker = down_cast<AotClassLinker*>(runtime->GetClassLinker()); + const std::vector<std::string> package_list = { + // Reserved conscrypt packages (includes sub-packages under these paths). + "android.net.ssl", + "com.android.org.conscrypt", + }; + bool list_applied = aot_class_linker->SetUpdatableBootClassPackages(package_list); + ASSERT_TRUE(list_applied); DoTest(); + + // Also test passing the list to dex2oat. + ScratchFile package_list_file; + for (const std::string& package : package_list) { + std::string data = package + '\n'; + ASSERT_TRUE(package_list_file.GetFile()->WriteFully(data.data(), data.size())); + } + ASSERT_EQ(0, package_list_file.GetFile()->Flush()); + ScratchDir scratch_dir; + std::string jar_name = GetModuleFileName(); + std::string odex_name = scratch_dir.GetPath() + module_ + ".odex"; + std::vector<std::string> argv; + std::string error_msg; + bool success = StartDex2OatCommandLine(&argv, &error_msg); + ASSERT_TRUE(success) << error_msg; + argv.insert(argv.end(), { + "--dex-file=" + jar_name, + "--dex-location=" + jar_name, + "--oat-file=" + odex_name, + "--compiler-filter=speed", + "--updatable-bcp-packages-file=" + package_list_file.GetFilename() + }); + success = RunDex2Oat(argv, &error_msg); + ASSERT_TRUE(success) << error_msg; + // Load the odex file. + std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1, + odex_name.c_str(), + odex_name.c_str(), + /*executable=*/ false, + /*low_4gb=*/ false, + jar_name, + &error_msg)); + ASSERT_TRUE(odex_file != nullptr) << error_msg; + // Check that no classes have been resolved. + for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) { + std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg); + ASSERT_TRUE(dex_file != nullptr); + for (size_t i = 0, num_class_defs = dex_file->NumClassDefs(); i != num_class_defs; ++i) { + ClassStatus status = oat_dex_file->GetOatClass(i).GetStatus(); + ASSERT_FALSE(mirror::Class::IsErroneous(status)); + ASSERT_LT(status, ClassStatus::kResolved); + } + } } } // namespace art |