#1 安装方式

  • 1 安装系统APK和预制APK时,通过PMS的构造函数中安装,即第一次开机时安装应用,没有安装界面。
  • 2 网络下载安装,通过应用商店等,即调用PackageManager.installPackages(),有安装界面。
  • 3 通过adb工具安装,没有安装界面,它通过启动pm脚本的形式,然后调用com.android.commands.pm.Pm类,之后调用到PMS.installStage()完成安装。
  • 4 安装本地apk,有安装界面,由PackageInstaller系统应用安装。
    上述几种方式均通过PackageInstallObserver来监听安装是否成功。

#2 安装流程分析

2.1 首次安装

首次安装即系统第一次开机时安装应用,包括系统应用和预制应用,其最主要过程在PMS构造函数中,

整个过程关键步骤大致为上述15步,与应用安装相关实际上就是扫描和安装两步。方法调用时序图如图1所示。
[图1 PMS安装应用时序图]

  • 1 向动态设置中添加系统默认的共享ID(system、phone、log、nfc、bluetooth、shell、se等)。
  • 2 初始化成员变量,如Installer、PackageDexOptimizer、DexManager、ArtManagerService、MoveCallbacks、OnPermissionChangeListeners等,并获取系统配置。
  • 3 启动一个服务类线程。
  • 4 初始化用户管理服务
  • 5 将权限配置传入包管理器
  • 6 清除代码路径不存在的孤立包
  • 7 将系统应用权限从安装态升级为运行时
  • 8 在扫描应用前,手机供应商的覆盖安装包(/overlay)
  • 9 扫描应用目录,依次为特权系统目录 priv-app、普通目录 app、供应商系统目录 vendor/app等
  • 10 解析存储管理器
  • 11 如果是第一次开机,需要初始化用户的默认偏好应用
  • 12 在启动时,为用户准备好存储空间,因为SystemUI等启动不能等待用户
  • 13 安装应用,完成后检查webview,默认浏览器等。
  • 14 启动PackageInstallerService
  • 15 向系统组件暴露私有服务
    下面我们结合代码做详细分析
  1. 判断应用包是否已安装,如果包名存在于uninstalled_deapp.xml中或者已安装,则直接返回null。

2.2 下载安装

下载安装可分为两部分:拷贝应用和安装应用。拷贝过程的函数调用时序图如图2所示。
【图2 下载安装应用程序时序图】

frameworks层的入口函数为PackageManager.installPackage,由应用市场APP调用,然后调用PMS.installPackageAsUser,然后发送消息INIT_COPY、MCS_BOUND开始复制,调用HandlerParams.startCopy。这个方法主要分两部分,一部分是拷贝应用的执行程序,另一部分是创建应用的数据目录,拷贝部分由handleStartCopy完成。之后调用handlerReturnCode来处理创建数据目录。拷贝部分会调用DefaultContainerService来完成,该服务为那些可能位于可删除空间上的文件提供检查和拷贝功能。当底层设置被移除时,这样设计可以防止系统进程保留打开的文件时,不被内核杀死。

handleStartcopy实现在PMS内部类InstallParams中,它的功能是调用远程方法获取包信息和安装位置,如有必要则给与默认车辆覆盖安装位置,然后基于安装位置创建安装参数。下面我们结合关键代码做进一步分析。

首先是拷贝应用过程

  • 1 PMS.installPackageAsUser的功能主要是:根据uid确定installFlags,并校验权限,并构造InstallParam,然后发送INIT_COPY消息。
@Override
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,int installFlags, String installerPackageName, int userId) {mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);final int callingUid = Binder.getCallingUid();enforceCrossUserPermission(callingUid, userId,true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {try {if (observer != null) {observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);}} catch (RemoteException re) {}return;}if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {installFlags |= PackageManager.INSTALL_FROM_ADB;} else {// Caller holds INSTALL_PACKAGES permission, so we're less strict// about installerPackageName.installFlags &= ~PackageManager.INSTALL_FROM_ADB;installFlags &= ~PackageManager.INSTALL_ALL_USERS;}UserHandle user;if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {user = UserHandle.ALL;} else {user = new UserHandle(userId);}// Only system components can circumvent runtime permissions when installing.if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0&& mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {throw new SecurityException("You need the "+ "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "+ "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");}if ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0|| (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {throw new IllegalArgumentException("New installs into ASEC containers no longer supported");}final File originFile = new File(originPath);final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);final Message msg = mHandler.obtainMessage(INIT_COPY);final VerificationInfo verificationInfo = new VerificationInfo(null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,null /*packageAbiOverride*/, null /*grantedPermissions*/,null /*certificates*/, PackageManager.INSTALL_REASON_UNKNOWN);params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));msg.obj = params;Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",System.identityHashCode(msg.obj));Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",System.identityHashCode(msg.obj));mHandler.sendMessage(msg);
}
  • 2 之后根据Handler.doHandleMessage调用到InstallParams.handleStartCopy方法,首先检查文件和cid是否已生成,如生成则设置installFlags。
