blob: 49b114d4278d0d9c36882b39aa8a300ccd25778f [file] [log] [blame]
package com.android.server.art;
import android.annotation.NonNull;
import android.app.job.JobParameters;
import android.os.Build;
import androidx.annotation.RequiresApi;
import com.android.server.art.model.DexoptResult;
import dalvik.system.DexFile;
import java.util.List;
import java.util.Optional;
/**
* This is an helper class to report the background DexOpt job metrics to StatsD.
*
* @hide
*/
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public class BackgroundDexoptJobStatsReporter {
public static void reportFailure() {
ArtStatsLog.write(ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED,
ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_FATAL_ERROR,
JobParameters.STOP_REASON_UNDEFINED, 0 /* durationMs */, 0 /* deprecated */,
0 /* optimizedPackagesCount */, 0 /* packagesDependingOnBootClasspathCount */,
0 /* totalPackagesCount */);
}
public static void reportSuccess(@NonNull BackgroundDexoptJob.CompletedResult completedResult,
Optional<Integer> stopReason) {
List<DexoptResult.PackageDexoptResult> packageDexoptResults =
completedResult.dexoptResult().getPackageDexoptResults();
ArtStatsLog.write(ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED,
getStatusForStats(completedResult, stopReason),
stopReason.orElse(JobParameters.STOP_REASON_UNDEFINED),
completedResult.durationMs(), 0 /* deprecated */,
getDexoptedPackagesCount(packageDexoptResults),
getPackagesDependingOnBootClasspathCount(packageDexoptResults),
packageDexoptResults.size());
}
private static int getStatusForStats(
@NonNull BackgroundDexoptJob.CompletedResult result, Optional<Integer> stopReason) {
if (result.dexoptResult().getFinalStatus() == DexoptResult.DEXOPT_CANCELLED) {
if (stopReason.isPresent()) {
return ArtStatsLog
.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BY_CANCELLATION;
} else {
return ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BY_API;
}
}
boolean isSkippedDueToStorageLow =
result.dexoptResult()
.getPackageDexoptResults()
.stream()
.flatMap(packageResult
-> packageResult.getDexContainerFileDexoptResults().stream())
.anyMatch(fileResult
-> (fileResult.getExtraStatus()
& DexoptResult.EXTRA_SKIPPED_STORAGE_LOW)
!= 0);
if (isSkippedDueToStorageLow) {
return ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_NO_SPACE_LEFT;
}
return ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED;
}
private static int getDexoptedPackagesCount(
@NonNull List<DexoptResult.PackageDexoptResult> packageResults) {
return (int) packageResults.stream()
.filter(result -> result.getStatus() == DexoptResult.DEXOPT_PERFORMED)
.count();
}
private static int getPackagesDependingOnBootClasspathCount(
@NonNull List<DexoptResult.PackageDexoptResult> packageResults) {
return (int) packageResults.stream()
.map(DexoptResult.PackageDexoptResult::getDexContainerFileDexoptResults)
.filter(BackgroundDexoptJobStatsReporter::isDependentOnBootClasspath)
.count();
}
private static boolean isDependentOnBootClasspath(
@NonNull List<DexoptResult.DexContainerFileDexoptResult> filesResults) {
return filesResults.stream()
.map(DexoptResult.DexContainerFileDexoptResult::getActualCompilerFilter)
.anyMatch(DexFile::isOptimizedCompilerFilter);
}
}