Android PKMS深入分析安装应用

一、安装的Activity

Android,通过发送Intent可以启动应用的安装过程,如下所示:

  1. Uri uri = Uri.fromFile(new File(filename));  
  2. Intent inent = new Intent(Intent.ACTION_VIEW);  
  3. intent.SetDataAndType(uri, application/vnd.android.package-archive);  
  4. startActivity(intent);  

在Android的系统应用PackageInstaller中有一个PackageInstallActivity会响应这个Intent。在这个Activity中有两个重要的成员变量mPm和mInstaller,分别是ApplicationPackageManger和PackageInstaller的实例对象,这两个对象也是PackageManagerService和PackageInstallerService在应用中的代理对象。

PackageInstallerAcivity中创建这两个对象的代码如下:

  1. protected void onCreate(Bundler icicle) {  
  2.     super.onCreate(icicle);  
  3.     mPm = getPackageManager();  
  4.     mInstaller = mPm.getPackageInstaller();  
  5.     ......  
  6. }  


二、管理安装会话

PackageManagerInstallerService是Android5.0新加入的服务,主要用于管理安装会话(Installer session)。在Android5.0中,可以通过PackageManagerInstallerService来分配一个SessionId,这个系统唯一的ID代表一次安装过程,如果一个应用的安装分成几个阶段来完成,即使设备重启了,也可以通过这个ID来继续安装过程。

PackageManagerInstallerService中提供的接口createSession来创建一个Session:

  1. @Override  
  2. public int createSession(SessionParams params, String installerPackageName, int userId) {  
  3.     try {  
  4.         return createSessionInternal(params, installerPackageName, userId);  
  5.     } catch (IOException e) {  
  6.         throw ExceptionUtils.wrap(e);  
  7.     }  
  8. }  

这个方法返回一个系统唯一值作为SessionID,如果希望再次使用这个Session,可以通过接口openSession方法来打开它,代码如下:

  1. @Override  
  2. public IPackageInstallerSession openSession(int sessionId) {  
  3.     try {  
  4.         return openSessionInternal(sessionId);  
  5.     } catch (IOException e) {  
  6.         throw ExceptionUtils.wrap(e);  
  7.     }  
  8. }  

openSession返回一个IPackageInstallerSession对象,它是Binder服务PackageInstallerSession的IBinder对象。每个Install Session都会在SystemServer中有一个对应的PackageInstallerSession对象。在PackageInstallerService中mSessions数组保存了所有PackageInstallerSession对象,定义如下:

  1. private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();  

当系统启动时,PackageManageService初始化时会创建PackageManagerInstallerService服务,在这个服务的初始化函数中,会读取/data/system目录下的install_sessions.xml文件,这个文件保存系统未完成的Install Session。然后PackagemanagerInstallerService会根据文件的内容创建PackageInstallerSession对象并插入mSessions中。

PackageInstallerSession中保存了应用安装相关的数据。例如,安装包路径,安装进度、中间数据保存的目录等。


三、应用安装过程

应用可以调用PackageManager的installPackage方法来开始安装过程,最终会调用到PackageManagerService的installPackage或者installPackageAsUser来执行安装过程,整个安装过程比较复杂。

整个安装过程可以分成两个阶段:

1.第一阶段把需要安装的应用复制到/data/app目录下

2.第二阶段是对apk文件扫描优化,装载到内存中。


3.1 复制文件

PackageManagerService的installPackage方法只是用当前用户安装应用,最后也会调用installPackageAsUser

  1. @Override  
  2. public void installPackage(String originPath, IPackageInstallObserver2 observer,  
  3.         int installFlags, String installerPackageName, VerificationParams verificationParams,  
  4.         String packageAbiOverride) {  
  5.     installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams,  
  6.             packageAbiOverride, UserHandle.getCallingUserId());  
  7. }  