// [InstallParams.handleStartCopy]
if (origin.staged) {if (origin.file != null) {installFlags |= PackageManager.INSTALL_INTERNAL;installFlags &= ~PackageManager.INSTALL_EXTERNAL;} else if (origin.cid != null) {installFlags |= PackageManager.INSTALL_EXTERNAL;installFlags &= ~PackageManager.INSTALL_INTERNAL;} else {throw new IllegalStateException("Invalid stage location");}
}
  • 3 然后检查空间大小,如果空间不够则释放无用空间。
// [InstallParams.handleStartCopy]
if (!origin.staged && pkgLite.recommendedInstallLocation== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {// TODO: focus freeing disk space on the target devicefinal StorageManager storage = StorageManager.from(mContext);final long lowThreshold = storage.getStorageLowBytes(Environment.getDataDirectory());final long sizeBytes = mContainerService.calculateInstalledSize(origin.resolvedPath, isForwardLocked(), packageAbiOverride);try {mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,installFlags, packageAbiOverride);} catch (InstallerException e) {Slog.w(TAG, "Failed to free cache", e);}if (pkgLite.recommendedInstallLocation== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {pkgLite.recommendedInstallLocation= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;}
}
  • 4 覆盖原有安装位置的文件,并根据返回结果来确定函数的返回值,并设置installFlags。
// [InstallParams.handleStartCopy]
// Override with defaults if needed.
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else if (!onSd && !onInt) {// Override install location with flagsif (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {// Set the flag to install on external media.installFlags |= PackageManager.INSTALL_EXTERNAL;installFlags &= ~PackageManager.INSTALL_INTERNAL;} else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {if (DEBUG_EPHEMERAL) {Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");}installFlags |= PackageManager.INSTALL_INSTANT_APP;installFlags &= ~(PackageManager.INSTALL_EXTERNAL|PackageManager.INSTALL_INTERNAL);} else {// Make sure the flag for installing on external// media is unsetinstallFlags |= PackageManager.INSTALL_INTERNAL;installFlags &= ~PackageManager.INSTALL_EXTERNAL;}
}
  • 5 确定是否有任何已安装的包验证器,如有,则延迟检测。主要分三步:首先新建一个验证Intent,然后设置相关的信息,之后获取验证器列表,最后向每个验证器发送验证Intent。
// [InstallParams.handleStartCopy]
final Intent verification = new Intent( //构造验证IntentIntent.ACTION_PACKAGE_NEEDS_VERIFICATION);// ......final PackageVerificationState verificationState = new PackageVerificationState(requiredUid, args);mPendingVerification.append(verificationId, verificationState);// 获取验证器列表final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,receivers, verificationState);DeviceIdleController.LocalService idleController = getDeviceIdleController();final long idleDuration = getVerificationTimeout();/** If any sufficient verifiers were listed in the package* manifest, attempt to ask them.*/if (sufficientVerifiers != null) {final int N = sufficientVerifiers.size();if (N == 0) {Slog.i(TAG, "Additional verifiers required, but none installed.");ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;} else {for (int i = 0; i < N; i++) {final ComponentName verifierComponent = sufficientVerifiers.get(i);idleController.addPowerSaveTempWhitelistApp(Process.myUid(),verifierComponent.getPackageName(), idleDuration,verifierUser.getIdentifier(), false, "package verifier");// 向每个验证器发送验证Intentfinal Intent sufficientIntent = new Intent(verification);sufficientIntent.setComponent(verifierComponent);mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);}}}
  • 6 向验证器客户端发送intent,只有当验证成功之后才会开启copy工作。如果没有任何验证器则直接拷贝。

下面为安装过程入口是PMS.processPendingInstall方法,调用时序图如图3
【图3 下载安装-安装过程图】

  • 1 首先启动一个新线程,然后设置安装信息,处理安装参数,开始安装,并发送关于安装状态的广播,然后处理安装完的事情,比如打印错误信息,清除临时文件等。
private void processPendingInstall(final InstallArgs args, final int currentStatus) {// Queue up an async operation since the package installation may take a little while.mHandler.post(new Runnable() {public void run() {mHandler.removeCallbacks(this);// Result object to be returnedPackageInstalledInfo res = new PackageInstalledInfo();res.setReturnCode(currentStatus);res.uid = -1;res.pkg = null;res.removedInfo = null;if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {args.doPreInstall(res.returnCode);synchronized (mInstallLock) {installPackageTracedLI(args, res);}args.doPostInstall(res.returnCode, res.uid);//......
}
  • 2 installPackageTracedLI是安装过程的核心方法,然后调用installPackageLI.首先检查安装包的完整性并解析安装包。
//[PMS.installPackageLI]
// 完整性校验
if (instantApp && (forwardLocked || onExternal)) {Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked+ " external=" + onExternal);res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);return;
}// 检索包设置,并解析应用
final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY| PackageParser.PARSE_ENFORCE_CODE| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)| (instantApp ? PackageParser.PARSE_IS_EPHEMERAL : 0)| (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {//解析安装包pkg = pp.parsePackage(tmpPackageFile, parseFlags);DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {res.setError("Failed parse during installPackageLI", e);return;
} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
  • 3 检查SDK版本和沙箱版本,同时检查是否有静态共享库,如有则需要放在内部存储中。
//[PMS.installPackageLI]
//检查SDK版本和沙箱版本
if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,"Instant app package must target O");return;
}
if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {Slog.w(TAG, "Instant app package " + pkg.packageName+ " does not target targetSandboxVersion 2");res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,"Instant app package must use targetSanboxVersion 2");return;
}
//检查是否有静态共享库
if (pkg.applicationInfo.isStaticSharedLibrary()) {// Static shared libraries have synthetic package namesrenameStaticSharedLibraryPackage(pkg);// No static shared libs on external storageif (onExternal) {Slog.i(TAG, "Static shared libs can only be installed on internal storage.");res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,"Packages declaring static-shared libs cannot be updated");return;}
}
  • 4 检查是否有子安装包,如有则子安装包也需要检测。
