Android中APK安装流程解析

时间:2024-10-08 07:12:10

前言:大家都知道,手机关机以后,就是一个冰冷的砖头,只能用来做防身的利器,但是开机后,点击桌面上的任何一个图片,都能开启一个APP,这说明在开机过程中,系统把已经安装好的APP加载到内存中,这到底是怎么做的?

所以我们可以推断,在安卓系统中肯定存在这么一块区域,用于存放已经安装的APP的信息,在开机的时候,通过系统扫描,这块区域,把对应的内容加载到内存中去。

其次,我们知道了在Android系统中存在这样一块区域,在开机的的时候,加载这块区域的信息,从而实现加载在内存中去。那么我们继续反推断,那这块区域的信息,是怎么来的?

应该在安装这个APK的时候,把这个APK的信息写入到该区域的。这样就可以实现了在安卓系统一次安装后,在删除APK文件后,还可以运行APP了。

该篇文章是讲述apk的安装流程,想要了解apk打包、app启动 流程的同学可以点击下面的传送门:

apk打包流程

app启动流程详解

apk信息存储在哪?

回到apk的安装话题上来,上面说的Android区域其实就是:“/data目录”下的system目录,这个目录用来保存很多系统文件。主要工作是创建了5个位于目录/data/system的File对象,分别是:

  • :记录了系统中所有安装的应用信息,包括基本信息、签名和权限。
  • :文件的备份。
  • :记录系统中被强制停止的运行的应用信息,系统在强制停止某个应用的时候,会将应用的信息记录在该文件中。
  • :文件的备份。
  • :保存普通应用的数据目录和uid等信息。

这5个文件中和是备份文件。当Android对文件packages.xml和写之前,会先把它们备份,如果写文件成功了,再把备份文件删除。如果写的时候,系统出问题了,重启后在需要读取这两个文件时,如果发现备份文件存在,会使用备份文件的内容,因为源文件可能已经损坏了。其中PackageManagerServcie启动时,需要用到的文件。

为了更直观的看一下,下面copy一张手机Root后,在/data/system目录下 截图如下:

把导出来,因为文件内容太大,所以展示局部内容如下:

  1. <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
  2. <packages>
  3. <version sdkVersion="23" databaseVersion="3" fingerprint="google/angler/angler:6.0.1/MTC20L/3230295:user/release-keys" />
  4. <version volumeUuid="primary_physical" sdkVersion="23" databaseVersion="23" fingerprint="google/angler/angler:6.0.1/MTC19T/2741993:user/release-keys" />
  5. <permission-trees>
  6. <item name=".GOOGLE_AUTH" package="" />
  7. </permission-trees>
  8. <permissions>
  9. <item name=".REAL_GET_TASKS" package="android" protection="18" />
  10. <item name=".REMOTE_AUDIO_PLAYBACK" package="android" protection="2" />
  11. .....
  12. <item name=".ADD_VOICEMAIL" package="android" protection="1" />
  13. </permissions>
  14. <package name="" codePath="/system/app/YouTube" nativeLibraryPath="/system/app/YouTube/lib" primaryCpuAbi="arm64-v8a" publicFlags="945307205" privateFlags="0" ft="11e9134c000" it="11e9134c000" ut="11e9134c000" version="107560144" userId="10075">
  15. <sigs count="1">
  16. <cert index="0" key="30820252308201bb02044934987e300d06092a864886f70d01010405003070310b3009060355040613025553310b3009060355040813024341311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c652c20496e6331143012060355040b130b476f6f676c652c20496e633110300e06035504031307556e6b6e6f776e301e170d3038313230323032303735385a170d3336303431393032303735385a3070310b3009060355040613025553310b3009060355040813024341311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c652c20496e6331143012060355040b130b476f6f676c652c20496e633110300e06035504031307556e6b6e6f776e30819f300d06092a864886f70d010101050003818d00308189028181009f48031990f9b14726384e0453d18f8c0bbf8dc77b2504a4b1207c4c6c44babc00adc6610fa6b6ab2da80e33f2eef16b26a3f6b85b9afaca909ffbbeb3f4c94f7e8122a798e0eba75ced3dd229fa7365f41516415aa9c1617dd583ce19bae8a0bbd885fc17a9b4bd2640805121aadb9377deb40013381418882ec52282fc580d0203010001300d06092a864886f70d0101040500038181004086669ed631da4384ddd061d226e073b98cc4b99df8b5e4be9e3cbe97501e83df1c6fa959c0ce605c4fd2ac6d1c84cede20476cbab19be8f2203aff7717ad652d8fcc890708d1216da84457592649e0e9d3c4bb4cf58da19db1d4fc41bcb9584f64e65f410d0529fd5b68838c141d0a9bd1db1191cb2a0df790ea0cb12db3a4" />
  17. </sigs>
  18. <perms>
  19. <item name="." granted="true" flags="0" />
  20. <item name=".USE_CREDENTIALS" granted="true" flags="0" />
  21. <item name=".READ_GSERVICES" granted="true" flags="0" />
  22. <item name=".C2D_MESSAGE" granted="true" flags="0" />
  23. <item name=".MANAGE_ACCOUNTS" granted="true" flags="0" />
  24. <item name="" granted="true" flags="0" />
  25. <item name=".CHANGE_NETWORK_STATE" granted="true" flags="0" />
  26. <item name=".RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
  27. <item name=".AD_ID_NOTIFICATION" granted="true" flags="0" />
  28. <item name="" granted="true" flags="0" />
  29. <item name=".ACCESS_NETWORK_STATE" granted="true" flags="0" />
  30. <item name="" granted="true" flags="0" />
  31. <item name=".ACCESS_WIFI_STATE" granted="true" flags="0" />
  32. <item name=".WAKE_LOCK" granted="true" flags="0" />
  33. </perms>
  34. <proper-signing-keyset identifier="11" />
  35. <domain-verification packageName="" status="0">
  36. <domain name="" />
  37. <domain name="" />
  38. <domain name="" />
  39. <domain name="" />
  40. </domain-verification>
  41. </package>

