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; 18 19 import static com.android.server.art.model.ArtFlags.PriorityClassApi; 20 21 import android.annotation.FlaggedApi; 22 import android.annotation.NonNull; 23 import android.annotation.StringDef; 24 import android.annotation.SystemApi; 25 import android.os.Build; 26 import android.os.SystemProperties; 27 import android.text.TextUtils; 28 29 import androidx.annotation.RequiresApi; 30 31 import com.android.art.flags.Flags; 32 import com.android.server.art.model.ArtFlags; 33 import com.android.server.pm.PackageManagerLocal; 34 35 import dalvik.system.DexFile; 36 37 import java.lang.annotation.Retention; 38 import java.lang.annotation.RetentionPolicy; 39 import java.util.Set; 40 41 /** 42 * Maps a compilation reason to a compiler filter and a priority class. 43 * 44 * @hide 45 */ 46 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) 47 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 48 public class ReasonMapping { ReasonMapping()49 private ReasonMapping() {} 50 51 // Keep this in sync with `ArtShellCommand.printHelp` except for 'inactive'. 52 53 /** Dexopting apps on the first boot after flashing or factory resetting the device. */ 54 public static final String REASON_FIRST_BOOT = "first-boot"; 55 /** Dexopting apps on the next boot after an OTA. */ 56 public static final String REASON_BOOT_AFTER_OTA = "boot-after-ota"; 57 /** Dexopting apps on the next boot after a mainline update. */ 58 public static final String REASON_BOOT_AFTER_MAINLINE_UPDATE = "boot-after-mainline-update"; 59 /** Installing an app after user presses the "install"/"update" button. */ 60 public static final String REASON_INSTALL = "install"; 61 /** Dexopting apps in the background. */ 62 public static final String REASON_BG_DEXOPT = "bg-dexopt"; 63 /** Invoked by cmdline. */ 64 public static final String REASON_CMDLINE = "cmdline"; 65 /** Downgrading the compiler filter when an app is not used for a long time. */ 66 public static final String REASON_INACTIVE = "inactive"; 67 /** 68 * Dexopting apps before the reboot for an OTA or a mainline update, known as Pre-reboot 69 * Dexopt. 70 */ 71 @FlaggedApi(Flags.FLAG_ART_SERVICE_V3) 72 public static final String REASON_PRE_REBOOT_DEXOPT = "ab-ota"; 73 74 // Reasons for Play Install Hints (go/install-hints). 75 public static final String REASON_INSTALL_FAST = "install-fast"; 76 public static final String REASON_INSTALL_BULK = "install-bulk"; 77 public static final String REASON_INSTALL_BULK_SECONDARY = "install-bulk-secondary"; 78 public static final String REASON_INSTALL_BULK_DOWNGRADED = "install-bulk-downgraded"; 79 public static final String REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 80 "install-bulk-secondary-downgraded"; 81 82 /** @hide */ 83 public static final Set<String> REASONS_FOR_INSTALL = Set.of(REASON_INSTALL, 84 REASON_INSTALL_FAST, REASON_INSTALL_BULK, REASON_INSTALL_BULK_SECONDARY, 85 REASON_INSTALL_BULK_DOWNGRADED, REASON_INSTALL_BULK_SECONDARY_DOWNGRADED); 86 87 // Keep this in sync with `ArtShellCommand.printHelp`. 88 /** @hide */ 89 public static final Set<String> BATCH_DEXOPT_REASONS = 90 Set.of(REASON_FIRST_BOOT, REASON_BOOT_AFTER_OTA, REASON_BOOT_AFTER_MAINLINE_UPDATE, 91 REASON_BG_DEXOPT, REASON_PRE_REBOOT_DEXOPT); 92 93 /** @hide */ 94 public static final Set<String> BOOT_REASONS = 95 Set.of(REASON_FIRST_BOOT, REASON_BOOT_AFTER_OTA, REASON_BOOT_AFTER_MAINLINE_UPDATE); 96 97 /** 98 * Reasons for {@link ArtManagerLocal#dexoptPackages}. 99 * 100 * @hide 101 */ 102 // clang-format off 103 @StringDef(prefix = "REASON_", value = { 104 REASON_FIRST_BOOT, 105 REASON_BOOT_AFTER_OTA, 106 REASON_BOOT_AFTER_MAINLINE_UPDATE, 107 REASON_BG_DEXOPT, 108 REASON_PRE_REBOOT_DEXOPT, 109 }) 110 // clang-format on 111 @Retention(RetentionPolicy.SOURCE) 112 public @interface BatchDexoptReason {} 113 114 /** 115 * Reasons for {@link ArtManagerLocal#onBoot(String, Executor, Consumer<OperationProgress>)}. 116 * 117 * @hide 118 */ 119 // clang-format off 120 @StringDef(prefix = "REASON_", value = { 121 REASON_FIRST_BOOT, 122 REASON_BOOT_AFTER_OTA, 123 REASON_BOOT_AFTER_MAINLINE_UPDATE, 124 }) 125 // clang-format on 126 @Retention(RetentionPolicy.SOURCE) 127 public @interface BootReason {} 128 129 /** 130 * Loads the compiler filter from the system property for the given reason and checks for 131 * validity. 132 * 133 * @throws IllegalArgumentException if the reason is invalid 134 * @throws IllegalStateException if the system property value is invalid 135 * 136 * @hide 137 */ 138 @NonNull getCompilerFilterForReason(@onNull String reason)139 public static String getCompilerFilterForReason(@NonNull String reason) { 140 String value = SystemProperties.get("pm.dexopt." + reason); 141 if (TextUtils.isEmpty(value)) { 142 throw new IllegalArgumentException("No compiler filter for reason '" + reason + "'"); 143 } 144 if (!Utils.isValidArtServiceCompilerFilter(value)) { 145 throw new IllegalStateException( 146 "Got invalid compiler filter '" + value + "' for reason '" + reason + "'"); 147 } 148 return value; 149 } 150 151 /** 152 * Loads the compiler filter from the system property for: 153 * - shared libraries 154 * - apps used by other apps without a dex metadata file 155 * 156 * @throws IllegalStateException if the system property value is invalid 157 * 158 * @hide 159 */ 160 @NonNull getCompilerFilterForShared()161 public static String getCompilerFilterForShared() { 162 // "shared" is technically not a compilation reason, but the compiler filter is defined as a 163 // system property as if "shared" is a reason. 164 String value = getCompilerFilterForReason("shared"); 165 if (DexFile.isProfileGuidedCompilerFilter(value)) { 166 throw new IllegalStateException( 167 "Compiler filter for 'shared' must not be profile guided, got '" + value + "'"); 168 } 169 return value; 170 } 171 172 /** 173 * Returns the priority for the given reason. 174 * 175 * @throws IllegalArgumentException if the reason is invalid 176 * @see PriorityClassApi 177 * 178 * @hide 179 */ getPriorityClassForReason(@onNull String reason)180 public static @PriorityClassApi byte getPriorityClassForReason(@NonNull String reason) { 181 switch (reason) { 182 case REASON_FIRST_BOOT: 183 case REASON_BOOT_AFTER_OTA: 184 case REASON_BOOT_AFTER_MAINLINE_UPDATE: 185 return ArtFlags.PRIORITY_BOOT; 186 case REASON_INSTALL_FAST: 187 return ArtFlags.PRIORITY_INTERACTIVE_FAST; 188 case REASON_INSTALL: 189 case REASON_CMDLINE: 190 return ArtFlags.PRIORITY_INTERACTIVE; 191 case REASON_BG_DEXOPT: 192 case REASON_PRE_REBOOT_DEXOPT: 193 case REASON_INACTIVE: 194 case REASON_INSTALL_BULK: 195 case REASON_INSTALL_BULK_SECONDARY: 196 case REASON_INSTALL_BULK_DOWNGRADED: 197 case REASON_INSTALL_BULK_SECONDARY_DOWNGRADED: 198 return ArtFlags.PRIORITY_BACKGROUND; 199 default: 200 throw new IllegalArgumentException("No priority class for reason '" + reason + "'"); 201 } 202 } 203 204 /** 205 * Loads the concurrency from the system property, for batch dexopt ({@link 206 * ArtManagerLocal#dexoptPackages}). The default is tuned to strike a good balance between 207 * device load and dexopt coverage, depending on the situation. 208 * 209 * @hide 210 */ getConcurrencyForReason(@onNull @atchDexoptReason String reason)211 public static int getConcurrencyForReason(@NonNull @BatchDexoptReason String reason) { 212 // TODO(jiakaiz): Revisit the concurrency for non-boot reasons. 213 return SystemProperties.getInt("pm.dexopt." + reason + ".concurrency", 214 BOOT_REASONS.contains(reason) ? 4 : 1 /* def */); 215 } 216 } 217