下面我们就来看看installPackageAsUser方法:

  1.    @Override  
  2.    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,  
  3.            int installFlags, String installerPackageName, VerificationParams verificationParams,  
  4.            String packageAbiOverride, int userId) {  
  5.        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);//检查调用进程的权限  
  6. //检查调用进程的永华是否有权限安装应用  
  7.        final int callingUid = Binder.getCallingUid();  
  8.        enforceCrossUserPermission(callingUid, userId, truetrue"installPackageAsUser");  
  9. //检查指定的用户是否被限制安装应用  
  10.        if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {  
  11.            try {  
  12.                if (observer != null) {  
  13.                    observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, nullnull);  
  14.                }  
  15.            } catch (RemoteException re) {  
  16.            }  
  17.            return;  
  18.        }  
  19.   
  20.        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {  
  21.            installFlags |= PackageManager.INSTALL_FROM_ADB;  
  22.   
  23.        } else {  
  24.            // Caller holds INSTALL_PACKAGES permission, so we're less strict  
  25.            // about installerPackageName.  
  26.   
  27.            installFlags &= ~PackageManager.INSTALL_FROM_ADB;  
  28.            installFlags &= ~PackageManager.INSTALL_ALL_USERS;  
  29.        }  
  30.   
  31.        UserHandle user;  
  32.        if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {//给所有用户安装  
  33.            user = UserHandle.ALL;  
  34.        } else {  
  35.            user = new UserHandle(userId);  
  36.        }  
  37.   
  38.        verificationParams.setInstallerUid(callingUid);  
  39.   
  40.        final File originFile = new File(originPath);  
  41.        final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);  
  42.   
  43.        final Message msg = mHandler.obtainMessage(INIT_COPY);  
  44.        msg.obj = new InstallParams(origin, observer, installFlags,//保存参数到InstallParamsm,发送消息  
  45.                installerPackageName, verificationParams, user, packageAbiOverride);  
  46.        mHandler.sendMessage(msg);  
  47.    }  

installPackageAsUser先检查调用进程是否有安装应用的权限,再检查调用进程所属的用户是否有权限安装应用,最后检查指定的用户是否被限制安装应用。如果参数installFlags带有INSTALL_ALL_USERS,则该应用将给系统中所有用户安装,否则只给指定用户安装。
安装应用实践比较长,因此不可能在一个函数中完成。上面函数把数据保存在installParams然后发送了INIT_COPY消息。

下面我们再来看看消息处理:

  1. void doHandleMessage(Message msg) {  
  2.     switch (msg.what) {  
  3.         case INIT_COPY: {  
  4.             HandlerParams params = (HandlerParams) msg.obj;  
  5.             int idx = mPendingInstalls.size();  
  6.             if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);  
  7.             // If a bind was already initiated we dont really  
  8.             // need to do anything. The pending install  
  9.             // will be processed later on.  
  10.             if (!mBound) {  
  11.                 // If this is the only one pending we might  
  12.                 // have to bind to the service again.  
  13.                 if (!connectToService()) {//绑定DefaultContainerService  
  14.                     Slog.e(TAG, "Failed to bind to media container service");  
  15.                     params.serviceError();  
  16.                     return;  
  17.                 } else {//连接成功把安装信息保存到mPendingInstalls  
  18.                     // Once we bind to the service, the first  
  19.                     // pending request will be processed.  
  20.                     mPendingInstalls.add(idx, params);  
  21.                 }  
  22.             } else {//如果已经绑定好了  
  23.                 mPendingInstalls.add(idx, params);  
  24.                 // Already bound to the service. Just make  
  25.                 // sure we trigger off processing the first request.  
  26.                 if (idx == 0) {  
  27.                     mHandler.sendEmptyMessage(MCS_BOUND);  
  28.                 }  
  29.             }  
  30.             break;  
  31.         }  

INIT_COPY消息的处理将绑定DefaultContainerService,因为这是一个异步的过程,要等待绑定的结果通过onServiceConnected返回,所以这里的安装参数放到了mPendingInstalls列表中。如果这个Service以前就绑定好了,现在就不需要再绑定,安装信息也会先放到mPendingInstalls。如果有多个安装请求同时到达,这里通过mPendingInstalls列表对他们进行排队。如果列表中只有一项,说明没有更多的安装请求,因此这种情况下回立即发出MCS_BOUND消息。而onServiceConnected方法同样是发出MCS_BOUND消息:

  1. class DefaultContainerConnection implements ServiceConnection {  
  2.     public void onServiceConnected(ComponentName name, IBinder service) {  
  3.         if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");  
  4.         IMediaContainerService imcs =  
  5.             IMediaContainerService.Stub.asInterface(service);  
  6.         mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));  
  7.     }  
  8.   
  9.     public void onServiceDisconnected(ComponentName name) {  
  10.         if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");  
  11.     }  
  12. };  