对上面的标签的含义,下面做一个简单的介绍:

<package>表示包信息,下面我们就来解释下标签<package>中的属性:

  • name表示应用的包名。
  • codePath表示的是apk文件的路径。
  • nativeLibraryPath表示应用的native库的存储路径。
  • flags是指应用的属性,如FLAG_SYSTEM、FLAG_PERSISTENT等。
  • it表示应用安装的时间。
  • ut表示应用最后一次修改的时间。
  • version表示应用的版本号。
  • userId表示所属于的id。

<sign>表示应用的签名,下面我们就来解释下 标签<sign>中的属性:

  • count表示标签中包含有多少个证书
  • cert表示具体的证书的值

<perms>表示应用声明使用的权限,每一个子标签代表一项权限。

在上面知道了apk的信息在系统的存储的位置和方式,有人就会有新的疑问:系统是怎么获取到apk的信息的?接下来就是要梳理apk的安装流程了,看了apk安装流程的解析,你就会知道apk的信息是怎么被系统获取到的了。

从源码角度分析apk安装过程

先介绍一下Apk安装的四种方式:

1. 系统应用安装:没有安装界面,在开机时自动完成。
2. 网络下载应用安装:  没有安装界面,在应用市场完成。
3. ADB命令安装:  没有安装界面,通过命令直接安装。
4. 外部设备安装:  有安装界面,通过SD卡等外部设备安装,由packageInstaller处理安装逻辑。

接下来介绍一下APK安装涉及到的几个常用目录:

/app : 系统自带的应用程序,获得root权限才能删除。

/app : 用户程序安装目录,安装时会把apk文件复制到此目录下。

/data : 存放应用程序的数据。

/dalvik-cache : 将apk中的dex文件安装到该目录下(dex文件是dalvik虚拟机的可执行文件,大小约为原始apk的四分之一)。

还有APK安装的预备知识点也说一下吧:

(1)PackageManagerService是由SystemServer启动,PMS负责应用的安装、卸载、权限检查等工作;

(2)在/system/app和/data/app目录下的apk文件,PMS在启动过程中,都会扫描安装;

(3)每次开机时,PMS都会在构造函数中对指定目录下的apk进行扫描,没有安装的apk就会触发安装;


在梳理源码之前先大概说一下apk安装的四大步骤:

(1)拷贝apk到指定的目录:默认情况下,用户安装的apk首先会拷贝到/data/app下,用户有访问/data/app目录的权限,但系统出厂的apk文件会被放到/system分区下,包括/system/app,/system/vendor/app,以及/system/priv-app等,该分区需要root权限的用户才能访问。
(2)加载apk、拷贝文件、创建应用的数据目录:
为了加快APP的启动速度,apk在安装的时候,会首先将APP的可执行文件(dex)拷贝到/data/dalvik-cache目录下,缓存起来。再在/data/data/目录下创建应用程序的数据目录(以应用包名命令),用来存放应用的数据库、xml文件、cache、二进制的so动态库等。
(3)解析apk的文件:
在安装apk的过程中,会解析apk的文件,将apk的权限、应用包名、apk的安装位置、版本、userID等重要信息保存在/data/system/文件中。这些操作都是在PackageManagerService中完成
的。
(4)显示icon图标:
应用程序经过PMS中的逻辑处理后,相当于已经注册好了,如果想要在Android桌面上看到icon图标,则需要Launcher将系统中已经安装的程序展现在桌面上。

概念说的差不多了,接下来就对不同的安装方式做源码的过程梳理。

源码解析系统应用安装

系统在创建PackageManagerService实例时,会在PMS的构造函数中开始执行安装应用程序的逻辑。

在PMS的构造函数中做了如下几点重要操作:

