Compile standalone system server jars.
This CL updates odrefresh to take an additional environment variable
`STANDALONE_SYSTEMSERVER_JARS` and compile standalone system server jars
accordingly.
Bug: 203198541
Test: atest odsign_e2e_tests
Test: atest art_standalone_odrefresh_tests
Test: atest art_standalone_artd_tests
Test: manual -
1. Patch aosp/1874113, aosp/1876173, aosp/1875774 and aosp/1875775.
2. Build a new system image and flash it to a device.
3. adb logcat odrefresh:D odsign:D "*:S"
4. See standalone system server jars being compiled and signed.
Change-Id: Ic824c7380cf9530437bc2a95b9ff816a63b22013
diff --git a/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl b/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl
index b351c67..bfb94e1 100644
--- a/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl
+++ b/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl
@@ -61,6 +61,7 @@
String oatLocation;
String[] classloaderContext;
boolean isBootImageOnSystem;
+ boolean classloaderContextAsParent;
// SECURITY: The server may accept the request to produce code for the specified architecture,
// if supported.
diff --git a/artd/libdexopt.cc b/artd/libdexopt.cc
index b9d4f4e..853f950 100644
--- a/artd/libdexopt.cc
+++ b/artd/libdexopt.cc
@@ -312,7 +312,11 @@
cmdline.emplace_back("--class-loader-context=PCL[]");
} else {
const std::string context_path = android::base::Join(args.classloaderContext, ':');
- cmdline.emplace_back("--class-loader-context=PCL[" + context_path + "]");
+ if (args.classloaderContextAsParent) {
+ cmdline.emplace_back("--class-loader-context=PCL[];PCL[" + context_path + "]");
+ } else {
+ cmdline.emplace_back("--class-loader-context=PCL[" + context_path + "]");
+ }
cmdline.emplace_back("--class-loader-context-fds=" +
android::base::Join(args.classloaderFds, ':'));
}
diff --git a/artd/libdexopt_test.cc b/artd/libdexopt_test.cc
index 7536dcd..e73c5d6 100644
--- a/artd/libdexopt_test.cc
+++ b/artd/libdexopt_test.cc
@@ -270,7 +270,7 @@
Contains("--compiler-filter=verify")));
}
- // Test classloader context
+ // Test empty classloader context
{
auto args = default_system_server_args_;
args.classloaderFds = {};
@@ -281,6 +281,15 @@
Not(Contains(HasSubstr("--class-loader-context-fds"))),
Contains("--class-loader-context=PCL[]")));
}
+
+ // Test classloader context as parent
+ {
+ auto args = default_system_server_args_;
+ args.classloaderContextAsParent = true;
+ std::vector<std::string> cmdline = Dex2oatArgsFromSystemServerArgs(args);
+
+ EXPECT_THAT(cmdline, Contains("--class-loader-context=PCL[];PCL[/cl/abc.jar:/cl/def.jar]"));
+ }
}
TEST_F(LibDexoptTest, AddDex2oatArgsFromSystemServerArgs_InvalidArguments) {
diff --git a/odrefresh/Android.bp b/odrefresh/Android.bp
index b527bbf..b4d0f49 100644
--- a/odrefresh/Android.bp
+++ b/odrefresh/Android.bp
@@ -52,6 +52,7 @@
"libtinyxml2",
],
tidy: true,
+ tidy_disabled_srcs: [":art-apex-cache-info"],
tidy_flags: [
"-format-style=file",
"-header-filter=(art/odrefresh/|system/apex/)",
diff --git a/odrefresh/CacheInfo.xsd b/odrefresh/CacheInfo.xsd
index 44f733f..3aa94a5 100644
--- a/odrefresh/CacheInfo.xsd
+++ b/odrefresh/CacheInfo.xsd
@@ -29,7 +29,7 @@
<xs:element name="moduleInfoList" minOccurs="1" maxOccurs="1" type="t:moduleInfoList" />
<xs:element name="bootClasspath" minOccurs="1" maxOccurs="1" type="t:classpath" />
<xs:element name="dex2oatBootClasspath" minOccurs="1" maxOccurs="1" type="t:classpath" />
- <xs:element name="systemServerClasspath" minOccurs="1" maxOccurs="1" type="t:classpath" />
+ <xs:element name="systemServerComponents" minOccurs="1" maxOccurs="1" type="t:systemServerComponents" />
</xs:sequence>
</xs:complexType>
</xs:element>
@@ -69,4 +69,20 @@
<xs:attribute name="checksums" type="xs:string" use="required" />
</xs:complexType>
+ <xs:complexType name="systemServerComponents">
+ <xs:sequence>
+ <xs:element name="component" type="t:systemServerComponent" />
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="systemServerComponent">
+ <xs:complexContent>
+ <xs:extension base="component">
+ <!-- True if the component is in SYSTEMSERVERCLASSPATH. Otherwise, the component is a
+ standalone one. -->
+ <xs:attribute name="isInClasspath" type="xs:boolean" use="required" />
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
</xs:schema>
diff --git a/odrefresh/odr_config.h b/odrefresh/odr_config.h
index 1798095..495ccf1 100644
--- a/odrefresh/odr_config.h
+++ b/odrefresh/odr_config.h
@@ -68,6 +68,7 @@
std::string artifact_dir_;
time_t max_execution_seconds_ = kMaximumExecutionSeconds;
time_t max_child_process_seconds_ = kMaxChildProcessSeconds;
+ std::string standalone_system_server_jars_;
// Staging directory for artifacts. The directory must exist and will be automatically removed
// after compilation. If empty, use the default directory.
@@ -185,6 +186,14 @@
staging_dir_ = staging_dir;
}
+ const std::string& GetStandaloneSystemServerJars() const {
+ return standalone_system_server_jars_;
+ }
+
+ void SetStandaloneSystemServerJars(const std::string& jars) {
+ standalone_system_server_jars_ = jars;
+ }
+
private:
// Returns a pair for the possible instruction sets for the configured instruction set
// architecture. The first item is the 32-bit architecture and the second item is the 64-bit
diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc
index 2bfc49a..72e0793 100644
--- a/odrefresh/odrefresh.cc
+++ b/odrefresh/odrefresh.cc
@@ -205,52 +205,77 @@
return module_info_list;
}
-bool CheckComponents(const std::vector<art_apex::Component>& expected_components,
- const std::vector<art_apex::Component>& actual_components,
- std::string* error_msg) {
+template <typename T>
+Result<void> CheckComponents(
+ const std::vector<T>& expected_components,
+ const std::vector<T>& actual_components,
+ const std::function<Result<void>(const T& expected, const T& actual)>& custom_checker =
+ [](const T&, const T&) -> Result<void> { return {}; }) {
if (expected_components.size() != actual_components.size()) {
- return false;
+ return Errorf(
+ "Component count differs ({} != {})", expected_components.size(), actual_components.size());
}
for (size_t i = 0; i < expected_components.size(); ++i) {
- const art_apex::Component& expected = expected_components[i];
- const art_apex::Component& actual = actual_components[i];
+ const T& expected = expected_components[i];
+ const T& actual = actual_components[i];
if (expected.getFile() != actual.getFile()) {
- *error_msg = android::base::StringPrintf("Component %zu file differs ('%s' != '%s')",
- i,
- expected.getFile().c_str(),
- actual.getFile().c_str());
- return false;
+ return Errorf(
+ "Component {} file differs ('{}' != '{}')", i, expected.getFile(), actual.getFile());
}
+
if (expected.getSize() != actual.getSize()) {
- *error_msg =
- android::base::StringPrintf("Component %zu size differs (%" PRIu64 " != %" PRIu64 ")",
- i,
- expected.getSize(),
- actual.getSize());
- return false;
+ return Errorf(
+ "Component {} size differs ({} != {})", i, expected.getSize(), actual.getSize());
}
+
if (expected.getChecksums() != actual.getChecksums()) {
- *error_msg = android::base::StringPrintf("Component %zu checksums differ ('%s' != '%s')",
- i,
- expected.getChecksums().c_str(),
- actual.getChecksums().c_str());
- return false;
+ return Errorf("Component {} checksums differ ('{}' != '{}')",
+ i,
+ expected.getChecksums(),
+ actual.getChecksums());
+ }
+
+ Result<void> result = custom_checker(expected, actual);
+ if (!result.ok()) {
+ return Errorf("Component {} {}", i, result.error().message());
}
}
- return true;
+ return {};
}
-std::vector<art_apex::Component> GenerateComponents(const std::vector<std::string>& jars) {
- std::vector<art_apex::Component> components;
+Result<void> CheckSystemServerComponents(
+ const std::vector<art_apex::SystemServerComponent>& expected_components,
+ const std::vector<art_apex::SystemServerComponent>& actual_components) {
+ return CheckComponents<art_apex::SystemServerComponent>(
+ expected_components,
+ actual_components,
+ [](const art_apex::SystemServerComponent& expected,
+ const art_apex::SystemServerComponent& actual) -> Result<void> {
+ if (expected.getIsInClasspath() != actual.getIsInClasspath()) {
+ return Errorf("isInClasspath differs ({} != {})",
+ expected.getIsInClasspath(),
+ actual.getIsInClasspath());
+ }
+
+ return {};
+ });
+}
+
+template <typename T>
+std::vector<T> GenerateComponents(
+ const std::vector<std::string>& jars,
+ const std::function<T(const std::string& path, uint64_t size, const std::string& checksum)>&
+ custom_generator) {
+ std::vector<T> components;
ArtDexFileLoader loader;
for (const std::string& path : jars) {
struct stat sb;
if (stat(path.c_str(), &sb) == -1) {
- PLOG(ERROR) << "Failed to get component: " << QuotePath(path);
+ PLOG(ERROR) << "Failed to stat component: " << QuotePath(path);
return {};
}
@@ -258,7 +283,7 @@
std::vector<std::string> dex_locations;
std::string error_msg;
if (!loader.GetMultiDexChecksums(path.c_str(), &checksums, &dex_locations, &error_msg)) {
- LOG(ERROR) << "Failed to get components: " << error_msg;
+ LOG(ERROR) << "Failed to get multi-dex checksums: " << error_msg;
return {};
}
@@ -271,12 +296,25 @@
}
const std::string checksum = oss.str();
- components.emplace_back(art_apex::Component{path, static_cast<uint64_t>(sb.st_size), checksum});
+ Result<T> component = custom_generator(path, static_cast<uint64_t>(sb.st_size), checksum);
+ if (!component.ok()) {
+ LOG(ERROR) << "Failed to generate component: " << component.error();
+ return {};
+ }
+
+ components.push_back(*std::move(component));
}
return components;
}
+std::vector<art_apex::Component> GenerateComponents(const std::vector<std::string>& jars) {
+ return GenerateComponents<art_apex::Component>(
+ jars, [](const std::string& path, uint64_t size, const std::string& checksum) {
+ return art_apex::Component{path, size, checksum};
+ });
+}
+
// Checks whether a group of artifacts exists. Returns true if all are present, false otherwise.
// If `checked_artifacts` is present, adds checked artifacts to `checked_artifacts`.
bool ArtifactsExist(const OdrArtifacts& artifacts,
@@ -501,8 +539,17 @@
}
}
- systemserver_compilable_jars_ = android::base::Split(config_.GetSystemServerClasspath(), ":");
+ all_systemserver_jars_ = android::base::Split(config_.GetSystemServerClasspath(), ":");
+ systemserver_classpath_jars_ = {all_systemserver_jars_.begin(), all_systemserver_jars_.end()};
boot_classpath_jars_ = android::base::Split(config_.GetBootClasspath(), ":");
+ std::string standalone_system_server_jars_str = config_.GetStandaloneSystemServerJars();
+ if (!standalone_system_server_jars_str.empty()) {
+ std::vector<std::string> standalone_systemserver_jars =
+ android::base::Split(standalone_system_server_jars_str, ":");
+ std::move(standalone_systemserver_jars.begin(),
+ standalone_systemserver_jars.end(),
+ std::back_inserter(all_systemserver_jars_));
+ }
}
time_t OnDeviceRefresh::GetExecutionTimeUsed() const {
@@ -580,7 +627,7 @@
return;
}
- std::optional<std::vector<art_apex::Component>> system_server_components =
+ std::optional<std::vector<art_apex::SystemServerComponent>> system_server_components =
GenerateSystemServerComponents();
if (!system_server_components.has_value()) {
LOG(ERROR) << "No system_server extension components.";
@@ -592,7 +639,7 @@
{art_apex::ModuleInfoList(module_info_list)},
{art_apex::Classpath(bcp_components.value())},
{art_apex::Classpath(bcp_compilable_components.value())},
- {art_apex::Classpath(system_server_components.value())});
+ {art_apex::SystemServerComponents(system_server_components.value())});
art_apex::write(out, info);
}
@@ -614,8 +661,14 @@
return GenerateComponents(boot_extension_compilable_jars_);
}
-std::vector<art_apex::Component> OnDeviceRefresh::GenerateSystemServerComponents() const {
- return GenerateComponents(systemserver_compilable_jars_);
+std::vector<art_apex::SystemServerComponent> OnDeviceRefresh::GenerateSystemServerComponents()
+ const {
+ return GenerateComponents<art_apex::SystemServerComponent>(
+ all_systemserver_jars_,
+ [&](const std::string& path, uint64_t size, const std::string& checksum) {
+ bool isInClasspath = ContainsElement(systemserver_classpath_jars_, path);
+ return art_apex::SystemServerComponent{path, size, checksum, isInClasspath};
+ });
}
std::string OnDeviceRefresh::GetBootImageExtensionImage(bool on_system) const {
@@ -673,7 +726,7 @@
/*out*/ std::string* error_msg,
/*out*/ std::set<std::string>* jars_missing_artifacts,
/*out*/ std::vector<std::string>* checked_artifacts) const {
- for (const std::string& jar_path : systemserver_compilable_jars_) {
+ for (const std::string& jar_path : all_systemserver_jars_) {
const std::string image_location = GetSystemServerImagePath(on_system, jar_path);
const OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
// .art files are optional and are not generated for all jars by the build system.
@@ -693,12 +746,11 @@
const apex::ApexInfo& art_apex_info,
const std::optional<art_apex::CacheInfo>& cache_info,
/*out*/ std::vector<std::string>* checked_artifacts) const {
- std::string error_msg;
-
if (art_apex_info.getIsFactory()) {
LOG(INFO) << "Factory ART APEX mounted.";
// ART is not updated, so we can use the artifacts on /system. Check if they exist.
+ std::string error_msg;
if (BootExtensionArtifactsExist(/*on_system=*/true, isa, &error_msg)) {
return true;
}
@@ -770,13 +822,16 @@
const std::vector<art_apex::Component>& bcp_compilable_components =
cache_info->getFirstDex2oatBootClasspath()->getComponent();
- if (!CheckComponents(expected_bcp_compilable_components, bcp_compilable_components, &error_msg)) {
- LOG(INFO) << "Dex2OatClasspath components mismatch: " << error_msg;
+ Result<void> result =
+ CheckComponents(expected_bcp_compilable_components, bcp_compilable_components);
+ if (!result.ok()) {
+ LOG(INFO) << "Dex2OatClasspath components mismatch: " << result.error();
metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
return false;
}
// Cache info looks good, check all compilation artifacts exist.
+ std::string error_msg;
if (!BootExtensionArtifactsExist(/*on_system=*/false, isa, &error_msg, checked_artifacts)) {
LOG(INFO) << "Incomplete boot extension artifacts. " << error_msg;
metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
@@ -797,7 +852,6 @@
return false;
};
- std::string error_msg;
std::set<std::string> jars_missing_artifacts_on_system;
bool artifacts_on_system_up_to_date = false;
@@ -807,6 +861,7 @@
LOG(INFO) << "Factory APEXes mounted.";
// APEXes are not updated, so we can use the artifacts on /system. Check if they exist.
+ std::string error_msg;
if (SystemServerArtifactsExist(
/*on_system=*/true, &error_msg, &jars_missing_artifacts_on_system)) {
return true;
@@ -894,20 +949,22 @@
//
// The system_server components may change unexpectedly, for example an OTA could update
// services.jar.
- const std::vector<art_apex::Component> expected_system_server_components =
+ const std::vector<art_apex::SystemServerComponent> expected_system_server_components =
GenerateSystemServerComponents();
if (expected_system_server_components.size() != 0 &&
- (!cache_info->hasSystemServerClasspath() ||
- !cache_info->getFirstSystemServerClasspath()->hasComponent())) {
- LOG(INFO) << "Missing SystemServerClasspath components.";
+ (!cache_info->hasSystemServerComponents() ||
+ !cache_info->getFirstSystemServerComponents()->hasComponent())) {
+ LOG(INFO) << "Missing SystemServerComponents.";
metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
return compile_all();
}
- const std::vector<art_apex::Component>& system_server_components =
- cache_info->getFirstSystemServerClasspath()->getComponent();
- if (!CheckComponents(expected_system_server_components, system_server_components, &error_msg)) {
- LOG(INFO) << "SystemServerClasspath components mismatch: " << error_msg;
+ const std::vector<art_apex::SystemServerComponent>& system_server_components =
+ cache_info->getFirstSystemServerComponents()->getComponent();
+ Result<void> result =
+ CheckSystemServerComponents(expected_system_server_components, system_server_components);
+ if (!result.ok()) {
+ LOG(INFO) << "SystemServerComponents mismatch: " << result.error();
metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
return compile_all();
}
@@ -923,14 +980,16 @@
const std::vector<art_apex::Component>& bcp_components =
cache_info->getFirstBootClasspath()->getComponent();
- if (!CheckComponents(expected_bcp_components, bcp_components, &error_msg)) {
- LOG(INFO) << "BootClasspath components mismatch: " << error_msg;
+ result = CheckComponents(expected_bcp_components, bcp_components);
+ if (!result.ok()) {
+ LOG(INFO) << "BootClasspath components mismatch: " << result.error();
metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
// Boot classpath components can be dependencies of system_server components, so system_server
// components need to be recompiled if boot classpath components are changed.
return compile_all();
}
+ std::string error_msg;
std::set<std::string> jars_missing_artifacts_on_data;
if (!SystemServerArtifactsExist(
/*on_system=*/false, &error_msg, &jars_missing_artifacts_on_data, checked_artifacts)) {
@@ -1238,9 +1297,12 @@
const std::string dex2oat = config_.GetDex2Oat();
const InstructionSet isa = config_.GetSystemServerIsa();
- for (const std::string& jar : systemserver_compilable_jars_) {
- auto scope_guard =
- android::base::make_scope_guard([&]() { classloader_context.emplace_back(jar); });
+ for (const std::string& jar : all_systemserver_jars_) {
+ auto scope_guard = android::base::make_scope_guard([&]() {
+ if (ContainsElement(systemserver_classpath_jars_, jar)) {
+ classloader_context.emplace_back(jar);
+ }
+ });
if (!ContainsElement(system_server_jars_to_compile, jar)) {
continue;
@@ -1332,6 +1394,9 @@
}
dexopt_args.classloaderFds = fds;
}
+ if (!art::ContainsElement(systemserver_classpath_jars_, jar)) {
+ dexopt_args.classloaderContextAsParent = true;
+ }
if (!PrepareDex2OatConcurrencyArguments(&dexopt_args.threads, &dexopt_args.cpuSet)) {
return false;
diff --git a/odrefresh/odrefresh.h b/odrefresh/odrefresh.h
index 17003ee..7969aa4 100644
--- a/odrefresh/odrefresh.h
+++ b/odrefresh/odrefresh.h
@@ -23,6 +23,7 @@
#include <optional>
#include <set>
#include <string>
+#include <unordered_set>
#include <vector>
#include "android-base/result.h"
@@ -69,7 +70,7 @@
// Returns a set of all system server jars.
std::set<std::string> AllSystemServerJars() const {
- return {systemserver_compilable_jars_.begin(), systemserver_compilable_jars_.end()};
+ return {all_systemserver_jars_.begin(), all_systemserver_jars_.end()};
}
private:
@@ -92,7 +93,7 @@
std::vector<com::android::art::Component> GenerateBootExtensionCompilableComponents() const;
- std::vector<com::android::art::Component> GenerateSystemServerComponents() const;
+ std::vector<com::android::art::SystemServerComponent> GenerateSystemServerComponents() const;
std::string GetBootImageExtensionImage(bool on_system) const;
@@ -168,13 +169,18 @@
// List of boot extension components that should be compiled.
std::vector<std::string> boot_extension_compilable_jars_;
- // List of system_server components that should be compiled.
- std::vector<std::string> systemserver_compilable_jars_;
+ // Set of system_server components in SYSTEMSERVERCLASSPATH that should be compiled.
+ std::unordered_set<std::string> systemserver_classpath_jars_;
// List of all boot classpath components. Used as the dependencies for compiling the
// system_server.
std::vector<std::string> boot_classpath_jars_;
+ // List of all system_server components, including those in SYSTEMSERVERCLASSPATH and those in
+ // STANDALONE_SYSTEMSERVER_JARS (jars that system_server loads dynamically using separate
+ // classloaders).
+ std::vector<std::string> all_systemserver_jars_;
+
const time_t start_time_;
std::unique_ptr<ExecUtils> exec_utils_;
diff --git a/odrefresh/odrefresh_main.cc b/odrefresh/odrefresh_main.cc
index 1cd4d5a..cd16e9c 100644
--- a/odrefresh/odrefresh_main.cc
+++ b/odrefresh/odrefresh_main.cc
@@ -95,6 +95,14 @@
return value;
}
+std::string GetEnvironmentVariableOrDefault(const char* name, std::string default_value) {
+ const char* value = getenv(name);
+ if (value == nullptr) {
+ return default_value;
+ }
+ return value;
+}
+
bool ArgumentMatches(std::string_view argument, std::string_view prefix, std::string* value) {
if (android::base::StartsWith(argument, prefix)) {
*value = std::string(argument.substr(prefix.size()));
@@ -162,6 +170,10 @@
config->SetIsa(art::GetInstructionSetFromString(value.c_str()));
} else if (ArgumentMatches(arg, "--system-server-classpath=", &value)) {
config->SetSystemServerClasspath(arg);
+ } else if (ArgumentMatches(arg, "--bootclasspath=", &value)) {
+ config->SetBootClasspath(arg);
+ } else if (ArgumentMatches(arg, "--standalone-system-server-jars=", &value)) {
+ config->SetStandaloneSystemServerJars(arg);
} else if (ArgumentMatches(arg, "--zygote-arch=", &value)) {
ZygoteKind zygote_kind;
if (!ParseZygoteKind(value.c_str(), &zygote_kind)) {
@@ -184,6 +196,8 @@
UsageError("--isa-root");
UsageError("--system-server-classpath");
UsageError("--zygote-arch");
+ UsageError("--bootclasspath");
+ UsageError("--standalone-system-server-jars");
}
int InitializeTargetConfig(int argc, char** argv, OdrConfig* config) {
@@ -192,6 +206,8 @@
config->SetBootClasspath(GetEnvironmentVariableOrDie("BOOTCLASSPATH"));
config->SetDex2oatBootclasspath(GetEnvironmentVariableOrDie("DEX2OATBOOTCLASSPATH"));
config->SetSystemServerClasspath(GetEnvironmentVariableOrDie("SYSTEMSERVERCLASSPATH"));
+ config->SetStandaloneSystemServerJars(
+ GetEnvironmentVariableOrDefault("STANDALONE_SYSTEMSERVER_JARS", /*default_value=*/""));
config->SetIsa(art::kRuntimeISA);
std::string zygote;
diff --git a/odrefresh/odrefresh_test.cc b/odrefresh/odrefresh_test.cc
index 5882424..dabfeb0 100644
--- a/odrefresh/odrefresh_test.cc
+++ b/odrefresh/odrefresh_test.cc
@@ -56,6 +56,7 @@
using ::aidl::com::android::art::DexoptBcpExtArgs;
using ::aidl::com::android::art::DexoptSystemServerArgs;
using ::aidl::com::android::art::Isa;
+using ::testing::_;
using ::testing::AllOf;
using ::testing::Contains;
using ::testing::ElementsAre;
@@ -90,17 +91,11 @@
public:
// A workaround to avoid MOCK_METHOD on a method with an `std::string*` parameter, which will lead
// to a conflict between gmock and android-base/logging.h (b/132668253).
- int DexoptBcpExtension(const DexoptBcpExtArgs& args,
- time_t,
- bool*,
- std::string*) override {
+ int DexoptBcpExtension(const DexoptBcpExtArgs& args, time_t, bool*, std::string*) override {
return DoDexoptBcpExtension(args);
}
- int DexoptSystemServer(const DexoptSystemServerArgs& args,
- time_t,
- bool*,
- std::string*) override {
+ int DexoptSystemServer(const DexoptSystemServerArgs& args, time_t, bool*, std::string*) override {
return DoDexoptSystemServer(args);
}
@@ -160,6 +155,8 @@
framework_jar_ = framework_dir_ + "/framework.jar";
location_provider_jar_ = framework_dir_ + "/com.android.location.provider.jar";
services_jar_ = framework_dir_ + "/services.jar";
+ services_foo_jar_ = framework_dir_ + "/services-foo.jar";
+ services_bar_jar_ = framework_dir_ + "/services-bar.jar";
std::string services_jar_prof = framework_dir_ + "/services.jar.prof";
std::string javalib_dir = android_art_root_path + "/javalib";
std::string boot_art = javalib_dir + "/boot.art";
@@ -169,6 +166,8 @@
CreateEmptyFile(framework_jar_);
CreateEmptyFile(location_provider_jar_);
CreateEmptyFile(services_jar_);
+ CreateEmptyFile(services_foo_jar_);
+ CreateEmptyFile(services_bar_jar_);
CreateEmptyFile(services_jar_prof);
ASSERT_TRUE(EnsureDirectoryExists(javalib_dir));
CreateEmptyFile(boot_art);
@@ -178,6 +177,7 @@
config_.SetBootClasspath(framework_jar_);
config_.SetDex2oatBootclasspath(framework_jar_);
config_.SetSystemServerClasspath(Concatenate({location_provider_jar_, ":", services_jar_}));
+ config_.SetStandaloneSystemServerJars(Concatenate({services_foo_jar_, ":", services_bar_jar_}));
config_.SetIsa(InstructionSet::kX86_64);
config_.SetZygoteKind(ZygoteKind::kZygote64_32);
@@ -201,9 +201,10 @@
std::pair<std::unique_ptr<OnDeviceRefresh>, MockOdrDexopt*> CreateOdRefresh() {
auto mock_odr_dexopt = std::make_unique<MockOdrDexopt>();
MockOdrDexopt* mock_odr_dexopt_ptr = mock_odr_dexopt.get();
- auto odrefresh = std::make_unique<OnDeviceRefresh>(
- config_, dalvik_cache_dir_ + "/cache-info.xml", std::make_unique<ExecUtils>(),
- std::move(mock_odr_dexopt));
+ auto odrefresh = std::make_unique<OnDeviceRefresh>(config_,
+ dalvik_cache_dir_ + "/cache-info.xml",
+ std::make_unique<ExecUtils>(),
+ std::move(mock_odr_dexopt));
return std::make_pair(std::move(odrefresh), mock_odr_dexopt_ptr);
}
@@ -216,6 +217,8 @@
std::string framework_jar_;
std::string location_provider_jar_;
std::string services_jar_;
+ std::string services_foo_jar_;
+ std::string services_bar_jar_;
std::string dalvik_cache_dir_;
std::string framework_dir_;
std::string boot_profile_file_;
@@ -234,12 +237,29 @@
EXPECT_CALL(*mock_odr_dexopt,
DoDexoptSystemServer(
AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
- Field(&DexoptSystemServerArgs::classloaderContext, IsEmpty()))))
+ Field(&DexoptSystemServerArgs::classloaderContext, IsEmpty()),
+ Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(false)))))
+ .WillOnce(Return(0));
+ EXPECT_CALL(
+ *mock_odr_dexopt,
+ DoDexoptSystemServer(AllOf(
+ Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContext, ElementsAre(location_provider_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(false)))))
.WillOnce(Return(0));
EXPECT_CALL(*mock_odr_dexopt,
- DoDexoptSystemServer(AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
- Field(&DexoptSystemServerArgs::classloaderContext,
- ElementsAre(location_provider_jar_)))))
+ DoDexoptSystemServer(
+ AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(services_foo_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContext,
+ ElementsAre(location_provider_jar_, services_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(true)))))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptSystemServer(
+ AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(services_bar_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContext,
+ ElementsAre(location_provider_jar_, services_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(true)))))
.WillOnce(Return(0));
EXPECT_EQ(
@@ -253,17 +273,40 @@
TEST_F(OdRefreshTest, PartialSystemServerJars) {
auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
+ EXPECT_CALL(
+ *mock_odr_dexopt,
+ DoDexoptSystemServer(AllOf(
+ Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContext, ElementsAre(location_provider_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(false)))))
+ .WillOnce(Return(0));
EXPECT_CALL(*mock_odr_dexopt,
- DoDexoptSystemServer(AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
- Field(&DexoptSystemServerArgs::classloaderContext,
- ElementsAre(location_provider_jar_)))))
+ DoDexoptSystemServer(
+ AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(services_bar_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContext,
+ ElementsAre(location_provider_jar_, services_jar_)),
+ Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(true)))))
.WillOnce(Return(0));
- EXPECT_EQ(odrefresh->Compile(*metrics_,
- CompilationOptions{
- .system_server_jars_to_compile = {services_jar_},
- }),
- ExitCode::kCompilationSuccess);
+ EXPECT_EQ(
+ odrefresh->Compile(*metrics_,
+ CompilationOptions{
+ .system_server_jars_to_compile = {services_jar_, services_bar_jar_},
+ }),
+ ExitCode::kCompilationSuccess);
+}
+
+// Verifies that odrefresh can run properly when the STANDALONE_SYSTEM_SERVER_JARS variable is
+// missing, which is expected on Android S.
+TEST_F(OdRefreshTest, MissingStandaloneSystemServerJars) {
+ config_.SetStandaloneSystemServerJars("");
+ auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
+ EXPECT_EQ(
+ odrefresh->Compile(*metrics_,
+ CompilationOptions{
+ .system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
+ }),
+ ExitCode::kCompilationSuccess);
}
TEST_F(OdRefreshTest, CompileSetsCompilerFilter) {
@@ -275,24 +318,23 @@
{
auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
+ ON_CALL(*mock_odr_dexopt, DoDexoptSystemServer(_)).WillByDefault(Return(0));
// Test setup: default compiler filter should be "speed".
auto guard = ScopedSetProperty("dalvik.vm.systemservercompilerfilter", "");
- EXPECT_CALL(
- *mock_odr_dexopt,
- DoDexoptSystemServer(AllOf(
- Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
- Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED)))))
- .WillOnce(Return(0))
- .RetiresOnSaturation();
- EXPECT_CALL(
- *mock_odr_dexopt,
- DoDexoptSystemServer(AllOf(
- Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
- Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED)))))
- .WillOnce(Return(0))
- .RetiresOnSaturation();
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptSystemServer(AllOf(
+ Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
+ Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED)))))
+ .WillOnce(Return(0))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptSystemServer(AllOf(
+ Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
+ Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED)))))
+ .WillOnce(Return(0))
+ .RetiresOnSaturation();
EXPECT_EQ(
odrefresh->Compile(*metrics_,
CompilationOptions{
@@ -315,15 +357,14 @@
Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
Field(&DexoptSystemServerArgs::profileFd, Ge(0)),
Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED_PROFILE)))))
- .WillOnce(Return(0))
- .RetiresOnSaturation();
- EXPECT_CALL(
- *mock_odr_dexopt,
- DoDexoptSystemServer(AllOf(
- Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
- Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED)))))
- .WillOnce(Return(0))
- .RetiresOnSaturation();
+ .WillOnce(Return(0))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptSystemServer(AllOf(
+ Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
+ Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED)))))
+ .WillOnce(Return(0))
+ .RetiresOnSaturation();
EXPECT_EQ(
odrefresh->Compile(*metrics_,
CompilationOptions{
@@ -338,20 +379,18 @@
// Test setup: "verify" compiler filter should be simply applied.
auto guard = ScopedSetProperty("dalvik.vm.systemservercompilerfilter", "verify");
- EXPECT_CALL(
- *mock_odr_dexopt,
- DoDexoptSystemServer(AllOf(
- Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
- Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::VERIFY)))))
- .WillOnce(Return(0))
- .RetiresOnSaturation();
- EXPECT_CALL(
- *mock_odr_dexopt,
- DoDexoptSystemServer(AllOf(
- Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
- Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::VERIFY)))))
- .WillOnce(Return(0))
- .RetiresOnSaturation();
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptSystemServer(AllOf(
+ Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
+ Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::VERIFY)))))
+ .WillOnce(Return(0))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptSystemServer(AllOf(
+ Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
+ Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::VERIFY)))))
+ .WillOnce(Return(0))
+ .RetiresOnSaturation();
EXPECT_EQ(
odrefresh->Compile(*metrics_,
CompilationOptions{
@@ -364,13 +403,11 @@
TEST_F(OdRefreshTest, OutputFilesAndIsa) {
auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
- EXPECT_CALL(
- *mock_odr_dexopt,
- DoDexoptBcpExtension(AllOf(
- Field(&DexoptBcpExtArgs::isa, Eq(Isa::X86_64)),
- Field(&DexoptBcpExtArgs::imageFd, Ge(0)),
- Field(&DexoptBcpExtArgs::vdexFd, Ge(0)),
- Field(&DexoptBcpExtArgs::oatFd, Ge(0)))))
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptBcpExtension(AllOf(Field(&DexoptBcpExtArgs::isa, Eq(Isa::X86_64)),
+ Field(&DexoptBcpExtArgs::imageFd, Ge(0)),
+ Field(&DexoptBcpExtArgs::vdexFd, Ge(0)),
+ Field(&DexoptBcpExtArgs::oatFd, Ge(0)))))
.WillOnce(Return(0));
EXPECT_CALL(*mock_odr_dexopt,
diff --git a/odrefresh/schema/current.txt b/odrefresh/schema/current.txt
index 4757c87..a7aa52e 100644
--- a/odrefresh/schema/current.txt
+++ b/odrefresh/schema/current.txt
@@ -7,12 +7,12 @@
method public com.android.art.Classpath getBootClasspath();
method public com.android.art.Classpath getDex2oatBootClasspath();
method public com.android.art.ModuleInfoList getModuleInfoList();
- method public com.android.art.Classpath getSystemServerClasspath();
+ method public com.android.art.SystemServerComponents getSystemServerComponents();
method public void setArtModuleInfo(com.android.art.ModuleInfo);
method public void setBootClasspath(com.android.art.Classpath);
method public void setDex2oatBootClasspath(com.android.art.Classpath);
method public void setModuleInfoList(com.android.art.ModuleInfoList);
- method public void setSystemServerClasspath(com.android.art.Classpath);
+ method public void setSystemServerComponents(com.android.art.SystemServerComponents);
}
public class Classpath {
@@ -49,6 +49,18 @@
method public void setModuleInfo(com.android.art.ModuleInfo);
}
+ public class SystemServerComponent extends com.android.art.Component {
+ ctor public SystemServerComponent();
+ method public boolean getIsInClasspath();
+ method public void setIsInClasspath(boolean);
+ }
+
+ public class SystemServerComponents {
+ ctor public SystemServerComponents();
+ method public com.android.art.SystemServerComponent getComponent();
+ method public void setComponent(com.android.art.SystemServerComponent);
+ }
+
public class XmlParser {
ctor public XmlParser();
method public static com.android.art.CacheInfo read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
diff --git a/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java b/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java
index 53f6b21..bcce9a0 100644
--- a/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java
+++ b/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java
@@ -28,9 +28,11 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Stream;
import java.util.stream.Collectors;
/**
@@ -105,10 +107,12 @@
verifyGeneratedArtifactsLoaded();
}
- private String[] getSystemServerClasspath() throws Exception {
- String systemServerClasspath =
- getDevice().executeShellCommand("echo $SYSTEMSERVERCLASSPATH");
- return systemServerClasspath.trim().split(":");
+ private String[] getListFromEnvironmentVariable(String name) throws Exception {
+ String systemServerClasspath = getDevice().executeShellCommand("echo $" + name).trim();
+ if (!systemServerClasspath.isEmpty()) {
+ return systemServerClasspath.split(":");
+ }
+ return new String[0];
}
private String getSystemServerIsa(String mappedArtifact) {
@@ -121,8 +125,12 @@
}
private void verifySystemServerLoadedArtifacts() throws Exception {
- String[] classpathElements = getSystemServerClasspath();
+ String[] classpathElements = getListFromEnvironmentVariable("SYSTEMSERVERCLASSPATH");
assertTrue("SYSTEMSERVERCLASSPATH is empty", classpathElements.length > 0);
+ String[] standaloneJars = getListFromEnvironmentVariable("STANDALONE_SYSTEMSERVER_JARS");
+ String[] allSystemServerJars = Stream
+ .concat(Arrays.stream(classpathElements), Arrays.stream(standaloneJars))
+ .toArray(String[]::new);
final Set<String> mappedArtifacts = sTestUtils.getSystemServerLoadedArtifacts();
assertTrue(
@@ -133,7 +141,7 @@
String.format("%s/%s", OdsignTestUtils.ART_APEX_DALVIK_CACHE_DIRNAME, isa);
// Check components in the system_server classpath have mapped artifacts.
- for (String element : classpathElements) {
+ for (String element : allSystemServerJars) {
String escapedPath = element.substring(1).replace('/', '@');
for (String extension : OdsignTestUtils.APP_ARTIFACT_EXTENSIONS) {
final String fullArtifactPath =