看下MCS_BOUND的消息处理

  1. case MCS_BOUND: {  
  2.     if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");  
  3.     if (msg.obj != null) {  
  4.         mContainerService = (IMediaContainerService) msg.obj;  
  5.     }  
  6.     if (mContainerService == null) {//没有连接成功  
  7.         // Something seriously wrong. Bail out  
  8.         Slog.e(TAG, "Cannot bind to media container service");  
  9.         for (HandlerParams params : mPendingInstalls) {  
  10.             // Indicate service bind error  
  11.             params.serviceError();//通知出错了  
  12.         }  
  13.         mPendingInstalls.clear();  
  14.     } else if (mPendingInstalls.size() > 0) {  
  15.         HandlerParams params = mPendingInstalls.get(0);  
  16.         if (params != null) {  
  17.             if (params.startCopy()) {//执行安装  
  18.                 // We are done...  look for more work or to  
  19.                 // go idle.  
  20.                 if (DEBUG_SD_INSTALL) Log.i(TAG,  
  21.                         "Checking for more work or unbind...");  
  22.                 // Delete pending install  
  23.                 if (mPendingInstalls.size() > 0) {  
  24.                     mPendingInstalls.remove(0);//工作完成,删除第一项  
  25.                 }  
  26.                 if (mPendingInstalls.size() == 0) {//如果没有安装消息了,延时发送10秒MCS_UNBIND消息  
  27.                     if (mBound) {  
  28.                         if (DEBUG_SD_INSTALL) Log.i(TAG,  
  29.                                 "Posting delayed MCS_UNBIND");  
  30.                         removeMessages(MCS_UNBIND);  
  31.                         Message ubmsg = obtainMessage(MCS_UNBIND);  
  32.                         // Unbind after a little delay, to avoid  
  33.                         // continual thrashing.  
  34.                         sendMessageDelayed(ubmsg, 10000);  
  35.                     }  
  36.                 } else {  
  37.                     // There are more pending requests in queue.  
  38.                     // Just post MCS_BOUND message to trigger processing  
  39.                     // of next pending install.  
  40.                     if (DEBUG_SD_INSTALL) Log.i(TAG,  
  41.                             "Posting MCS_BOUND for next work");  
  42.                     mHandler.sendEmptyMessage(MCS_BOUND);//还有消息继续发送MCS_BOUND消息  
  43.                 }  
  44.             }  
  45.         }  
  46.     } else {  
  47.         // Should never happen ideally.  
  48.         Slog.w(TAG, "Empty queue");  
  49.     }  
  50.     break;  
  51. }  

如果结束了我们看看MCS_UNBIND消息的处理

  1. case MCS_UNBIND: {  
  2.     // If there is no actual work left, then time to unbind.  
  3.     if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");  
  4.   
  5.     if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {  
  6.         if (mBound) {  
  7.             if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");  
  8.   
  9.             disconnectService();//断开连接  
  10.         }  
  11.     } else if (mPendingInstalls.size() > 0) {  
  12.         // There are more pending requests in queue.  
  13.         // Just post MCS_BOUND message to trigger processing  
  14.         // of next pending install.  
  15.         mHandler.sendEmptyMessage(MCS_BOUND);  
  16.     }  
  17.   
  18.     break;  
  19. }  

MCS_UNBIND消息的处理,如果处理的时候发现mPendingInstalls又有数据了,还是发送MCS_BOUND消息继续安装,否则断开和DefaultContainerService的连接,安装结束。
下面我们看执行安装的函数startCopy:

  1. final boolean startCopy() {  
  2.     boolean res;  
  3.     try {  
  4.         if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);  
  5.   
  6.         if (++mRetries > MAX_RETRIES) {//重试超过4次退出  
  7.             Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");  
  8.             mHandler.sendEmptyMessage(MCS_GIVE_UP);  
  9.             handleServiceError();  
  10.             return false;  
  11.         } else {  
  12.             handleStartCopy();  
  13.             res = true;  
  14.         }  
  15.     } catch (RemoteException e) {  
  16.         if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");  
  17.         mHandler.sendEmptyMessage(MCS_RECONNECT);//安装出错,发送重新连接  
  18.         res = false;  
  19.     }  
  20.     handleReturnCode();  
  21.     return res;  
  22. }  

handleStartCopy和copyApk代码就不分析了。

handleStartCopy函数先通过DefaultContainerService调用了getMinimallPackageInfo来确定安装位置是否有足够的空间,并在PackageInfoLite对象的recommendedIntallLocation记录错误原因。发现空间不够,会调用installer的freecache方法来释放一部分空间。

再接下来handleStartCopy有很长一段都在处理apk的校验,这个校验过程是通过发送Intent ACTION_PACKAGE_NEEDS_VERIFICATION给系统中所有接受该Intent的应用来完成。如果无需校验,直接调用InstallArgs对象的copyApk方法。

而copyApk方法同样是调用DefaultContainerService的copyPackage将应用的文件复制到/data/app下,如果还有native动态库,也会把包在apk文件中的动态库提取出来。

执行完copyApk后,应用安装到了data/app目录下了。


3.2 装载应用

接下来是第二阶段的工作,把应用的格式装换成oat格式,为应用创建数据目录。最后把应用信息装载进PackageManagerService的数据结构中。

