Android15 am命令 APP安装流程

一. PM 安装命令

使用命令

pm install -r xxx.apk

pm命令安装app 会触发PackageManagerShellCommand 中runInstall()方法

复制代码
frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java

1. onCommand 函数:

public int onCommand (String cmd) {

if (cmd == null) {

return handleDefaultCommands(cmd);

}

final PrintWriter pw = getOutPrintWriter();

try {

switch (cmd) {

case "install":

return runInstall();

}

  1. runInstall 函数:

private int runInstall() throws RemoteException {

//UNSUPPORTED_INSTALL_CMD_OPTS 就是参数:Set.of( "--multi-package");

//相当于isMultiPackage 为true

return doRunInstall (makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS));

}

  1. makeInstallParams 函数:

解析参数:

private InstallParams makeInstallParams(Set<String> unsupportedOptions) {

// MODE_FULL_INSTALL:安装会话的模式,其暂存的 APK 应该完全替换目标应用的任何现有 APK。

final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);

final InstallParams params = new InstallParams();

params.sessionParams = sessionParams;

// Allowlist all permissions by default

sessionParams.installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;

// Set package source to other by default. Can be overridden by "--package-source"

// 默认将包源设置为其他。可以通过"--package-source"覆盖

sessionParams.setPackageSource(PackageInstaller.PACKAGE_SOURCE_OTHER);

// Encodes one of the states:

// 1. Install request explicitly specified --staged, then value will be true.

// 2. Install request explicitly specified --non-staged, then value will be false.

// 3. Install request did not specify either --staged or --non-staged, then for APEX

// installs the value will be true, and for apk installs it will be false.

// 对以下状态之一进行编码:

// 1. 安装请求明确指定 --staged,则值为 true。

// 2. 安装请求明确指定 --non-staged,则值为 false。

// 3. 安装请求未指定 --staged 或 --non-staged,则对于 APEX

// 安装,则值为 true,对于 apk 安装,则值为 false。

Boolean staged = null;

String opt;

boolean replaceExisting = true;

boolean forceNonStaged = false;

while ((opt = getNextOption()) != null) {

if (unsupportedOptions.contains(opt)) {

throw new IllegalArgumentException("Unsupported option " + opt);

}

switch (opt) {

case "-r ": // ignore

break;

case "-R ":

replaceExisting = false;

break;

case "-i":

params.installerPackageName = getNextArg();

if (params.installerPackageName == null) {

throw new IllegalArgumentException("Missing installer package");

}

break;

case "-t ":

sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;

break;

case "-f ":

sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;

break;

case "-d ":

sessionParams.installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE;

break;

case "-g ":

sessionParams.installFlags |=

PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS;

break;

case "--restrict-permissions":

sessionParams.installFlags &=

~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;

break;

case "--dont-kill":

sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;

break;

case "--originating-uri":

sessionParams.originatingUri = Uri.parse(getNextArg());

break;

case "--referrer":

sessionParams.referrerUri = Uri.parse(getNextArg());

break;

case "-p":

sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING;

sessionParams.appPackageName = getNextArg();

if (sessionParams.appPackageName == null) {

throw new IllegalArgumentException("Missing inherit package name");

}

break;

case "--pkg":

sessionParams.appPackageName = getNextArg();

if (sessionParams.appPackageName == null) {

throw new IllegalArgumentException("Missing package name");

}

break;

case "-S":

final long sizeBytes = Long.parseLong(getNextArg());

if (sizeBytes <= 0) {

throw new IllegalArgumentException("Size must be positive");

}

sessionParams.setSize(sizeBytes);

break;

case "--abi":

sessionParams.abiOverride = checkAbiArgument(getNextArg());

break;

case "--ephemeral":

case "--instant":

case "--instantapp":

sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);

break;

case "--full":

sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);

break;

case "--preload":

sessionParams.setInstallAsVirtualPreload();

break;

case "--user":

params.userId = UserHandle.parseUserArg(getNextArgRequired());

break;

case "--install-location":

sessionParams.installLocation = Integer.parseInt(getNextArg());

break;

case "--install-reason":

sessionParams.installReason = Integer.parseInt(getNextArg());

break;

case "--update-ownership":

if (params.installerPackageName == null) {

// Enabling update ownership enforcement needs an installer. Since the

// default installer is null when using adb install, that effectively

// disable this enforcement.

params.installerPackageName = "com.android.shell";

}

sessionParams.installFlags |= PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;

break;

case "--force-uuid":

sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;

sessionParams.volumeUuid = getNextArg();

if ("internal".equals(sessionParams.volumeUuid)) {

sessionParams.volumeUuid = null;

}

break;

case "--force-sdk ": // ignore

break;

case "--apex":

sessionParams.setInstallAsApex();

break;

case "--force-non-staged":

forceNonStaged = true;

break;

case "--multi-package":

sessionParams.setMultiPackage();

break;

case "--staged":

staged = true;

break;

case "--non-staged":

staged = false;

break;

case "--force-queryable":

sessionParams.setForceQueryable();

break;

case "--enable-rollback":

if (params.installerPackageName == null) {

// com.android.shell has the TEST_MANAGE_ROLLBACKS

// permission needed to enable rollback for non-module

// packages, which is likely what the user wants when

// enabling rollback through the shell command. Set

// the installer to com.android.shell if no installer

// has been provided so that the user doesn't have to

// remember to set it themselves.

params.installerPackageName = "com.android.shell";

}

int rollbackStrategy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;

try {

rollbackStrategy = Integer.parseInt(peekNextArg());

if (rollbackStrategy < PackageManager.ROLLBACK_DATA_POLICY_RESTORE

|| rollbackStrategy > PackageManager.ROLLBACK_DATA_POLICY_RETAIN) {

throw new IllegalArgumentException(

rollbackStrategy + " is not a valid rollback data policy.");

}

getNextArg(); // pop the argument

} catch (NumberFormatException e) {

// not followed by a number assume ROLLBACK_DATA_POLICY_RESTORE.

}

sessionParams.setEnableRollback(true, rollbackStrategy);

break;

case "--rollback-impact-level":

if (!Flags.recoverabilityDetection()) {

throw new IllegalArgumentException("Unknown option " + opt);

}

int rollbackImpactLevel = Integer.parseInt(peekNextArg());

if (rollbackImpactLevel < PackageManager.ROLLBACK_USER_IMPACT_LOW

|| rollbackImpactLevel

> PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL) {

throw new IllegalArgumentException(

rollbackImpactLevel + " is not a valid rollback impact level.");

}

sessionParams.setRollbackImpactLevel(rollbackImpactLevel);

case "--staged-ready-timeout":

params.stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());

