Android 如何判断是首次开机?如何判断OTA升级后的首次开机?
Android 如何判断是首次开机?如何判断OTA升级后的首次开机?
参考:
导包:
import android.content.pm.IPackageManager;
import android.app.AppGlobals;
import android.os.RemoteException;
boolean isFirstBootOrUpgrade() { IPackageManager pm = AppGlobals.getPackageManager(); try { return pm.isFirstBoot() || pm.isDeviceUpgrading(); } catch (RemoteException e) { // throw e.rethrowFromSystemServer(); } }
然后就可以在系统应用里面进行调用了,比如Settings模块就可以获取到是否第一次开机
说明:
isFirstBoot() :首次开机
isDeviceUpgrading()) :ota升级后的首次开机
Android 13 T 源码 (http://aospxref.com/)
标记:SCAN_FIRST_BOOT_OR_UPGRADE ,用于标记首次开机或OTA升级后的首次开机

1.
http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
static final int SCAN_NO_DEX = 1 << 0;
static final int SCAN_UPDATE_SIGNATURE = 1 << 1;
static final int SCAN_NEW_INSTALL = 1 << 2;
static final int SCAN_UPDATE_TIME = 1 << 3;
static final int SCAN_BOOTING = 1 << 4;
static final int SCAN_REQUIRE_KNOWN = 1 << 7;
static final int SCAN_MOVE = 1 << 8;
static final int SCAN_INITIAL = 1 << 9;
static final int SCAN_DONT_KILL_APP = 1 << 10;
static final int SCAN_IGNORE_FROZEN = 1 << 11;
static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 12;
static final int SCAN_AS_INSTANT_APP = 1 << 13;
static final int SCAN_AS_FULL_APP = 1 << 14;
static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 15;
static final int SCAN_AS_SYSTEM = 1 << 16;
static final int SCAN_AS_PRIVILEGED = 1 << 17;
static final int SCAN_AS_OEM = 1 << 18;
static final int SCAN_AS_VENDOR = 1 << 19;
static final int SCAN_AS_PRODUCT = 1 << 20;
static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
static final int SCAN_AS_ODM = 1 << 22;
static final int SCAN_AS_APK_IN_APEX = 1 << 23;
static final int SCAN_DROP_CACHE = 1 << 24;
OTA升级的判断变量:
private final boolean mIsUpgrade;
private final boolean mIsPreNUpgrade;
private final boolean mIsPreNMR1Upgrade;
private final boolean mIsPreQUpgrade;
......
final VersionInfo ver = mSettings.getInternalVersion();
mIsUpgrade =
!buildFingerprint.equals(ver.fingerprint);
if (mIsUpgrade) {
PackageManagerServiceUtils.logCriticalInfo(Log.INFO, "Upgrading from "
+ ver.fingerprint + " to " + PackagePartitions.FINGERPRINT);
}
// when upgrading from pre-M, promote system app permissions from install to runtime
mPromoteSystemApps =
mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
// When upgrading from pre-N, we need to handle package extraction like first boot,
// as there is no profiling data available.
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;
......
// If the build fingerprint has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
// cases get permissions that the user didn't initially explicitly
// allow... it would be nice to have some better way to handle
// this situation.
if (mIsUpgrade) {
Slog.i(TAG, "Build fingerprint changed from " + ver.fingerprint + " to "
+ PackagePartitions.FINGERPRINT
+ "; regranting permissions for internal storage");
}
OTA升级后首次开机打印的log:
Slog.i(TAG, "Build fingerprint changed from " + ver.fingerprint + " to "+ PackagePartitions.FINGERPRINT+ "; regranting permissions for internal storage");
2.
http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/InitAppsHelper.java
// Set flag to monitor and not change apk file paths when scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; // 扫描apk之前,根据是否首次开机,添加 SCAN_FIRST_BOOT_OR_UPGRADE 标记
} else {
mScanFlags = scanFlags;
}
// TODO(b/198166813): remove PMS dependency
InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
InstallPackageHelper installPackageHelper,
List<ScanPartition> systemPartitions) {
mPm = pm;
mApexManager = apexManager;
mInstallPackageHelper = installPackageHelper;
mSystemPartitions = systemPartitions;
mDirsToScanAsSystem = getSystemScanPartitions();
mIsDeviceUpgrading = mPm.isDeviceUpgrading();
mIsOnlyCoreApps = mPm.isOnlyCoreApps();
// Set flag to monitor and not change apk file paths when scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
} else {
mScanFlags = scanFlags;
}
mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
mExecutorService = ParallelPackageParser.makeExecutorService();
}
InitAppsHelper这个工具类 被PKMS服务初始化调用

