在上一篇文章 Android包管理机制2 PackageInstaller安装APK 中,我们学习了 PackageInstaller 是如何安装 APK 的,最后会将 APK 的信息交由 PMS 处理。那么 PMS 是如何处理的呢?这篇文章会详细分析其中的细节。
一 PackageHandler处理安装消息
APK 的信息交由 PMS 后,PMS 通过向 PackageHandler 发送消息来驱动 APK 的复制和安装工作。
先来查看 PackageHandler 处理安装消息的调用时序图。
接着上一篇文章的代码逻辑来查看 PMS 的 installStage 方法。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void installStage(String packageName, File stagedDir, String stagedCid,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
Certificate[][] certificates) {
...
final Message msg = mHandler.obtainMessage(INIT_COPY);//1
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);//2
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
...
mHandler.sendMessage(msg);//3
}
注释2处创建 InstallParams,它对应于包的安装数据。注释1处创建了类型为 INIT_COPY 的消息,在注释3处将 InstallParams 通过消息发送出去。
1.1 对INIT_COPY的消息的处理
处理 INIT_COPY 类型的消息的代码如下所示。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
PackageManagerService.PackageHandler
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
//mBound用于标识是否绑定了服务,默认值为false
if (!mBound) {//1
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
//如果没有绑定服务,重新绑定,connectToService方法内部如果绑定成功会将mBound置为true
if (!connectToService()) {//2
Slog.e(TAG, "Failed to bind to media container service");
params.serviceError();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
params.traceCookie);
}
//绑定服务失败则return
return;
} else {
//绑定服务成功,将请求添加到ArrayList类型的mPendingInstalls中,等待处理
mPendingInstalls.add(idx, params);
}
} else {
//已经绑定服务
mPendingInstalls.add(idx, params);
if (idx == 0) {
mHandler.sendEmptyMessage(MCS_BOUND);//3
}
}
break;
}
....
}
}
}
PackageHandler 继承自 Handler,它被定义在 PMS 中,doHandleMessage 方法用于处理各个类型的消息,来查看对 INIT_COPY 类型消息的处理。
注释1处的 mBound 用于标识是否绑定了 DefaultContainerService,默认值为 false。
DefaultContainerService 是用于检查和复制可移动文件的服务,这是一个比较耗时的操作,因此 DefaultContainerService 没有和 PMS 运行在同一进程中,它运行在 com.android.defcontainer 进程,通过 IMediaContainerService 和 PMS 进行 IPC 通信,如下图所示。
注释2处的 connectToService 方法用来绑 定DefaultContainerService。
注释3处发送 MCS_BOUND 类型的消息,触发处理第一个安装请求。查看注释2处的 connectToService 方法:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#PackageHandler
private boolean connectToService() {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
" DefaultContainerService");
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
if (mContext.bindServiceAsUser(service, mDefContainerConn,
Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {//1
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mBound = true;//2
return true;
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return false;
}
注释2处如果绑定 DefaultContainerService 成功,mBound 会置为 ture 。
注释1处的 bindServiceAsUser 方法会传入 mDefContainerConn,bindServiceAsUser 方法的处理逻辑和我们调用 bindService 是类似的,服务建立连接后,会调用 onServiceConnected 方法:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
class DefaultContainerConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
final IMediaContainerService imcs = IMediaContainerService.Stub
.asInterface(Binder.allowBlocking(service));
mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, Object));//1
}
public void onServiceDisconnected(ComponentName name) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
}
}
注释1处发送了 MCS_BOUND 类型的消息,与 PackageHandler.doHandleMessage 方法的注释3处不同的是,这里发送消息带了 Object 类型的参数,这里会对这两种情况来进行讲解,一种是消息不带 Object 类型的参数,一种是消息带 Object 类型的参数。
1.2 对MCS_BOUND类型的消息的处理
消息不带 Object 类型的参数,查看对 MCS_BOUND 类型消息的处理:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
case MCS_BOUND: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
if (msg.obj != null) {//1
mContainerService = (IMediaContainerService) msg.obj;//2
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
}
if (mContainerService == null) {//3
if (!mBound) {//4
Slog.e(TAG, "Cannot bind to media container service");
for (HandlerParams params : mPendingInstalls) {
params.serviceError();//5
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
params.traceMethod, params.traceCookie);
}
return;
}
//绑定失败,清空安装请求队列
mPendingInstalls.clear();
} else {
//继续等待绑定服务
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {
...
else {
Slog.w(TAG, "Empty queue");
}
break;
}
如果消息不带 Object 类型的参数,就无法满足注释1处的条件,注释2处的 IMediaContainerService 类型的 mContainerService 也无法被赋值,这样就满足了注释3处的条件。
如果满足注释4处的条件,说明还没有绑定服务,而此前已经在 PackageHandler.doHandleMessage 方法的注释2处调用绑定服务的方法了,这显然是不正常的,因此在注释5处负责处理服务发生错误的情况。如果不满足注释4处的条件,说明已经绑定服务了,就会打印出系统log,告知用户等待系统绑定服务。
消息带 Object 类型的参数
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
case MCS_BOUND: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
if (msg.obj != null) {
...
}
if (mContainerService == null) {//1
...
} else if (mPendingInstalls.size() > 0) {//2
HandlerParams params = mPendingInstalls.get(0);//3
if (params != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
if (params.startCopy()) {//4
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Checking for more work or unbind...");
//如果APK安装成功,删除本次安装请求
if (mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) {
if (mBound) {
//如果没有安装请求了,发送解绑服务的请求
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting delayed MCS_UNBIND");
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
sendMessageDelayed(ubmsg, 10000);
}
} else {
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting MCS_BOUND for next work");
//如果还有其他的安装请求,接着发送MCS_BOUND消息继续处理剩余的安装请求
mHandler.sendEmptyMessage(MCS_BOUND);//5
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}else {
Slog.w(TAG, "Empty queue");//6
}
break;
}
如果 MCS_BOUND 类型消息带 Object 类型的参数就不会满足注释1处的条件,就会调用注释2处的判断,如果安装请求数不大于0就会打印出注释6处的 log,说明安装请求队列是空的。安装完一个 APK 后,就会在注释5处发出 MSC_BOUND 消息,继续处理剩下的安装请求直到安装请求队列为空。
注释3处得到安装请求队列第一个请求 HandlerParams ,如果 HandlerParams 不为 null 就会调用注释4处的 HandlerParams 的 startCopy 方法,用于开始复制 APK 的流程。
二 复制APK
先来查看复制 APK 的时序图。
HandlerParams 是 PMS 中的抽象类,它的实现类为 PMS 的内部类 InstallParams。HandlerParams 的 startCopy 方法如下所示。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#HandlerParams
final boolean startCopy() {
boolean res;
try {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
//startCopy方法尝试的次数,超过了4次,就放弃这个安装请求
if (++mRetries > MAX_RETRIES) {//1
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mHandler.sendEmptyMessage(MCS_GIVE_UP);//2
handleServiceError();
return false;
} else {
handleStartCopy();//3
res = true;
}
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
handleReturnCode();//4
return res;
}
注释1处的 mRetries 用于记录 startCopy 方法调用的次数,调用 startCopy 方法时会先自动加1,如果次数大于4次就放弃这个安装请求:在注释2处发送 MCS_GIVE_UP 类型消息,将第一个安装请求(本次安装请求)从安装请求队列 mPendingInstalls 中移除掉。
注释4处用于处理复制 APK 后的安装 APK 逻辑,第3小节中会再次提到它。注释3处调用了抽象方法 handleStartCopy,它的实现在 InstallParams 中,如下所示。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#InstallParams
public void handleStartCopy() throws RemoteException {
...
//确定APK的安装位置。onSd:安装到SD卡, onInt:内部存储即Data分区
// ephemeral:安装到临时存储(Instant Apps安装)
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
if (onInt && onSd) {
// APK不能同时安装在SD卡和Data分区
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
//安装标志冲突,Instant Apps不能安装到SD卡中
} else if (onSd && ephemeral) {
Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
//获取APK的少量的信息
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
packageAbiOverride);//1
if (DEBUG_EPHEMERAL && ephemeral) {
Slog.v(TAG, "pkgLite for install: " + pkgLite);
}
...
if (ret == PackageManager.INSTALL_SUCCEEDED) {
//判断安装的位置
int loc = pkgLite.recommendedInstallLocation;
if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
}
...
}else{
loc = installLocationPolicy(pkgLite);//2
...
}
}
//根据InstallParams创建InstallArgs对象
final InstallArgs args = createInstallArgs(this);//3
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
...
if (!origin.existing && requiredUid != -1
&& isVerificationEnabled(
verifierUser.getIdentifier(), installFlags, installerUid)) {
...
} else{
ret = args.copyApk(mContainerService, true);//4
}
}
mRet = ret;
}
handleStartCopy 方法的代码很多,这里截取关键的部分。
注释1处通过 IMediaContainerService 跨进程调用 DefaultContainerService 的 getMinimalPackageInfo 方法,该方法轻量解析 APK 并得到 APK 的少量信息,轻量解析的原因是这里不需要得到 APK 的全部信息,APK 的少量信息会封装到 PackageInfoLite 中。接着在注释2处确定 APK 的安装位置。注释3处创建了 InstallArgs,InstallArgs 是一个抽象类,定义了 APK 的安装逻辑,比如复制和重命名 APK 等,它有3个子类,都被定义在 PMS 中,如下图所示。
其中 FileInstallArgs 用于处理安装到非 ASEC 的存储空间的 APK,也就是内部存储空间(Data分区),AsecInstallArgs 用于处理安装到 ASEC 中(mnt/asec)即 SD 卡中的 APK。MoveInstallArgs 用于处理已安装 APK 的移动的逻辑。
对 APK 进行检查后就会在注释4处调用 InstallArgs 的 copyApk 方法进行安装。
不同的 InstallArgs 子类会有着不同的处理,这里以 FileInstallArgs 为例。FileInstallArgs 的 copyApk 方法中会直接 return FileInstallArgs 的 doCopyApk 方法:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#FileInstallArgs
private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
...
try {
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
//创建临时文件存储目录
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);//1
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
...
int ret = PackageManager.INSTALL_SUCCEEDED;
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);//2
...
return ret;
}
注释1处用于创建临时存储目录,比如 /data/app/vmdl18300388.tmp,其中 18300388 是安装的 sessionId。
注释2处通过 IMediaContainerService 跨进程调用 DefaultContainerService 的 copyPackage 方法,这个方法会在 DefaultContainerService
所在的进程中将 APK 复制到临时存储目录,比如 /data/app/vmdl18300388.tmp/base.apk。
目前为止 APK 的复制工作就完成了,接着就是 APK 的安装过程了。
三 安装APK
照例先来查看安装 APK 的时序图。
我们回到 APK 的复制调用链的头部方法:HandlerParams 的 startCopy 方法,在注释4处会调用 handleReturnCode 方法,它的实现在 InstallParams 中,如下所示。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void handleReturnCode() {
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
}
}
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
PackageInstalledInfo 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);//1
synchronized (mInstallLock) {
installPackageTracedLI(args, res);//2
}
//安装后收尾
args.doPostInstall(res.returnCode, res.uid);//3
}
...
}
});
}
handleReturnCode 方法中只调用了 processPendingInstall 方法,注释1处用于检查 APK 的状态的,在安装前确保安装环境的可靠,如果不可靠会清除复制的 APK 文件,注释3处用于处理安装后的收尾操作,如果安装不成功,删除掉安装相关的目录与文件。主要来看注释2处的 installPackageTracedLI 方法,其内部会调用 PMS 的 installPackageLI 方法。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
...
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 {
//解析APK
pkg = pp.parsePackage(tmpPackageFile, parseFlags);//1
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
...
pp = null;
String oldCodePath = null;
boolean systemApp = false;
synchronized (mPackages) {
// 检查APK是否存在
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
String oldName = mSettings.getRenamedPackageLPr(pkgName);//获取没被改名前的包名
if (pkg.mOriginalPackages != null
&& pkg.mOriginalPackages.contains(oldName)
&& mPackages.containsKey(oldName)) {
pkg.setPackageName(oldName);//2
pkgName = pkg.packageName;
replace = true;//设置标志位表示是替换安装
if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
+ oldName + " pkgName=" + pkgName);
}
...
}
PackageSetting ps = mSettings.mPackages.get(pkgName);
//查看Settings中是否存有要安装的APK的信息,如果有就获取签名信息
if (ps != null) {//3
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
if (libraryEntry != null) {
signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
}
}
//检查签名的正确性
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;
}
}
...
}
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
//遍历每个权限,对权限进行处理
PackageParser.Permission perm = pkg.permissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm.info.name);
}
}
}
if (systemApp) {
if (onExternal) {
//系统APP不能在SD卡上替换安装
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
return;
} else if (instantApp) {
//系统APP不能被Instant App替换
res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
"Cannot update a system app with an instant app");
return;
}
}
...
//重命名临时文件
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {//4
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
return;
}
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
"installPackageLI")) {
if (replace) {//5
//替换安装
...
replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, res, args.installReason);
} else {
//安装新的APK
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res, args.installReason);
}
}
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
//更新应用程序所属的用户
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
ps.setUpdateAvailable(false /*updateAvailable*/);
}
...
}
}
installPackageLI 方法的代码有将近500行,这里截取主要的部分,主要做了几件事:
- 创建 PackageParser 解析 APK
- 检查 APK 是否存在,如果存在就获取此前没被改名前的包名并在注释1处赋值给 PackageParser.Package 类型的 pkg,在注释3处将标志位 replace 置为 true 表示是替换安装
- 注释3处,如果 Settings 中保存有要安装的 APK 的信息,说明此前安装过该 APK,则需要校验 APK 的签名信息,确保安全的进行替换
- 在注释4处将临时文件重新命名,比如前面提到的 /data/app/vmdl18300388.tmp/base.apk,重命名为 /data/app/ 包名-1/base.apk。这个新命名的包名会带上一个数字后缀1,每次升级一个已有的 App,这个数字会不断的累加
- 系统 APP 的更新安装会有两个限制,一个是系统 APP 不能在 SD 卡上替换安装,另一个是系统 APP 不能被 Instant App 替换
- 注释5处根据 replace 来做区分,如果是替换安装就会调用 replacePackageLIF 方法,其方法内部还会对系统 APP 和非系统 APP 进行区分处理,如果是新安装 APK 会调用 installNewPackageLIF 方法
这里我们以新安装 APK 为例,会调用 PMS 的 installNewPackageLIF 方法。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res, int installReason) {
...
try {
//扫描APK
PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
System.currentTimeMillis(), user);
//更新Settings信息
updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
//安装成功后,为新安装的应用程序准备数据
prepareAppDataAfterInstallLIF(newPackage);
} else {
//安装失败则删除APK
deletePackageLIF(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);
}
installNewPackageLIF 主要做了以下3件事:
- 扫描 APK,将 APK 的信息存储在 PackageParser.Package 类型的 newPackage 中,一个 Package 的信息包含了1个 base APK 以及0个或者多个 split APK
- 更新该 APK 对应的 Settings 信息,Settings 用于保存所有包的动态设置
- 如果安装成功就为新安装的应用程序准备数据,安装失败就删除 APK
安装 APK 的过程就讲到这里,就不再往下分析下去,有兴趣的同学可以接着深挖。
四 总结
本文主要讲解了 PMS 是如何处理 APK 安装的,主要有几个步骤:
- PackageInstaller 安装 APK 时会将 APK 的信息交由 PMS 处理,PMS 通过向 PackageHandler 发送消息来驱动 APK 的复制和安装工作
- PMS 发送 INIT_COPY 和 MCS_BOUND 类型的消息,控制 PackageHandler 来绑定 DefaultContainerService,完成复制 APK 等工作
- 复制 APK 完成后,会开始进行安装 APK 的流程,包括安装前的检查、安装 APK 和安装后的收尾工作