break;

case "--skip-verification ":

sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;

break;

case "--skip-enable":

sessionParams.setApplicationEnabledSettingPersistent();

break;

case "--bypass-low-target-sdk-block":

sessionParams.installFlags |=

PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;

break;

case "--ignore-dexopt-profile":

sessionParams.installFlags |= PackageManager.INSTALL_IGNORE_DEXOPT_PROFILE;

break;

case "--package-source":

sessionParams.setPackageSource(Integer.parseInt(getNextArg()));

break;

case "--dexopt-compiler-filter":

sessionParams.dexoptCompilerFilter = getNextArgRequired();

// An early check that throws IllegalArgumentException if the compiler filter is

// invalid.

new DexoptParams.Builder(ReasonMapping.REASON_INSTALL)

.setCompilerFilter(sessionParams.dexoptCompilerFilter)

.build();

break;

default:

throw new IllegalArgumentException("Unknown option " + opt);

}

}

if (staged == null) {

staged = (sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;

}

if (replaceExisting) {

sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;

}

if (forceNonStaged) {

sessionParams.isStaged = false;

sessionParams.developmentInstallFlags |=

PackageManager.INSTALL_DEVELOPMENT_FORCE_NON_STAGED_APEX_UPDATE;

} else if (staged) {

sessionParams.setStaged();

}

if ((sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0

&& (sessionParams.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0

&& sessionParams.rollbackDataPolicy == PackageManager.ROLLBACK_DATA_POLICY_WIPE) {

throw new IllegalArgumentException("Data policy 'wipe' is not supported for apex.");

}

return params;

}

  1. doRunInstall 函数:

private int doRunInstall (final InstallParams params) throws RemoteException {

final PrintWriter pw = getOutPrintWriter();

// 默认为:UserHandle.USER_ALL

int requestUserId = params.userId;

if (requestUserId != UserHandle.USER_ALL && requestUserId != UserHandle.USER_CURRENT) {

UserManagerInternal umi =

LocalServices.getService(UserManagerInternal.class);

UserInfo userInfo = umi.getUserInfo(requestUserId);

if (userInfo == null) {

pw.println("Failure [user " + requestUserId + " doesn't exist]");

return 1;

}

}

final boolean isStreaming = params.sessionParams.dataLoaderParams != null;

final boolean isApex =

(params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;

final boolean installArchived =

(params.sessionParams.installFlags & PackageManager.INSTALL_ARCHIVED) != 0;

// 将剩余的参数变成集合.

ArrayList<String> args = getRemainingArgs();

final boolean fromStdIn = args.isEmpty() || STDIN_PATH.equals(args.get(0));

final boolean hasSplits = args.size() > 1;

if (fromStdIn && params.sessionParams.sizeBytes == -1) {

pw.println("Error: must either specify a package size or an APK file");

return 1;

}

//默认情况下都不会满足

if (isApex && hasSplits) {

pw.println("Error: can't specify SPLIT(s) for APEX");

return 1;

}

//默认情况下都不会满足

if (installArchived) {

if (hasSplits) {

pw.println("Error: can't have SPLIT(s) for Archival install");

return 1;

}

}

if (! isStreaming) {

if (fromStdIn && hasSplits) {

pw.println("Error: can't specify SPLIT(s) along with STDIN");

return 1;

}

if (args.isEmpty()) {

args.add(STDIN_PATH);

} else {

//默认会设置参数的大小.

setParamsSize (params, args);

}

}

//创建session

final int sessionId = doCreateSession (params.sessionParams,

params.installerPackageName, params.userId);

boolean abandonSession = true;

try {

if (isStreaming) {

if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex,

installArchived) != PackageInstaller.STATUS_SUCCESS) {

return 1;

}

} else {

if (doWriteSplits(sessionId, args, params.sessionParams.sizeBytes, isApex)

!= PackageInstaller.STATUS_SUCCESS) {

return 1;

}

}

//安装应用开发.

if (doCommitSession(sessionId, false /*logSuccess*/)

!= PackageInstaller.STATUS_SUCCESS) {

return 1;

}

abandonSession = false;

if (params.sessionParams.isStaged && params.stagedReadyTimeoutMs > 0) {

return doWaitForStagedSessionReady(sessionId, params.stagedReadyTimeoutMs, pw);

}

pw.println("Success");

return 0;

} finally {

if (abandonSession) {

try {

doAbandonSession(sessionId, false /*logSuccess*/);

} catch (Exception ignore) {

}

}

}

}

  1. setParamsSize 函数:

private void setParamsSize (InstallParams params, List<String> inPaths) {

if (params.sessionParams.sizeBytes != -1 || STDIN_PATH.equals(inPaths.get(0))) {

return;

}

long sessionSize = 0;

ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();

for (String inPath : inPaths) {

// 获取到apk的路径

final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");

if (fd == null) {

getErrPrintWriter().println("Error: Can't open file: " + inPath);

throw new IllegalArgumentException("Error: Can't open file: " + inPath);

}

try {

//解析此apk内容。

ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(

input.reset(), fd.getFileDescriptor(), inPath, 0);

if (apkLiteResult.isError()) {

//解析失败,报异常。

throw new IllegalArgumentException(

"Error: Failed to parse APK file: " + inPath + ": "

  • apkLiteResult.getErrorMessage(),

apkLiteResult.getException());

}

//获取到ApkLite 对象

final ApkLite apkLite = apkLiteResult.getResult();

final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite,

null /* splitNames */, null /* isFeatureSplits */,

null /* usesSplitNames */, null /* configForSplit */,

null /* splitApkPaths */, null /* splitRevisionCodes */,

apkLite.getTargetSdkVersion(), null /* requiredSplitTypes */,

null /* splitTypes */);

//计算安装文件大小。

sessionSize += InstallLocationUtils.calculateInstalledSize(pkgLite,

params.sessionParams.abiOverride, fd.getFileDescriptor());

} catch (IOException e) {

getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);

throw new IllegalArgumentException(

"Error: Failed to parse APK file: " + inPath, e);

} finally {

try {

fd.close();

} catch (IOException e) {

}

}

}