1.创建Settings对象,添加shareUserId。

  1. mSettings = new Settings(mPackages);
  2. ("", Process.SYSTEM_UID,
  3. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  4. ("", RADIO_UID,
  5. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  6. ("", LOG_UID,
  7. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  8. ("", NFC_UID,
  9. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  10. ("", BLUETOOTH_UID,
  11. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  12. ("", SHELL_UID,
  13. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

Settings是Android的包的全局管理者,用于协助PackageManagerService保存所有的安装包信息,同时用于存储系统执行过程中的一些设置,PackageManagerService和Settings之间的类图关系如下:

2.通过PackageManagerService构造函数参数获取应用安装器Installer

mInstaller = installer;

3.获取SystemConfig实例,读取“/system/etc/permissions/*.xml”资源文件,从资源文件中获取mGlobalsGids(Group-ids)、mSystemPermissions(系统权限)、mAvailableFeatures(系统支持的features)属性。

  1. SystemConfig systemConfig = ();
  2. mGlobalGids = ();
  3. mSystemPermissions = ();
  4. mAvailableFeatures = ();

4.创建系统消息处理线程。

  1. mHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
  2. ();
  3. mHandler = new PackageHandler(());
  4. ().addThread(mHandler, WATCHDOG_TIMEOUT);

5.执行.server.中的readLPw方法,读取安装包中的信息,并解析成对应的数据结构。

  1. File dataDir = ();
  2. mAppDataDir = new File(dataDir, "data");
  3. mAppInstallDir = new File(dataDir, "app");
  4. mAppLib32InstallDir = new File(dataDir, "app-lib");
  5. mAsecInternalPath = new File(dataDir, "app-asec").getPath();
  6. mUserAppDataDir = new File(dataDir, "user");
  7. mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
  8. sUserManager = new UserManagerService(context, this,
  9. mInstallLock, mPackages);
  10. // Propagate permission configuration in to package manager.
  11. ArrayMap<String, > permConfig
  12. = ();
  13. for (int i=0; i<(); i++) {
  14. SystemConfig.PermissionEntry perm = (i);
  15. BasePermission bp = ();
  16. if (bp == null) {
  17. bp = new BasePermission(, "android", BasePermission.TYPE_BUILTIN);
  18. (, bp);
  19. }
  20. if ( != null) {
  21. (, );
  22. }
  23. }
  24. ArrayMap<String, String> libConfig = ();
  25. for (int i=0; i<(); i++) {
  26. ((i),
  27. new SharedLibraryEntry((i), null));
  28. }
  29. mFoundPolicyFile = ();
  30. mRestoredSettings = (this, (false),
  31. mSdkVersion, mOnlyCore);

其中,读取的重要文件就是之前已经说过的保存apk信息的那几个:、、、、。并且这几个目录在创建Settings对象时就已经被封装成了对应的File文件。

6.执行PMS中的scanDirLI方法扫描系统安装目录和非系统apk信息。

  1. File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
  2. scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
  3. | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
  4. // Find base frameworks (resource packages without code).
  5. scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
  6. | PackageParser.PARSE_IS_SYSTEM_DIR
  7. | PackageParser.PARSE_IS_PRIVILEGED,
  8. scanFlags | SCAN_NO_DEX, 0);
  9. // Collected privileged system packages.
  10. final File privilegedAppDir = new File((), "priv-app");
  11. scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
  12. | PackageParser.PARSE_IS_SYSTEM_DIR
  13. | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
  14. // Collect ordinary system packages.
  15. final File systemAppDir = new File((), "app");
  16. scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
  17. | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
  18. // Collect all vendor packages.
  19. File vendorAppDir = new File("/vendor/app");
  20. try {
  21. vendorAppDir = ();
  22. } catch (IOException e) {
  23. // failed to look up canonical path, continue with original one
  24. }
  25. scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
  26. | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
  27. // Collect all OEM packages.
  28. final File oemAppDir = new File((), "app");
  29. scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
  30. | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

其中,系统安装目录有:

  • /system/framework 系统库;

  • /system/app 默认的系统应用;

  • /vendor/app 厂商定制的应用;

非系统apk信息目录有:

  • /data/app/;

  • /system/priv-app/;

  • /data/app-private/;

到此,PMS构造函数中主要的逻辑操作就介绍完了,接下来继续探究扫描安装过程:

(1)深入到PackageManagerService—>scanDirLI方法中:

  1. private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
  2. final File[] files = ();
  3. if ((files)) {
  4. (TAG, "No files in app dir " + dir);
  5. return;
  6. }
  7. if (DEBUG_PACKAGE_SCANNING) {
  8. (TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
  9. + " flags=0x" + (parseFlags));
  10. }
  11. for (File file : files) {
  12. final boolean isPackage = (isApkFile(file) || ())
  13. && !(());
  14. if (!isPackage) {
  15. // Ignore entries which are not packages
  16. continue;
  17. }
  18. try {
  19. scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
  20. scanFlags, currentTime, null);//注释1
  21. } catch (PackageManagerException e) {
  22. (TAG, "Failed to parse " + file + ": " + ());
  23. // Delete invalid userdata apps
  24. if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
  25. == PackageManager.INSTALL_FAILED_INVALID_APK) {
  26. logCriticalInfo(, "Deleting invalid package at " + file);
  27. if (()) {
  28. (());
  29. } else {
  30. ();
  31. }
  32. }
  33. }
  34. }
  35. }

在注释1处,对于目录中的每一个文件,如果是已apk作为后缀名的,就会调用PackageManagerService—>scanPackageLI方法进行扫描解析。

(2)深入到PackageManagerService—>scanPackageLI方法中:

  1. private scanPackageLI(File scanFile, int parseFlags, int scanFlags,
  2. long currentTime, UserHandle user) throws PackageManagerException {
  3. if (DEBUG_INSTALL) (TAG, "Parsing: " + scanFile);
  4. parseFlags |= mDefParseFlags;
  5. PackageParser pp = new PackageParser();//注释1
  6. (mSeparateProcesses);
  7. (mOnlyCore);
  8. (mMetrics);
  9. if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
  10. parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
  11. }
  12. final pkg;
  13. try {
  14. pkg = (scanFile, parseFlags);//注释2
  15. } catch (PackageParserException e) {
  16. throw (e);
  17. }
  18. ......省略......
  19. // reader
  20. synchronized (mPackages) {//注释3
  21. // Look to see if we already know about this package.
  22. String oldName = ();
  23. if ( != null && (oldName)) {
  24. // This package has been renamed to its original name. Let's
  25. // use that.
  26. ps = (oldName);
  27. }
  28. // If there was no original package, see one for the real package name.
  29. if (ps == null) {
  30. ps = ();
  31. }
  32. // Check to see if this package could be hiding/updating a system
  33. // package. Must look for it either under the original or real
  34. // package name depending on our state.
  35. updatedPkg = (ps != null ? : );
  36. if (DEBUG_INSTALL && updatedPkg != null) (TAG, "updatedPkg = " + updatedPkg);
  37. }
  38. ......省略......
  39. PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags
  40. | SCAN_UPDATE_SIGNATURE, currentTime, user);//注释4
  41. /*
  42. * If the system app should be overridden by a previously installed
  43. * data, hide the system app now and let the /data/app scan pick it up
  44. * again.
  45. */
  46. if (shouldHideSystemApp) {
  47. synchronized (mPackages) {
  48. ();
  49. }
  50. }
  51. return scannedPkg;
  52. }

在注释1处:创建一个PackageParser实例。

在注释2处:调用PackageParser的parsePackage函数来对apk安装包的文件扫描和提取证书信息,然后构建一个PackageParser.Package对象,并将其返回。

在注释3处:将解析返回的PackageParser对象中的信息保存到PMS中。

在注释4处:调用另一个重载的scanPackageLI方法来构建一个PackageSetting对象,这个对象保存的信息最后会通过writeLPr写入到/data/system/文件中去。

(3)根据(2)中注释2深入到PackageParser—>parsePackage方法中:

  1. public Package parsePackage(File packageFile, int flags) throws PackageParserException {
  2. if (()) {
  3. return parseClusterPackage(packageFile, flags);
  4. } else {
  5. return parseMonolithicPackage(packageFile, flags);
  6. }
  7. }

这里是根据packageFile是否是目录分别调用parseClusterPackage和parseMonolithicPackage去解析。

其中parseClusterPackage方法如下:

  1. private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
  2. final PackageLite lite = parseClusterPackageLite(packageDir, 0);
  3. if (mOnlyCoreApps && !) {
  4. throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
  5. "Not a coreApp: " + packageDir);
  6. }
  7. final AssetManager assets = new AssetManager();
  8. try {
  9. ...省略...
  10. final File baseApk = new File();
  11. final Package pkg = parseBaseApk(baseApk, assets, flags);//注释1
  12. if (pkg == null) {
  13. throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
  14. "Failed to parse base APK: " + baseApk);
  15. }
  16. ...省略...
  17. = ();
  18. return pkg;
  19. } finally {
  20. (assets);
  21. }
  22. }

parseMonolithicPackage方法如下:

  1. public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
  2. ...省略...
  3. final AssetManager assets = new AssetManager();
  4. try {
  5. final Package pkg = parseBaseApk(apkFile, assets, flags);//注释2
  6. = ();
  7. return pkg;
  8. } finally {
  9. (assets);
  10. }
  11. }

从parseClusterPackage的注释1和parseMonolithicPackage的注释2可以看出都是调用parseBaseApk去解析。

往下继续探究parseBaseApk方法:

  1. private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
  2. throws PackageParserException {
  3. ...省略...
  4. try {
  5. res = new Resources(assets, mMetrics, null);
  6. (0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  7. .RESOURCES_SDK_INT);
  8. parser = (cookie, ANDROID_MANIFEST_FILENAME);
  9. final String[] outError = new String[1];
  10. final Package pkg = parseBaseApk(res, parser, flags, outError);//注释1
  11. if (pkg == null) {
  12. throw new PackageParserException(mParseError,
  13. apkPath + " (at " + () + "): " + outError[0]);
  14. }
  15. ...省略...
  16. } catch (PackageParserException e) {
  17. throw e;
  18. } catch (Exception e) {
  19. throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
  20. "Failed to read manifest from " + apkPath, e);
  21. } finally {
  22. (parser);
  23. }
  24. }