接着上面startCopy方法最后会调用handleReturnCode方法,代码如下:

  1. @Override  
  2. void handleReturnCode() {  
  3.     // If mArgs is null, then MCS couldn't be reached. When it  
  4.     // reconnects, it will try again to install. At that point, this  
  5.     // will succeed.  
  6.     if (mArgs != null) {  
  7.         processPendingInstall(mArgs, mRet);  
  8.     }  
  9. }  

我们继续看下processPendingInstall函数。

  1. private void processPendingInstall(final InstallArgs args, final int currentStatus) {  
  2.     // Queue up an async operation since the package installation may take a little while.  
  3.     mHandler.post(new Runnable() {  
  4.         public void run() {  
  5.             mHandler.removeCallbacks(this);//防止重复调用  
  6.              // Result object to be returned  
  7.             PackageInstalledInfo res = new PackageInstalledInfo();  
  8.             res.returnCode = currentStatus;  
  9.             res.uid = -1;  
  10.             res.pkg = null;  
  11.             res.removedInfo = new PackageRemovedInfo();  
  12.             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//如果安装成功了  
  13.                 args.doPreInstall(res.returnCode);  
  14.                 synchronized (mInstallLock) {  
  15.                     installPackageLI(args, res);//装载安装的应用  
  16.                 }  
  17.                 args.doPostInstall(res.returnCode, res.uid);  
  18.             }  
  19. ..........  
  20.   
  21.             if (!doRestore) {  
  22.                 // 发送POST_INSTALL消息  
  23.                 Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);  
  24.                 mHandler.sendMessage(msg);  
  25.             }  
  26.         }  
  27.     });  
  28. }  

processPendingInstall方法post了一个消息,这样安装过程以异步的方式继续执行。在post消息的处理中,首先调用installPackageLI来装载应用,然后很大的代码在执行备份,备份是通过BackupManagerService来完成的。备份完成后,通过发送POST_INSTALL消息来继续处理。而这个消息的处理主要就是在发送广播,应用安装完成后要通知系统中其他的应用开始处理,比如Launcher中需要增加应用的图标等。

我们来分析下installPackageLI方法:

  1. private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {  
  2.     final int installFlags = args.installFlags;  
  3.     String installerPackageName = args.installerPackageName;  
  4.     File tmpPackageFile = new File(args.getCodePath());  
  5.     boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);  
  6.     boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);  
  7.     boolean replace = false;  
  8.     final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;  
  9.     // Result object to be returned  
  10.     res.returnCode = PackageManager.INSTALL_SUCCEEDED;  
  11.   
  12.     if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);  
  13.     // Retrieve PackageSettings and parse package  
  14.     final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY  
  15.             | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)  
  16.             | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);  
  17.     PackageParser pp = new PackageParser();  
  18.     pp.setSeparateProcesses(mSeparateProcesses);  
  19.     pp.setDisplayMetrics(mMetrics);  
  20.   
  21.     final PackageParser.Package pkg;  
  22.     try {  
  23.         pkg = pp.parsePackage(tmpPackageFile, parseFlags);//解析apk文件  
  24.     } catch (PackageParserException e) {  
  25.         res.setError("Failed parse during installPackageLI", e);  
  26.         return;  
  27.     }  

这里先调用parsePackage解析apk文件,这个之前分析过,我们就不再分析了。

继续分析processPendingInstall函数

  1. if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {//如果安装的升级应用,继续使用以前的老的包名  
  2.                 String oldName = mSettings.mRenamedPackages.get(pkgName);  
  3.                 if (pkg.mOriginalPackages != null  
  4.                         && pkg.mOriginalPackages.contains(oldName)  
  5.                         && mPackages.containsKey(oldName)) {  
  6.                     // This package is derived from an original package,  
  7.                     // and this device has been updating from that original  
  8.                     // name.  We must continue using the original name, so  
  9.                     // rename the new package here.  
  10.                     pkg.setPackageName(oldName);//设置老的包名  
  11.                     pkgName = pkg.packageName;  
  12.                     replace = true;  
  13.                     if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="  
  14.                             + oldName + " pkgName=" + pkgName);  
  15.                 } else if (mPackages.containsKey(pkgName)) {  
  16.                     // This package, under its official name, already exists  
  17.                     // on the device; we should replace it.  
  18.                     replace = true;  
  19.                     if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);  
  20.                 }  
  21.             }  

继续分析

  1. if (systemApp && onSd) {//不能将系统应用装载sd卡  
  2.     // Disable updates to system apps on sdcard  
  3.     res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,  
  4.             "Cannot install updates to system apps on sdcard");  
  5.     return;  
  6. }  
  7.   
  8. if (!args.doRename(res.returnCode, pkg, oldCodePath)) {//重命名出错  
  9.     res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");  
  10.     return;  
  11. }  