//[PMS.installPackageLI]
// If we are installing a clustered package add results for the children
if (pkg.childPackages != null) {synchronized (mPackages) {final int childCount = pkg.childPackages.size();for (int i = 0; i < childCount; i++) {PackageParser.Package childPkg = pkg.childPackages.get(i);PackageInstalledInfo childRes = new PackageInstalledInfo();childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);childRes.pkg = childPkg;childRes.name = childPkg.packageName;PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);if (childPs != null) {childRes.origUsers = childPs.queryInstalledUsers(sUserManager.getUserIds(), true);}if ((mPackages.containsKey(childPkg.packageName))) {childRes.removedInfo = new PackageRemovedInfo(this);childRes.removedInfo.removedPackage = childPkg.packageName;childRes.removedInfo.installerPackageName = childPs.installerPackageName;}if (res.addedChildPackages == null) {res.addedChildPackages = new ArrayMap<>();}res.addedChildPackages.put(childPkg.packageName, childRes);}}
}
  • 5 检查安装包是否已存在,如已存在则需要检查旧的父包、沙箱、sdk等是否已为空,否则会报错。
  • 6 校验安装包签名
//[PMS.installPackageLI]
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);if (libraryEntry != null) {signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);}
}// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "+ pkg.packageName + " upgrade keys do not match the "+ "previously installed version");return;}
} else {try {verifySignaturesLP(signatureCheckPs, pkg);} catch (PackageManagerException e) {res.setError(e.error, e.getMessage());return;}
}
  • 7 设置相关的全向,包括生成权限、移植权限等
  • 8 如果这是一个系统应用,则检查是否在外部存储上或是是否被其他应用替换等
//[PMS.installPackageLI]
if (systemApp) {if (onExternal) {// Abort update; system app can't be replaced with app on sdcardres.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,"Cannot install updates to system apps on sdcard");return;} else if (instantApp) {// Abort update; system app can't be replaced with an instant appres.setError(INSTALL_FAILED_INSTANT_APP_INVALID,"Cannot update a system app with an instant app");return;}
}
  • 9 生成安装包Abi(Application binary interface,应用二进制接口,描述应用程序和操作系统之间或其他应用程序的低级接口)
//[PMS.installPackageLI]
try {String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?args.abiOverride : pkg.cpuAbiOverride);final boolean extractNativeLibs = !pkg.isLibrary();derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,extractNativeLibs, mAppLib32InstallDir);
} catch (PackageManagerException pme) {Slog.e(TAG, "Error deriving application ABI", pme);res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");return;
}
  • 10更新共享库
