• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.model;
18 
19 import android.annotation.DurationMillisLong;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 
25 import com.android.internal.annotations.Immutable;
26 
27 import com.google.auto.value.AutoValue;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.List;
32 
33 /** @hide */
34 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
35 @Immutable
36 @AutoValue
37 public abstract class DexoptResult {
38     // Possible values of {@link #DexoptResultStatus}.
39     // A larger number means a higher priority. If multiple dex container files are processed, the
40     // final status will be the one with the highest priority.
41     /** Dexopt is skipped because there is no need to do it. */
42     public static final int DEXOPT_SKIPPED = 10;
43     /** Dexopt is performed successfully. */
44     public static final int DEXOPT_PERFORMED = 20;
45     /** Dexopt is failed. */
46     public static final int DEXOPT_FAILED = 30;
47     /** Dexopt is cancelled. */
48     public static final int DEXOPT_CANCELLED = 40;
49 
50     /** @hide */
51     // clang-format off
52     @IntDef(prefix = {"DEXOPT_"}, value = {
53         DEXOPT_SKIPPED,
54         DEXOPT_FAILED,
55         DEXOPT_PERFORMED,
56         DEXOPT_CANCELLED,
57     })
58     // clang-format on
59     @Retention(RetentionPolicy.SOURCE)
60     public @interface DexoptResultStatus {}
61 
62     /** @hide */
DexoptResult()63     protected DexoptResult() {}
64 
65     /** @hide */
create(@onNull String requestedCompilerFilter, @NonNull String reason, @NonNull List<PackageDexoptResult> packageDexoptResult)66     public static @NonNull DexoptResult create(@NonNull String requestedCompilerFilter,
67             @NonNull String reason, @NonNull List<PackageDexoptResult> packageDexoptResult) {
68         return new AutoValue_DexoptResult(requestedCompilerFilter, reason, packageDexoptResult);
69     }
70 
71     /**
72      * The requested compiler filter. Note that the compiler filter might be adjusted before the
73      * execution based on factors like whether the profile is available or whether the app is
74      * used by other apps.
75      *
76      * @see DexoptParams.Builder#setCompilerFilter(String)
77      * @see DexContainerFileDexoptResult#getActualCompilerFilter()
78      */
getRequestedCompilerFilter()79     public abstract @NonNull String getRequestedCompilerFilter();
80 
81     /** The compilation reason. */
getReason()82     public abstract @NonNull String getReason();
83 
84     /**
85      * The result of each individual package.
86      *
87      * If the request is to dexopt a single package without dexopting dependencies, the only
88      * element is the result of the requested package.
89      *
90      * If the request is to dexopt a single package with {@link
91      * ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES} set, the first element is the result of the
92      * requested package, and the rest are the results of the dependency packages.
93      *
94      * If the request is to dexopt multiple packages, the list contains the results of all the
95      * requested packages. The results of their dependency packages are also included if {@link
96      * ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES} is set.
97      *
98      * If the request is a batch dexopt operation that got cancelled, the list still has an entry
99      * for every package that was requested to be optimized.
100      */
getPackageDexoptResults()101     public abstract @NonNull List<PackageDexoptResult> getPackageDexoptResults();
102 
103     /** The final status. */
getFinalStatus()104     public @DexoptResultStatus int getFinalStatus() {
105         return getPackageDexoptResults()
106                 .stream()
107                 .mapToInt(result -> result.getStatus())
108                 .max()
109                 .orElse(DEXOPT_SKIPPED);
110     }
111 
112     /** @hide */
113     @NonNull
dexoptResultStatusToString(@exoptResultStatus int status)114     public static String dexoptResultStatusToString(@DexoptResultStatus int status) {
115         switch (status) {
116             case DexoptResult.DEXOPT_SKIPPED:
117                 return "SKIPPED";
118             case DexoptResult.DEXOPT_PERFORMED:
119                 return "PERFORMED";
120             case DexoptResult.DEXOPT_FAILED:
121                 return "FAILED";
122             case DexoptResult.DEXOPT_CANCELLED:
123                 return "CANCELLED";
124         }
125         throw new IllegalArgumentException("Unknown dexopt status " + status);
126     }
127 
128     /**
129      * Describes the result of a package.
130      *
131      * @hide
132      */
133     @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
134     @Immutable
135     @AutoValue
136     public static abstract class PackageDexoptResult {
137         /** @hide */
PackageDexoptResult()138         protected PackageDexoptResult() {}
139 
140         /** @hide */
create(@onNull String packageName, @NonNull List<DexContainerFileDexoptResult> dexContainerFileDexoptResults, @Nullable @DexoptResultStatus Integer packageLevelStatus)141         public static @NonNull PackageDexoptResult create(@NonNull String packageName,
142                 @NonNull List<DexContainerFileDexoptResult> dexContainerFileDexoptResults,
143                 @Nullable @DexoptResultStatus Integer packageLevelStatus) {
144             return new AutoValue_DexoptResult_PackageDexoptResult(
145                     packageName, dexContainerFileDexoptResults, packageLevelStatus);
146         }
147 
148         /** The package name. */
getPackageName()149         public abstract @NonNull String getPackageName();
150 
151         /**
152          * The results of dexopting dex container files. Note that there can be multiple entries
153          * for the same dex container file, but for different ABIs.
154          */
155         public abstract @NonNull List<DexContainerFileDexoptResult>
getDexContainerFileDexoptResults()156         getDexContainerFileDexoptResults();
157 
158         /** @hide */
getPackageLevelStatus()159         @Nullable @DexoptResultStatus public abstract Integer getPackageLevelStatus();
160 
161         /** The overall status of the package. */
getStatus()162         public @DexoptResultStatus int getStatus() {
163             return getPackageLevelStatus() != null ? getPackageLevelStatus()
164                                                    : getDexContainerFileDexoptResults()
165                                                              .stream()
166                                                              .mapToInt(result -> result.getStatus())
167                                                              .max()
168                                                              .orElse(DEXOPT_SKIPPED);
169         }
170 
171         /** True if the package has any artifacts updated by this operation. */
hasUpdatedArtifacts()172         public boolean hasUpdatedArtifacts() {
173             return getDexContainerFileDexoptResults().stream().anyMatch(
174                     result -> result.getStatus() == DEXOPT_PERFORMED);
175         }
176     }
177 
178     /**
179      * Describes the result of dexopting a dex container file.
180      *
181      * @hide
182      */
183     @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
184     @Immutable
185     @AutoValue
186     public static abstract class DexContainerFileDexoptResult {
187         /** @hide */
DexContainerFileDexoptResult()188         protected DexContainerFileDexoptResult() {}
189 
190         /** @hide */
create(@onNull String dexContainerFile, boolean isPrimaryAbi, @NonNull String abi, @NonNull String compilerFilter, @DexoptResultStatus int status, long dex2oatWallTimeMillis, long dex2oatCpuTimeMillis, long sizeBytes, long sizeBeforeBytes, boolean isSkippedDueToStorageLow)191         public static @NonNull DexContainerFileDexoptResult create(@NonNull String dexContainerFile,
192                 boolean isPrimaryAbi, @NonNull String abi, @NonNull String compilerFilter,
193                 @DexoptResultStatus int status, long dex2oatWallTimeMillis,
194                 long dex2oatCpuTimeMillis, long sizeBytes, long sizeBeforeBytes,
195                 boolean isSkippedDueToStorageLow) {
196             return new AutoValue_DexoptResult_DexContainerFileDexoptResult(dexContainerFile,
197                     isPrimaryAbi, abi, compilerFilter, status, dex2oatWallTimeMillis,
198                     dex2oatCpuTimeMillis, sizeBytes, sizeBeforeBytes, isSkippedDueToStorageLow);
199         }
200 
201         /** The absolute path to the dex container file. */
getDexContainerFile()202         public abstract @NonNull String getDexContainerFile();
203 
204         /**
205          * If true, the dexopt is for the primary ABI of the package (the ABI that the
206          * application is launched with). Otherwise, the dexopt is for an ABI that other
207          * applications might be launched with when using this application's code.
208          */
isPrimaryAbi()209         public abstract boolean isPrimaryAbi();
210 
211         /**
212          * Returns the ABI that the dexopt is for. Possible values are documented at
213          * https://developer.android.com/ndk/guides/abis#sa.
214          */
getAbi()215         public abstract @NonNull String getAbi();
216 
217         /**
218          * The actual compiler filter.
219          *
220          * @see DexoptParams.Builder#setCompilerFilter(String)
221          */
getActualCompilerFilter()222         public abstract @NonNull String getActualCompilerFilter();
223 
224         /** The status of dexopting this dex container file. */
getStatus()225         public abstract @DexoptResultStatus int getStatus();
226 
227         /**
228          * The wall time of the dex2oat invocation, in milliseconds, if dex2oat succeeded or was
229          * cancelled. Returns 0 if dex2oat failed or was not run, or if failed to get the value.
230          */
getDex2oatWallTimeMillis()231         public abstract @DurationMillisLong long getDex2oatWallTimeMillis();
232 
233         /**
234          * The CPU time of the dex2oat invocation, in milliseconds, if dex2oat succeeded or was
235          * cancelled. Returns 0 if dex2oat failed or was not run, or if failed to get the value.
236          */
getDex2oatCpuTimeMillis()237         public abstract @DurationMillisLong long getDex2oatCpuTimeMillis();
238 
239         /**
240          * The total size, in bytes, of the dexopt artifacts. Returns 0 if {@link #getStatus()}
241          * is not {@link #DEXOPT_PERFORMED}.
242          */
getSizeBytes()243         public abstract long getSizeBytes();
244 
245         /**
246          * The total size, in bytes, of the previous dexopt artifacts that has been replaced.
247          * Returns 0 if there were no previous dexopt artifacts or {@link #getStatus()} is not
248          * {@link #DEXOPT_PERFORMED}.
249          */
getSizeBeforeBytes()250         public abstract long getSizeBeforeBytes();
251 
252         /** @hide */
isSkippedDueToStorageLow()253         public abstract boolean isSkippedDueToStorageLow();
254 
255         @Override
256         @NonNull
toString()257         public String toString() {
258             return String.format("DexContainerFileDexoptResult{"
259                             + "dexContainerFile=%s, "
260                             + "primaryAbi=%b, "
261                             + "abi=%s, "
262                             + "actualCompilerFilter=%s, "
263                             + "status=%s, "
264                             + "dex2oatWallTimeMillis=%d, "
265                             + "dex2oatCpuTimeMillis=%d, "
266                             + "sizeBytes=%d, "
267                             + "sizeBeforeBytes=%d}",
268                     getDexContainerFile(), isPrimaryAbi(), getAbi(), getActualCompilerFilter(),
269                     DexoptResult.dexoptResultStatusToString(getStatus()),
270                     getDex2oatWallTimeMillis(), getDex2oatCpuTimeMillis(), getSizeBytes(),
271                     getSizeBeforeBytes());
272         }
273     }
274 }
275