在注释1处可以看到是调用另一个重载的parseBaseApk方法对apk进行解析。

(4) 先回到(2)中注释4处深入到PackageManagerService—>另一个scanPackageLI方法中:

  1. private scanPackageLI( 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);//注释1
  7. success = true;
  8. return res;
  9. } finally {
  10. if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
  11. removeDataDirsLI(, );
  12. }
  13. }
  14. }

接着由注释1继续深入PackageManagerService—>scanPackageDirtyLI方法中:

  1. private scanPackageDirtyLI( pkg, int parseFlags,
  2. int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
  3. final File scanFile = new File();
  4. ......省略......
  5. // And now re-install the app.
  6. ret = createDataDirsLI(, pkgName, ,
  7. HasSystemUidErrors = true;//注释1
  8. ......省略......
  9. //invoke installer to do the actual installation
  10. int ret = createDataDirsLI(, pkgName, ,
  11. );//注释2
  12. if (ret < 0) {
  13. // Error from installer
  14. throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
  15. "Unable to create data dirs [errorCode=" + ret + "]");
  16. }
  17. ......省略......
  18. }

从注释1和注释2处可以看出调用了PMS中的createDataDirsLI方法,给installed发送消息,为应用程序创建对应的数据目录,如果目录已经存在,也会重新创建一遍。