//[PMS.installPackageLI]
synchronized (mPackages) {try {updateSharedLibrariesLPr(pkg, null);} catch (PackageManagerException e) {Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());}
}
  • 11如有必要,优化dex文件
//[PMS.installPackageLI]
final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)&& !forwardLocked&& !pkg.applicationInfo.isExternalAsec()&& (!instantApp || Global.getInt(mContext.getContentResolver(),Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)&& ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);if (performDexopt) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
// Do not run PackageDexOptimizer through the local performDexOpt
// method because `pkg` may not be in `mPackages` yet.
//
// Also, don't fail application installs if the dexopt step fails.
DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,REASON_INSTALL,DexoptOptions.DEXOPT_BOOT_COMPLETE |DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,null /* instructionSets */,getOrCreateCompilerPackageStats(pkg),mDexManager.getPackageUseInfoOrDefault(pkg.packageName),dexoptOptions);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
  • 12替换安装,则直接安装新包,这里应用时生成应用数据目录。ps:替换安装:其主要过程为更新设置,清除原有的某些APP数据,重新生成相关的app数据目录等步骤,同事要区分系统应用替换和非系统应用替换。而安装新包:则直接更新设置,生成APP数据即可。
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,"installPackageLI")) {if (replace) {if (pkg.applicationInfo.isStaticSharedLibrary()) {// Static libs have a synthetic package name containing the version// and cannot be updated as an update would get a new package name,// unless this is the exact same version code which is useful for// development.PackageParser.Package existingPkg = mPackages.get(pkg.packageName);if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "+ "static-shared libs cannot be updated");return;}}replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,installerPackageName, res, args.installReason);} else {installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,args.user, installerPackageName, volumeUuid, res, args.installReason);}
}
  • 13 如果是安装一个不存在的包,则调用PMS.installNewPackageLIF方法。首先会检查是否有重复的包名,并更新设置,然后根据安装的结果,如果安装失败则删除安装过程中产生的文件。
private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,PackageInstalledInfo res, int installReason) {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");// Remember this for later, in case we need to rollback this installString pkgName = pkg.packageName;if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);synchronized(mPackages) {final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);if (renamedPackage != null) {// 如果已有相同包名的应用,则报错res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling package running as "+ renamedPackage);return;}if (mPackages.containsKey(pkgName)) {// Don't allow installation over an existing package with the same name.res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling.");return;}}try {PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, System.currentTimeMillis(), user);updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {prepareAppDataAfterInstallLIF(newPackage);} else {// Remove package from internal structures, but keep around any// data that might have already existeddeletePackageLIF(pkgName, UserHandle.ALL, false, null,PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);}} catch (PackageManagerException e) {res.setError("Package couldn't be installed in " + pkg.codePath, e);}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
  • 14 然后为已安装的应用准备数据目录,其依次的顺序是

    • PMS.prepareAppDataAfterInstallLIF
    • PMS.prepareAppDataLIF
    • PMS.prepareAppDataLeafLIF
    • Installer.createAppData

这个方法是PMS与Installer交互的接口函数,这里的数据目录是CE类型。

private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {if (DEBUG_APP_DATA) {Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"+ Integer.toHexString(flags));}final String volumeUuid = pkg.volumeUuid;final String packageName = pkg.packageName;final ApplicationInfo app = pkg.applicationInfo;final int appId = UserHandle.getAppId(app.uid);Preconditions.checkNotNull(app.seInfo);long ceDataInode = -1;try {// 调用Installd守护进程的入口ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,appId, app.seInfo, app.targetSdkVersion);} catch (InstallerException e) {//......}// Prepare the application profiles.mArtManagerService.prepareAppProfiles(pkg, userId);if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {// TODO: mark this structure as dirty so we persist it!synchronized (mPackages) {final PackageSetting ps = mSettings.mPackages.get(packageName);if (ps != null) {ps.setCeDataInode(ceDataInode, userId);}}}prepareAppDataContentsLeafLIF(pkg, userId, flags);
}
  • 15 如果是替换应用,一般情况是应用更新,或者是重新安装。它的主要过程包括:验证签名,如是系统更新则还需要校验hash值,检查共享ID的更改情况,不允许完整更新,更新已被删除数据,最后根据应用是否是系统应用来判断接下去的操作。
private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,UserHandle user, String installerPackageName, PackageInstalledInfo res,int installReason) {final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;final PackageParser.Package oldPackage;final PackageSetting ps;final String pkgName = pkg.packageName;final int[] allUsers;final int[] installedUsers;// ......boolean sysPkg = (isSystemApp(oldPackage));if (sysPkg) {// Set the system/privileged flags as neededfinal boolean privileged =(oldPackage.applicationInfo.privateFlags& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;final int systemPolicyFlags = policyFlags| PackageParser.PARSE_IS_SYSTEM| (privileged ? PackageParser.PARSE_IS_PRIVILEGED : 0);replaceSystemPackageLIF(oldPackage, pkg, systemPolicyFlags, scanFlags,user, allUsers, installerPackageName, res, installReason);} else {replaceNonSystemPackageLIF(oldPackage, pkg, policyFlags, scanFlags,user, allUsers, installerPackageName, res, installReason);}
}
  • 16 最后这两个方法均会调用到PMS.prepareAppDataLeafLIF。
  • 17 安装完成后,更新设置,更新安装锁等。

2.3 adb安装

关于adb安装,其copy过程与下载安装不同,但安装过程却与下载过程是相同的,这里不做重复分析,需要注意的是adb安装是不能替换安装的,具体原因?

拷贝过程
其调用时序图如图4 所示。
【图4 adb安装-copy过程时序图】

  • 1 adb的入口在com.android.commands.pm.Pm类,那么这是如何调用到这个类的呢,这是adb命令通过adbd守护进程调用到/system/bin/pm这个脚本,其脚本源码如下:
base=/system
export CLASSPATh-$base/framework/pm.jar
exec app_process $base/bin.com.android.commands.pm.Pm "$@"
  • 2 Pm类通过脚本启动,执行顺序是main->run->runInstall,然后提交session。
public static void main(String[] args) {int exitCode = 1;try {exitCode = new Pm().run(args);} catch (Exception e) {Log.e(TAG, "Error", e);System.err.println("Error: " + e);if (e instanceof RemoteException) {System.err.println(PM_NOT_RUNNING_ERR);}}System.exit(exitCode);
}
public int run(String[] args) throws RemoteException {boolean validCommand = false;if (args.length < 1) {return showUsage();}mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));if (mPm == null) {System.err.println(PM_NOT_RUNNING_ERR);return 1;}mInstaller = mPm.getPackageInstaller();mArgs = args;String op = args[0];mNextArg = 1;//......if ("install".equals(op)) {return runInstall();}//......
}
  • 3 Pm.runInstall中首先是创建session,然后提交session,代码如下。
    private int runInstall() throws RemoteException {long startedTime = SystemClock.elapsedRealtime();final InstallParams params = makeInstallParams();final String inPath = nextArg();if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {File file = new File(inPath);if (file.isFile()) {try {ApkLite baseApk = PackageParser.parseApkLite(file, 0);PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,null, null);params.sessionParams.setSize(PackageHelper.calculateInstalledSize(pkgLite, false,params.sessionParams.abiOverride));} catch (PackageParserException | IOException e) {System.err.println("Error: Failed to parse APK file: " + e);return 1;}} else {System.err.println("Error: Can't open non-file: " + inPath);return 1;}}final int sessionId = doCreateSession(params.sessionParams,params.installerPackageName, params.userId);try {if (inPath == null && params.sessionParams.sizeBytes == -1) {System.err.println("Error: must either specify a package size or an APK file");return 1;}if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {return 1;}Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);if (status.second != PackageInstaller.STATUS_SUCCESS) {return 1;}Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()- startedTime) + " ms");System.out.println("Success");return 0;} finally {try {mInstaller.abandonSession(sessionId);} catch (Exception ignore) {}}}
  • 4 这里Pm相当于客户端,接受session的服务端在PackageInstallerSession中,这里利用AIDL来完成传输,其调用过程为:

    • Pm.doCommitSession
    • PackageInstaller.Session.commit
    • IPackageInstallerSession.commit
    • PackageInstallerSession.commit
    • Handler.Callback.handleMessage
    • PackageInstallerSession.commitLock
    • PMS.installStage

