Android6.0 PackageManagerService(PMS)-安装
2017-08-21 16:58
567 查看
目录见上↑↑↑,整个安装过程可分为三步:
1.权限检查
2.复制文件
3.装载应用
其主要流程如图所示:
2.1 INIT_COPY
INIT_COPY消息的处理中将绑定DefaultContainerService,因为这是一个异步的过程,要等待的绑定的结果通过onServiceConnected()返回,所以这里就将安装的参数信息放到了mPendingInstalls列表中。
如果这个Service之前就绑定好了,现在就不要再次绑定了,安装信息同样要放到mPendingInstalls中。
如果有多个安装请求同时到达,就可以通过mPendingInstalls列表对它们进行排队。
如果列表中只有一项,说明没有更多的安装请求,因此这种情况下,需要立即发出MCS_BOUND消息,进入下一步的处理。(应该有个INIT_COPY的流程图 简书那个)
绑定成功后在onServiceConnected中将一个IBinder转换成了一个IMediaContainerService。这个就是在onServiceConnected回调函数中根据参数传进来的IMediaContainerService.Stub的对象引用创建的一个远程代理对象。以后PMS务通过该代理对象访问DefaultContainerService服务。
2.2 MCS_BOUND
MCS_BOUND消息的处理过程:调用InstallParams类的startCopy()方法来执行拷贝操作。只要mPendingInstalls中还有安装信息,就会重复发送MCS_BOUND消息,直到所有的应用都安装完毕,然后在发送一个延时10秒的MCS_UNBIND消息。(这块再来个流程图看的明显一些)
2.2.1 MCS_UNBOUND
MCS_UNBIND消息的处理过程:当mPendingInstalls中没有安装信息的时候,就调用disconnectService方法断开与DefaultContainerService的连接;如果发现还有安装信息,则继续发送MCS_BOUND消息。
2.3 拷贝方法startCopy
startCopy()方法通过调用其子类InstallParams的handleStartCopy()来完成拷贝操作。startCopy主要工作是进行错误处理,当捕获到handleStartCopy跑出的异常时,startCopy将发送MCS_RECONNECT消息。在对MCS_RECONNECT消息的处理中,将会重新绑定DefaultContainerService,如果绑定成功,那安装过程将会重新开始。startCopy也将会再次被调用,重试的次数记录在mRetries中
13834
,当累计重试超过4次时,安装将失败。如果安装失败,那么startCopy将会调用handleReturnCode()来继续处理。
handleStartCopy()方法会判断该app应该安装到哪里,如果安装空间不足的话,会尝试在清理一些cache空间后,再次尝试安装。该方法中很多代码是在将一些信息通过发送Intent android.intent.action.PACKAGE_NEEDS_VERIFICATION 给系统中所有接收该Intent进行处理。如果不需要校验的话,就直接调用InstallArgs的copyApk()方法。主要流程如图所示:
2.3.1.1 createInstallArgs
此处讨论安装在内部存储的,所以创建的就是FileInstallArgs了,那么调用的copyApk,也是FileInstallArgs的了。
copyApk主要是对apk内容进行拷贝,FileInstallArgs.copyApk的数据流如下:
创建data/app下的目录并修改权限为755
拷贝base.apk(DefaultContainerService.java里的copypackage函数,里用copyfile函数 构建输入输出流,调用Stream的方法进行拷贝)
拷贝so文件
3. 装载应用
在前面的处理MCS_BOUND时调用的HandlerParams的startCopy方法(2.3小节)中当复制完文件之后,会调用InstallParams的handleReturnCode方法。
3.1 handleReturnCode:
processPendingInstall()方法中post了一个消息,这样安装过程将以异步的方式继续执行。在post消息中,首先是调用installPackageLI()来装载应用,接下来的一大段代码是在执行设备备份操作,备份是通过BackupManagerService来完成的,暂不分析。备份完成之后,通过发送POST_INSTALL消息继续处理。
3.2 installPackageLI[重要]
分析在代码注释中
执行完installPackageLI之后,返回processPendingInstall方法中。
该消息的处理主要就是在发送广播(很多个),应用安装完成之后要通知系统中的其他应用开始处理,安装到此结束~
1.权限检查
2.复制文件
3.装载应用
1.权限检查
调用installPackageAsUser函数public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer, int installFlags, String installerPackageName, VerificationParams verificationParams, String packageAbiOverride, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); final int callingUid = Binder.getCallingUid();// 利用binder机制,获取安装发起进程的uid //检查权限 该函数主要是检查进程是否有权限安装 展开见1.1 enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser"); //检查当前用户是否具备安装app的权限 if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { try { if (observer != null) { observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null); } } catch (RemoteException re) { } return; } //如果是发起端进程是shell或者root,那么添加flags:PackageManager.INSTALL_FROM_ADB if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) { installFlags |= PackageManager.INSTALL_FROM_ADB; } else { // 从flags中去掉INSTALL_FROM_ADB和INSTALL_ALL_USERS installFlags &= ~PackageManager.INSTALL_FROM_ADB; installFlags &= ~PackageManager.INSTALL_ALL_USERS; } UserHandle user;//创建一个当前用户的handle if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) { user = UserHandle.ALL; } else { user = new UserHandle(userId); } // Only system components can circumvent runtime permissions when installing. // Android 6.0 当权限属于运行时权限时,需要弹出框,让用户授权,对于system app,应该取消运行时权限弹框授权,而是直接授权。 // 那么就要在system app中加入INSTALL_GRANT_RUNTIME_PERMISSIONS;安装第三方app,当然没有INSTALL_GRANT_RUNTIME_PERMISSIONS了 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"); } verificationParams.setInstallerUid(callingUid); final File originFile = new File(originPath); final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);//后续判断APK安装到哪里时,会用到 //构造InstallParams,注意packageAbiOverride为null,然后利用Android中的Handler机制,发送给相关的线程进行安装。 final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName, null, verificationParams, user, packageAbiOverride, null); mHandler.sendMessage(msg); }
其主要流程如图所示:
1.1 enforceCrossUserPermission
installPackageAsUser方法的前部调用了enforceCrossUserPermission,代码如下:void enforceCrossUserPermission(int callingUid, int userId, boolean requireFullPermission, boolean checkShell, String message) { if (userId < 0) { throw new IllegalArgumentException("Invalid userId " + userId); } //当前userid和发起者进程所属的userid一致,那么OK,直接返回 // 我们现在就属于这种情况 if (userId == UserHandle.getUserId(callingUid)) return; //不一致,那就要看是不是SYSTEM进程了,依旧不是,那么执行下逻辑,抛异常 if (callingUid != Process.SYSTEM_UID && callingUid != 0) { if (requireFullPermission) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); } else { try { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); } catch (SecurityException se) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS, message); } } } }
2.复制文件
权限检查中,installPackageAsUser方法尾部会发送一个INIT_COPY消息,接着会使用doHandleMessage方法处理收到的消息:2.1 INIT_COPY
void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { HandlerParams params = (HandlerParams) msg.obj;//取出InstallParams int idx = mPendingInstalls.size(); if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params); // If a bind was already initiated we dont really need to do anything. // The pending install will be processed later on. if (!mBound) { // If this is the only one pending we might have to bind to the service again. // 将绑定DefaultContainerService服务 if (!connectToService()) { Slog.e(TAG, "Failed to bind to media container service"); params.serviceError();//连接服务失败 return; } else { // Once we bind to the service, the first pending request will be processed. // 连接成功,把安装信息保存到mPendingInstalls中,等待收到连接的返回消息后,再继续安装 mPendingInstalls.add(idx, params); } } else { // 加入安装信息 mPendingInstalls.add(idx, params); // Already bound to the service. Just make // sure we trigger off processing the first request. if (idx == 0) { //如果mPendingInstalls中只有一项,那么立即发送MCS_BOUND消息 mHandler.sendEmptyMessage(MCS_BOUND); } } break; } ... case 巴拉巴拉 } }
INIT_COPY消息的处理中将绑定DefaultContainerService,因为这是一个异步的过程,要等待的绑定的结果通过onServiceConnected()返回,所以这里就将安装的参数信息放到了mPendingInstalls列表中。
如果这个Service之前就绑定好了,现在就不要再次绑定了,安装信息同样要放到mPendingInstalls中。
如果有多个安装请求同时到达,就可以通过mPendingInstalls列表对它们进行排队。
如果列表中只有一项,说明没有更多的安装请求,因此这种情况下,需要立即发出MCS_BOUND消息,进入下一步的处理。(应该有个INIT_COPY的流程图 简书那个)
2.1.1 connectToService
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.OWNER)) { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mBound = true; return true; } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return false; }
绑定成功后在onServiceConnected中将一个IBinder转换成了一个IMediaContainerService。这个就是在onServiceConnected回调函数中根据参数传进来的IMediaContainerService.Stub的对象引用创建的一个远程代理对象。以后PMS务通过该代理对象访问DefaultContainerService服务。
2.2 MCS_BOUND
case MCS_BOUND: { if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound"); if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; } if (mContainerService == null) {//如果刚才绑定的DefaultContainerService失败 if (!mBound) { // Something seriously wrong since we are not bound and we are not waiting for connection. Bail out. Slog.e(TAG, "Cannot bind to media container service"); for (HandlerParams params : mPendingInstalls) { // Indicate service bind error // 连接失败,通过参数中的毁掉接口,通知调用者出错了 params.serviceError(); } mPendingInstalls.clear(); } else { Slog.w(TAG, "Waiting to connect to media container service"); } } else if (mPendingInstalls.size() > 0) { HandlerParams params = mPendingInstalls.get(0); if (params != null) { if (params.startCopy()) {//==============执行拷贝操作2.3 // We are done... look for more work or to go idle. if (DEBUG_SD_INSTALL) Log.i(TAG, "Checking for more work or unbind..."); // Delete pending install 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); // Unbind after a little delay, to avoid continual thrashing. // 如果没有安装信息了,则发送延时10秒的MCS_UNBIND消息 sendMessageDelayed(ubmsg, 10000); } } else { // There are more pending requests in queue. // Just post MCS_BOUND message to trigger processing of next pending install. // 如果还有安装信息,则继续发送MCS_BOUND消息 if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting MCS_BOUND for next work"); mHandler.sendEmptyMessage(MCS_BOUND); } } } } else { // Should never happen ideally. Slog.w(TAG, "Empty queue"); } break; }
MCS_BOUND消息的处理过程:调用InstallParams类的startCopy()方法来执行拷贝操作。只要mPendingInstalls中还有安装信息,就会重复发送MCS_BOUND消息,直到所有的应用都安装完毕,然后在发送一个延时10秒的MCS_UNBIND消息。(这块再来个流程图看的明显一些)
2.2.1 MCS_UNBOUND
case MCS_UNBIND: { // If there is no actual work left, then time to unbind. if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind"); if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) { if (mBound) { if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()"); disconnectService(); } } else if (mPendingInstalls.size() > 0) { // There are more pending requests in queue. // Just post MCS_BOUND message to trigger processing of next pending install. mHandler.sendEmptyMessage(MCS_BOUND); } break; }
MCS_UNBIND消息的处理过程:当mPendingInstalls中没有安装信息的时候,就调用disconnectService方法断开与DefaultContainerService的连接;如果发现还有安装信息,则继续发送MCS_BOUND消息。
2.3 拷贝方法startCopy
final boolean startCopy() { boolean res; try { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); if (++mRetries > MAX_RETRIES) {// MAX_RETRIES为4 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { handleStartCopy();//展开2.3.1 res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } handleReturnCode();//会尝试重新绑定 展开,详见3 return res; }
startCopy()方法通过调用其子类InstallParams的handleStartCopy()来完成拷贝操作。startCopy主要工作是进行错误处理,当捕获到handleStartCopy跑出的异常时,startCopy将发送MCS_RECONNECT消息。在对MCS_RECONNECT消息的处理中,将会重新绑定DefaultContainerService,如果绑定成功,那安装过程将会重新开始。startCopy也将会再次被调用,重试的次数记录在mRetries中
13834
,当累计重试超过4次时,安装将失败。如果安装失败,那么startCopy将会调用handleReturnCode()来继续处理。
2.3.1 handleStartCopy
public void handleStartCopy() throws RemoteException{ int ret = PackageManager.INSTALL_SUCCEEDED; // If we're already staged, we've firmly committed to an install location // 新安装时staged为false,前面在创建origin时,传入的false // final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile); 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"); } } // 检查安装到哪里,SD卡还是内部 final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0; final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0; //精简版PackageInfo PackageInfoLite pkgLite = null; // 如果同时设置了安装在内部存储中和外部SD中,则报错 if (onInt && onSd) { // Check if both bits are set. Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, packageAbiOverride); //检查存储空间是否够安装该app,不够的话,执行如下分支 if (!origin.staged && pkgLite.recommendedInstallLocation == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { // TODO: focus freeing disk space on the target device final StorageManager storage = StorageManager.from(mContext); final long lowThreshold = storage.getStorageLowBytes(Environment.getDataDirectory()); final long sizeBytes = mContainerService.calculateInstalledSize( origin.resolvedPath, isForwardLocked(), packageAbiOverride); //尝试释放一些cache空间 if (mInstaller.freeCache(null, sizeBytes + lowThreshold) >= 0) { //然后重新获取PackageInfoLite pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, packageAbiOverride); } /* * The cache free must have deleted the file we * downloaded to install. * * TODO: fix the "freeCache" call to not delete * the file we care about. */ if (pkgLite.recommendedInstallLocation == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { pkgLite.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } } } if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果上面这些步骤没报错的话,再判断pkgLite的信息 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 if (loc == PackageHehandleStartCopylper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) { ret = PackageManager.INSTALL_FAILED_INVALID_APK; } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { ret = PackageManager.INSTALL_FAILED_INVALID_URI; } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) { ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; } else { // 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 flags if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { // Set the flag to install on external media. installFlags |= PackageManager.INSTALL_EXTERNAL; installFlags &= ~PackageManager.INSTALL_INTERNAL; } else { // Make sure the flag for installing on external // media is unset installFlags |= PackageManager.INSTALL_INTERNAL; installFlags &= ~PackageManager.INSTALL_EXTERNAL; } } } } // 其中abiOverride为null,创建一个安装参数对象 final InstallArgs args = createInstallArgs(this);//=====2.3.1.1展开 mArgs = args; if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果上面步骤没报错的话 /* * ADB installs appear as UserHandle.USER_ALL, and can only be performed by * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER. */ int userIdentifier = getUser().getIdentifier(); if (userIdentifier == UserHandle.USER_ALL && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) { userIdentifier = UserHandle.USER_OWNER; } /* * Determine if we have any installed package verifiers. If we * do, then we'll defer to them to verify the packages. */ final int requiredUid = mRequiredVerifierPackage == null ? -1 : getPackageUid(mRequiredVerifierPackage, userIdentifier); if (!origin.existing && requiredUid != -1 && isVerificationEnabled(userIdentifier, installFlags)) { //此处是进行校验,一大段代码 .................................. } else { /* * No package verification is enabled, so immediately start * the remote call to initiate copy using temporary file. */ ret = args.copyApk(mContainerService, true);//展开 } } mRet = ret; }
handleStartCopy()方法会判断该app应该安装到哪里,如果安装空间不足的话,会尝试在清理一些cache空间后,再次尝试安装。该方法中很多代码是在将一些信息通过发送Intent android.intent.action.PACKAGE_NEEDS_VERIFICATION 给系统中所有接收该Intent进行处理。如果不需要校验的话,就直接调用InstallArgs的copyApk()方法。主要流程如图所示:
2.3.1.1 createInstallArgs
private InstallArgs createInstallArgs(InstallParams params) { if (params.move != null) { // 移动app return new MoveInstallArgs(params); } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) { // 安装在SD return new AsecInstallArgs(params); } else { // 安装在内部存储 return new FileInstallArgs(params); } }
此处讨论安装在内部存储的,所以创建的就是FileInstallArgs了,那么调用的copyApk,也是FileInstallArgs的了。
copyApk主要是对apk内容进行拷贝,FileInstallArgs.copyApk的数据流如下:
创建data/app下的目录并修改权限为755
拷贝base.apk(DefaultContainerService.java里的copypackage函数,里用copyfile函数 构建输入输出流,调用Stream的方法进行拷贝)
拷贝so文件
3. 装载应用
在前面的处理MCS_BOUND时调用的HandlerParams的startCopy方法(2.3小节)中当复制完文件之后,会调用InstallParams的handleReturnCode方法。3.1 handleReturnCode:
void handleReturnCode() { if (mArgs != null) { processPendingInstall(mArgs, mRet); } } 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() {//向mHandler发一个Runnable对象,异步 public void run() { mHandler.removeCallbacks(this); // Result object to be returned PackageInstalledInfo res = new PackageInstalledInfo(); res.returnCode = currentStatus; res.uid = -1; res.pkg = null; if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { //欲安装阶段,主要是检查安装包的状态和安装环境,如果有问题就清理拷贝文件 args.doPreInstall(res.returnCode); synchronized (mInstallLock) { installPackageLI(args, res);//安装阶段, 展开详见3.2 } // 安装失败时,删除/data/app/包名中的内容 args.doPostInstall(res.returnCode, res.uid); } ..................................... // 用InstallArgs和PackageInstalledInfo构造一个PostInstallData对象,然后存放在mRunningInstalls里面 // 这样之后通过mRunningInstalls这个SparseArray查询就行 // 如果安装成功&需要备份,则调用BackupManagerService来完成备份,并设置doRestore为false ..................................... if (!doRestore) { // No restore possible, or the Backup Manager was mysteriously not // available -- just fire the post-install work request directly. if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token); Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);//展开详见3.3 mHandler.sendMessage(msg); } } }); }
processPendingInstall()方法中post了一个消息,这样安装过程将以异步的方式继续执行。在post消息中,首先是调用installPackageLI()来装载应用,接下来的一大段代码是在执行设备备份操作,备份是通过BackupManagerService来完成的,暂不分析。备份完成之后,通过发送POST_INSTALL消息继续处理。
3.2 installPackageLI[重要]
分析在代码注释中private void installPackageLI(InstallArgs args, PackageInstalledInfo res) { //此段做了一些初始化值的工作 final int installFlags = args.installFlags;//记录了app需要安装到哪里 final String installerPackageName = args.installerPackageName;// 安装程序的包名 final String volumeUuid = args.volumeUuid;// 与sd卡安装有关,一般为null final File tmpPackageFile = new File(args.getCodePath());// 前面copyApk中的临时阶段性文件夹/data/app/vmdl<安装回话id>.tmp/这个目录了 final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);// 没有设定INSTALL_FORWARD_LOCK final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)// 是否安装到外部存储 || (args.volumeUuid != null)); boolean replace = false;// 初始化替换flag为假 int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;// 设置浏览参数 if (args.move != null) {// 我们不是移动app,所以为null,不走这块代码 // moving a complete application; perfom an initial scan on the new install location scanFlags |= SCAN_INITIAL; } // Result object to be returned res.returnCode = PackageManager.INSTALL_SUCCEEDED; //此段解析APK,也就是解析AndroidMainifest.xml文件,将结果记录在PackageParser.Package中 if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile); // Retrieve PackageSettings and parse package // 设置解析apk的flags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0); PackageParser pp = new PackageParser();// 创建一个解析器 pp.setSeparateProcesses(mSeparateProcesses); pp.setDisplayMetrics(mMetrics);// 获得屏幕参数 final PackageParser.Package pkg; try { // 开始解析apk,传入tmpPackageFile为一个文件夹 pkg = pp.parsePackage(tmpPackageFile, parseFlags); } catch (PackageParserException e) { res.setError("Failed parse during installPackageLI", e); return; } // Mark that we have an install time CPU ABI override. pkg.cpuAbiOverride = args.abiOverride; String pkgName = res.name = pkg.packageName; if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) { if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) { res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI"); return; } } //此段搜集apk的签名信息,这块具体实现 待看.有两篇blog try { pp.collectCertificates(pkg, parseFlags); pp.collectManifestDigest(pkg); } catch (PackageParserException e) { res.setError("Failed collect during installPackageLI", e); return; } // 如果安装程序此前传入了一个清单文件,那么将解析到的清单文件与传入的进行对比。 //安装器的确传入了一个清单,PackageInstallerActivity中也解析了apk,那时记录了这个清单,并一并传入到这里了。 //这里又做了一步判断,判断两者是同一个apk. /* If the installer passed in a manifest digest, compare it now. */ if (args.manifestDigest != null) { if (DEBUG_INSTALL) { final String parsedManifest = pkg.manifestDigest == null ? "null" : pkg.manifestDigest.toString(); Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. " + parsedManifest); } if (!args.manifestDigest.equals(pkg.manifestDigest)) { res.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest changed"); return; } } else if (DEBUG_INSTALL) { final String parsedManifest = pkg.manifestDigest == null ? "null" : pkg.manifestDigest.toString(); Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest); } //分段 // Get rid of all references to package scan path via parser. pp = null; String oldCodePath = null; boolean systemApp = false; synchronized (mPackages) { // // 如果安装已经存在的应用的时候,PackageInstaller应用安装器会在会在installFlags中设置INSTALL_REPLACE_EXISTING if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { // 看看要替换的apk的包名是否存在原始包名 // 当app升级导致前后包名不一致的时候,需要记录仍然是原始包名, // 所以这里要先检查要覆盖的app是否是这样的情况,是的话设置包名为旧的包名 String oldName = mSettings.mRenamedPackages.get(pkgName); if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName) && mPackages.containsKey(oldName)) { // This package is derived from an original package, // and this device has been updating from that original // name. We must continue using the original name, so // rename the new package here. pkg.setPackageName(oldName); pkgName = pkg.packageName; replace = true; if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName=" + oldName + " pkgName=" + pkgName); } else if (mPackages.containsKey(pkgName)) { // This package, under its official name, already exists // on the device; we should replace it. replace = true; if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); } // Prevent apps opting out from runtime permissions // 当一个app按照6.0来编译的话,需要按照6.0的规则来解析app的权限。 if (replace) { PackageParser.Package oldPackage = mPackages.get(pkgName); final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion; final int newTargetSdk = pkg.applicationInfo.targetSdkVersion; if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1 && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) { res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE, "Package " + pkg.packageName + " new target SDK " + newTargetSdk + " doesn't support runtime permissions but the old" + " target SDK " + oldTargetSdk + " does."); return; } } } createDataDirsLI方法中调用mInstaller.install安装---->例如mActivities.addActivity(..) 把四大组件信息注册到PMS内部 PackageSetting ps = mSettings.mPackages.get(pkgName); // 如果ps不为null,同样说明,已经存在一个同包名的程序被安装,也就是还是处理覆盖安装的情况 // 这里主要是验证包名的签名,不一致的话,是不能覆盖安装的,另外版本号也不能比安装的低,否则也不能安装 if (ps != null) { if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); // 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(ps, scanFlags)) { if (!checkUpgradeKeySetLP(ps, pkg)) { res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + pkg.packageName + " upgrade keys do not match the " + "previously installed version"); return; } } else { try { //ps是已有的. pkg是新安装的. 检查签名 // 该函数分两步: // 如果有老版本的签名 则检查老版本的签名和新安装包的签名是否一致 // 如果有共享用户的签名,则检查共享用户的签名与新安装包的签名是否一致。 // 每一步都是三重机制:判断两个ArraySet是否相同->是否因为版本问题->恢复下证书(担心因为有变动)再试着比对一次 verifySignaturesLP(ps, pkg); } catch (PackageManagerException e) { res.setError(e.error, e.getMessage()); return; } } oldCodePath = mSettings.mPackages.get(pkgName).codePathString; if (ps.pkg != null && ps.pkg.applicationInfo != null) { systemApp = (ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); } // Check whether the newly-scanned package wants to define an already-defined perm // 此段 检查apk中定义的权限是否已被其他应用定义过,如果重定义的是系统应用定义的权限,那么忽略本app定义的这个权限;如果重定义的是非系统应用的权限,则本次安装失败。 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 (bp != null) { // If the defining package is signed with our cert, it's okay. This // also includes the "updating the same package" case, of course. // "updating same package" could also involve key-rotation. final boolean sigsOk; if (bp.sourcePackage.equals(pkg.packageName) && (bp.packageSetting instanceof PackageSetting) && (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting, scanFlags))) { sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg); } else { sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH; } if (!sigsOk) { // If the owning package is the system itself, we log but allow // install to proceed; we fail the install on all other permission // redefinitions. if (!bp.sourcePackage.equals("android")) { res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package " + pkg.packageName + " attempting to redeclare permission " + perm.info.name + " already owned by " + bp.sourcePackage); res.origPermission = perm.info.name; res.origPackage = bp.sourcePackage; return; } else { Slog.w(TAG, "Package " + pkg.packageName + " attempting to redeclare system permission " + perm.info.name + "; ignoring new declaration"); pkg.permissions.remove(i); } } else if (!"android".equals(pkg.packageName)) { // Prevent apps to change protection level to dangerous from any other // type as this would allow a privilege escalation where an app adds a // normal/signature permission in other app's group and later redefines // it as dangerous leading to the group auto-grant. if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_DANGEROUS) { if (bp != null && !bp.isRuntime()) { Slog.w(TAG, "Package " + pkg.packageName + " trying to change a " + "non-runtime permission " + perm.info.name + " to runtime; keeping old protection level"); perm.info.protectionLevel = bp.protectionLevel; } } } } } } //此段 当一个app是系统应用,但又希望安装在外部存储,那么就报错。 if (systemApp && onExternal) { // Disable updates to system apps on sdcard res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION, "Cannot install updates to system apps on sdcard"); return; } // 我们不是在移动app,所以不走这个分支,走else if分支 if (args.move != null) { // We did an in-place move, so dex is ready to roll scanFlags |= SCAN_NO_DEX; scanFlags |= SCAN_MOVE; synchronized (mPackages) { final PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps == null) { res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Missing settings for moved package " + pkgName); } // We moved the entire application as-is, so bring over the // previously derived ABI information. pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString; pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString; } } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) { // 设置SCAN_NO_DEX,这样在这个阶段就不会执行dexopt scanFlags |= SCAN_NO_DEX; try {//apk包里lib目录下有.so文件的,可以通过.so文件的ABI来确定app的primaryCpuAbi的值 derivePackageAbi(pkg, new File(pkg.codePath), args.abiOverride, true /* extract libs */); } catch (PackageManagerException pme) { Slog.e(TAG, "Error deriving application ABI", pme); res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI"); return; } // Run dexopt before old package gets removed, to minimize time when app is unavailable int result = mPackageDexOptimizer .performDexOpt(pkg, null /* instruction sets */, false /* forceDex */, false /* defer */, false /* inclDependencies */); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath); return; } }cc //重命名 将/data/app/vmdl<安装会话id>.tmp重命名为/data/app/包名-suffix,suffix为1,2...同时更新pkg中的受影响的字段。 if (!args.doRename(res.returnCode, pkg, oldCodePath)) { res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); return; } startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg); if (replace) {// 如果是覆盖安装,则走这里 replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user, installerPackageName, volumeUuid, res); } else {// 初次安装,走这里 installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, args.user, installerPackageName, volumeUuid, res); } synchronized (mPackages) { final PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps != null) { res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); } } }
执行完installPackageLI之后,返回processPendingInstall方法中。
3.3 发送POST_INSTALL消息并处理
case POST_INSTALL: { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); //Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); 所以msg.arg1是token PostInstallData data = mRunningInstalls.get(msg.arg1); //安装完毕,在"正在安装列表"中删除该项 mRunningInstalls.delete(msg.arg1); boolean deleteOld = false; if (data != null) { InstallArgs args = data.args; PackageInstalledInfo res = data.res; //如果安装成功 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { final String packageName = res.pkg.applicationInfo.packageName; //如果res.removedInfo.removedPackage != null 即如果是更新, 还会发送"ACTION_PACKAGE_REMOVED"广播 res.removedInfo.sendBroadcast(false, true, false); Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, res.uid); // Now that we successfully installed the package, grant runtime // permissions if requested before broadcasting the install. if ((args.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0) { grantRequestedRuntimePermissions(res.pkg, args.user.getIdentifier(), args.installGrantPermissions); } // Determine the set of users who are adding this // package for the first time vs. those who are seeing // an update. int[] firstUsers; int[] updateUsers = new int[0]; if (res.origUsers == null || res.origUsers.length == 0) { firstUsers = res.newUsers; } else { firstUsers = new int[0]; for (int i=0; i<res.newUsers.length; i++) { int user = res.newUsers[i]; boolean isNew = true; for (int j=0; j<res.origUsers.length; j++) { if (res.origUsers[j] == user) { isNew = false; break; } } if (isNew) { int[] newFirst = new int[firstUsers.length+1]; System.arraycopy(firstUsers, 0, newFirst, 0, firstUsers.length); newFirst[firstUsers.length] = user; firstUsers = newFirst; } else { int[] newUpdate = new int[updateUsers.length+1]; System.arraycopy(updateUsers, 0, newUpdate, 0, updateUsers.length); newUpdate[updateUsers.length] = user; updateUsers = newUpdate; } } } //上述是判断哪些用户是首次安装,哪些用户是更新安装 //发送一个ACTION_PACKAGE_ADDED广播(对首次安装的用户) sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, null, null, firstUsers); final boolean update = res.removedInfo.removedPackage != null; //如果是更新,extra字段添加一下值 if (update) { extras.putBoolean(Intent.EXTRA_REPLACING, true); } //发送一个ACTION_PACKAGE_ADDED广播(对更新的用户) sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, null, null, updateUsers); //如果是更新,发送ACTION_PACKAGE_REPLACED和ACTION_MY_PACKAGE_REPLACED广播 //sendPackageBroadcast的第四个参数是targetPkg if (update) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, null, null, updateUsers); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, packageName, null, updateUsers); // treat asec-hosted packages like removable media on upgrade //处理安装在SD卡的 if (res.pkg.isForwardLocked() || isExternal(res.pkg)) { if (DEBUG_INSTALL) { Slog.i(TAG, "upgrading pkg " + res.pkg + " is ASEC-hosted -> AVAILABLE"); } int[] uidArray = new int[] { res.pkg.applicationInfo.uid }; ArrayList<String> pkgList = new ArrayList<String>(1); pkgList.add(packageName); //发送app->SD的资源更改广播 sendResourcesChangedBroadcast(true, true, pkgList,uidArray, null); } } if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now deleteOld = true; } // If this app is a browser and it's newly-installed for some // users, clear any default-browser state in those users //如果是首次安装浏览器APP,则重置浏览器设置 if (firstUsers.length > 0) { // the app's nature doesn't depend on the user, so we can just // check its browser nature in any user and generalize. if (packageIsBrowser(packageName, firstUsers[0])) { synchronized (mPackages) { for (int userId : firstUsers) { mSettings.setDefaultBrowserPackageNameLPw(null, userId); } } } } // Log current value of "unknown sources" setting EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED, getUnknownSourcesSettings()); } // Force a gc to clear up things //GC操作 Runtime.getRuntime().gc(); // We delete after a gc for applications on sdcard. if (deleteOld) { synchronized (mInstallLock) { res.removedInfo.args.doPostDeleteLI(true); } } //回调args.observer.packageInstalled方法。 //告诉PackageInstaller安装结果,从而实现了安装回调到UI层。 if (args.observer != null) { try { Bundle extras = extrasForInstallResult(res); args.observer.onPackageInstalled(res.name, res.returnCode, res.returnMsg, extras); } catch (RemoteException e) { Slog.i(TAG, "Observer no longer exists."); } } } else { Slog.e(TAG, "Bogus post-install token " + msg.arg1); } } break;
该消息的处理主要就是在发送广播(很多个),应用安装完成之后要通知系统中的其他应用开始处理,安装到此结束~
相关文章推荐
- Android6.0 PackageManagerService(PMS)-简介
- Android6.0 PackageManagerService(PMS)-卸载
- Android6.0 PackageManagerService 安装lib
- PackageManagerService中运用inotify去监控目录中的APK更新、安装和删除
- Android -- PackageManagerService APK安装流程简要分析
- Android5.1--APK包的安装、卸载和优化(PackageManagerService)(三)
- Android L-preview PackageManagerService启动、安装和卸载分析
- Android6.0 PackageManagerService卸载应用
- Android6.0 PackageManagerService的mSettings、mPackages变量分析
- PackageManagerService——掌管APP的安装、卸载和查询
- Android5.1--APK包的安装、卸载和优化(PackageManagerService)(一)
- Android Fk-PKMS(2) PackageManagerService之应用的安装与卸载
- PackageManagerService安装流程
- Android5.1--APK包的安装、卸载和优化(PackageManagerService)
- 通过 PackageManagerService 接口queryIntentActivities 获取 全部 安装的apk信息
- Android7.0 PackageManagerService (3) APK安装
- Android PackageManagerService分析二:安装APK