继续深入到PMS的createDataDirsLI方法中:

  1. private int createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo) {
  2. int[] users = ();
  3. int res = (volumeUuid, packageName, uid, uid, seinfo);//注释1
  4. if (res < 0) {
  5. return res;
  6. }
  7. for (int user : users) {
  8. if (user != 0) {
  9. res = (volumeUuid, packageName,//注释2
  10. (user, uid), user, seinfo);
  11. if (res < 0) {
  12. return res;
  13. }
  14. }
  15. }
  16. return res;
  17. }

从上面代码可知最后是调用()函数完成APK安装。到此为止,系统应用的安装流程差不多就完成了。

网络下载应用安装

在网络应用下载完成后,会自动调用PackageManagerService中的installPackage方法:

  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,
  6. verificationParams, packageAbiOverride, ());
  7. }

在上面的代码里可以看到主要是调用了PMS—>installPackageAsUser方法:

  1. public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
  2. int installFlags, String installerPackageName, VerificationParams verificationParams,
  3. String packageAbiOverride, int userId) {
  4. (.INSTALL_PACKAGES, null);
  5. ......省略......
  6. final Message msg = (INIT_COPY);
  7. = new InstallParams(origin, null, observer, ,
  8. installerPackageName, , verifParams, user, ,
  9. );
  10. (msg);
  11. }

这里主要是获取用户安装位置,将InstallParams对象封装在Message里,然后发一个Handler消息。

