• 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 static com.android.server.art.model.ArtFlags.DexoptFlags;
20 import static com.android.server.art.model.ArtFlags.PriorityClassApi;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SystemApi;
25 import android.os.Build;
26 
27 import androidx.annotation.RequiresApi;
28 
29 import com.android.internal.annotations.Immutable;
30 import com.android.server.art.ArtConstants;
31 import com.android.server.art.ReasonMapping;
32 import com.android.server.art.Utils;
33 import com.android.server.art.proto.DexoptParamsProto;
34 
35 /** @hide */
36 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
37 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
38 @Immutable
39 public class DexoptParams {
40     /** @hide */
41     @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
42     public static final class Builder {
43         private DexoptParams mParams = new DexoptParams();
44 
45         /**
46          * Creates a builder.
47          *
48          * Uses default flags ({@link ArtFlags#defaultDexoptFlags()}).
49          *
50          * @param reason Compilation reason. Can be a string defined in {@link ReasonMapping} or a
51          *         custom string. If the value is a string defined in {@link ReasonMapping}, it
52          *         determines the compiler filter and/or the priority class, if those values are not
53          *         explicitly set. If the value is a custom string, the priority class and the
54          *         compiler filter must be explicitly set.
55          */
Builder(@onNull String reason)56         public Builder(@NonNull String reason) {
57             this(reason, ArtFlags.defaultDexoptFlags(reason));
58         }
59 
60         /**
61          * Same as above, but allows to specify flags.
62          */
Builder(@onNull String reason, @DexoptFlags int flags)63         public Builder(@NonNull String reason, @DexoptFlags int flags) {
64             mParams.mReason = reason;
65             setFlags(flags);
66         }
67 
68         /** Replaces all flags with the given value. */
69         @NonNull
setFlags(@exoptFlags int value)70         public Builder setFlags(@DexoptFlags int value) {
71             mParams.mFlags = value;
72             return this;
73         }
74 
75         /** Replaces the flags specified by the mask with the given value. */
76         @NonNull
setFlags(@exoptFlags int value, @DexoptFlags int mask)77         public Builder setFlags(@DexoptFlags int value, @DexoptFlags int mask) {
78             mParams.mFlags = (mParams.mFlags & ~mask) | (value & mask);
79             return this;
80         }
81 
82         /**
83          * The target compiler filter, passed as the {@code --compiler-filer} option to dex2oat.
84          * Supported values are listed in
85          * https://source.android.com/docs/core/dalvik/configure#compilation_options.
86          *
87          * Note that the compiler filter might be adjusted before the execution based on factors
88          * like dexopt flags, whether the profile is available, or whether the app is used by other
89          * apps. If not set, the default compiler filter for the given reason will be used.
90          */
91         @NonNull
setCompilerFilter(@onNull String value)92         public Builder setCompilerFilter(@NonNull String value) {
93             mParams.mCompilerFilter = value;
94             return this;
95         }
96 
97         /**
98          * The priority of the operation. If not set, the default priority class for the given
99          * reason will be used.
100          *
101          * @see PriorityClassApi
102          */
103         @NonNull
setPriorityClass(@riorityClassApi int value)104         public Builder setPriorityClass(@PriorityClassApi int value) {
105             mParams.mPriorityClass = value;
106             return this;
107         }
108 
109         /**
110          * The name of the split to dexopt, or null for the base split. This option is only
111          * available when {@link ArtFlags#FLAG_FOR_SINGLE_SPLIT} is set.
112          */
113         @NonNull
setSplitName(@ullable String value)114         public Builder setSplitName(@Nullable String value) {
115             mParams.mSplitName = value;
116             return this;
117         }
118 
119         /**
120          * Returns the built object.
121          *
122          * @throws IllegalArgumentException if the built options would be invalid
123          */
124         @NonNull
build()125         public DexoptParams build() {
126             if (mParams.mReason.isEmpty()) {
127                 throw new IllegalArgumentException("Reason must not be empty");
128             }
129             if (mParams.mReason.equals(ArtConstants.REASON_VDEX)) {
130                 throw new IllegalArgumentException(
131                         "Reason must not be '" + ArtConstants.REASON_VDEX + "'");
132             }
133 
134             if (mParams.mCompilerFilter.isEmpty()) {
135                 mParams.mCompilerFilter = ReasonMapping.getCompilerFilterForReason(mParams.mReason);
136             } else if (!Utils.isValidArtServiceCompilerFilter(mParams.mCompilerFilter)) {
137                 throw new IllegalArgumentException(
138                         "Invalid compiler filter '" + mParams.mCompilerFilter + "'");
139             }
140 
141             if (mParams.mPriorityClass == ArtFlags.PRIORITY_NONE) {
142                 mParams.mPriorityClass = ReasonMapping.getPriorityClassForReason(mParams.mReason);
143             } else if (mParams.mPriorityClass < 0 || mParams.mPriorityClass > 100) {
144                 throw new IllegalArgumentException("Invalid priority class "
145                         + mParams.mPriorityClass + ". Must be between 0 and 100");
146             }
147 
148             if ((mParams.mFlags & (ArtFlags.FLAG_FOR_PRIMARY_DEX | ArtFlags.FLAG_FOR_SECONDARY_DEX))
149                     == 0) {
150                 throw new IllegalArgumentException("Nothing to dexopt");
151             }
152 
153             if ((mParams.mFlags & ArtFlags.FLAG_FOR_PRIMARY_DEX) == 0
154                     && (mParams.mFlags & ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES) != 0) {
155                 throw new IllegalArgumentException(
156                         "FLAG_SHOULD_INCLUDE_DEPENDENCIES must not set if FLAG_FOR_PRIMARY_DEX is "
157                         + "not set.");
158             }
159 
160             if ((mParams.mFlags & ArtFlags.FLAG_FOR_SINGLE_SPLIT) != 0) {
161                 if ((mParams.mFlags & ArtFlags.FLAG_FOR_PRIMARY_DEX) == 0) {
162                     throw new IllegalArgumentException(
163                             "FLAG_FOR_PRIMARY_DEX must be set when FLAG_FOR_SINGLE_SPLIT is set");
164                 }
165                 if ((mParams.mFlags
166                             & (ArtFlags.FLAG_FOR_SECONDARY_DEX
167                                     | ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES))
168                         != 0) {
169                     throw new IllegalArgumentException(
170                             "FLAG_FOR_SECONDARY_DEX and FLAG_SHOULD_INCLUDE_DEPENDENCIES must "
171                             + "not be set when FLAG_FOR_SINGLE_SPLIT is set");
172                 }
173             } else {
174                 if (mParams.mSplitName != null) {
175                     throw new IllegalArgumentException(
176                             "Split name must not be set when FLAG_FOR_SINGLE_SPLIT is not set");
177                 }
178             }
179 
180             return mParams;
181         }
182     }
183 
184     /**
185      * A value indicating that dexopt shouldn't be run. This value is consumed by ART Services and
186      * is not propagated to dex2oat.
187      */
188     public static final String COMPILER_FILTER_NOOP = "skip";
189 
190     private @DexoptFlags int mFlags = 0;
191     private @NonNull String mCompilerFilter = "";
192     private @PriorityClassApi int mPriorityClass = ArtFlags.PRIORITY_NONE;
193     private @NonNull String mReason = "";
194     private @Nullable String mSplitName = null;
195 
DexoptParams()196     private DexoptParams() {}
197 
198     /** Returns all flags. */
getFlags()199     public @DexoptFlags int getFlags() {
200         return mFlags;
201     }
202 
203     /** The target compiler filter. */
getCompilerFilter()204     public @NonNull String getCompilerFilter() {
205         return mCompilerFilter;
206     }
207 
208     /** The priority class. */
getPriorityClass()209     public @PriorityClassApi int getPriorityClass() {
210         return mPriorityClass;
211     }
212 
213     /**
214      * The compilation reason.
215      *
216      * DO NOT directly use the string value to determine the resource usage and the process
217      * priority. Use {@link #getPriorityClass}.
218      */
getReason()219     public @NonNull String getReason() {
220         return mReason;
221     }
222 
223     /** The name of the split to dexopt, or null for the base split. */
getSplitName()224     public @Nullable String getSplitName() {
225         return mSplitName;
226     }
227 
228     /** @hide */
toBuilder()229     public @NonNull Builder toBuilder() {
230         return new Builder(mReason, mFlags)
231                 .setCompilerFilter(mCompilerFilter)
232                 .setPriorityClass(mPriorityClass)
233                 .setSplitName(mSplitName);
234     }
235 
236     /** @hide */
fromProto(@onNull DexoptParamsProto proto)237     public static @NonNull DexoptParams fromProto(@NonNull DexoptParamsProto proto) {
238         return new DexoptParams.Builder(proto.getReason(), proto.getFlags())
239                 .setCompilerFilter(proto.getCompilerFilter())
240                 .setPriorityClass(proto.getPriorityClass())
241                 .build();
242     }
243 
244     /** @hide */
toProto()245     public @NonNull DexoptParamsProto toProto() {
246         // The split name is intentionally omitted from the proto because it's for batch dexopt
247         // only. Extend the proto when it's used for other purposes.
248         Utils.check(getSplitName() == null);
249 
250         return DexoptParamsProto.newBuilder()
251                 .setFlags(getFlags())
252                 .setCompilerFilter(getCompilerFilter())
253                 .setPriorityClass(getPriorityClass())
254                 .setReason(getReason())
255                 .build();
256     }
257 }
258