Return dex2oat wall time and CPU time in results.
Bug: 245380798
Test: m test-art-host-gtest-art_artd_tests
Test: atest ArtServiceTests
Test: adb shell pm art optimize-package -m speed -f \
com.google.android.youtube
Ignore-AOSP-First: ART Services.
Change-Id: I08881e97ba51f44613eb7a31a59ba1e45ea78ee0
diff --git a/artd/artd.cc b/artd/artd.cc
index 36f7111..4cadee0 100644
--- a/artd/artd.cc
+++ b/artd/artd.cc
@@ -53,6 +53,7 @@
#include "base/file_utils.h"
#include "base/globals.h"
#include "base/os.h"
+#include "exec_utils.h"
#include "file_utils.h"
#include "fmt/format.h"
#include "oat_file_assistant.h"
@@ -70,6 +71,7 @@
using ::aidl::com::android::server::art::ArtifactsPath;
using ::aidl::com::android::server::art::DexoptOptions;
+using ::aidl::com::android::server::art::DexoptResult;
using ::aidl::com::android::server::art::DexoptTrigger;
using ::aidl::com::android::server::art::FileVisibility;
using ::aidl::com::android::server::art::FsPermission;
@@ -566,7 +568,9 @@
const std::optional<VdexPath>& in_inputVdex,
PriorityClass in_priorityClass,
const DexoptOptions& in_dexoptOptions,
- bool* _aidl_return) {
+ DexoptResult* _aidl_return) {
+ _aidl_return->cancelled = false;
+
std::string oat_path = OR_RETURN_FATAL(BuildOatPath(in_outputArtifacts.artifactsPath));
std::string vdex_path = OatPathToVdexPath(oat_path);
std::string art_path = OatPathToArtPath(oat_path);
@@ -673,9 +677,12 @@
LOG(INFO) << "Running dex2oat: " << Join(args.Get(), /*separator=*/" ")
<< "\nOpened FDs: " << fd_logger;
- Result<int> result = ExecAndReturnCode(args.Get(), kLongTimeoutSec);
+ ProcessStat stat;
+ Result<int> result = ExecAndReturnCode(args.Get(), kLongTimeoutSec, &stat);
+ _aidl_return->wallTimeMs = stat.wall_time_ms;
+ _aidl_return->cpuTimeMs = stat.cpu_time_ms;
if (!result.ok()) {
- // TODO(b/244412198): Return false if dexopt is cancelled upon request.
+ // TODO(b/244412198): Return cancelled=true if dexopt is cancelled upon request.
return NonFatal("Failed to run dex2oat: " + result.error().message());
}
if (result.value() != 0) {
@@ -684,7 +691,6 @@
NewFile::CommitAllOrAbandon(files_to_commit, files_to_delete);
- *_aidl_return = true;
return ScopedAStatus::ok();
}
@@ -863,10 +869,12 @@
}
android::base::Result<int> Artd::ExecAndReturnCode(const std::vector<std::string>& args,
- int timeout_sec) const {
+ int timeout_sec,
+ ProcessStat* stat) const {
bool ignored_timed_out = false; // This information is encoded in the error message.
std::string error_msg;
- int exit_code = exec_utils_->ExecAndReturnCode(args, timeout_sec, &ignored_timed_out, &error_msg);
+ int exit_code =
+ exec_utils_->ExecAndReturnCode(args, timeout_sec, &ignored_timed_out, stat, &error_msg);
if (exit_code < 0) {
return Error() << error_msg;
}
diff --git a/artd/artd.h b/artd/artd.h
index d637a0b..931f606 100644
--- a/artd/artd.h
+++ b/artd/artd.h
@@ -100,7 +100,7 @@
const std::optional<aidl::com::android::server::art::VdexPath>& in_inputVdex,
aidl::com::android::server::art::PriorityClass in_priorityClass,
const aidl::com::android::server::art::DexoptOptions& in_dexoptOptions,
- bool* _aidl_return) override;
+ aidl::com::android::server::art::DexoptResult* _aidl_return) override;
android::base::Result<void> Start();
@@ -117,7 +117,8 @@
bool DenyArtApexDataFiles();
android::base::Result<int> ExecAndReturnCode(const std::vector<std::string>& arg_vector,
- int timeout_sec) const;
+ int timeout_sec,
+ ProcessStat* stat = nullptr) const;
android::base::Result<std::string> GetProfman();
diff --git a/artd/artd_test.cc b/artd/artd_test.cc
index fcc15d4..c03b245 100644
--- a/artd/artd_test.cc
+++ b/artd/artd_test.cc
@@ -51,6 +51,7 @@
using ::aidl::com::android::server::art::ArtifactsPath;
using ::aidl::com::android::server::art::DexMetadataPath;
using ::aidl::com::android::server::art::DexoptOptions;
+using ::aidl::com::android::server::art::DexoptResult;
using ::aidl::com::android::server::art::FileVisibility;
using ::aidl::com::android::server::art::FsPermission;
using ::aidl::com::android::server::art::OutputArtifacts;
@@ -73,12 +74,15 @@
using ::testing::ContainsRegex;
using ::testing::DoAll;
using ::testing::ElementsAre;
+using ::testing::Field;
using ::testing::HasSubstr;
using ::testing::IsEmpty;
+using ::testing::Matcher;
using ::testing::MockFunction;
using ::testing::Not;
using ::testing::ResultOf;
using ::testing::Return;
+using ::testing::SetArgPointee;
using ::testing::WithArg;
using RefProfilePath = ProfilePath::RefProfilePath;
@@ -171,11 +175,15 @@
int ExecAndReturnCode(const std::vector<std::string>& arg_vector,
int,
bool*,
+ ProcessStat* stat,
std::string*) const override {
- return DoExecAndReturnCode(arg_vector);
+ return DoExecAndReturnCode(arg_vector, stat);
}
- MOCK_METHOD(int, DoExecAndReturnCode, (const std::vector<std::string>& arg_vector), (const));
+ MOCK_METHOD(int,
+ DoExecAndReturnCode,
+ (const std::vector<std::string>& arg_vector, ProcessStat* stat),
+ (const));
};
class ArtdTest : public CommonArtTest {
@@ -246,9 +254,11 @@
CommonArtTest::TearDown();
}
- void RunDexopt(binder_exception_t expected_status = EX_NONE, bool expected_aidl_return = true) {
+ void RunDexopt(binder_exception_t expected_status = EX_NONE,
+ Matcher<DexoptResult> aidl_return_matcher = Field(&DexoptResult::cancelled,
+ false)) {
InitDexoptInputFiles();
- bool aidl_return;
+ DexoptResult aidl_return;
ndk::ScopedAStatus status = artd_->dexopt(output_artifacts_,
dex_file_,
isa_,
@@ -261,7 +271,7 @@
&aidl_return);
ASSERT_EQ(status.getExceptionCode(), expected_status) << status.getMessage();
if (status.isOk()) {
- ASSERT_EQ(aidl_return, expected_aidl_return);
+ ASSERT_THAT(aidl_return, std::move(aidl_return_matcher));
}
}
@@ -410,38 +420,47 @@
}
TEST_F(ArtdTest, dexopt) {
- EXPECT_CALL(*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--",
- AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
- AllOf(Contains(art_root_ + "/bin/dex2oat32"),
- Contains(Flag("--zip-fd=", FdOf(dex_file_))),
- Contains(Flag("--zip-location=", dex_file_)),
- Contains(Flag("--oat-location=", scratch_path_ + "/a/oat/arm64/b.odex")),
- Contains(Flag("--instruction-set=", "arm64")),
- Contains(Flag("--compiler-filter=", "speed")),
- Contains(Flag(
- "--profile-file-fd=",
- FdOf(android_data_ +
- "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp")))))))
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy(
+ "--",
+ AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
+ AllOf(Contains(art_root_ + "/bin/dex2oat32"),
+ Contains(Flag("--zip-fd=", FdOf(dex_file_))),
+ Contains(Flag("--zip-location=", dex_file_)),
+ Contains(Flag("--oat-location=", scratch_path_ + "/a/oat/arm64/b.odex")),
+ Contains(Flag("--instruction-set=", "arm64")),
+ Contains(Flag("--compiler-filter=", "speed")),
+ Contains(
+ Flag("--profile-file-fd=",
+ FdOf(android_data_ +
+ "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"))))),
+ _))
.WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")),
WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")),
+ SetArgPointee<1>(ProcessStat{.wall_time_ms = 100, .cpu_time_ms = 400}),
Return(0)));
- RunDexopt();
+ RunDexopt(EX_NONE,
+ AllOf(Field(&DexoptResult::cancelled, false),
+ Field(&DexoptResult::wallTimeMs, 100),
+ Field(&DexoptResult::cpuTimeMs, 400)));
CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "oat");
CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "vdex");
}
TEST_F(ArtdTest, dexoptClassLoaderContext) {
- EXPECT_CALL(*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--",
- _,
- AllOf(Contains(ListFlag("--class-loader-context-fds=",
- ElementsAre(FdOf(clc_1_), FdOf(clc_2_)))),
- Contains(Flag("--class-loader-context=", class_loader_context_)),
- Contains(Flag("--classpath-dir=", scratch_path_ + "/a"))))))
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy("--",
+ _,
+ AllOf(Contains(ListFlag("--class-loader-context-fds=",
+ ElementsAre(FdOf(clc_1_), FdOf(clc_2_)))),
+ Contains(Flag("--class-loader-context=", class_loader_context_)),
+ Contains(Flag("--classpath-dir=", scratch_path_ + "/a")))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -451,20 +470,22 @@
DoExecAndReturnCode(WhenSplitBy("--",
_,
AllOf(Not(Contains(Flag("--dm-fd=", _))),
- Not(Contains(Flag("--input-vdex-fd=", _)))))))
+ Not(Contains(Flag("--input-vdex-fd=", _))))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
TEST_F(ArtdTest, dexoptInputVdex) {
vdex_path_ = artifacts_path_;
- EXPECT_CALL(
- *mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--",
- _,
- AllOf(Not(Contains(Flag("--dm-fd=", _))),
- Contains(Flag("--input-vdex-fd=", FdOf(scratch_path_ + "/a/oat/arm64/b.vdex")))))))
+ EXPECT_CALL(*mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy("--",
+ _,
+ AllOf(Not(Contains(Flag("--dm-fd=", _))),
+ Contains(Flag("--input-vdex-fd=",
+ FdOf(scratch_path_ + "/a/oat/arm64/b.vdex"))))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -476,7 +497,8 @@
WhenSplitBy("--",
_,
AllOf(Contains(Flag("--dm-fd=", FdOf(scratch_path_ + "/a/b.dm"))),
- Not(Contains(Flag("--input-vdex-fd=", _)))))))
+ Not(Contains(Flag("--input-vdex-fd=", _))))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -487,7 +509,8 @@
DoExecAndReturnCode(WhenSplitBy("--",
AllOf(Not(Contains(Flag("--set-task-profile=", _))),
Not(Contains(Flag("--set-priority=", _)))),
- Contains(Flag("--compact-dex-level=", "none")))))
+ Contains(Flag("--compact-dex-level=", "none"))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -499,7 +522,8 @@
WhenSplitBy("--",
AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBootComplete")),
Contains(Flag("--set-priority=", "background"))),
- Contains(Flag("--compact-dex-level=", "none")))))
+ Contains(Flag("--compact-dex-level=", "none"))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -511,7 +535,8 @@
WhenSplitBy("--",
AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBootComplete")),
Contains(Flag("--set-priority=", "background"))),
- Contains(Flag("--compact-dex-level=", "none")))))
+ Contains(Flag("--compact-dex-level=", "none"))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -523,7 +548,8 @@
WhenSplitBy("--",
AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBootComplete")),
Contains(Flag("--set-priority=", "background"))),
- Not(Contains(Flag("--compact-dex-level=", _))))))
+ Not(Contains(Flag("--compact-dex-level=", _)))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -545,7 +571,8 @@
Contains(Flag("-Xtarget-sdk-version:", "123")),
Not(Contains("--debuggable")),
Not(Contains(Flag("--app-image-fd=", _))),
- Not(Contains(Flag("-Xhidden-api-policy:", _)))))))
+ Not(Contains(Flag("-Xhidden-api-policy:", _))))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -566,7 +593,8 @@
AllOf(Contains(Flag("--compilation-reason=", "bg-dexopt")),
Contains(Flag("-Xtarget-sdk-version:", "456")),
Contains("--debuggable"),
- Contains(Flag("-Xhidden-api-policy:", "enabled"))))))
+ Contains(Flag("-Xhidden-api-policy:", "enabled")))),
+ _))
.WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")), Return(0)));
RunDexopt();
@@ -591,7 +619,8 @@
Not(Contains(Flag("-j", _))),
Not(Contains(Flag("-Xms", _))),
Not(Contains(Flag("-Xmx", _))),
- Not(Contains("--compile-individually"))))))
+ Not(Contains("--compile-individually")))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -629,7 +658,8 @@
Not(Contains("-Xdeny-art-apex-data-files")),
Contains(Flag("-Xms", "xms")),
Contains(Flag("-Xmx", "xmx")),
- Contains("--compile-individually")))))
+ Contains("--compile-individually"))),
+ _))
.WillOnce(Return(0));
RunDexopt();
}
@@ -645,8 +675,10 @@
// The default resource control properties don't apply to BOOT.
EXPECT_CALL(
*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--", _, AllOf(Not(Contains(Flag("--cpu-set=", _))), Contains(Not(Flag("-j", _)))))))
+ DoExecAndReturnCode(
+ WhenSplitBy(
+ "--", _, AllOf(Not(Contains(Flag("--cpu-set=", _))), Contains(Not(Flag("-j", _))))),
+ _))
.WillOnce(Return(0));
priority_class_ = PriorityClass::BOOT;
RunDexopt();
@@ -655,9 +687,12 @@
TEST_F(ArtdTest, dexoptDefaultResourceControlOther) {
SetDefaultResourceControlProps(mock_props_);
- EXPECT_CALL(*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4"))))))
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy(
+ "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4")))),
+ _))
.Times(3)
.WillRepeatedly(Return(0));
priority_class_ = PriorityClass::INTERACTIVE_FAST;
@@ -690,8 +725,10 @@
EXPECT_CALL(
*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--", _, AllOf(Contains(Flag("--cpu-set=", "0,1,2,3")), Contains(Flag("-j", "8"))))))
+ DoExecAndReturnCode(
+ WhenSplitBy(
+ "--", _, AllOf(Contains(Flag("--cpu-set=", "0,1,2,3")), Contains(Flag("-j", "8")))),
+ _))
.WillOnce(Return(0));
priority_class_ = PriorityClass::BOOT;
RunDexopt();
@@ -702,8 +739,10 @@
EXPECT_CALL(
*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2,3")), Contains(Flag("-j", "6"))))))
+ DoExecAndReturnCode(
+ WhenSplitBy(
+ "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2,3")), Contains(Flag("-j", "6")))),
+ _))
.WillOnce(Return(0));
priority_class_ = PriorityClass::INTERACTIVE_FAST;
RunDexopt();
@@ -713,9 +752,12 @@
SetAllResourceControlProps(mock_props_);
// INTERACTIVE always uses the default resource control properties.
- EXPECT_CALL(*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4"))))))
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy(
+ "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4")))),
+ _))
.WillOnce(Return(0));
priority_class_ = PriorityClass::INTERACTIVE;
RunDexopt();
@@ -724,9 +766,11 @@
TEST_F(ArtdTest, dexoptAllResourceControlBackground) {
SetAllResourceControlProps(mock_props_);
- EXPECT_CALL(*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--", _, AllOf(Contains(Flag("--cpu-set=", "0")), Contains(Flag("-j", "2"))))))
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy("--", _, AllOf(Contains(Flag("--cpu-set=", "0")), Contains(Flag("-j", "2")))),
+ _))
.WillOnce(Return(0));
priority_class_ = PriorityClass::BACKGROUND;
RunDexopt();
@@ -734,7 +778,7 @@
TEST_F(ArtdTest, dexoptFailed) {
dexopt_options_.generateAppImage = true;
- EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_))
+ EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _))
.WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")),
WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")),
WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")),
@@ -751,13 +795,15 @@
CreateFile(profile_file);
CreateFile(dex_file_);
- EXPECT_CALL(*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--",
- AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
- AllOf(Contains(art_root_ + "/bin/profman"),
- Contains(Flag("--reference-profile-file-fd=", FdOf(profile_file))),
- Contains(Flag("--apk-fd=", FdOf(dex_file_)))))))
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy("--",
+ AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
+ AllOf(Contains(art_root_ + "/bin/profman"),
+ Contains(Flag("--reference-profile-file-fd=", FdOf(profile_file))),
+ Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
+ _))
.WillOnce(Return(ProfmanResult::kSkipCompilationSmallDelta));
bool result;
@@ -770,7 +816,7 @@
CreateFile(profile_file);
CreateFile(dex_file_);
- EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_))
+ EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _))
.WillOnce(Return(ProfmanResult::kSkipCompilationEmptyProfiles));
bool result;
@@ -791,7 +837,7 @@
CreateFile(profile_file);
CreateFile(dex_file_);
- EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_)).WillOnce(Return(100));
+ EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _)).WillOnce(Return(100));
bool result;
ndk::ScopedAStatus status = artd_->isProfileUsable(profile_path_.value(), dex_file_, &result);
@@ -836,14 +882,16 @@
CreateFile(dex_file_);
- EXPECT_CALL(*mock_exec_utils_,
- DoExecAndReturnCode(WhenSplitBy(
- "--",
- AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
- AllOf(Contains(art_root_ + "/bin/profman"),
- Contains("--copy-and-update-profile-key"),
- Contains(Flag("--profile-file-fd=", FdOf(src_file))),
- Contains(Flag("--apk-fd=", FdOf(dex_file_)))))))
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy("--",
+ AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
+ AllOf(Contains(art_root_ + "/bin/profman"),
+ Contains("--copy-and-update-profile-key"),
+ Contains(Flag("--profile-file-fd=", FdOf(src_file))),
+ Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
+ _))
.WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
Return(ProfmanResult::kCopyAndUpdateSuccess)));
@@ -863,7 +911,7 @@
CreateFile(dex_file_);
- EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_))
+ EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _))
.WillOnce(Return(ProfmanResult::kCopyAndUpdateNoUpdate));
bool result;
@@ -892,7 +940,7 @@
CreateFile(dex_file_);
- EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_)).WillOnce(Return(100));
+ EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _)).WillOnce(Return(100));
bool result;
ndk::ScopedAStatus status = artd_->copyAndRewriteProfile(src, &dst, dex_file_, &result);
diff --git a/artd/binder/com/android/server/art/DexoptResult.aidl b/artd/binder/com/android/server/art/DexoptResult.aidl
new file mode 100644
index 0000000..1f1b053
--- /dev/null
+++ b/artd/binder/com/android/server/art/DexoptResult.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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;
+
+/**
+ * The result of {@code IArtd.dexopt}.
+ *
+ * @hide
+ */
+parcelable DexoptResult {
+ /** True if the operation is cancelled. */
+ boolean cancelled;
+ /**
+ * The wall time of the dex2oat invocation, in milliseconds, or 0 if dex2oat is not run or if
+ * failed to get the value.
+ */
+ long wallTimeMs;
+ /**
+ * The CPU time of the dex2oat invocation, in milliseconds, or 0 if dex2oat is not run or if
+ * failed to get the value.
+ */
+ long cpuTimeMs;
+}
diff --git a/artd/binder/com/android/server/art/IArtd.aidl b/artd/binder/com/android/server/art/IArtd.aidl
index 9328dab..a3eab2f 100644
--- a/artd/binder/com/android/server/art/IArtd.aidl
+++ b/artd/binder/com/android/server/art/IArtd.aidl
@@ -111,12 +111,12 @@
int dexoptTrigger);
/**
- * Dexopts a dex file for the given instruction set. Returns true on success, or false if
- * cancelled.
+ * Dexopts a dex file for the given instruction set.
*
* Throws fatal and non-fatal errors.
*/
- boolean dexopt(in com.android.server.art.OutputArtifacts outputArtifacts,
+ com.android.server.art.DexoptResult dexopt(
+ in com.android.server.art.OutputArtifacts outputArtifacts,
@utf8InCpp String dexFile, @utf8InCpp String instructionSet,
@utf8InCpp String classLoaderContext, @utf8InCpp String compilerFilter,
in @nullable com.android.server.art.ProfilePath profile,
diff --git a/libartservice/service/api/system-server-current.txt b/libartservice/service/api/system-server-current.txt
index c9ce7cd..6bf9d27 100644
--- a/libartservice/service/api/system-server-current.txt
+++ b/libartservice/service/api/system-server-current.txt
@@ -79,6 +79,8 @@
public static class OptimizeResult.DexFileOptimizeResult {
method @NonNull public String getActualCompilerFilter();
+ method public long getDex2oatCpuTimeMillis();
+ method public long getDex2oatWallTimeMillis();
method @NonNull public String getDexFile();
method @NonNull public String getInstructionSet();
method public int getStatus();
diff --git a/libartservice/service/java/com/android/server/art/ArtShellCommand.java b/libartservice/service/java/com/android/server/art/ArtShellCommand.java
index b797d8b..5bcae6d 100644
--- a/libartservice/service/java/com/android/server/art/ArtShellCommand.java
+++ b/libartservice/service/java/com/android/server/art/ArtShellCommand.java
@@ -103,10 +103,13 @@
for (DexFileOptimizeResult dexFileResult :
packageResult.getDexFileOptimizeResults()) {
pw.printf("dexFile = %s, instructionSet = %s, compilerFilter = %s, "
- + "status = %s\n",
+ + "status = %s, dex2oatWallTimeMillis = %d, "
+ + "dex2oatCpuTimeMillis = %d\n",
dexFileResult.getDexFile(), dexFileResult.getInstructionSet(),
dexFileResult.getActualCompilerFilter(),
- optimizeStatusToString(dexFileResult.getStatus()));
+ optimizeStatusToString(dexFileResult.getStatus()),
+ dexFileResult.getDex2oatWallTimeMillis(),
+ dexFileResult.getDex2oatCpuTimeMillis());
}
}
return 0;
diff --git a/libartservice/service/java/com/android/server/art/PrimaryDexOptimizer.java b/libartservice/service/java/com/android/server/art/PrimaryDexOptimizer.java
index a63e4e6..b2875e8 100644
--- a/libartservice/service/java/com/android/server/art/PrimaryDexOptimizer.java
+++ b/libartservice/service/java/com/android/server/art/PrimaryDexOptimizer.java
@@ -143,6 +143,8 @@
for (String isa : Utils.getAllIsas(pkgState)) {
@OptimizeResult.OptimizeStatus int status = OptimizeResult.OPTIMIZE_SKIPPED;
+ long wallTimeMs = 0;
+ long cpuTimeMs = 0;
try {
DexoptTarget target = DexoptTarget.builder()
.setDexInfo(dexInfo)
@@ -168,8 +170,13 @@
? ProfilePath.tmpRefProfilePath(profile.profilePath)
: null;
- status = dexoptFile(target, inputProfile, getDexoptNeededResult,
- permissionSettings, params.getPriorityClass(), dexoptOptions);
+ DexoptResult dexoptResult = dexoptFile(target, inputProfile,
+ getDexoptNeededResult, permissionSettings,
+ params.getPriorityClass(), dexoptOptions);
+ status = dexoptResult.cancelled ? OptimizeResult.OPTIMIZE_CANCELLED
+ : OptimizeResult.OPTIMIZE_PERFORMED;
+ wallTimeMs = dexoptResult.wallTimeMs;
+ cpuTimeMs = dexoptResult.cpuTimeMs;
} catch (ServiceSpecificException e) {
// Log the error and continue.
Log.e(TAG,
@@ -180,8 +187,8 @@
e);
status = OptimizeResult.OPTIMIZE_FAILED;
} finally {
- results.add(new DexFileOptimizeResult(
- dexInfo.dexPath(), isa, compilerFilter, status));
+ results.add(new DexFileOptimizeResult(dexInfo.dexPath(), isa,
+ compilerFilter, status, wallTimeMs, cpuTimeMs));
if (status != OptimizeResult.OPTIMIZE_SKIPPED
&& status != OptimizeResult.OPTIMIZE_PERFORMED) {
succeeded = false;
@@ -431,8 +438,8 @@
return dexoptTrigger;
}
- private @OptimizeResult.OptimizeStatus int dexoptFile(@NonNull DexoptTarget target,
- @Nullable ProfilePath profile, @NonNull GetDexoptNeededResult getDexoptNeededResult,
+ private DexoptResult dexoptFile(@NonNull DexoptTarget target, @Nullable ProfilePath profile,
+ @NonNull GetDexoptNeededResult getDexoptNeededResult,
@NonNull PermissionSettings permissionSettings, @PriorityClass int priorityClass,
@NonNull DexoptOptions dexoptOptions) throws RemoteException {
OutputArtifacts outputArtifacts = AidlUtils.buildOutputArtifacts(target.dexInfo().dexPath(),
@@ -441,13 +448,9 @@
VdexPath inputVdex =
getInputVdex(getDexoptNeededResult, target.dexInfo().dexPath(), target.isa());
- if (!mInjector.getArtd().dexopt(outputArtifacts, target.dexInfo().dexPath(), target.isa(),
- target.dexInfo().classLoaderContext(), target.compilerFilter(), profile,
- inputVdex, priorityClass, dexoptOptions)) {
- return OptimizeResult.OPTIMIZE_CANCELLED;
- }
-
- return OptimizeResult.OPTIMIZE_PERFORMED;
+ return mInjector.getArtd().dexopt(outputArtifacts, target.dexInfo().dexPath(), target.isa(),
+ target.dexInfo().classLoaderContext(), target.compilerFilter(), profile, inputVdex,
+ priorityClass, dexoptOptions);
}
@Nullable
diff --git a/libartservice/service/java/com/android/server/art/model/OptimizeResult.java b/libartservice/service/java/com/android/server/art/model/OptimizeResult.java
index f1c83d4..e9b1a00 100644
--- a/libartservice/service/java/com/android/server/art/model/OptimizeResult.java
+++ b/libartservice/service/java/com/android/server/art/model/OptimizeResult.java
@@ -144,14 +144,19 @@
private final @NonNull String mInstructionSet;
private final @NonNull String mActualCompilerFilter;
private final @OptimizeStatus int mStatus;
+ private final long mDex2oatWallTimeMillis;
+ private final long mDex2oatCpuTimeMillis;
/** @hide */
public DexFileOptimizeResult(@NonNull String dexFile, @NonNull String instructionSet,
- @NonNull String compilerFilter, @OptimizeStatus int status) {
+ @NonNull String compilerFilter, @OptimizeStatus int status,
+ long dex2oatWallTimeMillis, long dex2oatCpuTimeMillis) {
mDexFile = dexFile;
mInstructionSet = instructionSet;
mActualCompilerFilter = compilerFilter;
mStatus = status;
+ mDex2oatWallTimeMillis = dex2oatWallTimeMillis;
+ mDex2oatCpuTimeMillis = dex2oatCpuTimeMillis;
}
/** The absolute path to the dex file. */
@@ -173,5 +178,21 @@
public @OptimizeStatus int getStatus() {
return mStatus;
}
+
+ /**
+ * The wall time of the dex2oat invocation, in milliseconds, if dex2oat succeeded or was
+ * cancelled. Returns 0 if dex2oat failed or was not run, or if failed to get the value.
+ */
+ public long getDex2oatWallTimeMillis() {
+ return mDex2oatWallTimeMillis;
+ }
+
+ /**
+ * The CPU time of the dex2oat invocation, in milliseconds, if dex2oat succeeded or was
+ * cancelled. Returns 0 if dex2oat failed or was not run, or if failed to get the value.
+ */
+ public long getDex2oatCpuTimeMillis() {
+ return mDex2oatCpuTimeMillis;
+ }
}
}
diff --git a/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java b/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
index 3b4e045..fed5cfa 100644
--- a/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
+++ b/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
@@ -77,9 +77,11 @@
new OptimizeParams.Builder("install").setCompilerFilter("speed-profile").build();
private final List<DexFileOptimizeResult> mPrimaryResults =
List.of(new DexFileOptimizeResult("/data/app/foo/base.apk", "arm64", "verify",
- OptimizeResult.OPTIMIZE_PERFORMED),
+ OptimizeResult.OPTIMIZE_PERFORMED, 100 /* dex2oatWallTimeMillis */,
+ 400 /* dex2oatCpuTimeMillis */),
new DexFileOptimizeResult("/data/app/foo/base.apk", "arm", "verify",
- OptimizeResult.OPTIMIZE_FAILED));
+ OptimizeResult.OPTIMIZE_FAILED, 100 /* dex2oatWallTimeMillis */,
+ 400 /* dex2oatCpuTimeMillis */));
private DexOptHelper mDexOptHelper;
diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java
index 43aac8d..3de422f 100644
--- a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java
+++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java
@@ -206,12 +206,15 @@
.when(mArtd)
.getDexoptNeeded("/data/app/foo/base.apk", "arm64", "PCL[]",
mParams.mExpectedCompilerFilter, mParams.mExpectedDexoptTrigger);
- doReturn(true).when(mArtd).dexopt(
- deepEq(buildOutputArtifacts("/data/app/foo/base.apk", "arm64",
- mParams.mExpectedIsInDalvikCache, permissionSettings)),
- eq("/data/app/foo/base.apk"), eq("arm64"), eq("PCL[]"),
- eq(mParams.mExpectedCompilerFilter), isNull() /* profile */,
- isNull() /* inputVdex */, eq(PriorityClass.INTERACTIVE), deepEq(dexoptOptions));
+ doReturn(createDexoptResult(
+ false /* cancelled */, 100 /* wallTimeMs */, 400 /* cpuTimeMs */))
+ .when(mArtd)
+ .dexopt(deepEq(buildOutputArtifacts("/data/app/foo/base.apk", "arm64",
+ mParams.mExpectedIsInDalvikCache, permissionSettings)),
+ eq("/data/app/foo/base.apk"), eq("arm64"), eq("PCL[]"),
+ eq(mParams.mExpectedCompilerFilter), isNull() /* profile */,
+ isNull() /* inputVdex */, eq(PriorityClass.INTERACTIVE),
+ deepEq(dexoptOptions));
// The second one fails on `dexopt`.
doReturn(dexoptIsNeeded())
@@ -238,25 +241,31 @@
.when(mArtd)
.getDexoptNeeded("/data/app/foo/split_0.apk", "arm", "PCL[base.apk]",
mParams.mExpectedCompilerFilter, mParams.mExpectedDexoptTrigger);
- doReturn(true).when(mArtd).dexopt(
- deepEq(buildOutputArtifacts("/data/app/foo/split_0.apk", "arm",
- mParams.mExpectedIsInDalvikCache, permissionSettings)),
- eq("/data/app/foo/split_0.apk"), eq("arm"), eq("PCL[base.apk]"),
- eq(mParams.mExpectedCompilerFilter), isNull() /* profile */,
- isNull() /* inputVdex */, eq(PriorityClass.INTERACTIVE), deepEq(dexoptOptions));
+ doReturn(createDexoptResult(
+ false /* cancelled */, 200 /* wallTimeMs */, 200 /* cpuTimeMs */))
+ .when(mArtd)
+ .dexopt(deepEq(buildOutputArtifacts("/data/app/foo/split_0.apk", "arm",
+ mParams.mExpectedIsInDalvikCache, permissionSettings)),
+ eq("/data/app/foo/split_0.apk"), eq("arm"), eq("PCL[base.apk]"),
+ eq(mParams.mExpectedCompilerFilter), isNull() /* profile */,
+ isNull() /* inputVdex */, eq(PriorityClass.INTERACTIVE),
+ deepEq(dexoptOptions));
assertThat(mPrimaryDexOptimizer.dexopt(mPkgState, mPkg, mOptimizeParams))
.comparingElementsUsing(TestingUtils.<DexFileOptimizeResult>deepEquality())
.containsExactly(
new DexFileOptimizeResult("/data/app/foo/base.apk", "arm64",
- mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_PERFORMED),
+ mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_PERFORMED,
+ 100 /* dex2oatWallTimeMillis */, 400 /* dex2oatCpuTimeMillis */),
new DexFileOptimizeResult("/data/app/foo/base.apk", "arm",
- mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_FAILED),
+ mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_FAILED,
+ 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */),
new DexFileOptimizeResult("/data/app/foo/split_0.apk", "arm64",
- mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_SKIPPED),
+ mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_SKIPPED,
+ 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */),
new DexFileOptimizeResult("/data/app/foo/split_0.apk", "arm",
- mParams.mExpectedCompilerFilter,
- OptimizeResult.OPTIMIZE_PERFORMED));
+ mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_PERFORMED,
+ 200 /* dex2oatWallTimeMillis */, 200 /* dex2oatCpuTimeMillis */));
}
private static class Params {
diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java
index 03151e7..498657f 100644
--- a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java
+++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java
@@ -76,6 +76,9 @@
| DexoptTrigger.PRIMARY_BOOT_IMAGE_BECOMES_USABLE
| DexoptTrigger.COMPILER_FILTER_IS_SAME | DexoptTrigger.COMPILER_FILTER_IS_WORSE;
+ private final DexoptResult mDexoptResult =
+ createDexoptResult(false /* cancelled */, 200 /* wallTimeMs */, 200 /* cpuTimeMs */);
+
private List<ProfilePath> mUsedProfiles;
@Before
@@ -93,7 +96,7 @@
lenient()
.when(mArtd.dexopt(
any(), any(), any(), any(), any(), any(), any(), anyInt(), any()))
- .thenReturn(true);
+ .thenReturn(mDexoptResult);
mUsedProfiles = new ArrayList<>();
}
@@ -104,35 +107,43 @@
doReturn(dexoptIsNeeded(ArtifactsLocation.NONE_OR_ERROR))
.when(mArtd)
.getDexoptNeeded(eq(mDexPath), eq("arm64"), any(), any(), anyInt());
- doReturn(true).when(mArtd).dexopt(
- any(), eq(mDexPath), eq("arm64"), any(), any(), any(), isNull(), anyInt(), any());
+ doReturn(mDexoptResult)
+ .when(mArtd)
+ .dexopt(any(), eq(mDexPath), eq("arm64"), any(), any(), any(), isNull(), anyInt(),
+ any());
// ArtifactsPath, isInDalvikCache=true.
doReturn(dexoptIsNeeded(ArtifactsLocation.DALVIK_CACHE))
.when(mArtd)
.getDexoptNeeded(eq(mDexPath), eq("arm"), any(), any(), anyInt());
- doReturn(true).when(mArtd).dexopt(any(), eq(mDexPath), eq("arm"), any(), any(), any(),
- deepEq(VdexPath.artifactsPath(
- AidlUtils.buildArtifactsPath(mDexPath, "arm", true /* isInDalvikCache */))),
- anyInt(), any());
+ doReturn(mDexoptResult)
+ .when(mArtd)
+ .dexopt(any(), eq(mDexPath), eq("arm"), any(), any(), any(),
+ deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPath(
+ mDexPath, "arm", true /* isInDalvikCache */))),
+ anyInt(), any());
// ArtifactsPath, isInDalvikCache=false.
doReturn(dexoptIsNeeded(ArtifactsLocation.NEXT_TO_DEX))
.when(mArtd)
.getDexoptNeeded(eq(mSplit0DexPath), eq("arm64"), any(), any(), anyInt());
- doReturn(true).when(mArtd).dexopt(any(), eq(mSplit0DexPath), eq("arm64"), any(), any(),
- any(),
- deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPath(
- mSplit0DexPath, "arm64", false /* isInDalvikCache */))),
- anyInt(), any());
+ doReturn(mDexoptResult)
+ .when(mArtd)
+ .dexopt(any(), eq(mSplit0DexPath), eq("arm64"), any(), any(), any(),
+ deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPath(
+ mSplit0DexPath, "arm64", false /* isInDalvikCache */))),
+ anyInt(), any());
// DexMetadataPath.
doReturn(dexoptIsNeeded(ArtifactsLocation.DM))
.when(mArtd)
.getDexoptNeeded(eq(mSplit0DexPath), eq("arm"), any(), any(), anyInt());
- doReturn(true).when(mArtd).dexopt(any(), eq(mSplit0DexPath), eq("arm"), any(), any(), any(),
- deepEq(VdexPath.dexMetadataPath(AidlUtils.buildDexMetadataPath(mSplit0DexPath))),
- anyInt(), any());
+ doReturn(mDexoptResult)
+ .when(mArtd)
+ .dexopt(any(), eq(mSplit0DexPath), eq("arm"), any(), any(), any(),
+ deepEq(VdexPath.dexMetadataPath(
+ AidlUtils.buildDexMetadataPath(mSplit0DexPath))),
+ anyInt(), any());
mPrimaryDexOptimizer.dexopt(mPkgState, mPkg, mOptimizeParams);
}
diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTestBase.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTestBase.java
index 2f2c33f..7308318 100644
--- a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTestBase.java
+++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTestBase.java
@@ -133,4 +133,12 @@
}
return result;
}
+
+ protected DexoptResult createDexoptResult(boolean cancelled, long wallTimeMs, long cpuTimeMs) {
+ var result = new DexoptResult();
+ result.cancelled = cancelled;
+ result.wallTimeMs = wallTimeMs;
+ result.cpuTimeMs = cpuTimeMs;
+ return result;
+ }
}