继续分析

  1. if (replace) {//如果安装的是升级包,调用replacePackageLI  
  2.     replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,  
  3.             installerPackageName, res);  
  4. else {//如果是新应用,调用installNewPackageLI继续处理  
  5.     installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,  
  6.             args.user, installerPackageName, res);  
  7. }  
  8. synchronized (mPackages) {  
  9.     final PackageSetting ps = mSettings.mPackages.get(pkgName);  
  10.     if (ps != null) {  
  11.         res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);  
  12.     }  
  13. }  

下面我们分析下installNewPackageLI函数

  1. private void installNewPackageLI(PackageParser.Package pkg,  
  2.         int parseFlags, int scanFlags, UserHandle user,  
  3.         String installerPackageName, PackageInstalledInfo res) {  
  4.     // Remember this for later, in case we need to rollback this install  
  5.     String pkgName = pkg.packageName;  
  6.   
  7.     if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);  
  8.     boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();  
  9.     synchronized(mPackages) {  
  10.         if (mSettings.mRenamedPackages.containsKey(pkgName)) {  
  11.             // A package with the same name is already installed, though  
  12.             // it has been renamed to an older name.  The package we  
  13.             // are trying to install should be installed as an update to  
  14.             // the existing one, but that has not been requested, so bail.  
  15.             res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName  
  16.                     + " without first uninstalling package running as "  
  17.                     + mSettings.mRenamedPackages.get(pkgName));  
  18.             return;  
  19.         }  
  20.         if (mPackages.containsKey(pkgName)) {  
  21.             // Don't allow installation over an existing package with the same name.  
  22.             res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName  
  23.                     + " without first uninstalling.");  
  24.             return;  
  25.         }  
  26.     }  
  27.   
  28.     try {  
  29.         PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,//调用scanPackageLI  
  30.                 System.currentTimeMillis(), user);  
  31.   
  32.         updateSettingsLI(newPackage, installerPackageName, nullnull, res);  
  33.         // delete the partially installed application. the data directory will have to be  
  34.         // restored if it was already existing  
  35.         if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {  
  36.             // remove package from internal structures.  Note that we want deletePackageX to  
  37.             // delete the package data and cache directories that it created in  
  38.             // scanPackageLocked, unless those directories existed before we even tried to  
  39.             // install.  
  40.             deletePackageLI(pkgName, UserHandle.ALL, falsenullnull,  
  41.                     dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,  
  42.                             res.removedInfo, true);  
  43.         }  
  44.   
  45.     } catch (PackageManagerException e) {  
  46.         res.setError("Package couldn't be installed in " + pkg.codePath, e);  
  47.     }  
  48. }  

这里和上篇博客分析扫描apk文件类似,我们来看下这个函数scanPackageLI

  1. private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,  
  2.         int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {  
  3.     boolean success = false;  
  4.     try {  
  5.         final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,  
  6.                 currentTime, user);  
  7.         success = true;  
  8.         return res;  
  9.     } finally {  
  10.         if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {  
  11.             removeDataDirsLI(pkg.packageName);  
  12.         }  
  13.     }  
  14. }  

scanPackageLI函数主要调用了scanPackageDirtyLI函数,这个函数前面分析过了就不分析了。


