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 66 // Reasons for Play Install Hints (go/install-hints). 67 public static final String REASON_INSTALL_FAST = "install-fast"; 68 public static final String REASON_INSTALL_BULK = "install-bulk"; 69 public static final String REASON_INSTALL_BULK_SECONDARY = "install-bulk-secondary"; 70 public static final String REASON_INSTALL_BULK_DOWNGRADED = "install-bulk-downgraded"; 71 public static final String REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 72 "install-bulk-secondary-downgraded"; 73 74 /** @hide */ 75 public static final Set<String> REASONS_FOR_INSTALL = Set.of(REASON_INSTALL, 76 REASON_INSTALL_FAST, REASON_INSTALL_BULK, REASON_INSTALL_BULK_SECONDARY, 77 REASON_INSTALL_BULK_DOWNGRADED, REASON_INSTALL_BULK_SECONDARY_DOWNGRADED); 78 79 // Keep this in sync with `ArtShellCommand.printHelp`. 80 /** @hide */ 81 public static final Set<String> BATCH_DEXOPT_REASONS = Set.of(REASON_FIRST_BOOT, 82 REASON_BOOT_AFTER_OTA, REASON_BOOT_AFTER_MAINLINE_UPDATE, REASON_BG_DEXOPT); 83 84 /** 85 * Reasons for {@link ArtManagerLocal#dexoptPackages}. 86 * 87 * @hide 88 */ 89 // clang-format off 90 @StringDef(prefix = "REASON_", value = { 91 REASON_FIRST_BOOT, 92 REASON_BOOT_AFTER_OTA, 93 REASON_BOOT_AFTER_MAINLINE_UPDATE, 94 REASON_BG_DEXOPT, 95 }) 96 // clang-format on 97 @Retention(RetentionPolicy.SOURCE) 98 public @interface BatchDexoptReason {} 99 100 /** 101 * Reasons for {@link ArtManagerLocal#onBoot(String, Executor, Consumer<OperationProgress>)}. 102 * 103 * @hide 104 */ 105 // clang-format off 106 @StringDef(prefix = "REASON_", value = { 107 REASON_FIRST_BOOT, 108 REASON_BOOT_AFTER_OTA, 109 REASON_BOOT_AFTER_MAINLINE_UPDATE, 110 }) 111 // clang-format on 112 @Retention(RetentionPolicy.SOURCE) 113 public @interface BootReason {} 114 115 /** 116 * Loads the compiler filter from the system property for the given reason and checks for 117 * validity. 118 * 119 * @throws IllegalArgumentException if the reason is invalid 120 * @throws IllegalStateException if the system property value is invalid 121 * 122 * @hide 123 */ 124 @NonNull getCompilerFilterForReason(@onNull String reason)125 public static String getCompilerFilterForReason(@NonNull String reason) { 126 String value = SystemProperties.get("pm.dexopt." + reason); 127 if (TextUtils.isEmpty(value)) { 128 throw new IllegalArgumentException("No compiler filter for reason '" + reason + "'"); 129 } 130 if (!Utils.isValidArtServiceCompilerFilter(value)) { 131 throw new IllegalStateException( 132 "Got invalid compiler filter '" + value + "' for reason '" + reason + "'"); 133 } 134 return value; 135 } 136 137 /** 138 * Loads the compiler filter from the system property for: 139 * - shared libraries 140 * - apps used by other apps without a dex metadata file 141 * 142 * @throws IllegalStateException if the system property value is invalid 143 * 144 * @hide 145 */ 146 @NonNull getCompilerFilterForShared()147 public static String getCompilerFilterForShared() { 148 // "shared" is technically not a compilation reason, but the compiler filter is defined as a 149 // system property as if "shared" is a reason. 150 String value = getCompilerFilterForReason("shared"); 151 if (DexFile.isProfileGuidedCompilerFilter(value)) { 152 throw new IllegalStateException( 153 "Compiler filter for 'shared' must not be profile guided, got '" + value + "'"); 154 } 155 return value; 156 } 157 158 /** 159 * Returns the priority for the given reason. 160 * 161 * @throws IllegalArgumentException if the reason is invalid 162 * @see PriorityClassApi 163 * 164 * @hide 165 */ getPriorityClassForReason(@onNull String reason)166 public static @PriorityClassApi byte getPriorityClassForReason(@NonNull String reason) { 167 switch (reason) { 168 case REASON_FIRST_BOOT: 169 case REASON_BOOT_AFTER_OTA: 170 case REASON_BOOT_AFTER_MAINLINE_UPDATE: 171 return ArtFlags.PRIORITY_BOOT; 172 case REASON_INSTALL_FAST: 173 return ArtFlags.PRIORITY_INTERACTIVE_FAST; 174 case REASON_INSTALL: 175 case REASON_CMDLINE: 176 return ArtFlags.PRIORITY_INTERACTIVE; 177 case REASON_BG_DEXOPT: 178 case REASON_INACTIVE: 179 case REASON_INSTALL_BULK: 180 case REASON_INSTALL_BULK_SECONDARY: 181 case REASON_INSTALL_BULK_DOWNGRADED: 182 case REASON_INSTALL_BULK_SECONDARY_DOWNGRADED: 183 return ArtFlags.PRIORITY_BACKGROUND; 184 default: 185 throw new IllegalArgumentException("No priority class for reason '" + reason + "'"); 186 } 187 } 188 189 /** 190 * Loads the concurrency from the system property, for batch dexopt ({@link 191 * ArtManagerLocal#dexoptPackages}), or 1 if the system property is not found or cannot be 192 * parsed. 193 * 194 * @hide 195 */ getConcurrencyForReason(@onNull @atchDexoptReason String reason)196 public static int getConcurrencyForReason(@NonNull @BatchDexoptReason String reason) { 197 return SystemProperties.getInt("pm.dexopt." + reason + ".concurrency", 1 /* def */); 198 } 199 } 200