接下来深入到处理INIT_COPY的地方:PMS—>doHandleMessage方法中:

  1. void doHandleMessage(Message msg) {
  2. switch () {
  3. case INIT_COPY: {
  4. ......省略......
  5. if (!mBound) {
  6. // If this is the only one pending we might
  7. // have to bind to the service again.
  8. if (!connectToService()) {
  9. (TAG, "Failed to bind to media container service");
  10. ();
  11. return;
  12. } else {
  13. // Once we bind to the service, the first
  14. // pending request will be processed.
  15. (idx, params);
  16. }
  17. } else {
  18. (idx, params);
  19. // Already bound to the service. Just make
  20. // sure we trigger off processing the first request.
  21. if (idx == 0) {
  22. (MCS_BOUND);
  23. }
  24. }
  25. break;
  26. }
  27. case MCS_BOUND: {
  28. if (DEBUG_INSTALL) (TAG, "mcs_bound");
  29. if ( != null) {
  30. mContainerService = (IMediaContainerService) ;
  31. }
  32. if (mContainerService == null) {
  33. ......省略......
  34. } else if (() > 0) {
  35. HandlerParams params = (0);
  36. if (params != null) {
  37. if (()) {//注释1
  38. // We are done... look for more work or to
  39. // go idle.
  40. if (DEBUG_SD_INSTALL) (TAG,
  41. "Checking for more work or unbind...");
  42. // Delete pending install
  43. if (() > 0) {
  44. (0);
  45. }
  46. if (() == 0) {
  47. if (mBound) {
  48. if (DEBUG_SD_INSTALL) (TAG,
  49. "Posting delayed MCS_UNBIND");
  50. removeMessages(MCS_UNBIND);
  51. Message ubmsg = obtainMessage(MCS_UNBIND);
  52. // Unbind after a little delay, to avoid
  53. // continual thrashing.
  54. sendMessageDelayed(ubmsg, 10000);
  55. }
  56. } else {
  57. // There are more pending requests in queue.
  58. // Just post MCS_BOUND message to trigger processing
  59. // of next pending install.
  60. if (DEBUG_SD_INSTALL) (TAG,
  61. "Posting MCS_BOUND for next work");
  62. (MCS_BOUND);
  63. }
  64. }
  65. }
  66. } else {
  67. // Should never happen ideally.
  68. (TAG, "Empty queue");
  69. }
  70. break;
  71. }

上面的逻辑是:如果是INIT_COPY:则连接DefaultContainerService服务,将我们要安装的信息方法HandlerParams的mPendingInstalls中,然后再发送MCS_BOUND消息。

如果是MCS_BOUND:则通过HandlerParams params = (0)获取要安装包的信息,然后清除包信息,如果还有其他包,则继续发MCS_BOUND消息,一直循环,直到安装包都安装完。

然后再调用—>startCopy方法:

  1. final boolean startCopy() {
  2. boolean res;
  3. try {
  4. if (DEBUG_INSTALL) (TAG, "startCopy " + mUser + ": " + this);
  5. if (++mRetries > MAX_RETRIES) {
  6. (TAG, "Failed to invoke remote methods on default container service. Giving up");
  7. (MCS_GIVE_UP);
  8. handleServiceError();
  9. return false;
  10. } else {
  11. handleStartCopy();//注释1
  12. res = true;
  13. }
  14. } catch (RemoteException e) {
  15. if (DEBUG_INSTALL) (TAG, "Posting install MCS_RECONNECT");
  16. (MCS_RECONNECT);
  17. res = false;
  18. }
  19. handleReturnCode();//注释2
  20. return res;
  21. }

其中startCopy中有两个重要的方法handleStartCopy和handleReturnCode。handleStartCopy中会检查应用是否能安装成功,如果不能安装成功,则会返回failed的CODE;返回res标识,判断是否安装成功。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. (new Runnable() {
  4. public void run() {
  5. (this);
  6. // Result object to be returned
  7. PackageInstalledInfo res = new PackageInstalledInfo();
  8. = currentStatus;
  9. = -1;
  10. = null;
  11. = new PackageRemovedInfo();
  12. if ( == PackageManager.INSTALL_SUCCEEDED) {
  13. ();
  14. synchronized (mInstallLock) {
  15. installPackageLI(args, res);//注释1
  16. }
  17. (, );
  18. }
  19. ......省略......
  20. }

从注释1处可以看到,调用的是installPackageLI方法:

  1. private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
  2. ......省略......
  3. if (replace) {
  4. replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, ,
  5. installerPackageName, volumeUuid, res);
  6. } else {
  7. installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
  8. , installerPackageName, volumeUuid, res);
  9. }
  10. ......省略......
  11. }

如果是替换安装,则走replacePackageLI的逻辑。追踪replacePackageLI的逻辑流程:

 

  • replacePackageLI—>如果是系统应用则调用replaceSystemPackageLI—>再调用的scanPackageLI方法。
  • replacePackageLI—>如果是非系统应用则调用replaceNonSystemPackageLI—>再调用的scanPackageLI方法。

如果是第一次安装,则走installNewPackageLI。追踪installNewPackageLI的逻辑流程:

到了调用的scanPackageLI方法就到了系统应用安装过程中的“继续探究扫描安装过程”逻辑,后面的安装逻辑就与系统应用安装的逻辑一样了。

通过命令安装应用

命令安装应用的入口是:framework/base/cmds/pm/src/com/android/commands/pm/

应用安装的时候就会调用runInstall()方法:

  • installNewPackageLI—>再调用的scanPackageLI方法。
  1. private int runInstall() {
  2. ......省略......
  3. try {
  4. VerificationParams verificationParams = new VerificationParams(verificationURI,
  5. originatingURI, referrerURI, VerificationParams.NO_UID, null);
  6. (apkFilePath, (), installFlags,
  7. installerPackageName, verificationParams, abi, userId);//注释1
  8. ......省略......
  9. } catch (RemoteException e) {
  10. (());
  11. (PM_NOT_RUNNING_ERR);
  12. return 1;
  13. }
  14. }

从注释1处可以看到安装逻辑调用的是PackageManagerService—>installPackageAsUser方法。后面的调用逻辑就与“网络下载应用安装”的逻辑一样了。

通过外部设备安装应用

通过外部设备安装应用,调用的是Android内部的PackageInstaller去完成的,其本身也是一个apk。

代码位置在:/packages/apps/PackageInstaller/。 用于显示安装apk,但其最终的本质还是调用PackageManagerService去完成安装的。

当点击文件管理器中的apk时,文件管理器就会启动PackageInstaller中的PackageInstallerActivity,并将apk的信息通过intent传递给PackageInstallerActivity。

(1)深入到PackageInstallerActivity—>onCreate方法:

  1. @Override
  2. protected void onCreate(Bundle icicle) {
  3. super.onCreate(icicle);
  4. mPm = getPackageManager();
  5. mInstaller = ();//注释1
  6. mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
  7. final Intent intent = getIntent();
  8. //注释2
  9. if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(())) {
  10. final int sessionId = (PackageInstaller.EXTRA_SESSION_ID, -1);
  11. final PackageInstaller.SessionInfo info = (sessionId);
  12. if (info == null || !info.sealed || == null) {
  13. (TAG, "Session " + mSessionId + " in funky state; ignoring");
  14. finish();
  15. return;
  16. }
  17. mSessionId = sessionId;
  18. mPackageURI = (new File());
  19. mOriginatingURI = null;
  20. mReferrerURI = null;
  21. } else {
  22. mSessionId = -1;
  23. mPackageURI = ();
  24. mOriginatingURI = (Intent.EXTRA_ORIGINATING_URI);
  25. mReferrerURI = (Intent.EXTRA_REFERRER);
  26. }
  27. final boolean unknownSourcesAllowedByAdmin = isUnknownSourcesAllowedByAdmin();
  28. final boolean unknownSourcesAllowedByUser = isUnknownSourcesEnabled();
  29. //注释3
  30. boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
  31. ......省略.....
  32. // Block the install attempt on the Unknown Sources setting if necessary.
  33. if (!requestFromUnknownSource) {
  34. initiateInstall();//注释4
  35. return;
  36. }
  37. ......省略.....
  38. if (!unknownSourcesAllowedByAdmin
  39. || (!unknownSourcesAllowedByUser && isManagedProfile)) {
  40. showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES);
  41. (
  42. InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
  43. } else if (!unknownSourcesAllowedByUser) {
  44. // Ask user to enable setting first
  45. showDialogInner(DLG_UNKNOWN_SOURCES);
  46. (
  47. InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
  48. } else {
  49. initiateInstall();//注释5
  50. }
  51. }

注释1:获取PackageInstaller对象;

注释2:PackageInstaller检查权限;

注释3:PackageInstaller检查是否开启未知来源;

注释4、注释5:调用initiateInstall方法;

(2)继续深入到PackageInstallerActivity—>initiateInstall方法:

  1. private void initiateInstall() {
  2. String pkgName = ;
  3. // Check if there is already a package on the device with this name
  4. // but it has been renamed to something else.
  5. String[] oldName = (new String[] { pkgName });
  6. if (oldName != null && > 0 && oldName[0] != null) {
  7. pkgName = oldName[0];
  8. = pkgName;
  9. = pkgName;
  10. }
  11. // Check if package is already installed. display confirmation dialog if replacing pkg
  12. try {
  13. // This is a little convoluted because we want to get all uninstalled
  14. // apps, but this may include apps with just data, and if it is just
  15. // data we still want to count it as "installed".
  16. mAppInfo = (pkgName,
  17. PackageManager.GET_UNINSTALLED_PACKAGES);
  18. if ((&ApplicationInfo.FLAG_INSTALLED) == 0) {
  19. mAppInfo = null;
  20. }
  21. } catch (NameNotFoundException e) {
  22. mAppInfo = null;
  23. }
  24. (mAppInfo != null);
  25. (
  26. (mAppInfo != null) && (( & ApplicationInfo.FLAG_SYSTEM) != 0));
  27. startInstallConfirm();//调用
  28. }

initiateInstall方法主要负责检查是否已经安装过,是否是系统应用等。然后继续调用了startInstallConfirm方法。

(3) 接着深入到PackageInstallerActivity—>startInstallConfirm方法:

  1. private void startInstallConfirm() {
  2. TabHost tabHost = (TabHost)findViewById();
  3. ();
  4. ViewPager viewPager = (ViewPager)findViewById();
  5. TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager);
  6. (new TabHost.OnTabChangeListener() {
  7. @Override
  8. public void onTabChanged(String tabId) {
  9. if (TAB_ID_ALL.equals(tabId)) {
  10. (true);
  11. } else if (TAB_ID_NEW.equals(tabId)) {
  12. (true);
  13. }
  14. }
  15. });
  16. // If the app supports runtime permissions the new permissions will
  17. // be requested at runtime, hence we do not show them at install.
  18. boolean supportsRuntimePermissions =
  19. >= Build.VERSION_CODES.M;
  20. boolean permVisible = false;
  21. mScrollView = null;
  22. mOkCanInstall = false;
  23. int msg = 0;
  24. AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
  25. final int N = (AppSecurityPermissions.WHICH_ALL);
  26. if (mAppInfo != null) {
  27. msg = ( & ApplicationInfo.FLAG_SYSTEM) != 0
  28. ? .install_confirm_question_update_system
  29. : .install_confirm_question_update;
  30. mScrollView = new CaffeinatedScrollView(this);
  31. (true);
  32. boolean newPermissionsFound = false;
  33. if (!supportsRuntimePermissions) {
  34. newPermissionsFound =
  35. ((AppSecurityPermissions.WHICH_NEW) > 0);
  36. (newPermissionsFound);
  37. if (newPermissionsFound) {
  38. permVisible = true;
  39. ((
  40. AppSecurityPermissions.WHICH_NEW));
  41. }
  42. }
  43. if (!supportsRuntimePermissions && !newPermissionsFound) {
  44. LayoutInflater inflater = (LayoutInflater)getSystemService(
  45. Context.LAYOUT_INFLATER_SERVICE);
  46. TextView label = (TextView)(, null);
  47. (.no_new_perms);
  48. (label);
  49. }
  50. ((TAB_ID_NEW).setIndicator(
  51. getText()), mScrollView);
  52. } else {
  53. findViewById().setVisibility();
  54. findViewById().setVisibility();
  55. }
  56. if (!supportsRuntimePermissions && N > 0) {
  57. permVisible = true;
  58. LayoutInflater inflater = (LayoutInflater)getSystemService(
  59. Context.LAYOUT_INFLATER_SERVICE);
  60. View root = (.permissions_list, null);
  61. if (mScrollView == null) {
  62. mScrollView = (CaffeinatedScrollView)();
  63. }
  64. ((ViewGroup)(.permission_list)).addView(
  65. (AppSecurityPermissions.WHICH_ALL));
  66. ((TAB_ID_ALL).setIndicator(
  67. getText()), root);
  68. }
  69. (permVisible);
  70. if (!permVisible) {
  71. if (mAppInfo != null) {
  72. // This is an update to an application, but there are no
  73. // permissions at all.
  74. msg = ( & ApplicationInfo.FLAG_SYSTEM) != 0
  75. ? .install_confirm_question_update_system_no_perms
  76. : .install_confirm_question_update_no_perms;
  77. } else {
  78. // This is a new application with no permissions.
  79. msg = .install_confirm_question_no_perms;
  80. }
  81. ();
  82. (false);
  83. (false);
  84. findViewById().setVisibility();
  85. findViewById().setVisibility();
  86. mScrollView = null;
  87. }
  88. if (msg != 0) {
  89. ((TextView)findViewById(.install_confirm_question)).setText(msg);
  90. }
  91. ();
  92. mOk = (Button)findViewById(.ok_button);
  93. ();
  94. mCancel = (Button)findViewById(.cancel_button);
  95. (this);
  96. (this);
  97. //add by wangqi begin{@
  98. TabWidget tabWidget = ();
  99. int childCount = ();
  100. if (childCount == 2) {
  101. final View left = (0);
  102. final View right = (1);
  103. (() + 1);
  104. (() + 2);
  105. (());
  106. (new View.OnKeyListener() {
  107. @Override
  108. public boolean onKey(View v, int keyCode, KeyEvent event) {
  109. if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && () == KeyEvent.ACTION_DOWN) {
  110. ();
  111. }
  112. return true;
  113. }
  114. });
  115. }
  116. // end @}
  117. if (mScrollView == null) {
  118. // There is nothing to scroll view, so the ok button is immediately
  119. // set to install.
  120. //();
  121. mOkCanInstall = true;
  122. } else {
  123. (new Runnable() {
  124. @Override
  125. public void run() {
  126. //();
  127. mOkCanInstall = true;
  128. }
  129. });
  130. }
  131. }