我们再来看下在processPendingInstall函数中调用完installPackageLI函数之后,发送了一个POST_INSTALL消息,我们来看下这个消息的处理

  1. case POST_INSTALL: {  
  2.     if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);  
  3.     PostInstallData data = mRunningInstalls.get(msg.arg1);  
  4.     mRunningInstalls.delete(msg.arg1);  
  5.     boolean deleteOld = false;  
  6.   
  7.     if (data != null) {  
  8.         InstallArgs args = data.args;  
  9.         PackageInstalledInfo res = data.res;  
  10.   
  11.         if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//安装成功  
  12.             final String packageName = res.pkg.applicationInfo.packageName;  
  13.             res.removedInfo.sendBroadcast(falsetruefalse);  
  14.             Bundle extras = new Bundle(1);  
  15.             extras.putInt(Intent.EXTRA_UID, res.uid);  
  16.   
  17.             // Now that we successfully installed the package, grant runtime  
  18.             // permissions if requested before broadcasting the install.  
  19.             if ((args.installFlags  
  20.                     & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0) {  
  21.                 grantRequestedRuntimePermissions(res.pkg, args.user.getIdentifier(),  
  22.                         args.installGrantPermissions);  
  23.             }  
  24.   
  25.             // Determine the set of users who are adding this  
  26.             // package for the first time vs. those who are seeing  
  27.             // an update.  
  28.             int[] firstUsers;  
  29.             int[] updateUsers = new int[0];  
  30.             if (res.origUsers == null || res.origUsers.length == 0) {  
  31.                 firstUsers = res.newUsers;  
  32.             } else {  
  33.                 firstUsers = new int[0];  
  34.                 for (int i=0; i<res.newUsers.length; i++) {  
  35.                     int user = res.newUsers[i];  
  36.                     boolean isNew = true;  
  37.                     for (int j=0; j<res.origUsers.length; j++) {  
  38.                         if (res.origUsers[j] == user) {  
  39.                             isNew = false;  
  40.                             break;  
  41.                         }  
  42.                     }  
  43.                     if (isNew) {  
  44.                         int[] newFirst = new int[firstUsers.length+1];  
  45.                         System.arraycopy(firstUsers, 0, newFirst, 0,  
  46.                                 firstUsers.length);  
  47.                         newFirst[firstUsers.length] = user;  
  48.                         firstUsers = newFirst;  
  49.                     } else {  
  50.                         int[] newUpdate = new int[updateUsers.length+1];  
  51.                         System.arraycopy(updateUsers, 0, newUpdate, 0,  
  52.                                 updateUsers.length);  
  53.                         newUpdate[updateUsers.length] = user;  
  54.                         updateUsers = newUpdate;  
  55.                     }  
  56.                 }  
  57.             }  
  58.             sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,//发送ACTION_PACKAGE_ADDED广播  
  59.                     packageName, extras, null, null, firstUsers);  
  60.             final boolean update = res.removedInfo.removedPackage != null;  
  61.             if (update) {  
  62.                 extras.putBoolean(Intent.EXTRA_REPLACING, true);  
  63.             }  
  64.             sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,  
  65.                     packageName, extras, null, null, updateUsers);  
  66.             if (update) {//如果是升级,发送更多广播  
  67.                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,  
  68.                         packageName, extras, null, null, updateUsers);  
  69.                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,  
  70.                         null, null, packageName, null, updateUsers);  
  71.   
  72.                 // treat asec-hosted packages like removable media on upgrade  
  73.                 if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {  
  74.                     if (DEBUG_INSTALL) {  
  75.                         Slog.i(TAG, "upgrading pkg " + res.pkg  
  76.                                 + " is ASEC-hosted -> AVAILABLE");  
  77.                     }  
  78.                     int[] uidArray = new int[] { res.pkg.applicationInfo.uid };  
  79.                     ArrayList<String> pkgList = new ArrayList<String>(1);  
  80.                     pkgList.add(packageName);  
  81.                     sendResourcesChangedBroadcast(truetrue,  
  82.                             pkgList,uidArray, null);  
  83.                 }  
  84.             }  
  85.             if (res.removedInfo.args != null) {  
  86.                 // Remove the replaced package's older resources safely now  
  87.                 deleteOld = true;  
  88.             }  
  89.   
  90.             // If this app is a browser and it's newly-installed for some  
  91.             // users, clear any default-browser state in those users  
  92.             if (firstUsers.length > 0) {  
  93.                 // the app's nature doesn't depend on the user, so we can just  
  94.                 // check its browser nature in any user and generalize.  
  95.                 if (packageIsBrowser(packageName, firstUsers[0])) {  
  96.                     synchronized (mPackages) {  
  97.                         for (int userId : firstUsers) {  
  98.                             mSettings.setDefaultBrowserPackageNameLPw(null, userId);  
  99.                         }  
  100.                     }  
  101.                 }  
  102.             }  
  103.             // Log current value of "unknown sources" setting  
  104.             EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,  
  105.                 getUnknownSourcesSettings());  
  106.         }  
  107.         // Force a gc to clear up things  
  108.         Runtime.getRuntime().gc();  
  109.         // We delete after a gc for applications  on sdcard.  
  110.         if (deleteOld) {  
  111.             synchronized (mInstallLock) {  
  112.                 res.removedInfo.args.doPostDeleteLI(true);  
  113.             }  
  114.         }  
  115.         if (args.observer != null) {  
  116.             try {  
  117.                 Bundle extras = extrasForInstallResult(res);  
  118.                 args.observer.onPackageInstalled(res.name, res.returnCode,  
  119.                         res.returnMsg, extras);  
  120.             } catch (RemoteException e) {  
  121.                 Slog.i(TAG, "Observer no longer exists.");  
  122.             }  
  123.         }  
  124.     } else {  
  125.         Slog.e(TAG, "Bogus post-install token " + msg.arg1);  
  126.     }  
  127. break;  

这样安装应用的流程就讲完了。


流程的时序图


四 总结