//将计算文件大小存入。

params.sessionParams.setSize(sessionSize);

}

  1. openFileForSystem 函数:

/**

* Helper for just system services to ask the shell to open an output file.

* @hide

*/

public ParcelFileDescriptor openFileForSystem (String path, String mode) {

if (DEBUG) Slog.d(TAG, "openFileForSystem: " + path + " mode=" + mode);

try {

//获取文件,并且具有可打开的权限。

ParcelFileDescriptor pfd = getShellCallback().openFile(path ,

"u:r:system_server:s0", mode);

if (pfd != null) {

if (DEBUG) Slog.d(TAG, "Got file: " + pfd);

//获取到此文件

return pfd;

}

} catch (RuntimeException e) {

if (DEBUG) Slog.d(TAG, "Failure opening file: " + e.getMessage());

getErrPrintWriter().println("Failure opening file: " + e.getMessage());

}

if (DEBUG) Slog.d(TAG, "Error: Unable to open file: " + path);

//否则就获取不到文件.

getErrPrintWriter().println("Error: Unable to open file: " + path);

String suggestedPath = "/data/local/tmp/";

if (path == null || !path.startsWith(suggestedPath)) {

getErrPrintWriter().println("Consider using a file under " + suggestedPath);

}

return null;

}

  1. doCreateSession 函数:

private int doCreateSession (SessionParams params, String installerPackageName, int userId)

throws RemoteException {

//默认是USER_ALL

if (userId == UserHandle.USER_ALL) {

params.installFlags |= PackageManager.INSTALL_ALL_USERS ;

}

final int translatedUserId =

translateUserId(userId, UserHandle.USER_SYSTEM, "doCreateSession");

// 创建createSession

final int sessionId = mInterface.getPackageInstaller()

.createSession (params, installerPackageName, null /*installerAttributionTag*/,

translatedUserId);

return sessionId;

}

8. createSession 函数:

frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java

@Override

public int createSession (SessionParams params, String installerPackageName,

String callingAttributionTag, int userId) {

try {

if (params.dataLoaderParams != null

&& mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2)

!= PackageManager.PERMISSION_GRANTED) {

throw new SecurityException("You need the "

  • "com.android.permission.USE_INSTALLER_V2 permission "

  • "to use a data loader");

}

// Draft sessions cannot be created through the public API.

params.installFlags &= ~PackageManager.INSTALL_UNARCHIVE_DRAFT;

return createSessionInternal (params, installerPackageName, callingAttributionTag,

Binder.getCallingUid(), userId);

} catch (IOException e) {

throw ExceptionUtils.wrap(e);

}

}

  1. createSessionInternal 函数:

int createSessionInternal(SessionParams params, String installerPackageName,

String installerAttributionTag, int callingUid, int userId)

throws IOException {

final Computer snapshot = mPm.snapshotComputer();

snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");

if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {

// 若包含DISALLOW_INSTALL_APPS, 说明是禁止安装,则直接报错。

throw new SecurityException("User restriction prevents installing");

}

// INSTALL_REASON_ROLLBACK allows an app to be rolled back without requiring the ROLLBACK

// capability; ensure if this is set as the install reason the app has one of the necessary

// signature permissions to perform the rollback.

if (params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) {

//安装原因是INSTALL_REASON_ROLLBACK

if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)

!= PackageManager.PERMISSION_GRANTED &&

mContext.checkCallingOrSelfPermission(Manifest.permission.TEST_MANAGE_ROLLBACKS)

!= PackageManager.PERMISSION_GRANTED) {

//若没有授权,直接抛出异常。

throw new SecurityException(

"INSTALL_REASON_ROLLBACK requires the MANAGE_ROLLBACKS permission or the "

  • "TEST_MANAGE_ROLLBACKS permission");

}

}

// App package name and label length is restricted so that really long strings aren't

// written to disk.

if (params.appPackageName != null && **!**isValidPackageName(params.appPackageName)) {

//若包名是无效的,直接将包名设置为null.

params.appPackageName = null;

}

params.appLabel = TextUtils.trimToSize(params.appLabel,

PackageItemInfo.MAX_SAFE_LABEL_LENGTH);

// Validate requested installer package name.

if (params.installerPackageName != null && !isValidPackageName(

params.installerPackageName)) {

// 若安装包名是无效的,直接直接设置为null

params.installerPackageName = null;

}

// Validate installer package name.

