adb install 流程

应用安装涉及目录:        system/app ---------------系统自带的应用程序,获得adb root权限才能删除 data/app ---------------用户程序安装的目录。安装时把 apk文件复制到此目录 data/data ---------------存放应用程序的数据 data/dalvik-cache--------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一) 安装过程: 复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。 卸载过程: 删除安装过程中在上述三个目录下创建的文件及目录

带着这些知识去看安装过程,可能会更容易理解引起。

当我们利用adb安装一个软件包时,到底流程是怎么样的呢,这里主要介绍一个安装包在目标机中的安装过程。

adb install 也是用的pm命令去安装的,所以开始是在pm.java中。

我们看下流程:

1、调用pm程序开始安装

得用Pm安装时,一般是shell运行一个pm命令,并传送相应的参数,我们通过adb连接到机器,输入pm,会打出pm的一些参数

# pm pm
usage: pm [list|path|install|uninstall]        pm list packages [-f] [-d] [-e] [-u] [FILTER]        pm list permission-groups        pm list permissions [-g] [-f] [-d] [-u] [GROUP]        pm list instrumentation [-f] [TARGET-PACKAGE]        pm list features        pm list libraries        pm path PACKAGE        pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-        pm uninstall [-k] PACKAGE        pm clear PACKAGE        pm enable PACKAGE_OR_COMPONENT        pm disable PACKAGE_OR_COMPONENT        pm setInstallLocation [0/auto] [1/internal] [2/external]
当我们安装一个软件包时,shell运行pm程序并传入pm install ***等参数,我们看下pm.java

[cpp] view plaincopyprint?

  1. publicstaticvoid main(String[] args) { 
  2.         new Pm().run(args); 
  3.     } 

这里运行pm的run方法

[cpp] view plaincopyprint?

  1. publicvoid run(String[] args) { 
  2.       . 
  3.       . 
  4.       if ("install".equals(op)) { 
  5.             runInstall(); 
  6.             return
  7.         } 

匹配到install时,运行runInstall

runInstall主要对其它参数进行解析,最后调用:

[cpp] view plaincopyprint?

  1. try
  2.             mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags, 
  3.                     installerPackageName); 
  4.  
  5.             synchronized (obs) { 
  6.                 while (!obs.finished) { 
  7.                     try
  8.                         obs.wait(); 
  9.                     } catch (InterruptedException e) { 
  10.                     } 
  11.                 } 
  12.                 if (obs.result == PackageManager.INSTALL_SUCCEEDED) { 
  13.                     System.out.println("Success"); 
  14.                 } else
  15.                     System.err.println("Failure [" 
  16.                             + installFailureToString(obs.result) 
  17.                             + "]"); 
  18.                 } 
  19.             } 
  20.         } catch (RemoteException e) { 
  21.             System.err.println(e.toString()); 
  22.             System.err.println(PM_NOT_RUNNING_ERR); 
  23.         } 

2、PackageManagerService安装前处理 这里调用了PackageManager的installPackage接口,并最终调用PackageManagerService的installPackage进行具体的安装工作

在installPackage中,主要发送一条INIT_COPY消息到PackageHandler,PackageHandler处理这条消 息最后调用doHandleMessage,这中间的过程就不说了,对于INIT_COPY消息 ,首先调用connectToService,连接服务DefaultContainerService

在连接成功的时候触发DefaultContainerConnection的onServiceConnected,这里面又往PackageHandler发了一条MCS_BOUND。这里面触发startCopy

[cpp] view plaincopyprint?

  1. final void startCopy() { 
  2.             try
  3.                 if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy"); 
  4.                 retry++; 
  5.                 if (retry > MAX_RETRIES) { 
  6.                     Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 
  7.                     mHandler.sendEmptyMessage(MCS_GIVE_UP); 
  8.                     handleServiceError(); 
  9.                     return
  10.                 } else
  11.                     handleStartCopy(); 
  12.                     if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND"); 
  13.                     mHandler.sendEmptyMessage(MCS_UNBIND); 
  14.                 } 
  15.             } catch (RemoteException e) { 
  16.                 if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT"); 
  17.                 mHandler.sendEmptyMessage(MCS_RECONNECT); 
  18.             } 
  19.             handleReturnCode(); 

handleStartCopy进行一些安装前准备工作,最后调用handleReturnCode

[cpp] view plaincopyprint?

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

我们看下processPendingInstall

