Add the size of optimized artifacts to OptimizeResult.
Bug: 255566429
Test: m test-art-host-gtest-art_artd_tests
Test: atest ArtServiceTests
Test: adb shell pm art optimize-package -m speed-profile -f com.google.android.gms
Ignore-AOSP-First: ART Services
Change-Id: Icbffe6d56dcecdbac8154284f43d16828373db20
diff --git a/artd/artd.cc b/artd/artd.cc
index 2e86b38..4bdf1bf 100644
--- a/artd/artd.cc
+++ b/artd/artd.cc
@@ -117,9 +117,7 @@
// would take down the system server.
constexpr int kLongTimeoutSec = 570; // 9.5 minutes.
-// Deletes a file. Returns the size of the deleted file, or 0 if the deleted file is empty or an
-// error occurs.
-int64_t GetSizeAndDeleteFile(const std::string& path) {
+std::optional<int64_t> GetSize(std::string_view path) {
std::error_code ec;
int64_t size = std::filesystem::file_size(path, ec);
if (ec) {
@@ -127,15 +125,26 @@
if (ec.value() != ENOENT) {
LOG(ERROR) << "Failed to get the file size of '{}': {}"_format(path, ec.message());
}
+ return std::nullopt;
+ }
+ return size;
+}
+
+// Deletes a file. Returns the size of the deleted file, or 0 if the deleted file is empty or an
+// error occurs.
+int64_t GetSizeAndDeleteFile(const std::string& path) {
+ std::optional<int64_t> size = GetSize(path);
+ if (!size.has_value()) {
return 0;
}
+ std::error_code ec;
if (!std::filesystem::remove(path, ec)) {
LOG(ERROR) << "Failed to remove '{}': {}"_format(path, ec.message());
return 0;
}
- return size;
+ return size.value();
}
std::string EscapeErrorMessage(const std::string& message) {
@@ -860,8 +869,19 @@
return NonFatal("dex2oat returned an unexpected code: %d"_format(result.value()));
}
- NewFile::CommitAllOrAbandon(files_to_commit, files_to_delete);
+ int64_t size_bytes = 0;
+ int64_t size_before_bytes = 0;
+ for (const NewFile* file : files_to_commit) {
+ size_bytes += GetSize(file->TempPath()).value_or(0);
+ size_before_bytes += GetSize(file->FinalPath()).value_or(0);
+ }
+ for (std::string_view path : files_to_delete) {
+ size_before_bytes += GetSize(path).value_or(0);
+ }
+ OR_RETURN_NON_FATAL(NewFile::CommitAllOrAbandon(files_to_commit, files_to_delete));
+ _aidl_return->sizeBytes = size_bytes;
+ _aidl_return->sizeBeforeBytes = size_before_bytes;
return ScopedAStatus::ok();
}
diff --git a/artd/artd_test.cc b/artd/artd_test.cc
index a2ba7f5..c2db04b 100644
--- a/artd/artd_test.cc
+++ b/artd/artd_test.cc
@@ -518,7 +518,10 @@
RunDexopt(EX_NONE,
AllOf(Field(&DexoptResult::cancelled, false),
Field(&DexoptResult::wallTimeMs, 100),
- Field(&DexoptResult::cpuTimeMs, 400)));
+ Field(&DexoptResult::cpuTimeMs, 400),
+ Field(&DexoptResult::sizeBytes, strlen("oat") + strlen("vdex")),
+ Field(&DexoptResult::sizeBeforeBytes,
+ strlen("old_art") + strlen("old_oat") + strlen("old_vdex"))));
CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "oat");
CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "vdex");
@@ -874,6 +877,25 @@
CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
}
+TEST_F(ArtdTest, dexoptFailedToCommit) {
+ std::unique_ptr<ScopeGuard<std::function<void()>>> scoped_inaccessible;
+ std::unique_ptr<ScopeGuard<std::function<void()>>> scoped_unroot;
+
+ EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
+ .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
+ WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
+ [&](auto, auto, auto) {
+ scoped_inaccessible = std::make_unique<ScopeGuard<std::function<void()>>>(
+ ScopedInaccessible(scratch_path_ + "/a/oat/arm64"));
+ scoped_unroot =
+ std::make_unique<ScopeGuard<std::function<void()>>>(ScopedUnroot());
+ return 0;
+ }));
+
+ RunDexopt(EX_SERVICE_SPECIFIC,
+ AllOf(Field(&DexoptResult::sizeBytes, 0), Field(&DexoptResult::sizeBeforeBytes, 0)));
+}
+
TEST_F(ArtdTest, dexoptCancelledBeforeDex2oat) {
std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
diff --git a/artd/binder/com/android/server/art/DexoptResult.aidl b/artd/binder/com/android/server/art/DexoptResult.aidl
index 1f1b053..52df54d 100644
--- a/artd/binder/com/android/server/art/DexoptResult.aidl
+++ b/artd/binder/com/android/server/art/DexoptResult.aidl
@@ -34,4 +34,15 @@
* failed to get the value.
*/
long cpuTimeMs;
+ /**
+ * The total size, in bytes, of the optimized artifacts, or 0 if dex2oat fails, is cancelled, or
+ * is not run.
+ */
+ long sizeBytes;
+ /**
+ * The total size, in bytes, of the previous optimized artifacts that have been replaced, or
+ * 0 if there were no previous optimized artifacts or dex2oat fails, is cancelled, or is not
+ * run.
+ */
+ long sizeBeforeBytes;
}
diff --git a/libartservice/service/api/system-server-current.txt b/libartservice/service/api/system-server-current.txt
index 0fdabff..fc44bcd 100644
--- a/libartservice/service/api/system-server-current.txt
+++ b/libartservice/service/api/system-server-current.txt
@@ -135,6 +135,8 @@
method public long getDex2oatCpuTimeMillis();
method public long getDex2oatWallTimeMillis();
method @NonNull public String getDexContainerFile();
+ method public long getSizeBeforeBytes();
+ method public long getSizeBytes();
method public int getStatus();
method public boolean isPrimaryAbi();
}
diff --git a/libartservice/service/java/com/android/server/art/ArtShellCommand.java b/libartservice/service/java/com/android/server/art/ArtShellCommand.java
index d0986c1..5540ac3 100644
--- a/libartservice/service/java/com/android/server/art/ArtShellCommand.java
+++ b/libartservice/service/java/com/android/server/art/ArtShellCommand.java
@@ -326,12 +326,13 @@
packageResult.getDexContainerFileOptimizeResults()) {
pw.printf("dexContainerFile = %s, isPrimaryAbi = %b, abi = %s, "
+ "compilerFilter = %s, status = %s, "
- + "dex2oatWallTimeMillis = %d, dex2oatCpuTimeMillis = %d\n",
+ + "dex2oatWallTimeMillis = %d, dex2oatCpuTimeMillis = %d, "
+ + "sizeBytes = %d, sizeBeforeBytes = %d\n",
fileResult.getDexContainerFile(), fileResult.isPrimaryAbi(),
fileResult.getAbi(), fileResult.getActualCompilerFilter(),
optimizeStatusToString(fileResult.getStatus()),
- fileResult.getDex2oatWallTimeMillis(),
- fileResult.getDex2oatCpuTimeMillis());
+ fileResult.getDex2oatWallTimeMillis(), fileResult.getDex2oatCpuTimeMillis(),
+ fileResult.getSizeBytes(), fileResult.getSizeBeforeBytes());
}
}
}
diff --git a/libartservice/service/java/com/android/server/art/DexOptimizer.java b/libartservice/service/java/com/android/server/art/DexOptimizer.java
index 356d74b..efc25f1 100644
--- a/libartservice/service/java/com/android/server/art/DexOptimizer.java
+++ b/libartservice/service/java/com/android/server/art/DexOptimizer.java
@@ -147,6 +147,8 @@
@OptimizeResult.OptimizeStatus int status = OptimizeResult.OPTIMIZE_SKIPPED;
long wallTimeMs = 0;
long cpuTimeMs = 0;
+ long sizeBytes = 0;
+ long sizeBeforeBytes = 0;
try {
var target = DexoptTarget.<DexInfoType>builder()
.setDexInfo(dexInfo)
@@ -186,6 +188,8 @@
: OptimizeResult.OPTIMIZE_PERFORMED;
wallTimeMs = dexoptResult.wallTimeMs;
cpuTimeMs = dexoptResult.cpuTimeMs;
+ sizeBytes = dexoptResult.sizeBytes;
+ sizeBeforeBytes = dexoptResult.sizeBeforeBytes;
if (status == OptimizeResult.OPTIMIZE_CANCELLED) {
return results;
@@ -202,7 +206,7 @@
} finally {
results.add(new DexContainerFileOptimizeResult(dexInfo.dexPath(),
abi.isPrimaryAbi(), abi.name(), compilerFilter, status, wallTimeMs,
- cpuTimeMs));
+ cpuTimeMs, sizeBytes, sizeBeforeBytes));
if (status != OptimizeResult.OPTIMIZE_SKIPPED
&& status != OptimizeResult.OPTIMIZE_PERFORMED) {
succeeded = false;
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 6714f9a..b777e47 100644
--- a/libartservice/service/java/com/android/server/art/model/OptimizeResult.java
+++ b/libartservice/service/java/com/android/server/art/model/OptimizeResult.java
@@ -157,11 +157,14 @@
private final @OptimizeStatus int mStatus;
private final long mDex2oatWallTimeMillis;
private final long mDex2oatCpuTimeMillis;
+ private final long mSizeBytes;
+ private final long mSizeBeforeBytes;
/** @hide */
public DexContainerFileOptimizeResult(@NonNull String dexContainerFile,
boolean isPrimaryAbi, @NonNull String abi, @NonNull String compilerFilter,
- @OptimizeStatus int status, long dex2oatWallTimeMillis, long dex2oatCpuTimeMillis) {
+ @OptimizeStatus int status, long dex2oatWallTimeMillis, long dex2oatCpuTimeMillis,
+ long sizeBytes, long sizeBeforeBytes) {
mDexContainerFile = dexContainerFile;
mIsPrimaryAbi = isPrimaryAbi;
mAbi = abi;
@@ -169,6 +172,8 @@
mStatus = status;
mDex2oatWallTimeMillis = dex2oatWallTimeMillis;
mDex2oatCpuTimeMillis = dex2oatCpuTimeMillis;
+ mSizeBytes = sizeBytes;
+ mSizeBeforeBytes = sizeBeforeBytes;
}
/** The absolute path to the dex container file. */
@@ -222,5 +227,22 @@
public @DurationMillisLong long getDex2oatCpuTimeMillis() {
return mDex2oatCpuTimeMillis;
}
+
+ /**
+ * The total size, in bytes, of the optimized artifacts. Returns 0 if {@link #getStatus()}
+ * is not {@link #OPTIMIZE_PERFORMED}.
+ */
+ public long getSizeBytes() {
+ return mSizeBytes;
+ }
+
+ /**
+ * The total size, in bytes, of the previous optimized artifacts that has been replaced.
+ * Returns 0 if there were no previous optimized artifacts or {@link #getStatus()} is not
+ * {@link #OPTIMIZE_PERFORMED}.
+ */
+ public long getSizeBeforeBytes() {
+ return mSizeBeforeBytes;
+ }
}
}
diff --git a/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java b/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
index e12cd5d..0653efb 100644
--- a/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
+++ b/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
@@ -561,12 +561,14 @@
String dexPath, boolean partialFailure) {
return List.of(new DexContainerFileOptimizeResult(dexPath, true /* isPrimaryAbi */,
"arm64-v8a", "verify", OptimizeResult.OPTIMIZE_PERFORMED,
- 100 /* dex2oatWallTimeMillis */, 400 /* dex2oatCpuTimeMillis */),
+ 100 /* dex2oatWallTimeMillis */, 400 /* dex2oatCpuTimeMillis */,
+ 0 /* sizeBytes */, 0 /* sizeBeforeBytes */),
new DexContainerFileOptimizeResult(dexPath, false /* isPrimaryAbi */, "armeabi-v7a",
"verify",
partialFailure ? OptimizeResult.OPTIMIZE_FAILED
: OptimizeResult.OPTIMIZE_PERFORMED,
- 100 /* dex2oatWallTimeMillis */, 400 /* dex2oatCpuTimeMillis */));
+ 100 /* dex2oatWallTimeMillis */, 400 /* dex2oatCpuTimeMillis */,
+ 0 /* sizeBytes */, 0 /* sizeBeforeBytes */));
}
private void checkPackageResult(OptimizeResult result, int index, String packageName,
diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java
index bff34ee..bc5e3b6 100644
--- a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java
+++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerParameterizedTest.java
@@ -216,8 +216,8 @@
.when(mArtd)
.getDexoptNeeded("/data/app/foo/base.apk", "arm64", "PCL[]",
mParams.mExpectedCompilerFilter, mParams.mExpectedDexoptTrigger);
- doReturn(createDexoptResult(
- false /* cancelled */, 100 /* wallTimeMs */, 400 /* cpuTimeMs */))
+ doReturn(createDexoptResult(false /* cancelled */, 100 /* wallTimeMs */,
+ 400 /* cpuTimeMs */, 30000 /* sizeBytes */, 32000 /* sizeBeforeBytes */))
.when(mArtd)
.dexopt(deepEq(buildOutputArtifacts("/data/app/foo/base.apk", "arm64",
mParams.mExpectedIsInDalvikCache, permissionSettings)),
@@ -251,8 +251,8 @@
.when(mArtd)
.getDexoptNeeded("/data/app/foo/split_0.apk", "arm", "PCL[base.apk]",
mParams.mExpectedCompilerFilter, mParams.mExpectedDexoptTrigger);
- doReturn(createDexoptResult(
- false /* cancelled */, 200 /* wallTimeMs */, 200 /* cpuTimeMs */))
+ doReturn(createDexoptResult(false /* cancelled */, 200 /* wallTimeMs */,
+ 200 /* cpuTimeMs */, 10000 /* sizeBytes */, 0 /* sizeBeforeBytes */))
.when(mArtd)
.dexopt(deepEq(buildOutputArtifacts("/data/app/foo/split_0.apk", "arm",
mParams.mExpectedIsInDalvikCache, permissionSettings)),
@@ -267,19 +267,23 @@
new DexContainerFileOptimizeResult("/data/app/foo/base.apk",
true /* isPrimaryAbi */, "arm64-v8a",
mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_PERFORMED,
- 100 /* dex2oatWallTimeMillis */, 400 /* dex2oatCpuTimeMillis */),
+ 100 /* dex2oatWallTimeMillis */, 400 /* dex2oatCpuTimeMillis */,
+ 30000 /* sizeBytes */, 32000 /* sizeBeforeBytes */),
new DexContainerFileOptimizeResult("/data/app/foo/base.apk",
false /* isPrimaryAbi */, "armeabi-v7a",
mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_FAILED,
- 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */),
+ 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */,
+ 0 /* sizeBytes */, 0 /* sizeBeforeBytes */),
new DexContainerFileOptimizeResult("/data/app/foo/split_0.apk",
true /* isPrimaryAbi */, "arm64-v8a",
mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_SKIPPED,
- 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */),
+ 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */,
+ 0 /* sizeBytes */, 0 /* sizeBeforeBytes */),
new DexContainerFileOptimizeResult("/data/app/foo/split_0.apk",
false /* isPrimaryAbi */, "armeabi-v7a",
mParams.mExpectedCompilerFilter, OptimizeResult.OPTIMIZE_PERFORMED,
- 200 /* dex2oatWallTimeMillis */, 200 /* dex2oatCpuTimeMillis */));
+ 200 /* dex2oatWallTimeMillis */, 200 /* dex2oatCpuTimeMillis */,
+ 10000 /* sizeBytes */, 0 /* sizeBeforeBytes */));
}
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 ff74e15..3aee484 100644
--- a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java
+++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTest.java
@@ -92,8 +92,7 @@
| 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 final DexoptResult mDexoptResult = createDexoptResult(false /* cancelled */);
private PrimaryDexOptimizer mPrimaryDexOptimizer;
@@ -467,8 +466,7 @@
doAnswer(invocation -> {
verify(artdCancellationSignal).cancel();
- return createDexoptResult(
- true /* cancelled */, 200 /* wallTimeMs */, 200 /* cpuTimeMs */);
+ return createDexoptResult(true /* cancelled */);
})
.when(mArtd)
.dexopt(any(), any(), any(), any(), any(), any(), any(), any(), anyInt(), any(),
@@ -501,8 +499,7 @@
doAnswer(invocation -> {
dexoptStarted.release();
assertThat(dexoptCancelled.tryAcquire(TIMEOUT_SEC, TimeUnit.SECONDS)).isTrue();
- return createDexoptResult(
- true /* cancelled */, 200 /* wallTimeMs */, 200 /* cpuTimeMs */);
+ return createDexoptResult(true /* cancelled */);
})
.when(mArtd)
.dexopt(any(), any(), any(), any(), any(), any(), any(), any(), anyInt(), any(),
diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTestBase.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTestBase.java
index 9b272d9..15b3f4b 100644
--- a/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTestBase.java
+++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexOptimizerTestBase.java
@@ -178,11 +178,19 @@
return result;
}
- protected DexoptResult createDexoptResult(boolean cancelled, long wallTimeMs, long cpuTimeMs) {
+ protected DexoptResult createDexoptResult(boolean cancelled, long wallTimeMs, long cpuTimeMs,
+ long sizeBytes, long sizeBeforeBytes) {
var result = new DexoptResult();
result.cancelled = cancelled;
result.wallTimeMs = wallTimeMs;
result.cpuTimeMs = cpuTimeMs;
+ result.sizeBytes = sizeBytes;
+ result.sizeBeforeBytes = sizeBeforeBytes;
return result;
}
+
+ protected DexoptResult createDexoptResult(boolean cancelled) {
+ return createDexoptResult(cancelled, 0 /* wallTimeMs */, 0 /* cpuTimeMs */,
+ 0 /* sizeBytes */, 0 /* sizeBeforeBytes */);
+ }
}
diff --git a/libartservice/service/javatests/com/android/server/art/SecondaryDexOptimizerTest.java b/libartservice/service/javatests/com/android/server/art/SecondaryDexOptimizerTest.java
index 4e9a7f1..a9518d3 100644
--- a/libartservice/service/javatests/com/android/server/art/SecondaryDexOptimizerTest.java
+++ b/libartservice/service/javatests/com/android/server/art/SecondaryDexOptimizerTest.java
@@ -164,16 +164,20 @@
.containsExactly(
new DexContainerFileOptimizeResult(DEX_1, true /* isPrimaryAbi */,
"arm64-v8a", "speed-profile", OptimizeResult.OPTIMIZE_PERFORMED,
- 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */),
+ 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */,
+ 0 /* sizeBytes */, 0 /* sizeBeforeBytes */),
new DexContainerFileOptimizeResult(DEX_2, true /* isPrimaryAbi */,
"arm64-v8a", "speed", OptimizeResult.OPTIMIZE_PERFORMED,
- 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */),
+ 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */,
+ 0 /* sizeBytes */, 0 /* sizeBeforeBytes */),
new DexContainerFileOptimizeResult(DEX_2, false /* isPrimaryAbi */,
"armeabi-v7a", "speed", OptimizeResult.OPTIMIZE_PERFORMED,
- 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */),
+ 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */,
+ 0 /* sizeBytes */, 0 /* sizeBeforeBytes */),
new DexContainerFileOptimizeResult(DEX_3, true /* isPrimaryAbi */,
"arm64-v8a", "verify", OptimizeResult.OPTIMIZE_PERFORMED,
- 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */));
+ 0 /* dex2oatWallTimeMillis */, 0 /* dex2oatCpuTimeMillis */,
+ 0 /* sizeBytes */, 0 /* sizeBeforeBytes */));
// It should use profile for dex 1.
@@ -307,6 +311,8 @@
result.cancelled = false;
result.wallTimeMs = 0;
result.cpuTimeMs = 0;
+ result.sizeBytes = 0;
+ result.sizeBeforeBytes = 0;
return result;
}