从上面代码可以看到startInstallConfirm主要负责界面初始化,显示权限信息等。

界面初始化完成后,安装界面就会呈现在用户面前,如果用户想要安装这个应用程序,可以直接点击确认按钮,此时就会调用PackageInstallerActivity中的onClick方法:

  1. public void onClick(View v) {
  2. if (v == mOk) {
  3. if (mOkCanInstall || mScrollView == null) {
  4. ();
  5. if (mSessionId != -1) {
  6. (mSessionId, true);
  7. // We're only confirming permissions, so we don't really know how the
  8. // story ends; assume success.
  9. (
  10. PackageManager.INSTALL_SUCCEEDED);
  11. finish();
  12. } else {
  13. startInstall();//注释1
  14. }
  15. } else {
  16. (View.FOCUS_DOWN);
  17. }
  18. } else if(v == mCancel) {
  19. // Cancel and finish
  20. setResult(RESULT_CANCELED);
  21. if (mSessionId != -1) {
  22. (mSessionId, false);
  23. }
  24. (
  25. InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);
  26. finish();
  27. }
  28. }

onClick方法中分别会对取消和确定按钮做处理,如果是确定按钮,就会调用注释1处的startInstall方法。

(4) 下面到PackageInstallerActivity—>startInstall方法:

  1. private void startInstall() {
  2. // Start subactivity to actually install the application
  3. Intent newIntent = new Intent();
  4. (PackageUtil.INTENT_ATTR_APPLICATION_INFO,
  5. );
  6. (mPackageURI);
  7. (this, );//跳转的Activity
  8. (InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);
  9. (
  10. InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics);
  11. String installerPackageName = getIntent().getStringExtra(
  12. Intent.EXTRA_INSTALLER_PACKAGE_NAME);
  13. ......省略.....
  14. if(localLOGV) (TAG, "downloaded app uri="+mPackageURI);
  15. startActivity(newIntent);//注释1
  16. finish();
  17. }