if (installerPackageName != null && !isValidPackageName(installerPackageName)) {

installerPackageName = null;

}

String requestedInstallerPackageName =

params.installerPackageName != null ? params.installerPackageName

: installerPackageName;

if (PackageManagerServiceUtils.isRootOrShell(callingUid)

|| PackageInstallerSession.isSystemDataLoaderInstallation(params)

|| PackageManagerServiceUtils.isAdoptedShell(callingUid, mContext)) {

params.installFlags |= PackageManager.INSTALL_FROM_ADB;

// adb installs can override the installingPackageName, but not the

// initiatingPackageName

//安装来源于adb

installerPackageName = SHELL_PACKAGE_NAME;

} else {

if (callingUid != SYSTEM_UID) {

// The supplied installerPackageName must always belong to the calling app.

//若调用者不是system,则要检查权限。

mAppOps.checkPackage(callingUid, installerPackageName);

}

// Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the

// caller.

if (! TextUtils.equals(requestedInstallerPackageName, installerPackageName)) {

if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)

!= PackageManager.PERMISSION_GRANTED) {

// 若请求安装包名和安装包名不一致,

// 需要判断是否有INSTALL_PACKAGES权限,若没有的话,进行权限检查。

mAppOps.checkPackage(callingUid, requestedInstallerPackageName);

}

}

//移除 FLAG:INSTALL_FROM_ADB,INSTALL_ALL_USERS,INSTALL_ARCHIVED

params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;

params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;

params.installFlags &= ~PackageManager.INSTALL_ARCHIVED;

//增加flag:INSTALL_REPLACE_EXISTING

params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;

if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0

&& !mPm.isCallerVerifier(snapshot, callingUid)) {

params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;

}

if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_TEST_ONLY_PACKAGE)

!= PackageManager.PERMISSION_GRANTED) {

params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST;

}

// developmentInstallFlags can ony be set by shell or root.

params.developmentInstallFlags = 0;

}

String originatingPackageName = null;

if (params.originatingUid != SessionParams.UID_UNKNOWN

&& params.originatingUid != callingUid) {

String[] packages = snapshot.getPackagesForUid(params.originatingUid);

if (packages != null && packages.length > 0) {

// Choose an arbitrary representative package in the case of a shared UID.

originatingPackageName = packages[0];

}

}

if (Build.IS_DEBUGGABLE || PackageManagerServiceUtils.isSystemOrRoot(callingUid)) {

params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;

} else {

params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;

}

if (mDisableVerificationForUid != INVALID_UID) {

if (callingUid == mDisableVerificationForUid) {

params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;

} else {

// Clear the flag if current calling uid doesn't match the requested uid.

params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;

}

// Reset the field as this is a one-off request.

mDisableVerificationForUid = INVALID_UID;

} else if ((params.installFlags & ADB_DEV_MODE) != ADB_DEV_MODE) {

// Only tools under specific conditions (test app installed through ADB, and

// verification disabled flag specified) can disable verification.

params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;

}

if (Flags.rollbackLifetime()) {

if (params.rollbackLifetimeMillis > 0) {

if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {

throw new IllegalArgumentException(

"Can't set rollbackLifetimeMillis when rollback is not enabled");

}

if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)

!= PackageManager.PERMISSION_GRANTED) {

throw new SecurityException(

"Setting rollback lifetime requires the MANAGE_ROLLBACKS permission");

}

} else if (params.rollbackLifetimeMillis < 0) {

throw new IllegalArgumentException("rollbackLifetimeMillis can't be negative.");

}

}

if (Flags.recoverabilityDetection()) {

if (params.rollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH

|| params.rollbackImpactLevel

== PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL) {

if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {

throw new IllegalArgumentException(

"Can't set rollbackImpactLevel when rollback is not enabled");

}

if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)

!= PackageManager.PERMISSION_GRANTED) {

throw new SecurityException(

"Setting rollbackImpactLevel requires the MANAGE_ROLLBACKS permission");

}

} else if (params.rollbackImpactLevel < 0) {

throw new IllegalArgumentException("rollbackImpactLevel can't be negative.");

}

}

boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;

if (isApex) {

if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES)

== PackageManager.PERMISSION_DENIED

&& mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)

== PackageManager.PERMISSION_DENIED) {

throw new SecurityException("Not allowed to perform APEX updates");

}

} else if (params.isStaged) {

mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);

}

