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