[cpp] view plaincopyprint?

  1. privatevoid 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.         publicvoid 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, true, res); 
  16.                 } 
  17.                 args.doPostInstall(res.returnCode); 
  18.             } 
  19.  
  20.             // A restore should be performed at this point if (a) the install 
  21.             // succeeded, (b) the operation is not an update, and (c) the new 
  22.             // package has a backupAgent defined. 
  23.             final boolean update = res.removedInfo.removedPackage != null; 
  24.             boolean doRestore = (!update 
  25.                     && res.pkg != null 
  26.                     && res.pkg.applicationInfo.backupAgentName != null); 
  27.  
  28.             // Set up the post-install work request bookkeeping.  This will be used 
  29.             // and cleaned up by the post-install event handling regardless of whether 
  30.             // there's a restore pass performed.  Token values are >= 1. 
  31.             int token; 
  32.             if (mNextInstallToken < 0) mNextInstallToken = 1; 
  33.             token = mNextInstallToken++; 
  34.  
  35.             PostInstallData data = new PostInstallData(args, res); 
  36.             mRunningInstalls.put(token, data); 
  37.             if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token); 
  38.  
  39.             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) { 
  40.                 // Pass responsibility to the Backup Manager.  It will perform a 
  41.                 // restore if appropriate, then pass responsibility back to the 
  42.                 // Package Manager to run the post-install observer callbacks 
  43.                 // and broadcasts. 
  44.                 IBackupManager bm = IBackupManager.Stub.asInterface( 
  45.                         ServiceManager.getService(Context.BACKUP_SERVICE)); 
  46.                 if (bm != null) { 
  47.                     if (DEBUG_INSTALL) Log.v(TAG, "token " + token 
  48.                             + " to BM for possible restore"); 
  49.                     try
  50.                         bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token); 
  51.                     } catch (RemoteException e) { 
  52.                         // can't happen; the backup manager is local 
  53.                     } catch (Exception e) { 
  54.                         Slog.e(TAG, "Exception trying to enqueue restore", e); 
  55.                         doRestore = false
  56.                     } 
  57.                 } else
  58.                     Slog.e(TAG, "Backup Manager not found!"); 
  59.                     doRestore = false
  60.                 } 
  61.             } 
  62.  
  63.             if (!doRestore) { 
  64.                 // No restore possible, or the Backup Manager was mysteriously not 
  65.                 // available -- just fire the post-install work request directly. 
  66.                 if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token); 
  67.                 Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); 
  68.                 mHandler.sendMessage(msg); 
  69.             } 
  70.         } 
  71.     }); 

这里New了一个消息,把它的callback设置为这里new出来的Runnable,这里重载了run方法,最后会通过Handle,Looper,Message机制调用到这个run方法中进行。

这里主要是调用了installPackageLI函数进行安装

3、解析apk

在installPackageLI中,会new 一个PackageParser对package进行解析,调用parsePackage函数 parsePackage(File sourceFile, String destCodePath,             DisplayMetrics metrics, int flags)函数根据参数进行一些处理后最终调用parsePackage(         Resources res, XmlResourceParser parser, int flags, String[] outError)对包进行解析,我们看到这个函数里面主要对配置文件AndroidManifest.xml文件进行了解析。我们会看到如下类似的代码

[cpp] view plaincopyprint?

  1.     private Package parsePackage( 
  2.         Resources res, XmlResourceParser parser, int flags, String[] outError) 
  3.         throws XmlPullParserException, IOException { 
  4.    . 
  5.    . 
  6.     int outerDepth = parser.getDepth(); 
  7.         while ((type=parser.next()) != parser.END_DOCUMENT 
  8.                && (type != parser.END_TAG || parser.getDepth() > outerDepth)) { 
  9.             if (type == parser.END_TAG || type == parser.TEXT) { 
  10.                 continue
  11.             } 
  12.  
  13.             String tagName = parser.getName(); 
  14.             if (tagName.equals("application")) { 
  15.                 if (foundApp) { 
  16.                     if (RIGID_PARSER) { 
  17.                         outError[0] = "<manifest> has more than one <application>"
  18.                         mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 
  19.                         return null; 
  20.                     } else
  21.                         Log.w(TAG, "<manifest> has more than one <application>"); 
  22.                         XmlUtils.skipCurrentTag(parser); 
  23.                         continue
  24.                     } 
  25.                 } 
  26.    . 
  27.    . 

4、安装包

解析完之后 ,调用installNewPackageLI进行包的安装

这里主要调用了scanPackageLI,对包进行安装,及保存package、provider、service、receiver和activity等信息保存在PackageManagerService服务中,我们会看到有如下代码

[cpp] view plaincopyprint?

  1. private PackageParser.Package scanPackageLI(PackageParser.Package pkg, 
  2.             int parseFlags, int scanMode, long currentTime) { 
  3.                                 // And now re-install the app. 
  4.                                 ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid, 
  5.                                         pkg.applicationInfo.uid); 
  6.                                 
  7.    . 
  8.     
  9.     // Add the new setting to mSettings 
  10.             mSettings.insertPackageSettingLP(pkgSetting, pkg); 
  11.             // Add the new setting to mPackages 
  12.             mPackages.put(pkg.applicationInfo.packageName, pkg); 
  13.             // Make sure we don't accidentally delete its data. 
  14.             mSettings.mPackagesToBeCleaned.remove(pkgName); 
  15. } 

这里的install最终会通过socket通信调用到installd.c中的do_install,其实也就是创建了一些目录而已。

原文地址:https://www.cnblogs.com/wangxianzhen/p/3008963.html