summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jiakai Zhang <jiakaiz@google.com> 2024-01-31 10:26:02 +0800
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-02-06 05:08:04 +0000
commitc5ee51b87354b5f741eb956528ef9367917e9030 (patch)
tree1f0115d98e23b8a2e48f713838e2023b268a72b4
parenteeb1396a833d0df33da1578c3f4efed41673562d (diff)
Add service dexopt_chroot_setup and artd_pre_reboot.
Boilerplate changes. Bug: 311377497 Test: manual - Call getDexoptChrootSetupServiceRegisterer().waitForService() Test: manual - Set up a chroot environment and call getArtdPreRebootServiceRegisterer().waitForService() Test: manual - Test the fuzzers on host and on device following the instructions at https://source.android.com/docs/security/test/libfuzzer. Change-Id: Ic576d741ae0fe058833d3bbad6ebb5188ccf200a
-rw-r--r--artd/Android.bp27
-rw-r--r--artd/artd.cc5
-rw-r--r--artd/artd.h13
-rw-r--r--artd/artd_fuzzer.cc31
-rw-r--r--artd/artd_main.cc31
-rw-r--r--artd/artd_test.cc3
-rw-r--r--build/Android.gtest.mk2
-rw-r--r--build/apex/Android.bp2
-rw-r--r--build/apex/art.rc27
-rwxr-xr-xbuild/apex/art_apex_test.py2
-rw-r--r--dexopt_chroot_setup/Android.bp111
-rw-r--r--dexopt_chroot_setup/README.md10
-rw-r--r--dexopt_chroot_setup/binder/Android.bp56
-rw-r--r--dexopt_chroot_setup/binder/com/android/server/art/IDexoptChrootSetup.aidl21
-rw-r--r--dexopt_chroot_setup/dexopt_chroot_setup.cc52
-rw-r--r--dexopt_chroot_setup/dexopt_chroot_setup.h35
-rw-r--r--dexopt_chroot_setup/dexopt_chroot_setup_fuzzer.cc31
-rw-r--r--dexopt_chroot_setup/dexopt_chroot_setup_main.cc43
-rw-r--r--dexopt_chroot_setup/dexopt_chroot_setup_test.cc41
-rw-r--r--libarttools/art_exec.cc11
-rwxr-xr-xtest/utils/regen-test-files1
21 files changed, 547 insertions, 8 deletions
diff --git a/artd/Android.bp b/artd/Android.bp
index 5449cd90a6..8b74981e2f 100644
--- a/artd/Android.bp
+++ b/artd/Android.bp
@@ -105,3 +105,30 @@ art_cc_test {
],
test_config_template: "art_standalone_artd_tests.xml",
}
+
+cc_fuzz {
+ name: "artd_fuzzer",
+ defaults: [
+ "service_fuzzer_defaults",
+ "art_module_source_build_defaults",
+ "artd_defaults",
+ // Fuzzer is on a special variant, different from the APEX variant. When
+ // linking against "libdexfile" as a shared library, the build system
+ // incorrectly picks the platform variant, which only exposes system
+ // APIs. As a workaround, we link against "libdexfile" as a static
+ // library.
+ "libdexfile_static_defaults",
+ ],
+ host_supported: true,
+ srcs: ["artd_fuzzer.cc"],
+ shared_libs: [
+ "libart",
+ "libartbase",
+ "liblog",
+ ],
+ fuzz_config: {
+ cc: [
+ "art-module-team@google.com",
+ ],
+ },
+}
diff --git a/artd/artd.cc b/artd/artd.cc
index f1fc558306..c44013b740 100644
--- a/artd/artd.cc
+++ b/artd/artd.cc
@@ -123,6 +123,7 @@ using ::ndk::ScopedAStatus;
using TmpProfilePath = ProfilePath::TmpProfilePath;
constexpr const char* kServiceName = "artd";
+constexpr const char* kPreRebootServiceName = "artd_pre_reboot";
constexpr const char* kArtdCancellationSignalType = "ArtdCancellationSignal";
// Timeout for short operations, such as merging profiles.
@@ -1336,8 +1337,8 @@ Result<void> Artd::Start() {
OR_RETURN(SetLogVerbosity());
MemMap::Init();
- ScopedAStatus status = ScopedAStatus::fromStatus(
- AServiceManager_registerLazyService(this->asBinder().get(), kServiceName));
+ ScopedAStatus status = ScopedAStatus::fromStatus(AServiceManager_registerLazyService(
+ this->asBinder().get(), options_.is_pre_reboot ? kPreRebootServiceName : kServiceName));
if (!status.isOk()) {
return Error() << status.getDescription();
}
diff --git a/artd/artd.h b/artd/artd.h
index fd1ce19e55..f1dc18a503 100644
--- a/artd/artd.h
+++ b/artd/artd.h
@@ -46,6 +46,12 @@
namespace art {
namespace artd {
+struct Options {
+ // If true, this artd instance is for Pre-reboot Dexopt. It runs in a chroot environment that is
+ // set up by dexopt_chroot_setup.
+ bool is_pre_reboot = false;
+};
+
class ArtdCancellationSignal : public aidl::com::android::server::art::BnArtdCancellationSignal {
public:
explicit ArtdCancellationSignal(std::function<int(pid_t, int)> kill_func)
@@ -69,12 +75,14 @@ class ArtdCancellationSignal : public aidl::com::android::server::art::BnArtdCan
class Artd : public aidl::com::android::server::art::BnArtd {
public:
- explicit Artd(std::unique_ptr<art::tools::SystemProperties> props =
+ explicit Artd(Options&& options,
+ std::unique_ptr<art::tools::SystemProperties> props =
std::make_unique<art::tools::SystemProperties>(),
std::unique_ptr<ExecUtils> exec_utils = std::make_unique<ExecUtils>(),
std::function<int(pid_t, int)> kill_func = kill,
std::function<int(int, struct stat*)> fstat_func = fstat)
- : props_(std::move(props)),
+ : options_(std::move(options)),
+ props_(std::move(props)),
exec_utils_(std::move(exec_utils)),
kill_(std::move(kill_func)),
fstat_(std::move(fstat_func)) {}
@@ -256,6 +264,7 @@ class Artd : public aidl::com::android::server::art::BnArtd {
std::mutex ofa_context_mu_;
std::unique_ptr<OatFileAssistantContext> ofa_context_ GUARDED_BY(ofa_context_mu_);
+ const Options options_;
const std::unique_ptr<art::tools::SystemProperties> props_;
const std::unique_ptr<ExecUtils> exec_utils_;
const std::function<int(pid_t, int)> kill_;
diff --git a/artd/artd_fuzzer.cc b/artd/artd_fuzzer.cc
new file mode 100644
index 0000000000..23d9a9013a
--- /dev/null
+++ b/artd/artd_fuzzer.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "artd.h"
+#include "fuzzbinder/libbinder_ndk_driver.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+using ::android::fuzzService;
+using ::art::artd::Artd;
+using ::ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto artd = SharedRefBase::make<Artd>(art::artd::Options());
+
+ fuzzService(artd->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
diff --git a/artd/artd_main.cc b/artd/artd_main.cc
index 9fe5bd81b4..212e9c4046 100644
--- a/artd/artd_main.cc
+++ b/artd/artd_main.cc
@@ -22,10 +22,39 @@
#include "android/binder_process.h"
#include "artd.h"
+namespace art {
+namespace artd {
+namespace {
+
+constexpr int kErrorUsage = 100;
+
+[[noreturn]] void ParseError(const std::string& error_msg) {
+ LOG(ERROR) << error_msg;
+ std::cerr << error_msg << "\n";
+ exit(kErrorUsage);
+}
+
+Options ParseOptions(int argc, char** argv) {
+ Options options;
+ for (int i = 1; i < argc; i++) {
+ std::string_view arg = argv[i];
+ if (arg == "--pre-reboot") {
+ options.is_pre_reboot = true;
+ } else {
+ ParseError("Unknown option " + std::string(arg));
+ }
+ }
+ return options;
+}
+
+} // namespace
+} // namespace artd
+} // namespace art
+
int main([[maybe_unused]] int argc, char* argv[]) {
android::base::InitLogging(argv);
- auto artd = ndk::SharedRefBase::make<art::artd::Artd>();
+ auto artd = ndk::SharedRefBase::make<art::artd::Artd>(art::artd::ParseOptions(argc, argv));
LOG(INFO) << "Starting artd";
diff --git a/artd/artd_test.cc b/artd/artd_test.cc
index fc7c0765ef..79fa7cd4e1 100644
--- a/artd/artd_test.cc
+++ b/artd/artd_test.cc
@@ -320,7 +320,8 @@ class ArtdTest : public CommonArtTest {
EXPECT_CALL(*mock_props_, GetProperty).Times(AnyNumber()).WillRepeatedly(Return(""));
auto mock_exec_utils = std::make_unique<MockExecUtils>();
mock_exec_utils_ = mock_exec_utils.get();
- artd_ = ndk::SharedRefBase::make<Artd>(std::move(mock_props),
+ artd_ = ndk::SharedRefBase::make<Artd>(Options(),
+ std::move(mock_props),
std::move(mock_exec_utils),
mock_kill_.AsStdFunction(),
mock_fstat_.AsStdFunction());
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 434145d39c..750c62d9ea 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -136,6 +136,7 @@ endif
ART_TEST_MODULES_TARGET := $(ART_TEST_MODULES_COMMON) \
art_artd_tests \
+ art_dexopt_chroot_setup_tests \
art_odrefresh_tests \
ART_TEST_MODULES_HOST := $(ART_TEST_MODULES_COMMON)
@@ -145,6 +146,7 @@ ifneq (,$(wildcard frameworks/native/libs/binder))
# can build the libbinder_ndk dependency. It is not available as a prebuilt on
# master-art.
ART_TEST_MODULES_HOST += art_artd_tests
+ ART_TEST_MODULES_HOST += art_dexopt_chroot_setup_tests
endif
ART_TARGET_GTEST_NAMES := $(foreach tm,$(ART_TEST_MODULES_TARGET),\
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index c2a4153e70..fed90e4718 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -217,6 +217,7 @@ apex_defaults {
"art_boot",
"art_exec",
"artd",
+ "dexopt_chroot_setup",
],
multilib: {
both: {
@@ -341,6 +342,7 @@ art_gtests = [
"art_dexdump_tests",
"art_dexlayout_tests",
"art_dexlist_tests",
+ "art_dexopt_chroot_setup_tests",
"art_disassembler_tests",
"art_dexoptanalyzer_tests",
"art_imgdiag_tests",
diff --git a/build/apex/art.rc b/build/apex/art.rc
index 6afa446282..b3eea29982 100644
--- a/build/apex/art.rc
+++ b/build/apex/art.rc
@@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# A lazy service that is started and stopped dynamically as needed.
+# A service that handles dexopt. See art/artd/README.md. It's a lazy service
+# that is started and stopped dynamically as needed.
service artd /apex/com.android.art/bin/artd
interface aidl artd
disabled # Prevents the service from automatically starting at boot.
@@ -22,6 +23,30 @@ service artd /apex/com.android.art/bin/artd
group artd
capabilities DAC_OVERRIDE DAC_READ_SEARCH FOWNER CHOWN
+# Same as above, but for Pre-reboot Dexopt. It runs in a chroot environment that
+# is set up by dexopt_chroot_setup. It's a lazy service that is started and
+# stopped dynamically as needed.
+service artd_pre_reboot /apex/com.android.art/bin/art_exec --chroot=/mnt/pre_reboot_dexopt -- /apex/com.android.art/bin/artd --pre-reboot
+ interface aidl artd_pre_reboot
+ disabled # Prevents the service from automatically starting at boot.
+ oneshot # Prevents the service from automatically restarting each time it is stopped.
+ class core
+ user artd
+ group artd
+ capabilities DAC_OVERRIDE DAC_READ_SEARCH FOWNER CHOWN SYS_CHROOT
+ seclabel u:r:artd:s0
+
+# A service that sets up the chroot environment for Pre-reboot Dexopt. See
+# art/dexopt_chroot_setup/README.md. It's a lazy service that is started and
+# stopped dynamically as needed.
+service dexopt_chroot_setup /apex/com.android.art/bin/dexopt_chroot_setup
+ interface aidl dexopt_chroot_setup
+ disabled # Prevents the service from automatically starting at boot.
+ oneshot # Prevents the service from automatically restarting each time it is stopped.
+ class core
+ user artd
+ group artd
+
# Run at boot in Android U and later.
service art_boot /apex/com.android.art/bin/art_boot
disabled # Started explicitly from system/core/rootdir/init.rc
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index 7693c1a3c7..a12403118b 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -552,6 +552,7 @@ class ReleaseTargetChecker:
self._checker.check_executable('art_boot')
self._checker.check_executable('art_exec')
self._checker.check_executable('artd')
+ self._checker.check_executable('dexopt_chroot_setup')
self._checker.check_executable('oatdump')
self._checker.check_executable("odrefresh")
self._checker.check_symlinked_multilib_executable('dex2oat')
@@ -681,6 +682,7 @@ class TestingTargetChecker:
self._checker.check_art_test_executable('art_dexdump_tests')
self._checker.check_art_test_executable('art_dexlayout_tests')
self._checker.check_art_test_executable('art_dexlist_tests')
+ self._checker.check_art_test_executable('art_dexopt_chroot_setup_tests')
self._checker.check_art_test_executable('art_dexoptanalyzer_tests')
self._checker.check_art_test_executable('art_disassembler_tests')
self._checker.check_art_test_executable('art_imgdiag_tests')
diff --git a/dexopt_chroot_setup/Android.bp b/dexopt_chroot_setup/Android.bp
new file mode 100644
index 0000000000..93e012a594
--- /dev/null
+++ b/dexopt_chroot_setup/Android.bp
@@ -0,0 +1,111 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "art_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["art_license"],
+}
+
+cc_defaults {
+ name: "dexopt_chroot_setup_defaults",
+ defaults: ["art_defaults"],
+ srcs: [
+ "dexopt_chroot_setup.cc",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "dexopt_chroot_setup-aidl-ndk",
+ ],
+}
+
+art_cc_binary {
+ name: "dexopt_chroot_setup",
+ defaults: ["dexopt_chroot_setup_defaults"],
+ srcs: [
+ "dexopt_chroot_setup_main.cc",
+ ],
+ shared_libs: [
+ "libart",
+ "libartbase",
+ ],
+ apex_available: [
+ "com.android.art",
+ "com.android.art.debug",
+ ],
+}
+
+art_cc_defaults {
+ name: "art_dexopt_chroot_setup_tests_defaults",
+ defaults: ["dexopt_chroot_setup_defaults"],
+ static_libs: [
+ "libgmock",
+ ],
+ srcs: [
+ "dexopt_chroot_setup_test.cc",
+ ],
+}
+
+// Version of ART gtest `art_dexopt_chroot_setup_tests` bundled with the ART
+// APEX on target.
+//
+// This test requires the full libbinder_ndk implementation on host, which is
+// not available as a prebuilt on the thin master-art branch. Hence it won't
+// work there, and there's a conditional in Android.gtest.mk to exclude it from
+// test-art-host-gtest.
+art_cc_test {
+ name: "art_dexopt_chroot_setup_tests",
+ defaults: [
+ "art_gtest_defaults",
+ "art_dexopt_chroot_setup_tests_defaults",
+ ],
+}
+
+// Standalone version of ART gtest `art_dexopt_chroot_setup_tests`, not bundled
+// with the ART APEX on target.
+art_cc_test {
+ name: "art_standalone_dexopt_chroot_setup_tests",
+ defaults: [
+ "art_standalone_gtest_defaults",
+ "art_dexopt_chroot_setup_tests_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "dexopt_chroot_setup_fuzzer",
+ defaults: [
+ "service_fuzzer_defaults",
+ "art_module_source_build_defaults",
+ "dexopt_chroot_setup_defaults",
+ ],
+ host_supported: true,
+ srcs: ["dexopt_chroot_setup_fuzzer.cc"],
+ shared_libs: [
+ "libart",
+ "libartbase",
+ "liblog",
+ ],
+ fuzz_config: {
+ cc: [
+ "art-module-team@google.com",
+ ],
+ },
+}
diff --git a/dexopt_chroot_setup/README.md b/dexopt_chroot_setup/README.md
new file mode 100644
index 0000000000..71401248d6
--- /dev/null
+++ b/dexopt_chroot_setup/README.md
@@ -0,0 +1,10 @@
+## dexopt_chroot_setup
+
+dexopt_chroot_setup is a component of ART Service. It sets up the chroot
+environment for Pre-reboot Dexopt, to dexopt apps on a best-effort basis before
+the reboot after a Mainline update or an OTA update is downloaded, to support
+seamless updates.
+
+It requires elevated permissions that are not available to system_server, such
+as mounting filesystems. It publishes a binder interface that is internal to ART
+Service's Java code.
diff --git a/dexopt_chroot_setup/binder/Android.bp b/dexopt_chroot_setup/binder/Android.bp
new file mode 100644
index 0000000000..629a783062
--- /dev/null
+++ b/dexopt_chroot_setup/binder/Android.bp
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "art_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["art_license"],
+}
+
+aidl_interface {
+ name: "dexopt_chroot_setup-aidl",
+ srcs: [
+ "com/android/server/art/*.aidl",
+ ],
+ host_supported: true,
+ backend: {
+ java: {
+ enabled: true,
+ apex_available: [
+ "com.android.art",
+ "com.android.art.debug",
+ ],
+ },
+ cpp: {
+ enabled: false,
+ },
+ ndk: {
+ enabled: true,
+ apex_available: [
+ "com.android.art",
+ "com.android.art.debug",
+ ],
+ },
+ },
+ unstable: true,
+ visibility: [
+ "//system/tools/aidl/build",
+ "//art:__subpackages__",
+ ],
+ min_sdk_version: "31",
+}
diff --git a/dexopt_chroot_setup/binder/com/android/server/art/IDexoptChrootSetup.aidl b/dexopt_chroot_setup/binder/com/android/server/art/IDexoptChrootSetup.aidl
new file mode 100644
index 0000000000..f38fceade8
--- /dev/null
+++ b/dexopt_chroot_setup/binder/com/android/server/art/IDexoptChrootSetup.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.art;
+
+/** @hide */
+interface IDexoptChrootSetup {
+}
diff --git a/dexopt_chroot_setup/dexopt_chroot_setup.cc b/dexopt_chroot_setup/dexopt_chroot_setup.cc
new file mode 100644
index 0000000000..c9a1c735c2
--- /dev/null
+++ b/dexopt_chroot_setup/dexopt_chroot_setup.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dexopt_chroot_setup.h"
+
+#include "aidl/com/android/server/art/BnDexoptChrootSetup.h"
+#include "android-base/errors.h"
+#include "android-base/result.h"
+#include "android/binder_auto_utils.h"
+#include "android/binder_manager.h"
+#include "android/binder_process.h"
+
+namespace art {
+namespace dexopt_chroot_setup {
+
+namespace {
+
+using ::android::base::Error;
+using ::android::base::Result;
+using ::ndk::ScopedAStatus;
+
+constexpr const char* kServiceName = "dexopt_chroot_setup";
+
+} // namespace
+
+Result<void> DexoptChrootSetup::Start() {
+ ScopedAStatus status = ScopedAStatus::fromStatus(
+ AServiceManager_registerLazyService(this->asBinder().get(), kServiceName));
+ if (!status.isOk()) {
+ return Error() << status.getDescription();
+ }
+
+ ABinderProcess_startThreadPool();
+
+ return {};
+}
+
+} // namespace dexopt_chroot_setup
+} // namespace art
diff --git a/dexopt_chroot_setup/dexopt_chroot_setup.h b/dexopt_chroot_setup/dexopt_chroot_setup.h
new file mode 100644
index 0000000000..858c71711d
--- /dev/null
+++ b/dexopt_chroot_setup/dexopt_chroot_setup.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_DEXOPT_CHROOT_SETUP_DEXOPT_CHROOT_SETUP_H_
+#define ART_DEXOPT_CHROOT_SETUP_DEXOPT_CHROOT_SETUP_H_
+
+#include "aidl/com/android/server/art/BnDexoptChrootSetup.h"
+#include "android-base/result.h"
+
+namespace art {
+namespace dexopt_chroot_setup {
+
+// A service that sets up the chroot environment for Pre-reboot Dexopt.
+class DexoptChrootSetup : public aidl::com::android::server::art::BnDexoptChrootSetup {
+ public:
+ android::base::Result<void> Start();
+};
+
+} // namespace dexopt_chroot_setup
+} // namespace art
+
+#endif // ART_DEXOPT_CHROOT_SETUP_DEXOPT_CHROOT_SETUP_H_
diff --git a/dexopt_chroot_setup/dexopt_chroot_setup_fuzzer.cc b/dexopt_chroot_setup/dexopt_chroot_setup_fuzzer.cc
new file mode 100644
index 0000000000..fe3663e38e
--- /dev/null
+++ b/dexopt_chroot_setup/dexopt_chroot_setup_fuzzer.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dexopt_chroot_setup.h"
+#include "fuzzbinder/libbinder_ndk_driver.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+using ::android::fuzzService;
+using ::art::dexopt_chroot_setup::DexoptChrootSetup;
+using ::ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto dexopt_chroot_setup = SharedRefBase::make<DexoptChrootSetup>();
+
+ fuzzService(dexopt_chroot_setup->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
diff --git a/dexopt_chroot_setup/dexopt_chroot_setup_main.cc b/dexopt_chroot_setup/dexopt_chroot_setup_main.cc
new file mode 100644
index 0000000000..5e74783619
--- /dev/null
+++ b/dexopt_chroot_setup/dexopt_chroot_setup_main.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "android/binder_interface_utils.h"
+#include "android/binder_process.h"
+#include "dexopt_chroot_setup.h"
+
+int main([[maybe_unused]] int argc, char* argv[]) {
+ android::base::InitLogging(argv);
+
+ auto dexopt_chroot_setup =
+ ndk::SharedRefBase::make<art::dexopt_chroot_setup::DexoptChrootSetup>();
+
+ LOG(INFO) << "Starting dexopt_chroot_setup";
+
+ if (android::base::Result<void> ret = dexopt_chroot_setup->Start(); !ret.ok()) {
+ LOG(ERROR) << "Unable to start dexopt_chroot_setup: " << ret.error();
+ exit(1);
+ }
+
+ ABinderProcess_joinThreadPool();
+
+ LOG(INFO) << "dexopt_chroot_setup shutting down";
+
+ return 0;
+}
diff --git a/dexopt_chroot_setup/dexopt_chroot_setup_test.cc b/dexopt_chroot_setup/dexopt_chroot_setup_test.cc
new file mode 100644
index 0000000000..ba42fc53ea
--- /dev/null
+++ b/dexopt_chroot_setup/dexopt_chroot_setup_test.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dexopt_chroot_setup.h"
+
+#include "base/common_art_test.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace art {
+namespace dexopt_chroot_setup {
+namespace {
+
+class DexoptChrootSetupTest : public CommonArtTest {
+ protected:
+ void SetUp() override {
+ CommonArtTest::SetUp();
+ dexopt_chroot_setup_ = ndk::SharedRefBase::make<DexoptChrootSetup>();
+ }
+
+ std::shared_ptr<DexoptChrootSetup> dexopt_chroot_setup_;
+};
+
+TEST_F(DexoptChrootSetupTest, HelloWorld) { EXPECT_NE(dexopt_chroot_setup_, nullptr); }
+
+} // namespace
+} // namespace dexopt_chroot_setup
+} // namespace art
diff --git a/libarttools/art_exec.cc b/libarttools/art_exec.cc
index 37a2a5fb70..a382342def 100644
--- a/libarttools/art_exec.cc
+++ b/libarttools/art_exec.cc
@@ -30,7 +30,6 @@
#include <unordered_set>
#include <vector>
-#include "android-base/format.h"
#include "android-base/logging.h"
#include "android-base/parseint.h"
#include "android-base/result.h"
@@ -80,6 +79,7 @@ struct Options {
bool drop_capabilities = false;
std::unordered_set<int> keep_fds{fileno(stdin), fileno(stdout), fileno(stderr)};
std::unordered_map<std::string, std::string> envs;
+ std::string chroot;
};
[[noreturn]] void Usage(const std::string& error_msg) {
@@ -123,6 +123,8 @@ Options ParseOptions(int argc, char** argv) {
}
options.envs[std::string(arg.substr(/*pos=*/0, /*n=*/pos))] =
std::string(arg.substr(pos + 1));
+ } else if (ConsumePrefix(&arg, "--chroot=")) {
+ options.chroot = arg;
} else if (arg == "--") {
if (i + 1 >= argc) {
Usage("Missing command after '--'");
@@ -215,6 +217,13 @@ int main(int argc, char** argv) {
setenv(key.c_str(), value.c_str(), /*overwrite=*/1);
}
+ if (!options.chroot.empty()) {
+ if (chroot(options.chroot.c_str()) != 0) {
+ PLOG(ERROR) << ART_FORMAT("Failed to chroot to '{}'", options.chroot);
+ return kErrorOther;
+ }
+ }
+
execv(argv[options.command_pos], argv + options.command_pos);
std::vector<const char*> command_args(argv + options.command_pos, argv + argc);
diff --git a/test/utils/regen-test-files b/test/utils/regen-test-files
index 71b857e50e..36ac9ef9b1 100755
--- a/test/utils/regen-test-files
+++ b/test/utils/regen-test-files
@@ -244,6 +244,7 @@ art_gtest_user_module_names = [
"art_standalone_dex2oat_tests",
"art_standalone_dexdump_tests",
"art_standalone_dexlist_tests",
+ "art_standalone_dexopt_chroot_setup_tests",
"art_standalone_libartbase_tests",
"art_standalone_libartpalette_tests",
"art_standalone_libartservice_tests",