startInstall方法启动后,将会跳转到注释1处的InstallAppProgress界面,并关掉当前的PackageInstallerActivity。

(5) 接着深入到文件中:

当启动时,会先调用—>onCreate方法:

  1. @Override
  2. public void onCreate(Bundle icicle) {
  3. ......省略.....
  4. initView();
  5. }
  1. public void initView() {
  2. ......省略.....
  3. if ("package".equals(())) {
  4. try {
  5. ();
  6. (,
  7. PackageManager.INSTALL_SUCCEEDED);
  8. } catch ( e) {
  9. (,
  10. PackageManager.INSTALL_FAILED_INVALID_APK);
  11. }
  12. } else {
  13. (mPackageURI, observer, installFlags,
  14. installerPackageName, verificationParams, null);
  15. }
  16. }

可以看到有两条安装逻辑,我这里只探索else中的逻辑。else中实际上是调用了ApplicationPackageManager的installPackageWithVerificationAndEncryption方法来安装。

(6) 再到ApplicationPackageManager—>installPackageWithVerificationAndEncryption方法:

  1. @Override
  2. public void installPackageWithVerificationAndEncryption(Uri packageURI,
  3. PackageInstallObserver observer, int flags, String installerPackageName,
  4. VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
  5. installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
  6. encryptionParams);//注释1
  7. }

注意installPackageWithVerificationAndEncryption方法上有个Override,说明继承于父类的PackageManager中。

从注释1中可以看到调用的是installCommon方法:

  1. private void installCommon(Uri packageURI,
  2. PackageInstallObserver observer, int flags, String installerPackageName,
  3. VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
  4. ......省略.....
  5. try {
  6. (originPath, (), flags, installerPackageName,
  7. verificationParams, null);//注释1
  8. } catch (RemoteException ignored) {
  9. }
  10. }

从注释1中可以看到调用的是PMS中的installPackage方法,到这里后续的逻辑就与前面的“网络下载应用安装”中的逻辑一样了。

结论:看到这里咱们就可以对apk的安装过程有清晰的感知了,在四种安装方式中每种安装方式的入口部分是特殊的流程,但是后面的流程都是一致的。

并且咱们对之前的疑惑也算是有了答案:apk的信息就是在安装的过程中通过对apk解析得到其信息并保存在对应的文件中的。

总结APK的安装流程如下:

复制APK安装包到/data/app目录下,解压缩并扫描安装包,向资源管理器注入APK资源,解析AndroidManifest文件,并在/data/data目录下创建对应的应用数据目录,然后针对Dalvik/ART环境优化dex文件,保存到dalvik-cache目录,将AndroidManifest文件解析出的组件、权限注册到PackageManagerService并发送广播。

see you