1 /* 2 * Copyright (C) 2017 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.pm.dex; 18 19 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason; 20 21 import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; 22 23 import android.annotation.NonNull; 24 import android.util.Log; 25 26 import com.android.server.art.ReasonMapping; 27 import com.android.server.art.model.ArtFlags; 28 import com.android.server.art.model.DexoptParams; 29 import com.android.server.pm.PackageManagerService; 30 31 /** 32 * Options used for dexopt invocations. 33 */ 34 public final class DexoptOptions { 35 private static final String TAG = "DexoptOptions"; 36 37 // When set, the profiles will be checked for updates before calling dexopt. If 38 // the apps profiles didn't update in a meaningful way (decided by the compiler), dexopt 39 // will be skipped. 40 // Currently this only affects the optimization of primary apks. Secondary dex files 41 // will always check the profiles for updates. 42 public static final int DEXOPT_CHECK_FOR_PROFILES_UPDATES = 1 << 0; 43 44 // When set, dexopt will execute unconditionally (even if not needed). 45 public static final int DEXOPT_FORCE = 1 << 1; 46 47 // Whether or not the invocation of dexopt is done after the boot is completed. This is used 48 // in order to adjust the priority of the compilation thread. 49 public static final int DEXOPT_BOOT_COMPLETE = 1 << 2; 50 51 // When set, the dexopt invocation will optimize only the secondary dex files. If false, dexopt 52 // will only consider the primary apk. 53 public static final int DEXOPT_ONLY_SECONDARY_DEX = 1 << 3; 54 55 // When set, dexopt will attempt to scale down the optimizations previously applied in order 56 // save disk space. 57 public static final int DEXOPT_DOWNGRADE = 1 << 5; 58 59 // When set, dexopt will compile the dex file as a shared library even if it is not actually 60 // used by other apps. This is used to force the compilation or shared libraries declared 61 // with in the manifest with ''uses-library' before we have a chance to detect they are 62 // actually shared at runtime. 63 public static final int DEXOPT_AS_SHARED_LIBRARY = 1 << 6; 64 65 // When set, indicates that dexopt is invoked from the background service. 66 public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9; 67 68 // When set, indicates that dexopt is invoked from the install time flow and 69 // should get the dex metdata file if present. 70 public static final int DEXOPT_INSTALL_WITH_DEX_METADATA_FILE = 1 << 10; 71 72 // When set, indicates that dexopt is being invoked from the install flow during device restore 73 // or device setup and should be scheduled appropriately. 74 public static final int DEXOPT_FOR_RESTORE = 1 << 11; // TODO(b/135202722): remove 75 76 // The name of package to optimize. 77 private final String mPackageName; 78 79 // The intended target compiler filter. Note that dexopt might adjust the filter before the 80 // execution based on factors like: vmSafeMode and packageUsedByOtherApps. 81 private final String mCompilerFilter; 82 83 // The set of flags for the dexopt options. It's a mix of the DEXOPT_* flags. 84 private final int mFlags; 85 86 // When not null, dexopt will optimize only the split identified by this APK file name (not 87 // split name). It only applies for primary apk and it's always null if mOnlySecondaryDex is 88 // true. 89 private final String mSplitName; 90 91 // The reason for invoking dexopt (see PackageManagerService.REASON_* constants). 92 // A -1 value denotes an unknown reason. 93 private final int mCompilationReason; 94 DexoptOptions(String packageName, String compilerFilter, int flags)95 public DexoptOptions(String packageName, String compilerFilter, int flags) { 96 this(packageName, /*compilationReason*/ -1, compilerFilter, /*splitName*/ null, flags); 97 } 98 DexoptOptions(String packageName, int compilationReason, int flags)99 public DexoptOptions(String packageName, int compilationReason, int flags) { 100 this(packageName, compilationReason, getCompilerFilterForReason(compilationReason), 101 /*splitName*/ null, flags); 102 } 103 DexoptOptions(String packageName, int compilationReason, String compilerFilter, String splitName, int flags)104 public DexoptOptions(String packageName, int compilationReason, String compilerFilter, 105 String splitName, int flags) { 106 int validityMask = 107 DEXOPT_CHECK_FOR_PROFILES_UPDATES | 108 DEXOPT_FORCE | 109 DEXOPT_BOOT_COMPLETE | 110 DEXOPT_ONLY_SECONDARY_DEX | 111 DEXOPT_DOWNGRADE | 112 DEXOPT_AS_SHARED_LIBRARY | 113 DEXOPT_IDLE_BACKGROUND_JOB | 114 DEXOPT_INSTALL_WITH_DEX_METADATA_FILE | 115 DEXOPT_FOR_RESTORE; 116 if ((flags & (~validityMask)) != 0) { 117 throw new IllegalArgumentException("Invalid flags : " + Integer.toHexString(flags)); 118 } 119 120 mPackageName = packageName; 121 mCompilerFilter = compilerFilter; 122 mFlags = flags; 123 mSplitName = splitName; 124 mCompilationReason = compilationReason; 125 } 126 getPackageName()127 public String getPackageName() { 128 return mPackageName; 129 } 130 isCheckForProfileUpdates()131 public boolean isCheckForProfileUpdates() { 132 return (mFlags & DEXOPT_CHECK_FOR_PROFILES_UPDATES) != 0; 133 } 134 getCompilerFilter()135 public String getCompilerFilter() { 136 return mCompilerFilter; 137 } 138 isForce()139 public boolean isForce() { 140 return (mFlags & DEXOPT_FORCE) != 0; 141 } 142 isBootComplete()143 public boolean isBootComplete() { 144 return (mFlags & DEXOPT_BOOT_COMPLETE) != 0; 145 } 146 isDexoptOnlySecondaryDex()147 public boolean isDexoptOnlySecondaryDex() { 148 return (mFlags & DEXOPT_ONLY_SECONDARY_DEX) != 0; 149 } 150 isDowngrade()151 public boolean isDowngrade() { 152 return (mFlags & DEXOPT_DOWNGRADE) != 0; 153 } 154 isDexoptAsSharedLibrary()155 public boolean isDexoptAsSharedLibrary() { 156 return (mFlags & DEXOPT_AS_SHARED_LIBRARY) != 0; 157 } 158 isDexoptIdleBackgroundJob()159 public boolean isDexoptIdleBackgroundJob() { 160 return (mFlags & DEXOPT_IDLE_BACKGROUND_JOB) != 0; 161 } 162 isDexoptInstallWithDexMetadata()163 public boolean isDexoptInstallWithDexMetadata() { 164 return (mFlags & DEXOPT_INSTALL_WITH_DEX_METADATA_FILE) != 0; 165 } 166 isDexoptInstallForRestore()167 public boolean isDexoptInstallForRestore() { 168 return (mFlags & DEXOPT_FOR_RESTORE) != 0; 169 } 170 getSplitName()171 public String getSplitName() { 172 return mSplitName; 173 } 174 getFlags()175 public int getFlags() { 176 return mFlags; 177 } 178 getCompilationReason()179 public int getCompilationReason() { 180 return mCompilationReason; 181 } 182 183 /** 184 * Creates a new set of DexoptOptions which are the same with the exception of the compiler 185 * filter (set to the given value). 186 */ overrideCompilerFilter(String newCompilerFilter)187 public DexoptOptions overrideCompilerFilter(String newCompilerFilter) { 188 return new DexoptOptions( 189 mPackageName, 190 mCompilationReason, 191 newCompilerFilter, 192 mSplitName, 193 mFlags); 194 } 195 196 /** 197 * Returns the ART Service reason for the given PackageManagerService reason. Throws unchecked 198 * exceptions for reasons that aren't supported. 199 */ convertToArtServiceDexoptReason(int pmDexoptReason)200 public static @NonNull String convertToArtServiceDexoptReason(int pmDexoptReason) { 201 switch (pmDexoptReason) { 202 case PackageManagerService.REASON_FIRST_BOOT: 203 return ReasonMapping.REASON_FIRST_BOOT; 204 case PackageManagerService.REASON_BOOT_AFTER_OTA: 205 return ReasonMapping.REASON_BOOT_AFTER_OTA; 206 case PackageManagerService.REASON_INSTALL: 207 return ReasonMapping.REASON_INSTALL; 208 case PackageManagerService.REASON_INSTALL_FAST: 209 return ReasonMapping.REASON_INSTALL_FAST; 210 case PackageManagerService.REASON_INSTALL_BULK: 211 return ReasonMapping.REASON_INSTALL_BULK; 212 case PackageManagerService.REASON_INSTALL_BULK_SECONDARY: 213 return ReasonMapping.REASON_INSTALL_BULK_SECONDARY; 214 case PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED: 215 return ReasonMapping.REASON_INSTALL_BULK_DOWNGRADED; 216 case PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED: 217 return ReasonMapping.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED; 218 case PackageManagerService.REASON_BACKGROUND_DEXOPT: 219 return ReasonMapping.REASON_BG_DEXOPT; 220 case PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE: 221 return ReasonMapping.REASON_INACTIVE; 222 case PackageManagerService.REASON_CMDLINE: 223 return ReasonMapping.REASON_CMDLINE; 224 case PackageManagerService.REASON_BOOT_AFTER_MAINLINE_UPDATE: 225 return ReasonMapping.REASON_BOOT_AFTER_MAINLINE_UPDATE; 226 case PackageManagerService.REASON_POST_BOOT: 227 case PackageManagerService.REASON_SHARED: 228 case PackageManagerService.REASON_AB_OTA: 229 // REASON_POST_BOOT isn't supported - that dexopt stage is getting removed. 230 // REASON_SHARED shouldn't go to ART Service - it's only used at lower levels 231 // in PackageDexOptimizer. 232 // TODO(b/251921228): OTA isn't supported, so REASON_AB_OTA shouldn't come this way 233 // either. 234 throw new UnsupportedOperationException( 235 "ART Service unsupported compilation reason " + pmDexoptReason); 236 default: 237 throw new IllegalArgumentException("Invalid compilation reason " + pmDexoptReason); 238 } 239 } 240 241 /** 242 * Returns an {@link DexoptParams} instance corresponding to this object, for use with 243 * {@link com.android.server.art.ArtManagerLocal}. 244 * 245 * @param extraFlags extra {@link ArtFlags#DexoptFlags} to set in the returned 246 * {@code DexoptParams} beyond those converted from this object 247 * @throws UnsupportedOperationException if the settings cannot be accurately represented. 248 */ convertToDexoptParams( int extraFlags)249 public @NonNull DexoptParams convertToDexoptParams(/*@DexoptFlags*/ int extraFlags) { 250 if (mSplitName != null) { 251 // ART Service supports dexopting a single split - see ArtFlags.FLAG_FOR_SINGLE_SPLIT. 252 // However using it here requires searching through the splits to find the one matching 253 // the APK file name in mSplitName, and we don't have the AndroidPackage available for 254 // that. 255 // 256 // Hence we throw here instead, under the assumption that no code paths that dexopt 257 // splits need this conversion (e.g. shell commands with the --split argument are 258 // handled by ART Service directly). 259 throw new UnsupportedOperationException( 260 "Request to optimize only split " + mSplitName + " for " + mPackageName); 261 } 262 263 /*@DexoptFlags*/ int flags = extraFlags; 264 if ((mFlags & DEXOPT_CHECK_FOR_PROFILES_UPDATES) == 0 265 && isProfileGuidedCompilerFilter(mCompilerFilter)) { 266 // ART Service doesn't support bypassing the profile update check when profiles are 267 // used, so not setting this flag is not supported. 268 throw new IllegalArgumentException( 269 "DEXOPT_CHECK_FOR_PROFILES_UPDATES must be set with profile guided filter"); 270 } 271 if ((mFlags & DEXOPT_FORCE) != 0) { 272 flags |= ArtFlags.FLAG_FORCE; 273 } 274 if ((mFlags & DEXOPT_ONLY_SECONDARY_DEX) != 0) { 275 flags |= ArtFlags.FLAG_FOR_SECONDARY_DEX; 276 } else { 277 flags |= ArtFlags.FLAG_FOR_PRIMARY_DEX; 278 } 279 if ((mFlags & DEXOPT_DOWNGRADE) != 0) { 280 flags |= ArtFlags.FLAG_SHOULD_DOWNGRADE; 281 } 282 if ((mFlags & DEXOPT_INSTALL_WITH_DEX_METADATA_FILE) == 0) { 283 // ART Service cannot be instructed to ignore a DM file if present. 284 Log.w(TAG, 285 "DEXOPT_INSTALL_WITH_DEX_METADATA_FILE not set in request to optimise " 286 + mPackageName 287 + " - ART Service will unconditionally use a DM file if present."); 288 } 289 290 /*@PriorityClassApi*/ int priority; 291 // Replicates logic in RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags in installd. 292 if ((mFlags & DEXOPT_BOOT_COMPLETE) != 0) { 293 if ((mFlags & DEXOPT_FOR_RESTORE) != 0) { 294 priority = ArtFlags.PRIORITY_INTERACTIVE_FAST; 295 } else if ((mFlags & DEXOPT_IDLE_BACKGROUND_JOB) != 0) { 296 priority = ArtFlags.PRIORITY_BACKGROUND; 297 } else { 298 priority = ArtFlags.PRIORITY_INTERACTIVE; 299 } 300 } else { 301 priority = ArtFlags.PRIORITY_BOOT; 302 } 303 304 // The following flags in mFlags are ignored: 305 // 306 // - DEXOPT_AS_SHARED_LIBRARY: It's implicit with ART Service since it always looks at 307 // <uses-library> rather than actual dependencies. 308 // 309 // We don't require it to be set either. It's safe when switching between old and new 310 // code paths since the only effect is that some packages may be unnecessarily compiled 311 // without user profiles. 312 313 return new DexoptParams.Builder(convertToArtServiceDexoptReason(mCompilationReason), flags) 314 .setCompilerFilter(mCompilerFilter) 315 .setPriorityClass(priority) 316 .build(); 317 } 318 } 319