我们主要分析一下scanPackageLI方法,还是仅仅分析,不帖代码,因为代码太长了,帖出来没法看了,这个方法不仅仅是完成apk包的扫描,还解析AndroidManifest.xml文件并提取出所有的intent-filter和permission信息,apk安装的主要功能都由它来完成的,当apk包扫描完成后,系统会调用updatePermissionsLPw方法更新系统所具有的权限。

scanPackageLI方法有两个,其第一个参数分别接受File和PackageParser.Package类型,第一个方法会从File中提取出package信息然后再调用第二个方法,下面分析第二个scanPackageLI方法,其完成的事情如下:

1. 如果包名是android,则会做一些特殊处理,这个包名为android的应用是系统内部应用的,其他应用的包名如果叫android则安装会有问题,大家可以试一下

2. 解析常见的use-feature、shared-userId、use-library标签并保存到成员变量中

3. 进行签名验证,对应的方法是verifySignaturesLP,验证失败则应用无法安装

4. 创建应用程序目录/data/data/包名,同时将apk中提取出dex文件并保存到/data/dalvik-cache,把apk当做zip解压就能得到dex文件

5. 解析AndroidManifest.xml文件,提取出所需信息,包括具有intent-filter的四大组件信息(Activity、Service、BroadcastReceiver、ContentProvider)和声明的系统权限等

到此为止,scanPackageLI方法结束了。而updatePermissionsLPw的作用是对系统中所有的权限进行更新,大家可以查看下/system/etc/permissons目录,下面定义了android系统中所有的权限,开发中最常用的权限定义在目录下的platform.xml里面,大家可以打开看看,可以看到常见的访问网络、读写外部存储等权限等都是在这里定义的。权限更新完毕以后,系统就会发送ACTION_PACKAGE_ADDED广播,告知所有应用有新应用安装了。另外,大家可以查看下data/system/目录,里面有两个文件packages.list和packages.xml,在packages.list里面放的是手机上安装的所有应用列表,而packages.xml中存放的是所有应用的设置应用,比如一个应用声明了哪些系统权限就定义在这里面。关于应用的卸载,我们可以想到是应用安装过程的逆过程,大致要做的是:停止应用、删除各种文件,更新系统设置、权限等,大家感兴趣自己看一下,完全是安装过程的逆过程,这里不介绍了。