以上关于session传递过程暂不分析,下面我们来详细看下installStage方法。

  • 5 installStage方法主要功能就是构造InstallParam对象,并发送INIT_COPY。
void installStage(String packageName, File stagedDir, String stagedCid,IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,String installerPackageName, int installerUid, UserHandle user,Certificate[][] certificates) {if (DEBUG_EPHEMERAL) {if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {Slog.d(TAG, "Ephemeral install of " + packageName);}}final VerificationInfo verificationInfo = new VerificationInfo(sessionParams.originatingUri, sessionParams.referrerUri,sessionParams.originatingUid, installerUid);final OriginInfo origin;if (stagedDir != null) {origin = OriginInfo.fromStagedFile(stagedDir);} else {origin = OriginInfo.fromStagedContainer(stagedCid);}final Message msg = mHandler.obtainMessage(INIT_COPY);final int installReason = fixUpInstallReason(installerPackageName, installerUid,sessionParams.installReason);final InstallParams params = new InstallParams(origin, null, observer,sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,verificationInfo, user, sessionParams.abiOverride,sessionParams.grantedRuntimePermissions, certificates, installReason);params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));msg.obj = params;Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",System.identityHashCode(msg.obj));Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",System.identityHashCode(msg.obj));mHandler.sendMessage(msg);
}
  • 6 发送完Handler消息后就与下载安装过程相同了。

