blob: ffc3fad7d27e24c97f2819701bc9e630d222cc0c [file]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.art;
import static com.android.server.art.model.ArtFlags.PriorityClassApi;
import android.annotation.NonNull;
import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.os.Build;
import android.os.SystemProperties;
import android.text.TextUtils;
import androidx.annotation.RequiresApi;
import com.android.server.art.model.ArtFlags;
import com.android.server.pm.PackageManagerLocal;
import dalvik.system.DexFile;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Set;
/**
* Maps a compilation reason to a compiler filter and a priority class.
*
* @hide
*/
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public class ReasonMapping {
private ReasonMapping() {}
// Keep this in sync with `ArtShellCommand.printHelp` except for 'inactive'.
/** Dexopting apps on the first boot after flashing or factory resetting the device. */
public static final String REASON_FIRST_BOOT = "first-boot";
/** Dexopting apps on the next boot after an OTA. */
public static final String REASON_BOOT_AFTER_OTA = "boot-after-ota";
/** Dexopting apps on the next boot after a mainline update. */
public static final String REASON_BOOT_AFTER_MAINLINE_UPDATE = "boot-after-mainline-update";
/** Installing an app after user presses the "install"/"update" button. */
public static final String REASON_INSTALL = "install";
/** Dexopting apps in the background. */
public static final String REASON_BG_DEXOPT = "bg-dexopt";
/** Invoked by cmdline. */
public static final String REASON_CMDLINE = "cmdline";
/** Downgrading the compiler filter when an app is not used for a long time. */
public static final String REASON_INACTIVE = "inactive";
/**
* Dexopting apps before the reboot for an OTA or a mainline update, known as Pre-reboot
* Dexopt.
*/
public static final String REASON_PRE_REBOOT_DEXOPT = "ab-ota";
// Reasons for Play Install Hints (go/install-hints).
public static final String REASON_INSTALL_FAST = "install-fast";
public static final String REASON_INSTALL_BULK = "install-bulk";
public static final String REASON_INSTALL_BULK_SECONDARY = "install-bulk-secondary";
public static final String REASON_INSTALL_BULK_DOWNGRADED = "install-bulk-downgraded";
public static final String REASON_INSTALL_BULK_SECONDARY_DOWNGRADED =
"install-bulk-secondary-downgraded";
/** @hide */
public static final Set<String> REASONS_FOR_INSTALL = Set.of(REASON_INSTALL,
REASON_INSTALL_FAST, REASON_INSTALL_BULK, REASON_INSTALL_BULK_SECONDARY,
REASON_INSTALL_BULK_DOWNGRADED, REASON_INSTALL_BULK_SECONDARY_DOWNGRADED);
// Keep this in sync with `ArtShellCommand.printHelp`.
/** @hide */
public static final Set<String> BATCH_DEXOPT_REASONS =
Set.of(REASON_FIRST_BOOT, REASON_BOOT_AFTER_OTA, REASON_BOOT_AFTER_MAINLINE_UPDATE,
REASON_BG_DEXOPT, REASON_PRE_REBOOT_DEXOPT);
/** @hide */
public static final Set<String> BOOT_REASONS =
Set.of(REASON_FIRST_BOOT, REASON_BOOT_AFTER_OTA, REASON_BOOT_AFTER_MAINLINE_UPDATE);
/**
* Reasons for {@link ArtManagerLocal#dexoptPackages}.
*
* @hide
*/
// clang-format off
@StringDef(prefix = "REASON_", value = {
REASON_FIRST_BOOT,
REASON_BOOT_AFTER_OTA,
REASON_BOOT_AFTER_MAINLINE_UPDATE,
REASON_BG_DEXOPT,
REASON_PRE_REBOOT_DEXOPT,
})
// clang-format on
@Retention(RetentionPolicy.SOURCE)
public @interface BatchDexoptReason {}
/**
* Reasons for {@link ArtManagerLocal#onBoot(String, Executor, Consumer<OperationProgress>)}.
*
* @hide
*/
// clang-format off
@StringDef(prefix = "REASON_", value = {
REASON_FIRST_BOOT,
REASON_BOOT_AFTER_OTA,
REASON_BOOT_AFTER_MAINLINE_UPDATE,
})
// clang-format on
@Retention(RetentionPolicy.SOURCE)
public @interface BootReason {}
/**
* Loads the compiler filter from the system property for the given reason and checks for
* validity.
*
* @throws IllegalArgumentException if the reason is invalid
* @throws IllegalStateException if the system property value is invalid
*
* @hide
*/
@NonNull
public static String getCompilerFilterForReason(@NonNull String reason) {
String value = SystemProperties.get("pm.dexopt." + reason);
if (TextUtils.isEmpty(value)) {
throw new IllegalArgumentException("No compiler filter for reason '" + reason + "'");
}
if (!Utils.isValidArtServiceCompilerFilter(value)) {
throw new IllegalStateException(
"Got invalid compiler filter '" + value + "' for reason '" + reason + "'");
}
return value;
}
/**
* Loads the compiler filter from the system property for:
* - shared libraries
* - apps used by other apps without a dex metadata file
*
* @throws IllegalStateException if the system property value is invalid
*
* @hide
*/
@NonNull
public static String getCompilerFilterForShared() {
// "shared" is technically not a compilation reason, but the compiler filter is defined as a
// system property as if "shared" is a reason.
String value = getCompilerFilterForReason("shared");
if (DexFile.isProfileGuidedCompilerFilter(value)) {
throw new IllegalStateException(
"Compiler filter for 'shared' must not be profile guided, got '" + value + "'");
}
return value;
}
/**
* Returns the priority for the given reason.
*
* @throws IllegalArgumentException if the reason is invalid
* @see PriorityClassApi
*
* @hide
*/
public static @PriorityClassApi byte getPriorityClassForReason(@NonNull String reason) {
switch (reason) {
case REASON_FIRST_BOOT:
case REASON_BOOT_AFTER_OTA:
case REASON_BOOT_AFTER_MAINLINE_UPDATE:
return ArtFlags.PRIORITY_BOOT;
case REASON_INSTALL_FAST:
return ArtFlags.PRIORITY_INTERACTIVE_FAST;
case REASON_INSTALL:
case REASON_CMDLINE:
return ArtFlags.PRIORITY_INTERACTIVE;
case REASON_BG_DEXOPT:
case REASON_PRE_REBOOT_DEXOPT:
case REASON_INACTIVE:
case REASON_INSTALL_BULK:
case REASON_INSTALL_BULK_SECONDARY:
case REASON_INSTALL_BULK_DOWNGRADED:
case REASON_INSTALL_BULK_SECONDARY_DOWNGRADED:
return ArtFlags.PRIORITY_BACKGROUND;
default:
throw new IllegalArgumentException("No priority class for reason '" + reason + "'");
}
}
/**
* Loads the concurrency from the system property, for batch dexopt ({@link
* ArtManagerLocal#dexoptPackages}). The default is tuned to strike a good balance between
* device load and dexopt coverage, depending on the situation.
*
* @hide
*/
public static int getConcurrencyForReason(@NonNull @BatchDexoptReason String reason) {
// TODO(jiakaiz): Revisit the concurrency for non-boot reasons.
return SystemProperties.getInt("pm.dexopt." + reason + ".concurrency",
BOOT_REASONS.contains(reason) ? 4 : 1 /* def */);
}
/**
* Maps the compiler filter string to an integer representation for reporting stats defined in
* the "framework" module (specifically, the {@code package_optimization_compilation_filter}
* field of the {@code AppStartOccurred} and {@code AppStartFullyDrawn} protos defined in {@code
* frameworks/proto_logging/stats/atoms.proto}). The integer is not supposed to be understood by
* the caller but to be filled as is into the fields mentioned above.
*
* Note that this mapping is different from the one used in the "art" module and must not be
* used for reporting ART stats (e.g., ART runtime metrics).
*/
@FlaggedApi(Flags.FLAG_UPDATABLE_FILTER_AND_REASON)
public static int getCompilerFilterValueForFrameworkStatsReporting(
@NonNull String compilerFilter) {
return switch (compilerFilter) {
// Reserved 3, 5, 14-27.
case "error" -> 0;
case "unknown" -> 1;
case "assume-verified" -> 2;
case "verify" -> 4;
case "space-profile" -> 6;
case "space" -> 7;
case "speed-profile" -> 8;
case "speed" -> 9;
case "everything-profile" -> 10;
case "everything" -> 11;
case "run-from-apk" -> 12;
case "run-from-apk-fallback" -> 13;
default -> 1;
};
}
/**
* Maps the compilation reason string to an integer representation for reporting stats defined
* in the "framework" module (specifically, the {@code package_optimization_compilation_reason}
* field of the {@code AppStartOccurred} and {@code AppStartFullyDrawn} protos defined in {@code
* frameworks/proto_logging/stats/atoms.proto}). The integer is not supposed to be understood by
* the caller but to be filled as is into the fields mentioned above.
*
* Note that this mapping is different from the one used in the "art" module and must not be
* used for reporting ART stats (e.g., ART runtime metrics).
*/
@FlaggedApi(Flags.FLAG_UPDATABLE_FILTER_AND_REASON)
public static int getCompilationReasonValueForFrameworkStatsReporting(
@NonNull String compilationReason) {
return switch (compilationReason) {
// Reserved 3, 8, 21.
case "error" -> 0;
case "unknown" -> 1;
case "first-boot" -> 2;
case "install" -> 4;
case "bg-dexopt" -> 5;
case "ab-ota" -> 6;
case "inactive" -> 7;
case "install-dm" -> 9;
case "install-fast" -> 10;
case "install-bulk" -> 11;
case "install-bulk-secondary" -> 12;
case "install-bulk-downgraded" -> 13;
case "install-bulk-secondary-downgraded" -> 14;
case "install-fast-dm" -> 15;
case "install-bulk-dm" -> 16;
case "install-bulk-secondary-dm" -> 17;
case "install-bulk-downgraded-dm" -> 18;
case "install-bulk-secondary-downgraded-dm" -> 19;
case "boot-after-ota" -> 20;
case "cmdline" -> 22;
case "prebuilt" -> 23;
case "vdex" -> 24;
case "boot-after-mainline-update" -> 25;
case "cloud" -> 26;
default -> 1;
};
}
}