6.关于 so 的拷贝我们还是照旧不细说 App 的安装流程了,主要还是和之前一样不论是替换还是新安装,都会调用 PackageManagerService 的 scanPackageLI() 函数,然后跑去 scanPackageDirtyLI 函数,而在这个函数中对于非系统的 APP 他调用了 derivePackageABI 这个函数,通过这个函数他将会觉得系统的abi是多少,并且也会进行我们最关心的 so 拷贝操作。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1章 搭建Android源码工作环境 1.1 Android系统架构 1.2 搭建开发环境 1.2.1 下载源码 1.2.2 编译源码 1.2.3 利用Eclipse调试system_process 1.3 本章小结 第2章 深入理解Java Binder和MessageQueue 2.1 概述 2.2 Java层中的Binder架构分析 2.2.1 Binder架构总览 2.2.2 初始化Java层Binder框架 2.2.3 addService实例分析 2.2.4 Java层Binder架构总结 2.3 心系两界的MessageQueue 2.3.1 MessageQueue的创建 2.3.2 提取消息 2.3.3 nativePollOnce函数分析 2.3.4 MessageQueue总结 2.4 本章小结 第3章 深入理解SystemServer 3.1 概述 3.2 SystemServer分析 3.2.1 main函数分析 3.2.2 Service群英会 3.3 EntropyService分析 3.4 DropBoxManagerService分析 3.4.1 DBMS构造函数分析 3.4.2 dropbox日志文件的添加 3.4.3 DBMS和settings数据库 3.5 DiskStatsService和DeviceStorageMonitorService分析 3.5.1 DiskStatsService分析 3.5.2 DeviceStorageManagerService分析 3.6 SamplingProfilerService分析 3.6.1 SamplingProfilerService构造函数分析 3.6.2 SamplingProfilerIntegration分析 3.7 ClipboardService分析 3.7.1 复制数据到剪贴板 3.7.2 从剪切板粘贴数据 3.7.3 CBS中的权限管理 3.8 本章小结 第4章 深入理解PackageManagerService 4.1 概述 4.2 初识PackageManagerService 4.3 PKMS的main函数分析 4.3.1 构造函数分析之前期准备工作 4.3.2 构造函数分析之扫描Package 4.3.3 构造函数分析之扫尾工作 4.3.4 PKMS构造函数总结 4.4 APK Installation分析 4.4.1 adb install分析 4.4.2 pm分析 4.4.3 installPackageWithVerification函数分析 4.4.4 APK 安装流程总结 4.4.5 Verification介绍 4.5 queryIntentActivities分析 4.5.1 Intent及IntentFilter介绍 4.5.2 Activity信息的管理 4.5.3 Intent 匹配查询分析 4.5.4 queryIntentActivities总结 4.6 installd及UserManager介绍 4.6.1 installd介绍 4.6.2 UserManager介绍 4.7 本章学习指导 4.8 本章小结 第5章 深入理解PowerManagerService 5.1 概述 5.2 初识PowerManagerService 5.2.1 PMS构造函数分析 5.2.2 init分析 5.2.3 systemReady分析 5.2.4 BootComplete处理 5.2.5 初识PowerManagerService总结 5.3 PMS WakeLock分析 5.3.1 WakeLock客户端分析 5.3.2 PMS acquireWakeLock分析 5.3.3 Power类及LightService类介绍 5.3.4 WakeLock总结 5.4 userActivity及Power按键处理分析 5.4.1 userActivity分析 5.4.2 Power按键处理分析 5.5 BatteryService及BatteryStatsService分析 5.5.1 BatteryService分析 5.5.2 BatteryStatsService分析 5.5.3 BatteryService及BatteryStatsService总结 5.6 本章学习指导 5.7 本章小结 第6章 深入理解ActivityManagerService 6.1 概述 6.2 初识ActivityManagerService 6.2.1 ActivityManagerService的main函数分析 6.2.2 AMS的 setSystemProcess分析 6.2.3 AMS的 installSystemProviders函数分析 6.2.4 AMS的 systemReady分析 6.2.5 初识ActivityManagerService总结 6.3 startActivity分析 6.3.1 从am说起 6.3.2 AMS的startActivityAndWait函数分析 6.3.3 startActivityLocked分析 6.4 Broadcast和BroadcastReceiver分析 6.4.1 registerReceiver流程分析 6.4.2 sendBroadcast流程分析 6.4.3 BROADCAST_INTENT_MSG消息处理函数 6.4.4 应用进程处理广播分析 6.4.5 广播处理总结 6.5 startService之按图索骥 6.5.1 Service知识介绍 6.5.2 startService流程图 6.6 AMS中的进程管理 6.6.1 Linux进程管理介绍 6.6.2 关于Android中的进程管理的介绍 6.6.3 AMS进程管理函数分析 6.6.4 AMS进程管理总结 6.7 App的 Crash处理 6.7.1 应用进程的Crash处理 6.7.2 AMS的handleApplicationCrash分析 6.7.3 AppDeathRecipient binderDied分析 6.7.4 App的Crash处理总结 6.8 本章学习指导 6.9 本章小结 第7章 深入理解ContentProvider 7.1 概述 7.2 MediaProvider的启动及创建 7.2.1 Context的getContentResolver函数分析 7.2.2 MediaStore.Image.Media的query函数分析 7.2.3 MediaProvider的启动及创建总结 7.3 SQLite创建数据库分析 7.3.1 SQLite及SQLiteDatabase家族 7.3.2 MediaProvider创建数据库分析 7.3.3 SQLiteDatabase创建数据库的分析总结 7.4 Cursor 的query函数的实现分析 7.4.1 提取query关键点 7.4.2 MediaProvider 的query分析 7.4.3 query关键点分析 7.4.4 Cursor query实现分析总结 7.5 Cursor close函数实现分析 7.5.1 客户端close的分析 7.5.2 服务端close的分析 7.5.3 finalize函数分析 7.5.4 Cursor close函数总结 7.6 ContentResolver openAssetFileDescriptor函数分析 7.6.1 openAssetFileDescriptor之客户端调用分析 7.6.2 ContentProvider的 openTypedAssetFile函数分析 7.6.3 跨进程传递文件描述符的探讨 7.6.4 openAssetFileDescriptor函数分析总结 7.7 本章学习指导 7.8 本章小结 第8章 深入理解ContentService和AccountManagerService 8.1 概述 8.2 数据更新通知机制分析 8.2.1 初识ContentService 8.2.2 ContentResovler 的registerContentObserver分析 8.2.3 ContentResolver的 notifyChange分析 8.2.4 数据更新通知机制总结和深入探讨 8.3 AccountManagerService分析 8.3.1 初识AccountManagerService 8.3.2 AccountManager addAccount分析 8.3.3 AccountManagerService的分析总结 8.4 数据同步管理SyncManager分析 8.4.1 初识SyncManager 8.4.2 ContentResolver 的requestSync分析 8.4.3 数据同步管理SyncManager分析总结 8.5 本章学习指导 8.6 本章小结

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值