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