2.4 本地安装

本地安装参与对象包括PackageInstaller应用,PMS两部分。下面我们就来分析下PackageInstaller是如何调用到PMS中的。函数调用时序图如图5所示。
【图5 本地安装前提调用时序图】

  • 1 点击文件管理器中的apk文件时,会调用到FolderFragment类的openFile方法,然后调用startActivitySafety方法启动PackageInstallerActivity。
private void openFile(File f) {  final Uri fileUri = Uri.fromFile(f);  final Intent intent = new Intent();  intent.setAction(android.content.Intent.ACTION_VIEW);  intent.putExtra(Intent.EXTRA_TITLE, f.getName());  intent.putExtra(EXTRA_ALL_VIDEO_FOLDER, true);  Uri contentUri = null;  String type = getMIMEType(f);  //......  if (contentUri != null) {  intent.setDataAndType(contentUri, type);  } else {  intent.setDataAndType(fileUri, type);  }  try {  startActivitySafely(intent);  }   //......
}
  • 2 如下为PackageInstallerActivity.onCreate方法源码,其主要过程初始化各个服务的成员变量如PMS,校验session,并加载UI界面,然用户确定是否安装。
//[PackageInstallerActivity.java]
protected void onCreate(Bundle icicle) {super.onCreate(icicle);if (icicle != null) {mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);}//初始化各个关键参数mPm = getPackageManager();mIpm = AppGlobals.getPackageManager();mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);mInstaller = mPm.getPackageInstaller();mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);final Intent intent = getIntent();mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);mSourceInfo = intent.getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO);mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,PackageInstaller.SessionParams.UID_UNKNOWN);mOriginatingPackage = (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN)? getPackageNameForUid(mOriginatingUid) : null;final Uri packageUri;//校验sessionif (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");finish();return;}mSessionId = sessionId;packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));mOriginatingURI = null;mReferrerURI = null;} else {mSessionId = -1;packageUri = intent.getData();mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);}// if there's nothing to do, quietly slip into the etherif (packageUri == null) {Log.w(TAG, "Unspecified source");setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);finish();return;}if (DeviceUtils.isWear(this)) {showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR);return;}boolean wasSetUp = processPackageUri(packageUri);if (!wasSetUp) {return;}// 加载UI界面bindUi(R.layout.install_confirm, false);checkIfAllowedAndInitiateInstall();
}
  • 3 当用户点击安装按钮时,响应函数为PackageInstallerActivity.onClick方法,
