• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.art;
18 
19 import static com.android.server.art.model.ArtFlags.BatchDexoptPass;
20 
21 import android.annotation.NonNull;
22 import android.app.job.JobParameters;
23 import android.os.Build;
24 
25 import androidx.annotation.RequiresApi;
26 
27 import com.android.server.art.model.ArtFlags;
28 import com.android.server.art.model.DexoptResult;
29 
30 import dalvik.system.DexFile;
31 
32 import java.util.List;
33 import java.util.Optional;
34 
35 /**
36  * This is a helper class to report the background DexOpt job metrics to StatsD.
37  *
38  * @hide
39  */
40 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
41 public class BackgroundDexoptJobStatsReporter {
reportFailure()42     public static void reportFailure() {
43         // The fatal error can occur during any pass, but we attribute it to the main pass for
44         // simplicity.
45         ArtStatsLog.write(ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED,
46                 ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_FATAL_ERROR,
47                 JobParameters.STOP_REASON_UNDEFINED, 0L /* durationMs */, 0L /* deprecated */,
48                 0 /* optimizedPackagesCount */, 0 /* packagesDependingOnBootClasspathCount */,
49                 0 /* totalPackagesCount */,
50                 ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__PASS__PASS_MAIN);
51     }
52 
reportSuccess(@onNull BackgroundDexoptJob.CompletedResult completedResult, Optional<Integer> stopReason)53     public static void reportSuccess(@NonNull BackgroundDexoptJob.CompletedResult completedResult,
54             Optional<Integer> stopReason) {
55         for (var entry : completedResult.dexoptResultByPass().entrySet()) {
56             reportPass(entry.getKey(), entry.getValue(),
57                     completedResult.durationMsByPass().getOrDefault(entry.getKey(), 0l),
58                     stopReason);
59         }
60     }
61 
reportPass(@atchDexoptPass int pass, @NonNull DexoptResult dexoptResult, long durationMs, Optional<Integer> stopReason)62     public static void reportPass(@BatchDexoptPass int pass, @NonNull DexoptResult dexoptResult,
63             long durationMs, Optional<Integer> stopReason) {
64         // The job contains multiple passes, so the stop reason may not be for the current pass. We
65         // shouldn't report the stop reason if the current pass finished before the job was
66         // cancelled.
67         int reportedStopReason = dexoptResult.getFinalStatus() == DexoptResult.DEXOPT_CANCELLED
68                 ? stopReason.orElse(JobParameters.STOP_REASON_UNDEFINED)
69                 : JobParameters.STOP_REASON_UNDEFINED;
70 
71         List<DexoptResult.PackageDexoptResult> packageDexoptResults =
72                 getFilteredPackageResults(dexoptResult);
73 
74         ArtStatsLog.write(ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED,
75                 getStatusForStats(dexoptResult, stopReason), reportedStopReason, durationMs,
76                 0L /* deprecated */, getDexoptedPackagesCount(packageDexoptResults),
77                 getPackagesDependingOnBootClasspathCount(packageDexoptResults),
78                 packageDexoptResults.size(), toStatsdPassEnum(pass));
79     }
80 
81     @NonNull
getFilteredPackageResults( @onNull DexoptResult dexoptResult)82     private static List<DexoptResult.PackageDexoptResult> getFilteredPackageResults(
83             @NonNull DexoptResult dexoptResult) {
84         return dexoptResult.getPackageDexoptResults()
85                 .stream()
86                 .filter(packageResult
87                         -> packageResult.getDexContainerFileDexoptResults().stream().anyMatch(
88                                 fileResult
89                                 -> (fileResult.getExtendedStatusFlags()
90                                            & DexoptResult.EXTENDED_SKIPPED_NO_DEX_CODE)
91                                         == 0))
92                 .toList();
93     }
94 
getStatusForStats( @onNull DexoptResult dexoptResult, Optional<Integer> stopReason)95     private static int getStatusForStats(
96             @NonNull DexoptResult dexoptResult, Optional<Integer> stopReason) {
97         if (dexoptResult.getFinalStatus() == DexoptResult.DEXOPT_CANCELLED) {
98             if (stopReason.isPresent()) {
99                 return ArtStatsLog
100                         .BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BY_CANCELLATION;
101             } else {
102                 return ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BY_API;
103             }
104         }
105 
106         boolean isSkippedDueToStorageLow =
107                 dexoptResult.getPackageDexoptResults()
108                         .stream()
109                         .flatMap(packageResult
110                                 -> packageResult.getDexContainerFileDexoptResults().stream())
111                         .anyMatch(fileResult
112                                 -> (fileResult.getExtendedStatusFlags()
113                                            & DexoptResult.EXTENDED_SKIPPED_STORAGE_LOW)
114                                         != 0);
115         if (isSkippedDueToStorageLow) {
116             return ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_NO_SPACE_LEFT;
117         }
118 
119         return ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED;
120     }
121 
getDexoptedPackagesCount( @onNull List<DexoptResult.PackageDexoptResult> packageResults)122     private static int getDexoptedPackagesCount(
123             @NonNull List<DexoptResult.PackageDexoptResult> packageResults) {
124         return (int) packageResults.stream()
125                 .filter(result -> result.getStatus() == DexoptResult.DEXOPT_PERFORMED)
126                 .count();
127     }
128 
getPackagesDependingOnBootClasspathCount( @onNull List<DexoptResult.PackageDexoptResult> packageResults)129     private static int getPackagesDependingOnBootClasspathCount(
130             @NonNull List<DexoptResult.PackageDexoptResult> packageResults) {
131         return (int) packageResults.stream()
132                 .map(DexoptResult.PackageDexoptResult::getDexContainerFileDexoptResults)
133                 .filter(BackgroundDexoptJobStatsReporter::isDependentOnBootClasspath)
134                 .count();
135     }
136 
isDependentOnBootClasspath( @onNull List<DexoptResult.DexContainerFileDexoptResult> filesResults)137     private static boolean isDependentOnBootClasspath(
138             @NonNull List<DexoptResult.DexContainerFileDexoptResult> filesResults) {
139         return filesResults.stream()
140                 .map(DexoptResult.DexContainerFileDexoptResult::getActualCompilerFilter)
141                 .anyMatch(DexFile::isOptimizedCompilerFilter);
142     }
143 
toStatsdPassEnum(@atchDexoptPass int pass)144     private static int toStatsdPassEnum(@BatchDexoptPass int pass) {
145         switch (pass) {
146             case ArtFlags.PASS_DOWNGRADE:
147                 return ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__PASS__PASS_DOWNGRADE;
148             case ArtFlags.PASS_MAIN:
149                 return ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__PASS__PASS_MAIN;
150             case ArtFlags.PASS_SUPPLEMENTARY:
151                 return ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__PASS__PASS_SUPPLEMENTARY;
152         }
153         throw new IllegalArgumentException("Unknown batch dexopt pass " + pass);
154     }
155 }
156