if (isApex) {

if (!mApexManager.isApexSupported()) {

throw new IllegalArgumentException(

"This device doesn't support the installation of APEX files");

}

if (params.isMultiPackage) {

throw new IllegalArgumentException("A multi-session can't be set as APEX.");

}

if (PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)

|| mBypassNextAllowedApexUpdateCheck) {

params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;

} else {

// Only specific APEX updates (installed through ADB, or for CTS tests) can disable

// allowed APEX update check.

params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;

}

}

if ((params.installFlags & PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK) != 0

&& !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)

&& !Build.IS_DEBUGGABLE

&& !PackageManagerServiceUtils.isAdoptedShell(callingUid, mContext)) {

// If the bypass flag is set, but not running as system root or shell then remove

// the flag

params.installFlags &= ~PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;

}

params.installFlags &= ~PackageManager.INSTALL_UNARCHIVE;

if (isArchivingEnabled() && params.appPackageName != null) {

PackageStateInternal ps = mPm.snapshotComputer().getPackageStateInternal(

params.appPackageName, SYSTEM_UID);

if (ps != null

&& PackageArchiver.isArchived(ps.getUserStateOrDefault(userId))

&& PackageArchiver.getResponsibleInstallerPackage(ps)

.equals(requestedInstallerPackageName)) {

params.installFlags |= PackageManager.INSTALL_UNARCHIVE;

}

}

if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0

&& !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)

&& (snapshot.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)

== 0) {

throw new SecurityException(

"Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag.");

}

if (params.isStaged && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)) {

if (!mBypassNextStagedInstallerCheck

&& !isStagedInstallerAllowed(requestedInstallerPackageName)) {

throw new SecurityException("Installer not allowed to commit staged install");

}

}

if (isApex && !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)) {

if (!mBypassNextStagedInstallerCheck

&& !isStagedInstallerAllowed(requestedInstallerPackageName)) {

throw new SecurityException(

"Installer not allowed to commit non-staged APEX install");

}

}

mBypassNextStagedInstallerCheck = false;

mBypassNextAllowedApexUpdateCheck = false;

if (!params.isMultiPackage) {

var hasInstallGrantRuntimePermissions = mContext.checkCallingOrSelfPermission(

Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)

== PackageManager.PERMISSION_GRANTED;

// Only system components can circumvent runtime permissions when installing.

if ((params.installFlags & PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS) != 0

&& !hasInstallGrantRuntimePermissions) {

throw new SecurityException("You need the "

  • Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS

  • " permission to use the"

  • " PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS flag");

}

var permissionStates = params.getPermissionStates();

if (!permissionStates.isEmpty()) {

if (!hasInstallGrantRuntimePermissions) {

for (int index = 0; index < permissionStates.size(); index++) {

var permissionName = permissionStates.keyAt(index);

if (!INSTALLER_CHANGEABLE_APP_OP_PERMISSIONS.contains(permissionName)) {

throw new SecurityException("You need the "

  • Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS

  • " permission to grant runtime permissions for a session");

}

}

}

}

// Defensively resize giant app icons

if (params.appIcon != null) {

final ActivityManager am = (ActivityManager) mContext.getSystemService(

Context.ACTIVITY_SERVICE);

final int iconSize = am.getLauncherLargeIconSize();

if ((params.appIcon.getWidth() > iconSize * 2)

|| (params.appIcon.getHeight() > iconSize * 2)) {

params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,

true);

}

}

switch (params.mode) {

case SessionParams.MODE_FULL_INSTALL:

case SessionParams.MODE_INHERIT_EXISTING:

break;

default:

throw new IllegalArgumentException("Invalid install mode: " + params.mode);

}

// If caller requested explicit location, validity check it, otherwise

// resolve the best internal or adopted location.

if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {

if (!InstallLocationUtils.fitsOnInternal(mContext, params)) {

throw new IOException("No suitable internal storage available");

}

} else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {

// For now, installs to adopted media are treated as internal from

// an install flag point-of-view.

params.installFlags |= PackageManager.INSTALL_INTERNAL;

} else {

params.installFlags |= PackageManager.INSTALL_INTERNAL;

// Resolve best location for install, based on combination of

// requested install flags, delta size, and manifest settings.

final long ident = Binder.clearCallingIdentity();

try {

params.volumeUuid = InstallLocationUtils.resolveInstallVolume(mContext, params);

} finally {

Binder.restoreCallingIdentity(ident);

}

}

}

