PMS安装APP流程
- 获取APK文件:在应用程序安装之前,需要先获取APK文件。APK文件是Android应用程序的安装包,包含了应用程序的代码和资源文件。
- 解析APK文件:PMS需要对APK文件进行解析,以获取应用程序的信息和组件信息,例如应用程序包名、版本号、权限列表、组件列表(如Activity、Service、Receiver等)。这一步通常由PackageParser类完成。
- 校验应用程序签名:在安装之前,PMS会校验应用程序的签名,以确保应用程序没有被篡改或伪装。签名校验是保证应用程序安全性的重要步骤。
- 安装应用:如果校验通过,PMS会为应用程序分配一个UID,并继续进行安装过程。这通常涉及文件复制、处理安装参数等步骤。
文件复制
PackageManagerService.java#installStage安装阶段:
- 创建了一个InstallParams对象
- 创建并发送了一个INIT_COPY的Message消息。
- InstallParams继承自HandlerParams,用来记录安装应用的参数。
InstallParams中有一个成员变量mArgs,是一个抽象类型InstallArgs,主要是用来执行APK的复制,真正的实现类包括FileInstallArgs用来完成非ASEC应用的安装,ASEC全称是Android Secure External Cache,MoveInstallArgs用来完成已安装应用的移动安装。
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);
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;
...
//发送信息拷贝INIT_COPY 信息
mHandler.sendMessage(msg);
}
PackageManagerService.java#PackageHandler包处理:connectToService()用于检查和复制可移动文件的服务发送MCS_BOUND信息,触发处理第一个安装请求。
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) {
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS", System.identityHashCode(mHandler));
//connectToService里面的DefaultContainerService是用于检查和复制可移动文件的服务
if (!connectToService()) {
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) { //5
//发送MCS_BOUND类型的消息,触发处理第一个安装请求
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
....
}
}
MCS_BOUND 流程处理:
case MCS_BOUND:
if (mContainerService == null) { //判断是否已经绑定了服务
if (!mBound) { //绑定服务的标识位,没有绑定成功
Slog.e(TAG, "Cannot bind to media container service");
for (HandlerParams params : mPendingInstalls) {
params.serviceError();
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) { //安装APK的队列
HandlerParams params = mPendingInstalls.get(0); //安装队列有参数
if (params != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
if (params.startCopy()) { //HandlerParams开始拷贝
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) { //已经绑定服务,需要发送一个解绑MCS_UNBIND的message
//如果没有安装请求了,发送解绑服务的请求
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);
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}else {
Slog.w(TAG, "Empty queue");
}
break;
DefaultContainerService: 真正处理复制APP文件的类
PackageManagerService.java#HandlerParams#startCopy开始复制:
- 尝试安装次数是否超过4次,超过就移除安装的列表数据
- handleStartCopy : //复制APK文件
- handleReturnCode : //开始安装APK
final boolean startCopy() {
boolean res;
try {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
//startCopy方法尝试的次数,超过了4次,就放弃这个安装请求
if (++mRetries > MAX_RETRIES) {
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mHandler.sendEmptyMessage(MCS_GIVE_UP); //发送放弃安装信息
handleServiceError();
return false;
} else {
handleStartCopy(); //复制APK文件
res = true;
}
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
handleReturnCode(); //处理复制APK后的安装APK逻辑
return res;
}
}
PackageManagerService.java#InstallParams#handleStartCopy复制apk文件:
- 获取APP的部分安装信息
- 获取APP的安装位置
- InstallArgs复制APP----> FileInstallArgs复制APP---->DefaultContainerService复制APP
InstallArgs做为抽象类,FileInstallArgs和MoveInstallArgs继承InstallArgs FileInstallArgs对data/data/包名(系统应用),MoveInstallArgs用于处理已安装APK的移动:
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分区
Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
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);
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); //确定APP安装的位置
...
}
}
//根据InstallParams创建InstallArgs对象
final InstallArgs args = createInstallArgs(this); InstallArgs作用时:复制和重命名APK
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
...
if (!origin.existing && requiredUid != -1 && isVerificationEnabled(verifierUser.getIdentifier(), installFlags, installerUid)) {
...
} else{
ret = args.copyApk(mContainerService, true); // InstallArgs开始复制APP
}
}
mRet = ret;
}
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);
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);
...
return ret;
}
安装APK
- 在安装前检查是否环境的可靠,如果不可靠会清除复制的APK文件。
- installPackageTracedLI其内部会调用PMS的installPackageLI方法,进行APP安装。
- 处理安装后操作,如果安装不成功,删除掉安装相关的目录与文件。
final boolean startCopy() {
......
handleStartCopy(); //APP文件复制拷贝
.....
//开始安装APP
handleReturnCode();
}
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);
synchronized (mInstallLock) {
//开始安装
installPackageTracedLI(args, res);
}
//安装后收尾
args.doPostInstall(res.returnCode, res.uid);
}
...
}
});
}