3.
http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/ScanPackageUtils.java
boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
public static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
PackageManagerServiceInjector injector,
boolean isUnderFactoryTest, long currentTime)
throws PackageManagerException {
final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
ParsedPackage parsedPackage = request.mParsedPackage;
PackageSetting pkgSetting = request.mPkgSetting;
final PackageSetting disabledPkgSetting = request.mDisabledPkgSetting;
final PackageSetting originalPkgSetting = request.mOriginalPkgSetting;
final @ParsingPackageUtils.ParseFlags int parseFlags = request.mParseFlags;
final @PackageManagerService.ScanFlags int scanFlags = request.mScanFlags;
final String realPkgName = request.mRealPkgName;
final SharedUserSetting oldSharedUserSetting = request.mOldSharedUserSetting;
final SharedUserSetting sharedUserSetting = request.mSharedUserSetting;
final UserHandle user = request.mUser;
final boolean isPlatformPackage = request.mIsPlatformPackage;
List<String> changedAbiCodePath = null;
if (DEBUG_PACKAGE_SCANNING) {
if ((parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0) {
Log.d(TAG, "Scanning package " + parsedPackage.getPackageName());
}
}
// Initialize package source and resource directories
final File destCodeFile = new File(parsedPackage.getPath());
// We keep references to the derived CPU Abis from settings in oder to reuse
// them in the case where we're not upgrading or booting for the first time.
String primaryCpuAbiFromSettings = null;
String secondaryCpuAbiFromSettings = null;
boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
if (!needToDeriveAbi) {
if (pkgSetting != null) {
// TODO(b/154610922): if it is not first boot or upgrade, we should directly use
// API info from existing package setting. However, stub packages currently do not
// preserve ABI info, thus the special condition check here. Remove the special
// check after we fix the stub generation.
if (pkgSetting.getPkg() != null && pkgSetting.getPkg().isStub()) {
needToDeriveAbi = true;
} else {
primaryCpuAbiFromSettings = pkgSetting.getPrimaryCpuAbi();
secondaryCpuAbiFromSettings = pkgSetting.getSecondaryCpuAbi();
}
} else {
// Re-scanning a system package after uninstalling updates; need to derive ABI
needToDeriveAbi = true;
}
}
......
}
ScanPackageUtils 这个工具类被 InstallPackageHelper.java 调用

4.
http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
处理apk的so库路径
private static NativeLibraryPaths deriveNativeLibraryPaths(final Abis abis,
final File appLib32InstallDir, final String codePath, final String sourceDir,
final boolean isSystemApp, final boolean isUpdatedSystemApp) {
final File codeFile = new File(codePath);
final boolean bundledApp = isSystemApp && !isUpdatedSystemApp;
final String nativeLibraryRootDir;
final boolean nativeLibraryRootRequiresIsa;
final String nativeLibraryDir;
final String secondaryNativeLibraryDir;
if (isApkFile(codeFile)) {
// Monolithic install
if (bundledApp) {
// If "/system/lib64/apkname" exists, assume that is the per-package
// native library directory to use; otherwise use "/system/lib/apkname".
final String apkRoot = calculateBundledApkRoot(sourceDir);
final boolean is64Bit = VMRuntime.is64BitInstructionSet(
getPrimaryInstructionSet(abis));
// This is a bundled system app so choose the path based on the ABI.
// if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
// is just the default path.
final String apkName = deriveCodePathName(codePath);
final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
apkName).getAbsolutePath();
if (abis.secondary != null) {
final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
secondaryLibDir, apkName).getAbsolutePath();
} else {
secondaryNativeLibraryDir = null;
}
} else {
final String apkName = deriveCodePathName(codePath);
nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
.getAbsolutePath();
secondaryNativeLibraryDir = null;
}
nativeLibraryRootRequiresIsa = false;
nativeLibraryDir = nativeLibraryRootDir;
} else {
// Cluster install
nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
nativeLibraryRootRequiresIsa = true;
nativeLibraryDir = new File(nativeLibraryRootDir,
getPrimaryInstructionSet(abis)).getAbsolutePath();
if (abis.secondary != null) {
secondaryNativeLibraryDir = new File(nativeLibraryRootDir,
VMRuntime.getInstructionSet(abis.secondary)).getAbsolutePath();
} else {
secondaryNativeLibraryDir = null;
}
}
return new NativeLibraryPaths(nativeLibraryRootDir, nativeLibraryRootRequiresIsa,
nativeLibraryDir, secondaryNativeLibraryDir);
}

浙公网安备 33010602011771号