int requestedInstallerPackageUid = INVALID_UID;

if (requestedInstallerPackageName != null) {

requestedInstallerPackageUid = snapshot.getPackageUid(requestedInstallerPackageName,

0 /* flags */, userId);

}

if (requestedInstallerPackageUid == INVALID_UID) {

// Requested installer package is invalid, reset it

requestedInstallerPackageName = null;

}

final int sessionId;

final PackageInstallerSession session;

synchronized (mSessions) {

// Check that the installer does not have too many active sessions.

final int activeCount = getSessionCount(mSessions, callingUid);

if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)

== PackageManager.PERMISSION_GRANTED) {

if (activeCount >= MAX_ACTIVE_SESSIONS_WITH_PERMISSION) {

throw new IllegalStateException(

"Too many active sessions for UID " + callingUid);

}

} else if (activeCount >= MAX_ACTIVE_SESSIONS_NO_PERMISSION) {

throw new IllegalStateException(

"Too many active sessions for UID " + callingUid);

}

final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);

if (historicalCount >= MAX_HISTORICAL_SESSIONS) {

throw new IllegalStateException(

"Too many historical sessions for UID " + callingUid);

}

final int existingDraftSessionId =

getExistingDraftSessionId(requestedInstallerPackageUid, params, userId);

sessionId = existingDraftSessionId != SessionInfo.INVALID_ID ? existingDraftSessionId

: allocateSessionIdLocked();

}

final long createdMillis = System.currentTimeMillis();

// We're staging to exactly one location

File stageDir = null;

String stageCid = null;

if (!params.isMultiPackage) {

if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {

stageDir = buildSessionDir(sessionId, params);

} else {

stageCid = buildExternalStageCid(sessionId);

}

}

// reset the force queryable param if it's not called by an approved caller.

if (params.forceQueryableOverride) {

if (!PackageManagerServiceUtils.isRootOrShell(callingUid)) {

params.forceQueryableOverride = false;

}

}

final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class);

if (dpmi != null && dpmi.isUserOrganizationManaged(userId)) {

params.installFlags |= PackageManager.INSTALL_FROM_MANAGED_USER_OR_PROFILE;

}

if (isApex || mContext.checkCallingOrSelfPermission(

Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) == PackageManager.PERMISSION_DENIED) {

params.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;

}

InstallSource installSource = InstallSource.create(installerPackageName,

originatingPackageName, requestedInstallerPackageName, requestedInstallerPackageUid,

requestedInstallerPackageName, installerAttributionTag, params.packageSource);

session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,

mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId,

userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid,

null, null, false, false, false, false, null, SessionInfo.INVALID_ID,

false, false, false, PackageManager.INSTALL_UNKNOWN, "", null);

synchronized (mSessions) {

mSessions.put(sessionId, session);

}

mPm.addInstallerPackageName(session.getInstallSource());

mCallbacks.notifySessionCreated(session.sessionId, session.userId);

mSettingsWriteRequest.schedule();

if (LOGD) {

Slog.d(TAG, "Created session id=" + sessionId + " staged=" + params.isStaged);

}

return sessionId;

}

相关推荐
用户277844910499312 小时前
借助DeepSeek智能生成测试用例:从提示词到Excel表格的全流程实践
人工智能·python
JavaEdge在掘金14 小时前
ssl.SSLCertVerificationError报错解决方案
python
我不会编程55515 小时前
Python Cookbook-5.1 对字典排序
开发语言·数据结构·python
李少兄15 小时前
Unirest:优雅的Java HTTP客户端库
java·开发语言·http
老歌老听老掉牙15 小时前
平面旋转与交线投影夹角计算
python·线性代数·平面·sympy
满怀101515 小时前
Python入门(7):模块
python
无名之逆15 小时前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
你觉得20515 小时前
哈尔滨工业大学DeepSeek公开课:探索大模型原理、技术与应用从GPT到DeepSeek|附视频与讲义下载方法
大数据·人工智能·python·gpt·学习·机器学习·aigc
似水এ᭄往昔15 小时前
【C语言】文件操作
c语言·开发语言
啊喜拔牙15 小时前
1. hadoop 集群的常用命令
java·大数据·开发语言·python·scala