//[PackageInstallerActivity.java]
public void onClick(View v) {if (v == mOk) {if (mOk.isEnabled()) {if (mOkCanInstall || mScrollView == null) {if (mSessionId != -1) {mInstaller.setPermissionsResult(mSessionId, true);finish();} else {startInstall();}} else {mScrollView.pageScroll(View.FOCUS_DOWN);}}} else if (v == mCancel) {// Cancel and finishsetResult(RESULT_CANCELED);if (mSessionId != -1) {mInstaller.setPermissionsResult(mSessionId, false);}finish();}
}
  • 4 之后调用 PackageInstallerActivity.startInstall方法,构造Intent,然后启动InstallInstalling,并销毁PackageInstallerActivity。
private void startInstall() {// Start subactivity to actually install the applicationIntent newIntent = new Intent();newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,mPkgInfo.applicationInfo);newIntent.setData(mPackageURI);newIntent.setClass(this, InstallInstalling.class);String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);if (mOriginatingURI != null) {newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);}if (mReferrerURI != null) {newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);}if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);}if (installerPackageName != null) {newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,installerPackageName);}if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);}if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);startActivity(newIntent);finish();
}
  • 5 之后启动InstallInstalling,因为Activity中的默认成员方法的执行顺序是onCreate->onStart->onResume...其中onCreate的方法中主要过程包括:

    • 1 获取待安装应用信息
    • 2 根据应用安装与否决定如何调用方法
    • 3 如果已存在,则直接调用PackageManager.installExistingPackage
    • 4 如果不存在则构造session
    • 5 之后则为安装事件广播添加一个监测
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.install_installing);// 获取待安装应用信息ApplicationInfo appInfo = getIntent().getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);mPackageURI = getIntent().getData();// 如果应用已存在,则使用这条路径安装if ("package".equals(mPackageURI.getScheme())) {try {getPackageManager().installExistingPackage(appInfo.packageName);launchSuccess();} catch (PackageManager.NameNotFoundException e) {launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);}} else { //否则使用session提交安装应用final File sourceFile = new File(mPackageURI.getPath());PackageUtil.initSnippetForNewApp(this, PackageUtil.getAppSnippet(this, appInfo,sourceFile), R.id.app_snippet);// 如果session已存在,则获取sessionId等数据if (savedInstanceState != null) {mSessionId = savedInstanceState.getInt(SESSION_ID);mInstallId = savedInstanceState.getInt(INSTALL_ID);// Reregister for result; might instantly call back if result was delivered while// activity was destroyedtry {InstallEventReceiver.addObserver(this, mInstallId,this::launchFinishBasedOnResult);} catch (EventResultPersister.OutOfIdsException e) {// Does not happen}} else { // 否则创建sessionPackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);// ......try {mInstallId = InstallEventReceiver.addObserver(this, EventResultPersister.GENERATE_NEW_ID,this::launchFinishBasedOnResult);} catch (EventResultPersister.OutOfIdsException e) {launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);}//创建sessiontry {mSessionId = getPackageManager().getPackageInstaller().createSession(params);} catch (IOException e) {launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);}}//......mSessionCallback = new InstallSessionCallback();}
}
  • 6 InstallInstalling.onStart中注册回调函数,然后onResume中执行AsyncTask。
@Override
protected void onResume() {super.onResume();// This is the first onResume in a single life of the activityif (mInstallingTask == null) {PackageInstaller installer = getPackageManager().getPackageInstaller();PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);//如果session非空,则执行AsyncTaskif (sessionInfo != null && !sessionInfo.isActive()) {mInstallingTask = new InstallingAsyncTask();mInstallingTask.execute();} else {// we will receive a broadcast when the install is finishedmCancelButton.setEnabled(false);setFinishOnTouchOutside(false);}}
}
  • 7 AsyncTask是Android提供的一种轻量级的异步类,执行过程可以表示为5个阶段。

    • 1 准备执行,onPreExecute()
    • 2 正在后台执行,doInBackgroud()
    • 3 进度更新,onProcessUpdate()
    • 4 完成后台任务,onPostExecute()
    • 5 取消任务,onCacelled()

此处重写了方法onPostExecute方法,源码如下。

@Override
protected void onPostExecute(PackageInstaller.Session session) {if (session != null) {Intent broadcastIntent = new Intent(BROADCAST_ACTION);broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);broadcastIntent.setPackage(getPackageManager().getPermissionControllerPackageName());broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);PendingIntent pendingIntent = PendingIntent.getBroadcast(InstallInstalling.this,mInstallId,broadcastIntent,PendingIntent.FLAG_UPDATE_CURRENT);//提交sessionsession.commit(pendingIntent.getIntentSender());mCancelButton.setEnabled(false);setFinishOnTouchOutside(false);} else {getPackageManager().getPackageInstaller().abandonSession(mSessionId);if (!isCancelled()) {launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);}}
}
  • 8 session对象传输顺序为:

    • 1 PackageInstaller.Session.commit
    • 2 IPackageInstallerSession.commit
    • 3 PackageInstallerSession.commit
    • 4 Handler.Callback.handleMessage
    • 5 PackageInstallerSession.commitLock
    • 6 PMS.installStage
      这里是不是似曾相识,这一步跟Adb安装的第4步几乎相同,之后就调用installStage方法完成安装。

#3 总结

安装应用的场景就是上述所示的PMS构造函数安装、adb安装、网络下载安装、本地安装。其最终的入口为PMS.prepareAppDataLeafLIF,然后调用Installer类完成安装,这里涉及到System_server到Installd守护进程的转移。

