Merge changes from topic "art-enable-apex-libs"
* changes:
Revert^2 "Switch from version script to APEX stubs for libdexfile_external and add it to the Runtime APEX."
Add remaining libnative* libs to the Runtime APEX.
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index d7ca168..f7ed826 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -89,6 +89,11 @@
art_tools_device_binaries = art_tools_common_binaries + art_tools_device_only_binaries
art_tools_host_binaries = art_tools_common_binaries + art_tools_host_only_binaries
+// Libraries needed to use com.android.runtime.host for zipapex run-tests
+art_runtime_host_run_test_libs = [
+ "libartd-disassembler"
+]
+
// Libcore native libraries.
libcore_native_shared_libs = [
"libjavacore",
@@ -107,6 +112,14 @@
"apache-xml",
]
+// Temporary library includes for b/123591866 as all libraries are moved into the main art-apex.
+art_runtime_libraries_zipapex = [
+ "libnativebridge",
+ "libnativeloader",
+ "libnativehelper",
+ "libcutils",
+]
+
apex_key {
name: "com.android.runtime.key",
public_key: "com.android.runtime.avbpubkey",
@@ -192,7 +205,7 @@
// because binaries have different multilib classes and 'multilib: {}' isn't
// supported by target: { ... }.
// See b/120617876 for more information.
-art_apex {
+art_apex_test {
name: "com.android.runtime.host",
compile_multilib: "both",
payload_type: "zip",
@@ -204,7 +217,9 @@
native_shared_libs: art_runtime_base_native_shared_libs
+ art_runtime_debug_native_shared_libs
+ libcore_native_shared_libs
- + libcore_debug_native_shared_libs,
+ + libcore_debug_native_shared_libs
+ + art_runtime_libraries_zipapex
+ + art_runtime_host_run_test_libs,
multilib: {
both: {
// TODO: Add logic to create a `dalvikvm` symlink to `dalvikvm32` or `dalvikvm64`
diff --git a/build/art.go b/build/art.go
index 5236e31..4b63829 100644
--- a/build/art.go
+++ b/build/art.go
@@ -298,11 +298,11 @@
// changes this to 'prefer32' on all host binaries. Since HOST_PREFER_32_BIT is
// only used for testing we can just disable the module.
// See b/120617876 for more information.
- android.RegisterModuleType("art_apex", artApexBundleFactory)
+ android.RegisterModuleType("art_apex_test", artTestApexBundleFactory)
}
-func artApexBundleFactory() android.Module {
- module := apex.ApexBundleFactory()
+func artTestApexBundleFactory() android.Module {
+ module := apex.ApexBundleFactory( /*testApex*/ true)
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
if envTrue(ctx, "HOST_PREFER_32_BIT") {
type props struct {
@@ -356,7 +356,7 @@
func libartStaticDefaultsFactory() android.Module {
c := &codegenProperties{}
module := cc.DefaultsFactory(c)
- android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, true) })
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, true) })
return module
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index c70674b..4670b3f 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2355,10 +2355,6 @@
// 2) Their inputs are identical.
bool Equals(const HInstruction* other) const;
- // TODO: Remove this indirection when the [[pure]] attribute proposal (n3744)
- // is adopted and implemented by our C++ compiler(s). Fow now, we need to hide
- // the virtual function because the __attribute__((__pure__)) doesn't really
- // apply the strong requirement for virtual functions, preventing optimizations.
InstructionKind GetKind() const { return GetPackedField<InstructionKindField>(); }
virtual size_t ComputeHashCode() const {
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 92850f7..988c612 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -15,14 +15,16 @@
*/
#include <string>
+#include <string_view>
-#include "base/logging.h" // For InitLogging.
-#include "base/mutex.h"
-#include "base/os.h"
-#include "base/utils.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
#include "base/file_utils.h"
+#include "base/logging.h" // For InitLogging.
+#include "base/mutex.h"
+#include "base/os.h"
+#include "base/string_view_cpp20.h"
+#include "base/utils.h"
#include "compiler_filter.h"
#include "class_loader_context.h"
#include "dex/dex_file.h"
@@ -155,56 +157,57 @@
}
for (int i = 0; i < argc; ++i) {
- const StringPiece option(argv[i]);
+ const char* raw_option = argv[i];
+ const std::string_view option(raw_option);
if (option == "--assume-profile-changed") {
assume_profile_changed_ = true;
- } else if (option.starts_with("--dex-file=")) {
- dex_file_ = option.substr(strlen("--dex-file=")).ToString();
- } else if (option.starts_with("--compiler-filter=")) {
- std::string filter_str = option.substr(strlen("--compiler-filter=")).ToString();
- if (!CompilerFilter::ParseCompilerFilter(filter_str.c_str(), &compiler_filter_)) {
- Usage("Invalid compiler filter '%s'", option.data());
+ } else if (StartsWith(option, "--dex-file=")) {
+ dex_file_ = std::string(option.substr(strlen("--dex-file=")));
+ } else if (StartsWith(option, "--compiler-filter=")) {
+ const char* filter_str = raw_option + strlen("--compiler-filter=");
+ if (!CompilerFilter::ParseCompilerFilter(filter_str, &compiler_filter_)) {
+ Usage("Invalid compiler filter '%s'", raw_option);
}
- } else if (option.starts_with("--isa=")) {
- std::string isa_str = option.substr(strlen("--isa=")).ToString();
- isa_ = GetInstructionSetFromString(isa_str.c_str());
+ } else if (StartsWith(option, "--isa=")) {
+ const char* isa_str = raw_option + strlen("--isa=");
+ isa_ = GetInstructionSetFromString(isa_str);
if (isa_ == InstructionSet::kNone) {
- Usage("Invalid isa '%s'", option.data());
+ Usage("Invalid isa '%s'", raw_option);
}
- } else if (option.starts_with("--image=")) {
- image_ = option.substr(strlen("--image=")).ToString();
+ } else if (StartsWith(option, "--image=")) {
+ image_ = std::string(option.substr(strlen("--image=")));
} else if (option == "--runtime-arg") {
if (i + 1 == argc) {
Usage("Missing argument for --runtime-arg\n");
}
++i;
runtime_args_.push_back(argv[i]);
- } else if (option.starts_with("--android-data=")) {
+ } else if (StartsWith(option, "--android-data=")) {
// Overwrite android-data if needed (oat file assistant relies on a valid directory to
// compute dalvik-cache folder). This is mostly used in tests.
- std::string new_android_data = option.substr(strlen("--android-data=")).ToString();
- setenv("ANDROID_DATA", new_android_data.c_str(), 1);
- } else if (option.starts_with("--downgrade")) {
+ const char* new_android_data = raw_option + strlen("--android-data=");
+ setenv("ANDROID_DATA", new_android_data, 1);
+ } else if (option == "--downgrade") {
downgrade_ = true;
- } else if (option.starts_with("--oat-fd")) {
- oat_fd_ = std::stoi(option.substr(strlen("--oat-fd=")).ToString(), nullptr, 0);
+ } else if (StartsWith(option, "--oat-fd=")) {
+ oat_fd_ = std::stoi(std::string(option.substr(strlen("--oat-fd="))), nullptr, 0);
if (oat_fd_ < 0) {
Usage("Invalid --oat-fd %d", oat_fd_);
}
- } else if (option.starts_with("--vdex-fd")) {
- vdex_fd_ = std::stoi(option.substr(strlen("--vdex-fd=")).ToString(), nullptr, 0);
+ } else if (StartsWith(option, "--vdex-fd=")) {
+ vdex_fd_ = std::stoi(std::string(option.substr(strlen("--vdex-fd="))), nullptr, 0);
if (vdex_fd_ < 0) {
Usage("Invalid --vdex-fd %d", vdex_fd_);
}
- } else if (option.starts_with("--zip-fd")) {
- zip_fd_ = std::stoi(option.substr(strlen("--zip-fd=")).ToString(), nullptr, 0);
- if (zip_fd_ < 0) {
- Usage("Invalid --zip-fd %d", zip_fd_);
- }
- } else if (option.starts_with("--class-loader-context=")) {
- context_str_ = option.substr(strlen("--class-loader-context=")).ToString();
+ } else if (StartsWith(option, "--zip-fd=")) {
+ zip_fd_ = std::stoi(std::string(option.substr(strlen("--zip-fd="))), nullptr, 0);
+ if (zip_fd_ < 0) {
+ Usage("Invalid --zip-fd %d", zip_fd_);
+ }
+ } else if (StartsWith(option, "--class-loader-context=")) {
+ context_str_ = std::string(option.substr(strlen("--class-loader-context=")));
} else {
- Usage("Unknown argument '%s'", option.data());
+ Usage("Unknown argument '%s'", raw_option);
}
}
diff --git a/libartbase/base/utils.cc b/libartbase/base/utils.cc
index b989d9e..30423a4 100644
--- a/libartbase/base/utils.cc
+++ b/libartbase/base/utils.cc
@@ -190,45 +190,6 @@
#endif
}
-static void ParseStringAfterChar(const std::string& s,
- char c,
- std::string* parsed_value,
- UsageFn Usage) {
- std::string::size_type colon = s.find(c);
- if (colon == std::string::npos) {
- Usage("Missing char %c in option %s\n", c, s.c_str());
- }
- // Add one to remove the char we were trimming until.
- *parsed_value = s.substr(colon + 1);
-}
-
-void ParseDouble(const std::string& option,
- char after_char,
- double min,
- double max,
- double* parsed_value,
- UsageFn Usage) {
- std::string substring;
- ParseStringAfterChar(option, after_char, &substring, Usage);
- bool sane_val = true;
- double value;
- if ((false)) {
- // TODO: this doesn't seem to work on the emulator. b/15114595
- std::stringstream iss(substring);
- iss >> value;
- // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range.
- sane_val = iss.eof() && (value >= min) && (value <= max);
- } else {
- char* end = nullptr;
- value = strtod(substring.c_str(), &end);
- sane_val = *end == '\0' && value >= min && value <= max;
- }
- if (!sane_val) {
- Usage("Invalid double value %s for option %s\n", substring.c_str(), option.c_str());
- }
- *parsed_value = value;
-}
-
void SleepForever() {
while (true) {
usleep(1000000);
diff --git a/libartbase/base/utils.h b/libartbase/base/utils.h
index 11472a8..9284950 100644
--- a/libartbase/base/utils.h
+++ b/libartbase/base/utils.h
@@ -30,7 +30,6 @@
#include "enums.h"
#include "globals.h"
#include "macros.h"
-#include "stringpiece.h"
namespace art {
@@ -91,44 +90,6 @@
return reinterpret_cast<const void*>(code);
}
-using UsageFn = void (*)(const char*, ...);
-
-template <typename T>
-static void ParseIntOption(const StringPiece& option,
- const std::string& option_name,
- T* out,
- UsageFn usage,
- bool is_long_option = true) {
- std::string option_prefix = option_name + (is_long_option ? "=" : "");
- DCHECK(option.starts_with(option_prefix)) << option << " " << option_prefix;
- const char* value_string = option.substr(option_prefix.size()).data();
- int64_t parsed_integer_value = 0;
- if (!android::base::ParseInt(value_string, &parsed_integer_value)) {
- usage("Failed to parse %s '%s' as an integer", option_name.c_str(), value_string);
- }
- *out = dchecked_integral_cast<T>(parsed_integer_value);
-}
-
-template <typename T>
-static void ParseUintOption(const StringPiece& option,
- const std::string& option_name,
- T* out,
- UsageFn usage,
- bool is_long_option = true) {
- ParseIntOption(option, option_name, out, usage, is_long_option);
- if (*out < 0) {
- usage("%s passed a negative value %d", option_name.c_str(), *out);
- *out = 0;
- }
-}
-
-void ParseDouble(const std::string& option,
- char after_char,
- double min,
- double max,
- double* parsed_value,
- UsageFn Usage);
-
#if defined(__BIONIC__)
struct Arc4RandomGenerator {
typedef uint32_t result_type;
diff --git a/profman/profman.cc b/profman/profman.cc
index 82d9df0..b29e743 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -25,6 +25,7 @@
#include <iostream>
#include <set>
#include <string>
+#include <string_view>
#include <unordered_set>
#include <vector>
@@ -36,7 +37,7 @@
#include "base/mem_map.h"
#include "base/scoped_flock.h"
#include "base/stl_util.h"
-#include "base/stringpiece.h"
+#include "base/string_view_cpp20.h"
#include "base/time_utils.h"
#include "base/unix_file/fd_file.h"
#include "base/utils.h"
@@ -188,6 +189,33 @@
exit(1);
}
+template <typename T>
+static void ParseUintOption(const char* raw_option,
+ std::string_view option_prefix,
+ T* out) {
+ DCHECK(EndsWith(option_prefix, "="));
+ DCHECK(StartsWith(raw_option, option_prefix)) << raw_option << " " << option_prefix;
+ const char* value_string = raw_option + option_prefix.size();
+ int64_t parsed_integer_value = 0;
+ if (!android::base::ParseInt(value_string, &parsed_integer_value)) {
+ std::string option_name(option_prefix.substr(option_prefix.size() - 1u));
+ Usage("Failed to parse %s '%s' as an integer", option_name.c_str(), value_string);
+ }
+ if (parsed_integer_value < 0) {
+ std::string option_name(option_prefix.substr(option_prefix.size() - 1u));
+ Usage("%s passed a negative value %" PRId64, option_name.c_str(), parsed_integer_value);
+ }
+ if (static_cast<uint64_t>(parsed_integer_value) >
+ static_cast<std::make_unsigned_t<T>>(std::numeric_limits<T>::max())) {
+ std::string option_name(option_prefix.substr(option_prefix.size() - 1u));
+ Usage("%s passed a value %" PRIu64 " above max (%" PRIu64 ")",
+ option_name.c_str(),
+ static_cast<uint64_t>(parsed_integer_value),
+ static_cast<uint64_t>(std::numeric_limits<T>::max()));
+ }
+ *out = dchecked_integral_cast<T>(parsed_integer_value);
+}
+
// TODO(calin): This class has grown too much from its initial design. Split the functionality
// into smaller, more contained pieces.
class ProfMan final {
@@ -226,7 +254,8 @@
}
for (int i = 0; i < argc; ++i) {
- const StringPiece option(argv[i]);
+ const char* raw_option = argv[i];
+ const std::string_view option(raw_option);
const bool log_options = false;
if (log_options) {
LOG(INFO) << "profman: option[" << i << "]=" << argv[i];
@@ -235,66 +264,60 @@
dump_only_ = true;
} else if (option == "--dump-classes-and-methods") {
dump_classes_and_methods_ = true;
- } else if (option.starts_with("--create-profile-from=")) {
- create_profile_from_file_ = option.substr(strlen("--create-profile-from=")).ToString();
- } else if (option.starts_with("--dump-output-to-fd=")) {
- ParseUintOption(option, "--dump-output-to-fd", &dump_output_to_fd_, Usage);
+ } else if (StartsWith(option, "--create-profile-from=")) {
+ create_profile_from_file_ = std::string(option.substr(strlen("--create-profile-from=")));
+ } else if (StartsWith(option, "--dump-output-to-fd=")) {
+ ParseUintOption(raw_option, "--dump-output-to-fd=", &dump_output_to_fd_);
} else if (option == "--generate-boot-image-profile") {
generate_boot_image_profile_ = true;
- } else if (option.starts_with("--boot-image-class-threshold=")) {
- ParseUintOption(option,
- "--boot-image-class-threshold",
- &boot_image_options_.image_class_theshold,
- Usage);
- } else if (option.starts_with("--boot-image-clean-class-threshold=")) {
- ParseUintOption(option,
- "--boot-image-clean-class-threshold",
- &boot_image_options_.image_class_clean_theshold,
- Usage);
- } else if (option.starts_with("--boot-image-sampled-method-threshold=")) {
- ParseUintOption(option,
- "--boot-image-sampled-method-threshold",
- &boot_image_options_.compiled_method_threshold,
- Usage);
- } else if (option.starts_with("--profile-file=")) {
- profile_files_.push_back(option.substr(strlen("--profile-file=")).ToString());
- } else if (option.starts_with("--profile-file-fd=")) {
- ParseFdForCollection(option, "--profile-file-fd", &profile_files_fd_);
- } else if (option.starts_with("--reference-profile-file=")) {
- reference_profile_file_ = option.substr(strlen("--reference-profile-file=")).ToString();
- } else if (option.starts_with("--reference-profile-file-fd=")) {
- ParseUintOption(option, "--reference-profile-file-fd", &reference_profile_file_fd_, Usage);
- } else if (option.starts_with("--dex-location=")) {
- dex_locations_.push_back(option.substr(strlen("--dex-location=")).ToString());
- } else if (option.starts_with("--apk-fd=")) {
- ParseFdForCollection(option, "--apk-fd", &apks_fd_);
- } else if (option.starts_with("--apk=")) {
- apk_files_.push_back(option.substr(strlen("--apk=")).ToString());
- } else if (option.starts_with("--generate-test-profile=")) {
- test_profile_ = option.substr(strlen("--generate-test-profile=")).ToString();
- } else if (option.starts_with("--generate-test-profile-num-dex=")) {
- ParseUintOption(option,
- "--generate-test-profile-num-dex",
- &test_profile_num_dex_,
- Usage);
- } else if (option.starts_with("--generate-test-profile-method-percentage")) {
- ParseUintOption(option,
- "--generate-test-profile-method-percentage",
- &test_profile_method_percerntage_,
- Usage);
- } else if (option.starts_with("--generate-test-profile-class-percentage")) {
- ParseUintOption(option,
- "--generate-test-profile-class-percentage",
- &test_profile_class_percentage_,
- Usage);
- } else if (option.starts_with("--generate-test-profile-seed=")) {
- ParseUintOption(option, "--generate-test-profile-seed", &test_profile_seed_, Usage);
- } else if (option.starts_with("--copy-and-update-profile-key")) {
+ } else if (StartsWith(option, "--boot-image-class-threshold=")) {
+ ParseUintOption(raw_option,
+ "--boot-image-class-threshold=",
+ &boot_image_options_.image_class_theshold);
+ } else if (StartsWith(option, "--boot-image-clean-class-threshold=")) {
+ ParseUintOption(raw_option,
+ "--boot-image-clean-class-threshold=",
+ &boot_image_options_.image_class_clean_theshold);
+ } else if (StartsWith(option, "--boot-image-sampled-method-threshold=")) {
+ ParseUintOption(raw_option,
+ "--boot-image-sampled-method-threshold=",
+ &boot_image_options_.compiled_method_threshold);
+ } else if (StartsWith(option, "--profile-file=")) {
+ profile_files_.push_back(std::string(option.substr(strlen("--profile-file="))));
+ } else if (StartsWith(option, "--profile-file-fd=")) {
+ ParseFdForCollection(raw_option, "--profile-file-fd=", &profile_files_fd_);
+ } else if (StartsWith(option, "--reference-profile-file=")) {
+ reference_profile_file_ = std::string(option.substr(strlen("--reference-profile-file=")));
+ } else if (StartsWith(option, "--reference-profile-file-fd=")) {
+ ParseUintOption(raw_option, "--reference-profile-file-fd=", &reference_profile_file_fd_);
+ } else if (StartsWith(option, "--dex-location=")) {
+ dex_locations_.push_back(std::string(option.substr(strlen("--dex-location="))));
+ } else if (StartsWith(option, "--apk-fd=")) {
+ ParseFdForCollection(raw_option, "--apk-fd=", &apks_fd_);
+ } else if (StartsWith(option, "--apk=")) {
+ apk_files_.push_back(std::string(option.substr(strlen("--apk="))));
+ } else if (StartsWith(option, "--generate-test-profile=")) {
+ test_profile_ = std::string(option.substr(strlen("--generate-test-profile=")));
+ } else if (StartsWith(option, "--generate-test-profile-num-dex=")) {
+ ParseUintOption(raw_option,
+ "--generate-test-profile-num-dex=",
+ &test_profile_num_dex_);
+ } else if (StartsWith(option, "--generate-test-profile-method-percentage=")) {
+ ParseUintOption(raw_option,
+ "--generate-test-profile-method-percentage=",
+ &test_profile_method_percerntage_);
+ } else if (StartsWith(option, "--generate-test-profile-class-percentage=")) {
+ ParseUintOption(raw_option,
+ "--generate-test-profile-class-percentage=",
+ &test_profile_class_percentage_);
+ } else if (StartsWith(option, "--generate-test-profile-seed=")) {
+ ParseUintOption(raw_option, "--generate-test-profile-seed=", &test_profile_seed_);
+ } else if (option == "--copy-and-update-profile-key") {
copy_and_update_profile_key_ = true;
- } else if (option.starts_with("--store-aggregation-counters")) {
+ } else if (option == "--store-aggregation-counters") {
store_aggregation_counters_ = true;
} else {
- Usage("Unknown argument '%s'", option.data());
+ Usage("Unknown argument '%s'", raw_option);
}
}
@@ -1265,11 +1288,11 @@
}
private:
- static void ParseFdForCollection(const StringPiece& option,
- const char* arg_name,
+ static void ParseFdForCollection(const char* raw_option,
+ std::string_view option_prefix,
std::vector<int>* fds) {
int fd;
- ParseUintOption(option, arg_name, &fd, Usage);
+ ParseUintOption(raw_option, option_prefix, &fd);
fds->push_back(fd);
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 2e1f364..148fdba 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1449,6 +1449,7 @@
static void UpdateInternStrings(
gc::space::ImageSpace* space,
+ bool use_preresolved_strings,
const SafeMap<mirror::String*, mirror::String*>& intern_remap)
REQUIRES_SHARED(Locks::mutator_lock_);
};
@@ -1464,8 +1465,10 @@
ScopedTrace app_image_timing("AppImage:Updating");
Thread* const self = Thread::Current();
- gc::Heap* const heap = Runtime::Current()->GetHeap();
+ Runtime* const runtime = Runtime::Current();
+ gc::Heap* const heap = runtime->GetHeap();
const ImageHeader& header = space->GetImageHeader();
+ bool load_app_image_startup_cache = runtime->LoadAppImageStartupCache();
{
// Register dex caches with the class loader.
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
@@ -1479,6 +1482,10 @@
class_linker->RegisterDexFileLocked(*dex_file, dex_cache, class_loader.Get());
}
+ if (!load_app_image_startup_cache) {
+ dex_cache->ClearPreResolvedStrings();
+ }
+
if (kIsDebugBuild) {
CHECK(new_class_set != nullptr);
mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes();
@@ -1545,11 +1552,13 @@
void AppImageLoadingHelper::UpdateInternStrings(
gc::space::ImageSpace* space,
+ bool use_preresolved_strings,
const SafeMap<mirror::String*, mirror::String*>& intern_remap) {
const uint8_t* target_base = space->Begin();
const ImageSection& sro_section =
space->GetImageHeader().GetImageStringReferenceOffsetsSection();
const size_t num_string_offsets = sro_section.Size() / sizeof(AppImageReferenceOffsetInfo);
+ InternTable* const intern_table = Runtime::Current()->GetInternTable();
VLOG(image)
<< "ClassLinker:AppImage:InternStrings:imageStringReferenceOffsetCount = "
@@ -1582,24 +1591,29 @@
WriteBarrier::ForEveryFieldWrite(dex_cache);
dex_cache->GetStrings()[string_index].store(
mirror::StringDexCachePair(it->second, source.index));
+ } else if (!use_preresolved_strings) {
+ dex_cache->GetStrings()[string_index].store(
+ mirror::StringDexCachePair(intern_table->InternStrong(referred_string), source.index));
}
} else if (HasDexCachePreResolvedStringNativeRefTag(base_offset)) {
- base_offset = ClearDexCacheNativeRefTags(base_offset);
- DCHECK_ALIGNED(base_offset, 2);
+ if (use_preresolved_strings) {
+ base_offset = ClearDexCacheNativeRefTags(base_offset);
+ DCHECK_ALIGNED(base_offset, 2);
- ObjPtr<mirror::DexCache> dex_cache =
- reinterpret_cast<mirror::DexCache*>(space->Begin() + base_offset);
- uint32_t string_index = sro_base[offset_index].second;
+ ObjPtr<mirror::DexCache> dex_cache =
+ reinterpret_cast<mirror::DexCache*>(space->Begin() + base_offset);
+ uint32_t string_index = sro_base[offset_index].second;
- ObjPtr<mirror::String> referred_string =
- dex_cache->GetPreResolvedStrings()[string_index].Read();
- DCHECK(referred_string != nullptr);
+ ObjPtr<mirror::String> referred_string =
+ dex_cache->GetPreResolvedStrings()[string_index].Read();
+ DCHECK(referred_string != nullptr);
- auto it = intern_remap.find(referred_string.Ptr());
- if (it != intern_remap.end()) {
- // Because we are not using a helper function we need to mark the GC card manually.
- WriteBarrier::ForEveryFieldWrite(dex_cache);
- dex_cache->GetPreResolvedStrings()[string_index] = GcRoot<mirror::String>(it->second);
+ auto it = intern_remap.find(referred_string.Ptr());
+ if (it != intern_remap.end()) {
+ // Because we are not using a helper function we need to mark the GC card manually.
+ WriteBarrier::ForEveryFieldWrite(dex_cache);
+ dex_cache->GetPreResolvedStrings()[string_index] = GcRoot<mirror::String>(it->second);
+ }
}
} else {
uint32_t raw_member_offset = sro_base[offset_index].second;
@@ -1622,6 +1636,13 @@
/* kCheckTransaction= */ false,
kVerifyNone,
/* kIsVolatile= */ false>(member_offset, it->second);
+ } else if (!use_preresolved_strings) {
+ obj_ptr->SetFieldObject</* kTransactionActive= */ false,
+ /* kCheckTransaction= */ false,
+ kVerifyNone,
+ /* kIsVolatile= */ false>(
+ member_offset,
+ intern_table->InternStrong(referred_string));
}
}
}
@@ -1632,13 +1653,16 @@
// the strings they point to.
ScopedTrace timing("AppImage:InternString");
- InternTable* const intern_table = Runtime::Current()->GetInternTable();
+ Runtime* const runtime = Runtime::Current();
+ InternTable* const intern_table = runtime->GetInternTable();
+
+ const bool load_startup_cache = runtime->LoadAppImageStartupCache();
// Add the intern table, removing any conflicts. For conflicts, store the new address in a map
// for faster lookup.
// TODO: Optimize with a bitmap or bloom filter
SafeMap<mirror::String*, mirror::String*> intern_remap;
- intern_table->AddImageStringsToTable(space, [&](InternTable::UnorderedSet& interns)
+ auto func = [&](InternTable::UnorderedSet& interns)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(Locks::intern_table_lock_) {
const size_t non_boot_image_strings = intern_table->CountInterns(
@@ -1681,14 +1705,23 @@
CHECK(intern_table->LookupStrongLocked(string) == nullptr) << string->ToModifiedUtf8();
}
}
- });
+ };
- VLOG(image) << "AppImage:conflictingInternStrings = " << intern_remap.size();
+ bool update_intern_strings;
+ if (load_startup_cache) {
+ // Only add the intern table if we are using the startup cache. Otherwise,
+ // UpdateInternStrings adds the strings to the intern table.
+ intern_table->AddImageStringsToTable(space, func);
+ update_intern_strings = kIsDebugBuild || !intern_remap.empty();
+ VLOG(image) << "AppImage:conflictingInternStrings = " << intern_remap.size();
+ } else {
+ update_intern_strings = true;
+ }
// For debug builds, always run the code below to get coverage.
- if (kIsDebugBuild || !intern_remap.empty()) {
+ if (update_intern_strings) {
// Slow path case is when there are conflicting intern strings to fix up.
- UpdateInternStrings(space, intern_remap);
+ UpdateInternStrings(space, /*use_preresolved_strings=*/ load_startup_cache, intern_remap);
}
}
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index c9bdbda..91cea79 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -409,7 +409,7 @@
void AssertDexFileClass(ObjPtr<mirror::ClassLoader> class_loader, const std::string& descriptor)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ASSERT_TRUE(descriptor != nullptr);
+ ASSERT_FALSE(descriptor.empty());
Thread* self = Thread::Current();
StackHandleScope<1> hs(self);
Handle<mirror::Class> klass(
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 47b621a..f0ad931 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -110,8 +110,7 @@
WriteBarrier::ForEveryFieldWrite(this);
}
-inline void DexCache::SetPreResolvedString(dex::StringIndex string_idx,
- ObjPtr<String> resolved) {
+inline void DexCache::SetPreResolvedString(dex::StringIndex string_idx, ObjPtr<String> resolved) {
DCHECK(resolved != nullptr);
DCHECK_LT(string_idx.index_, GetDexFile()->NumStringIds());
GetPreResolvedStrings()[string_idx.index_] = GcRoot<mirror::String>(resolved);
@@ -122,6 +121,17 @@
WriteBarrier::ForEveryFieldWrite(this);
}
+inline void DexCache::ClearPreResolvedStrings() {
+ SetFieldPtr64</*kTransactionActive=*/false,
+ /*kCheckTransaction=*/false,
+ kVerifyNone,
+ GcRoot<mirror::String>*>(PreResolvedStringsOffset(), nullptr);
+ SetField32</*kTransactionActive=*/false,
+ /*bool kCheckTransaction=*/false,
+ kVerifyNone,
+ /*kIsVolatile=*/false>(NumPreResolvedStringsOffset(), 0);
+}
+
inline void DexCache::ClearString(dex::StringIndex string_idx) {
DCHECK(Runtime::Current()->IsAotCompiler());
uint32_t slot_idx = StringSlotIndex(string_idx);
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index c742928..b5619f8 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -283,6 +283,11 @@
ObjPtr<mirror::String> resolved)
ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_);
+ // Clear the preresolved string cache to prevent further usage. Not thread safe, so should only
+ // be called when the string cache is guaranteed to not be accessed.
+ void ClearPreResolvedStrings()
+ ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_);
+
// Clear a string for a string_idx, used to undo string intern transactions to make sure
// the string isn't kept live.
void ClearString(dex::StringIndex string_idx) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 26fc5e9..891ecef 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -149,6 +149,7 @@
HIDDEN_API_ENFORCEMENT_POLICY_MASK = (1 << 12)
| (1 << 13),
PROFILE_SYSTEM_SERVER = 1 << 14,
+ USE_APP_IMAGE_STARTUP_CACHE = 1 << 16,
// bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value
// corresponding to hiddenapi::EnforcementPolicy
@@ -298,6 +299,10 @@
bool profile_system_server = (runtime_flags & PROFILE_SYSTEM_SERVER) == PROFILE_SYSTEM_SERVER;
runtime_flags &= ~PROFILE_SYSTEM_SERVER;
+ Runtime::Current()->SetLoadAppImageStartupCacheEnabled(
+ (runtime_flags & USE_APP_IMAGE_STARTUP_CACHE) != 0u);
+ runtime_flags &= ~USE_APP_IMAGE_STARTUP_CACHE;
+
if (runtime_flags != 0) {
LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index ee2c514..81c17a5 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -823,6 +823,14 @@
ThreadPool* const thread_pool_;
};
+ bool LoadAppImageStartupCache() const {
+ return load_app_image_startup_cache_;
+ }
+
+ void SetLoadAppImageStartupCacheEnabled(bool enabled) {
+ load_app_image_startup_cache_ = enabled;
+ }
+
private:
static void InitPlatformSignalHandlers();
@@ -1145,6 +1153,8 @@
uint32_t verifier_logging_threshold_ms_;
+ bool load_app_image_startup_cache_ = false;
+
// Note: See comments on GetFaultMessage.
friend std::string GetFaultMessageForAbortLogging();
friend class ScopedThreadPoolUsage;
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index 36890a6..09171a4 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -35,7 +35,7 @@
protected:
void VerifyClass(const std::string& descriptor)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ASSERT_TRUE(descriptor != nullptr);
+ ASSERT_FALSE(descriptor.empty());
Thread* self = Thread::Current();
ObjPtr<mirror::Class> klass = class_linker_->FindSystemClass(self, descriptor.c_str());
diff --git a/test/005-annotations/expected.txt b/test/005-annotations/expected.txt
index ee5b0c7..b537c8f 100644
--- a/test/005-annotations/expected.txt
+++ b/test/005-annotations/expected.txt
@@ -109,4 +109,4 @@
Get annotation with missing class should not throw
Got expected TypeNotPresentException
-Got expected NoSuchFieldError
+Got expected Error for renamed enum
diff --git a/test/005-annotations/src/android/test/anno/TestAnnotations.java b/test/005-annotations/src/android/test/anno/TestAnnotations.java
index 8ea8e8e..a3e32f9 100644
--- a/test/005-annotations/src/android/test/anno/TestAnnotations.java
+++ b/test/005-annotations/src/android/test/anno/TestAnnotations.java
@@ -17,6 +17,7 @@
package android.test.anno;
import java.lang.annotation.Annotation;
+import java.lang.annotation.AnnotationFormatError;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -241,8 +242,8 @@
Annotation[] annos = m.getDeclaredAnnotations();
System.out.println(" annotations on METH " + m + ":");
}
- } catch (NoSuchFieldError expected) {
- System.out.println("Got expected NoSuchFieldError");
+ } catch (Error expected) {
+ System.out.println("Got expected Error for renamed enum");
}
// Test if annotations marked VISIBILITY_BUILD are visible to runtime in M and earlier.
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 660c971..2910920 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -1005,12 +1005,14 @@
export ANDROID_DATA="$DEX_LOCATION"
export ANDROID_ROOT="${ANDROID_ROOT}"
export ANDROID_RUNTIME_ROOT="${ANDROID_RUNTIME_ROOT}"
- export LD_LIBRARY_PATH="${ANDROID_ROOT}/${LIBRARY_DIRECTORY}:${ANDROID_ROOT}/${TEST_DIRECTORY}"
if [ "$USE_ZIPAPEX" = "y" ]; then
# Put the zipapex files in front of the ld-library-path
- export LD_LIBRARY_PATH="${ANDROID_DATA}/zipapex/${LIBRARY_DIRECTORY}:${LD_LIBRARY_PATH}"
+ export LD_LIBRARY_PATH="${ANDROID_DATA}/zipapex/${LIBRARY_DIRECTORY}:${ANDROID_ROOT}/${TEST_DIRECTORY}"
+ export DYLD_LIBRARY_PATH="${ANDROID_DATA}/zipapex/${LIBRARY_DIRECTORY}:${ANDROID_ROOT}/${TEST_DIRECTORY}"
+ else
+ export LD_LIBRARY_PATH="${ANDROID_ROOT}/${LIBRARY_DIRECTORY}:${ANDROID_ROOT}/${TEST_DIRECTORY}"
+ export DYLD_LIBRARY_PATH="${ANDROID_ROOT}/${LIBRARY_DIRECTORY}:${ANDROID_ROOT}/${TEST_DIRECTORY}"
fi
- export DYLD_LIBRARY_PATH="${ANDROID_ROOT}/${LIBRARY_DIRECTORY}:${ANDROID_ROOT}/${TEST_DIRECTORY}"
export PATH="$PATH:$BIN_DIR"
# Temporarily disable address space layout randomization (ASLR).
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index 2692f68..141dd22 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -18,6 +18,8 @@
#include <iostream>
#include <map>
#include <set>
+#include <string>
+#include <string_view>
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -27,6 +29,7 @@
#include "base/mem_map.h"
#include "base/os.h"
#include "base/stl_util.h"
+#include "base/string_view_cpp20.h"
#include "base/unix_file/fd_file.h"
#include "dex/art_dex_file_loader.h"
#include "dex/class_accessor-inl.h"
@@ -887,45 +890,48 @@
argc--;
if (argc > 0) {
- const StringPiece command(argv[0]);
+ const char* raw_command = argv[0];
+ const std::string_view command(raw_command);
if (command == "encode") {
for (int i = 1; i < argc; ++i) {
- const StringPiece option(argv[i]);
- if (option.starts_with("--input-dex=")) {
- boot_dex_paths_.push_back(option.substr(strlen("--input-dex=")).ToString());
- } else if (option.starts_with("--output-dex=")) {
- output_dex_paths_.push_back(option.substr(strlen("--output-dex=")).ToString());
- } else if (option.starts_with("--api-flags=")) {
- api_flags_path_ = option.substr(strlen("--api-flags=")).ToString();
+ const char* raw_option = argv[i];
+ const std::string_view option(raw_option);
+ if (StartsWith(option, "--input-dex=")) {
+ boot_dex_paths_.push_back(std::string(option.substr(strlen("--input-dex="))));
+ } else if (StartsWith(option, "--output-dex=")) {
+ output_dex_paths_.push_back(std::string(option.substr(strlen("--output-dex="))));
+ } else if (StartsWith(option, "--api-flags=")) {
+ api_flags_path_ = std::string(option.substr(strlen("--api-flags=")));
} else if (option == "--no-force-assign-all") {
force_assign_all_ = false;
} else {
- Usage("Unknown argument '%s'", option.data());
+ Usage("Unknown argument '%s'", raw_option);
}
}
return Command::kEncode;
} else if (command == "list") {
for (int i = 1; i < argc; ++i) {
- const StringPiece option(argv[i]);
- if (option.starts_with("--boot-dex=")) {
- boot_dex_paths_.push_back(option.substr(strlen("--boot-dex=")).ToString());
- } else if (option.starts_with("--public-stub-classpath=")) {
+ const char* raw_option = argv[i];
+ const std::string_view option(raw_option);
+ if (StartsWith(option, "--boot-dex=")) {
+ boot_dex_paths_.push_back(std::string(option.substr(strlen("--boot-dex="))));
+ } else if (StartsWith(option, "--public-stub-classpath=")) {
stub_classpaths_.push_back(std::make_pair(
- option.substr(strlen("--public-stub-classpath=")).ToString(),
+ std::string(option.substr(strlen("--public-stub-classpath="))),
ApiList::Whitelist()));
- } else if (option.starts_with("--core-platform-stub-classpath=")) {
+ } else if (StartsWith(option, "--core-platform-stub-classpath=")) {
stub_classpaths_.push_back(std::make_pair(
- option.substr(strlen("--core-platform-stub-classpath=")).ToString(),
+ std::string(option.substr(strlen("--core-platform-stub-classpath="))),
ApiList::CorePlatformApi()));
- } else if (option.starts_with("--out-api-flags=")) {
- api_flags_path_ = option.substr(strlen("--out-api-flags=")).ToString();
+ } else if (StartsWith(option, "--out-api-flags=")) {
+ api_flags_path_ = std::string(option.substr(strlen("--out-api-flags=")));
} else {
- Usage("Unknown argument '%s'", option.data());
+ Usage("Unknown argument '%s'", raw_option);
}
}
return Command::kList;
} else {
- Usage("Unknown command '%s'", command.data());
+ Usage("Unknown command '%s'", raw_command);
}
} else {
Usage("No command specified");