转载于:https://www.cnblogs.com/z1987/p/8974719.html

Android中应用安装分析相关推荐

  1. Android中AppWidget的分析与应用:AppWidgetProvider .

    from: http://blog.csdn.net/thl789/article/details/7887968 本文从开发AppWidgetProvider角度出发,看一个AppWidgetPrv ...

  2. 【Android】提取Android中已安装app的apk

    提取Android中已安装的apk,这个需求很多时候都会遇到.比如从google play上安装过apk后,如何提取出来给别人用? 本文1. 先介绍转载的apk提取方法并 2. 验证提取出来的apk和 ...

  3. android中SELINUX规则分析和语法简介

    点击打开链接 1. SELINUX是可以理解为一种Android上面的安全机制,是有美国国家安全局和一些公司设计的一个针对linux的安全加强系统 我们可以通过配置SELINUX的相关policy,来 ...

  4. Android中APK安装流程解析

    前言:大家都知道,手机关机以后,就是一个冰冷的砖头,只能用来做防身的利器,但是开机后,点击桌面上的任何一个图片,都能开启一个APP,这说明在开机过程中,系统把已经安装好的APP加载到内存中,这到底是怎 ...

  5. Android中Parcel的分析以及使用

    简单点来说:Parcel就是一个存放读取数据的容器, android系统中的binder进程间通信(IPC)就使用了Parcel类来进行客户端与服务端数据的交互,而且AIDL的数据也是通过Parcel ...

  6. android linux应用安装位置,Android中App安装位置详解

    Android应用可以安装在本机自带存储,同时也可以安装到外部存储(SD卡).自从API 8后也就是Android2.2后,我们能使APK安装到外部存储上.这是一个可选的特性,在工程的manifest ...

  7. 从源码角度解析Android中APK安装过程

    从源码角度解析Android中APK的安装过程 1. Android中APK简介 Android应用Apk的安装有如下四种方式: 1.1 系统应用安装 没有安装界面,在开机时自动完成 1.2 网络下载 ...

  8. Android中图片压缩分析(上)

    此文章首发:https://mp.weixin.qq.com/s/QZ-XTsO7WnNvpnbr3DWQmg 一.前言 在 Android 中进行图片压缩是非常常见的开发场景,主要的压缩方法有两种: ...

  9. Android中Bitmap的分析与使用

    下面总结一下Bitmap的分析与使用 Bitmap的创建 创建Bitmap的时候,Java不提供new Bitmap()的形式去创建,而是通过BitmapFactory中的静态方法去创建,如:Bitm ...

最新文章

  1. 05-连接数据库方法
  2. grunt -- javascript自动化工具
  3. Angular 服务器端渲染的一个错误消息 - No provider for InjectionToken REQUEST
  4. SAP Spartacus language和currency Component data加载
  5. 最常被程序员们谎称读过的计算机书籍
  6. php 前置匹配,浅析PHP正则表达式匹配的特定实现
  7. 自媒体公约:良性发展大于利益本能
  8. linux 连接两个异构网,用cheops-ng管理Linux异构网络(图)
  9. VS2015 fatal error C1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include “stdafx.h”
  10. 使用NVIDIA端到端深度学习平台进行缺陷自动检测
  11. java excel 插入新行_使用POI往EXCEL中插入行
  12. springBoot配置 https 和http转htpps协议。
  13. Linux下RTL8723BE无线网卡驱动问题解决方法
  14. 【MySQL】navicat for mysql 安装及使用
  15. ThinkPHP中的getLastSql函数---获取上次执行的SQL语句
  16. Odoo ERP 14 客户关系管理
  17. PCIe四通道光纤数据传输板PCIe-Fib-4Ch5G
  18. 飞思卡尔智能车总结 之中断的处理方法
  19. 小程序下拉刷新 上拉加载等多
  20. ACA大数据助理工程师题库总结

热门文章

  1. 【收藏】idea 背景图插件
  2. 【收藏】为什么在Scala中可以在运行时将AnyVal转换为AnyRef?AnyVal转换为AnyRef
  3. Spark分区与并行度
  4. 【网址收藏】windows安装Docker Desktop常见问题整理
  5. JVM内存区域:常用指令集
  6. Linux 查找redis进程命令:ps -ef | grep redis
  7. 【软考】2017年11月软件设计师上午真题5-8题答案解析
  8. 【学亮IT手记】jQuery DOM插入操作
  9. Hibernate的配置详解
  10. Spring注解开发-属性依赖注入指定名称的bean