• Apk安装的主要步骤:
  • 1. 将apk文件copy至data/app目录
    • 1.1 installPackageAsUser
    • 1.2 handleMessage(INIT_COPY)&handleMessage(MCS_BOUND)
    • 1.3 HandlerParams.startCopy
    • 1.4 handleStartCopy()
  • 2 .解析apk信息
    • 2.1 processPendingInstall()
    • 2.2 installPackageLI(args, res)
    • 2.3 installNewPackageLI()
    • 2.4 scanPackageLI()
  • 3. dexopt操作
    • 3.1 performDexOptLI()
    • 3.2 Installer.dexopt
    • 3.3 commands::dexopt()
  • 4. 更新权限信息
    • 4.1 updatePermissionsLPw
  • 4.2 完成安装

    Apk安装的主要步骤:

    为了学习这个过程,真的是陷入了pms的源码很久,也看了很多前人的博文,才算是有了些思路,所以此处先把主要步骤列出来,后面再慢慢分析细节。

    1. 将apk文件复制到data/app目录
    2. 解析apk信息
    3. dexopt操作
    4. 更新权限信息
    5. 完成安装,发送Intent.ACTION_PACKAGE_ADDED广播

    下面将具体步骤列张图出来:

    Android Apk安装过程 - 图1

    由图可见安装过程中流转的步骤还是比较多的,下面具体分析

    1. 将apk文件copy至data/app目录

    1.1 installPackageAsUser

    1. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
    2. final int callingUid = Binder.getCallingUid();
    3. ...
    4. ...
    5. if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
    6. installFlags |= PackageManager.INSTALL_FROM_ADB;
    7. } else {
    8. // Caller holds INSTALL_PACKAGES permission, so we're less strict
    9. // about installerPackageName.
    10. installFlags &= ~PackageManager.INSTALL_FROM_ADB;
    11. installFlags &= ~PackageManager.INSTALL_ALL_USERS;
    12. }
    13. UserHandle user;
    14. if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
    15. user = UserHandle.ALL;
    16. } else {
    17. user = new UserHandle(userId);
    18. }
    19. verificationParams.setInstallerUid(callingUid);
    20. final File originFile = new File(originPath);
    21. final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
    22. final Message msg = mHandler.obtainMessage(INIT_COPY);
    23. msg.obj = new InstallParams(origin, observer, installFlags,
    24. installerPackageName, verificationParams, user, packageAbiOverride);
    25. mHandler.sendMessage(msg);

    这个方法主要是判断安装来源,包括adb,shell,all_user,然后向PMS的mHandler发送INIT_COPY的消息,这个mHandler运行在一个HandlerThread中。

    1.2 handleMessage(INIT_COPY)&handleMessage(MCS_BOUND)

    1. case INIT_COPY:{
    2. HandlerParams params = (HandlerParams) msg.obj;
    3. int idx = mPendingInstalls.size();
    4. if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
    5. // If a bind was already initiated we dont really
    6. // need to do anything. The pending install
    7. // will be processed later on.
    8. if (!mBound) {
    9. // If this is the only one pending we might
    10. // have to bind to the service again.
    11. if (!connectToService()) {
    12. Slog.e(TAG, "Failed to bind to media container service");
    13. params.serviceError();
    14. return;
    15. } else {
    16. // Once we bind to the service, the first
    17. // pending request will be processed.
    18. mPendingInstalls.add(idx, params);
    19. }
    20. } else {
    21. mPendingInstalls.add(idx, params);
    22. // Already bound to the service. Just make
    23. // sure we trigger off processing the first request.
    24. if (idx == 0) {
    25. mHandler.sendEmptyMessage(MCS_BOUND);
    26. }
    27. }
    28. }
    29. case MCS_BOUND:{
    30. ...
    31. ...
    32. HandlerParams params = mPendingInstalls.get(0);
    33. if (params != null) {
    34. if (params.startCopy()) {
    35. // We are done... look for more work or to
    36. // go idle.
    37. if (DEBUG_SD_INSTALL) Log.i(TAG,
    38. "Checking for more work or unbind...");
    39. // Delete pending install
    40. if (mPendingInstalls.size() > 0) {
    41. mPendingInstalls.remove(0);
    42. }
    43. if (mPendingInstalls.size() == 0) {
    44. if (mBound) {
    45. if (DEBUG_SD_INSTALL) Log.i(TAG,
    46. "Posting delayed MCS_UNBIND");
    47. removeMessages(MCS_UNBIND);
    48. Message ubmsg = obtainMessage(MCS_UNBIND);
    49. // Unbind after a little delay, to avoid
    50. // continual thrashing.
    51. sendMessageDelayed(ubmsg, 10000);
    52. }
    53. ...
    54. ...
    55. }

    INIT_COPY主要是确保DefaultContainerService已bound,DefaultContainerService是一个应用服务,具体负责实现APK等相关资源文件在内部或外部存储器上的存储工作。而MCS_BOUND中则执行了
    params.startCopy()这句,也是最关键的开始copy文件。

    1.3 HandlerParams.startCopy

    1. final boolean startCopy() {
    2. boolean res;
    3. try {
    4. if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
    5. if (++mRetries > 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 false;
    10. } else {
    11. handleStartCopy();
    12. res = true;
    13. }
    14. } catch (RemoteException e) {
    15. if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
    16. mHandler.sendEmptyMessage(MCS_RECONNECT);
    17. res = false;
    18. }
    19. handleReturnCode();
    20. return res;
    21. }

    该方法中除了检查重试次数外只是简单的调用了handleStartCopy()handleReturnCode()方法.

    1.4 handleStartCopy()

    这个方法内容非常多,下面只列出些核心部分

    1. public void handleStartCopy() throws RemoteException {
    2. int ret = PackageManager.INSTALL_SUCCEEDED;
    3. ...
    4. ...
    5. final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
    6. final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
    7. PackageInfoLite pkgLite = null;
    8. if (onInt && onSd) {
    9. // Check if both bits are set.
    10. Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
    11. ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
    12. } else {
    13. pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
    14. packageAbiOverride);
    15. /*
    16. * If we have too little free space, try to free cache
    17. * before giving up.
    18. */
    19. if (!origin.staged && pkgLite.recommendedInstallLocation
    20. == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
    21. final StorageManager storage = StorageManager.from(mContext);
    22. final long lowThreshold = storage.getStorageLowBytes(
    23. Environment.getDataDirectory());
    24. final long sizeBytes = mContainerService.calculateInstalledSize(
    25. origin.resolvedPath, isForwardLocked(), packageAbiOverride);
    26. if (mInstaller.freeCache(sizeBytes + lowThreshold) >= 0) {
    27. pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
    28. installFlags, packageAbiOverride);
    29. }
    30. }
    31. }
    32. ...
    33. ...
    34. * No package verification is enabled, so immediately start
    35. * the remote call to initiate copy using temporary file.
    36. */
    37. ret = args.copyApk(mContainerService, true);
    38. }
    39. mRet = ret;
    40. }

    handleStartCopy的核心就是copyApk,其他的都是些存储空间检查,权限检查等等安全校验

    2 .解析apk信息

    完成apk copy到data/app目录的操作后,下一步就到了 handleReturnCode,这个方法又跳转到processPendingInstall()方法,下面先来看看processPendingInstall()方法:

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

    这个方法有几个关键步骤,一是installPackageLI(args, res);,这个方法具体执行了解析package和后续操作,而再installPackageLI(args, res);执行完毕后会走到bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);,会调用backupservice的restoreAtInstall方法,而restoreAtInstall方法最终又会调用PMSfinishPackageInstall()方法,完成安装。

    2.2 installPackageLI(args, res)

    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. if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
    12. // Retrieve PackageSettings and parse package
    13. final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
    14. | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
    15. | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
    16. PackageParser pp = new PackageParser();
    17. pp.setSeparateProcesses(mSeparateProcesses);
    18. pp.setDisplayMetrics(mMetrics);
    19. final PackageParser.Package pkg;
    20. try {
    21. pkg = pp.parsePackage(tmpPackageFile, parseFlags);
    22. } catch (PackageParserException e) {
    23. res.setError("Failed parse during installPackageLI", e);
    24. return;
    25. }
    26. // Mark that we have an install time CPU ABI override.
    27. pkg.cpuAbiOverride = args.abiOverride;
    28. String pkgName = res.name = pkg.packageName;
    29. if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
    30. if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
    31. res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
    32. return;
    33. }
    34. }
    35. try {
    36. pp.collectCertificates(pkg, parseFlags);
    37. pp.collectManifestDigest(pkg);
    38. } catch (PackageParserException e) {
    39. res.setError("Failed collect during installPackageLI", e);
    40. return;
    41. }
    42. /* If the installer passed in a manifest digest, compare it now. */
    43. if (args.manifestDigest != null) {
    44. if (DEBUG_INSTALL) {
    45. final String parsedManifest = pkg.manifestDigest == null ? "null"
    46. : pkg.manifestDigest.toString();
    47. Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
    48. + parsedManifest);
    49. }
    50. if (!args.manifestDigest.equals(pkg.manifestDigest)) {
    51. res.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest changed");
    52. return;
    53. }
    54. } else if (DEBUG_INSTALL) {
    55. final String parsedManifest = pkg.manifestDigest == null
    56. ? "null" : pkg.manifestDigest.toString();
    57. Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);
    58. }
    59. // Get rid of all references to package scan path via parser.
    60. pp = null;
    61. String oldCodePath = null;
    62. boolean systemApp = false;
    63. synchronized (mPackages) {
    64. // Check whether the newly-scanned package wants to define an already-defined perm
    65. int N = pkg.permissions.size();
    66. for (int i = N-1; i >= 0; i--) {
    67. PackageParser.Permission perm = pkg.permissions.get(i);
    68. BasePermission bp = mSettings.mPermissions.get(perm.info.name);
    69. if (bp != null) {
    70. // If the defining package is signed with our cert, it's okay. This
    71. // also includes the "updating the same package" case, of course.
    72. // "updating same package" could also involve key-rotation.
    73. final boolean sigsOk;
    74. if (!bp.sourcePackage.equals(pkg.packageName)
    75. || !(bp.packageSetting instanceof PackageSetting)
    76. || !bp.packageSetting.keySetData.isUsingUpgradeKeySets()
    77. || ((PackageSetting) bp.packageSetting).sharedUser != null) {
    78. sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
    79. pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
    80. } else {
    81. sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
    82. }
    83. if (!sigsOk) {
    84. // If the owning package is the system itself, we log but allow
    85. // install to proceed; we fail the install on all other permission
    86. // redefinitions.
    87. if (!bp.sourcePackage.equals("android")) {
    88. res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
    89. + pkg.packageName + " attempting to redeclare permission "
    90. + perm.info.name + " already owned by " + bp.sourcePackage);
    91. res.origPermission = perm.info.name;
    92. res.origPackage = bp.sourcePackage;
    93. return;
    94. } else {
    95. Slog.w(TAG, "Package " + pkg.packageName
    96. + " attempting to redeclare system permission "
    97. + perm.info.name + "; ignoring new declaration");
    98. pkg.permissions.remove(i);
    99. }
    100. }
    101. }
    102. }
    103. // Check if installing already existing package
    104. if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
    105. String oldName = mSettings.mRenamedPackages.get(pkgName);
    106. if (pkg.mOriginalPackages != null
    107. && pkg.mOriginalPackages.contains(oldName)
    108. && mPackages.containsKey(oldName)) {
    109. // This package is derived from an original package,
    110. // and this device has been updating from that original
    111. // name. We must continue using the original name, so
    112. // rename the new package here.
    113. pkg.setPackageName(oldName);
    114. pkgName = pkg.packageName;
    115. replace = true;
    116. if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
    117. + oldName + " pkgName=" + pkgName);
    118. } else if (mPackages.containsKey(pkgName)) {
    119. // This package, under its official name, already exists
    120. // on the device; we should replace it.
    121. replace = true;
    122. if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
    123. }
    124. }
    125. PackageSetting ps = mSettings.mPackages.get(pkgName);
    126. if (ps != null) {
    127. if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
    128. oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
    129. if (ps.pkg != null && ps.pkg.applicationInfo != null) {
    130. systemApp = (ps.pkg.applicationInfo.flags &
    131. ApplicationInfo.FLAG_SYSTEM) != 0;
    132. }
    133. res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
    134. }
    135. }
    136. if (systemApp && onSd) {
    137. // Disable updates to system apps on sdcard
    138. res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
    139. "Cannot install updates to system apps on sdcard");
    140. return;
    141. }
    142. if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
    143. res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
    144. return;
    145. }
    146. if (replace) {
    147. replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
    148. installerPackageName, res);
    149. } else {
    150. installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
    151. args.user, installerPackageName, res);
    152. }
    153. synchronized (mPackages) {
    154. final PackageSetting ps = mSettings.mPackages.get(pkgName);
    155. if (ps != null) {
    156. res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
    157. }
    158. }
    159. }

    这个方法先是解析了package包,然后做了大量签名和权限校验的工作,最终会走到

    1. if (replace) {
    2. replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
    3. installerPackageName, res);
    4. } else {
    5. installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
    6. args.user, installerPackageName, res);
    7. }

    这两个方法分别是覆盖安装和安装新应用对应的具体执行.我们来看看installNewPackageLI()

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

    这个方法核心的步骤有两个:

    • PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,System.currentTimeMillis(), user);
    • updateSettingsLI(newPackage, installerPackageName, null, null, res);

    scanPackageLI负责安装,而updateSettingLI则是完成安装后的设置信息更新

    2.4 scanPackageLI()

    scanPackageLI()方法主要逻辑是由scanPackageDirtyLI()实现的,scanPackageDirtyLI()实在太长了,此处就不列出了,主要说下,这个方法实现了以下操作:

    • 设置系统App的一些参数
    • 校验签名
    • 解析app的provider,校验是否与已有的provider冲突
    • 32/64位abi的一些设置
    • 四大组件的解析,注册

    scanPackageDirtyLI()里面的操作确实是太多了,并不止这几点。如需更详细的信息还请查看源码。

    另一方面,这个方法里,会调用到performDexOptLI(),其会去执行dexopt操作

    3. dexopt操作

    Apk文件其实只是一个归档zip压缩包,而我们编写的代码最终都编译成了.dex文件,但为了提高运行性能,android系统并不会直接执行.dex,而是会在安装过程中执行dexopt操作来优化.dex文件,最终android系统执行的时优化后的’odex’文件(注意:这个odex文件的后缀也是.dex,其路径在data/dalvik-cache)。对于dalvik虚拟机,dexopt就是优化操作,而对于art虚拟机,dexopt执行的则是dex2oat操作,既将.dex文件翻译成oat文件。关于artdex2oat的更多信息请看后文。

    这里我们先来看看PMSdexopt操作:

    3.1 performDexOptLI()

    这个方法的核心是

    1. final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg), pkg.packageName, dexCodeInstructionSet, vmSafeMode);

    其作用就是调用PMSmInstaller成员变量的dexopt操作。

    3.2 Installer.dexopt

    Installer类的dexopt方法又调用InstallerConnection类的dexopt方法,来看看这个方法:

    1. public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
    2. String instructionSet, boolean vmSafeMode) {
    3. StringBuilder builder = new StringBuilder("dexopt");
    4. builder.append(' ');
    5. builder.append(apkPath);
    6. builder.append(' ');
    7. builder.append(uid);
    8. builder.append(isPublic ? " 1" : " 0");
    9. builder.append(' ');
    10. builder.append(pkgName);
    11. builder.append(' ');
    12. builder.append(instructionSet);
    13. builder.append(' ');
    14. builder.append(vmSafeMode ? " 1" : " 0");
    15. return execute(builder.toString());
    16. }
    17. public synchronized String transact(String cmd) {
    18. if (!connect()) {
    19. Slog.e(TAG, "connection failed");
    20. return "-1";
    21. }
    22. if (!writeCommand(cmd)) {
    23. /*
    24. * If installd died and restarted in the background (unlikely but
    25. * possible) we'll fail on the next write (this one). Try to
    26. * reconnect and write the command one more time before giving up.
    27. */
    28. Slog.e(TAG, "write command failed? reconnect!");
    29. if (!connect() || !writeCommand(cmd)) {
    30. return "-1";
    31. }
    32. }
    33. if (LOCAL_DEBUG) {
    34. Slog.i(TAG, "send: '" + cmd + "'");
    35. }
    36. final int replyLength = readReply();
    37. if (replyLength > 0) {
    38. String s = new String(buf, 0, replyLength);
    39. if (LOCAL_DEBUG) {
    40. Slog.i(TAG, "recv: '" + s + "'");
    41. }
    42. return s;
    43. } else {
    44. if (LOCAL_DEBUG) {
    45. Slog.i(TAG, "fail");
    46. }
    47. return "-1";
    48. }
    49. }
    50. public int execute(String cmd) {
    51. String res = transact(cmd);
    52. try {
    53. return Integer.parseInt(res);
    54. } catch (NumberFormatException ex) {
    55. return -1;
    56. }
    57. }
    58. private boolean connect() {
    59. if (mSocket != null) {
    60. return true;
    61. }
    62. Slog.i(TAG, "connecting...");
    63. try {
    64. mSocket = new LocalSocket();
    65. LocalSocketAddress address = new LocalSocketAddress("installd",
    66. LocalSocketAddress.Namespace.RESERVED);
    67. mSocket.connect(address);
    68. mIn = mSocket.getInputStream();
    69. mOut = mSocket.getOutputStream();
    70. } catch (IOException ex) {
    71. disconnect();
    72. return false;
    73. }
    74. return true;
    75. }

    由上面的几个方法可以知道,最终dexopt操作是通过socket的方式来跨进程通知守护进程installd,由其去执行dexopt操作。

    3.3 commands::dexopt()

    最终守护进程installd会调用Commands.c文件(位于/source/framework/native/cmds/installd)的dexopt方法。

    1. int dexopt(const char *apk_path, uid_t uid, bool is_public,
    2. const char *pkgname, const char *instruction_set,
    3. bool vm_safe_mode, bool is_patchoat)
    4. {
    5. struct utimbuf ut;
    6. struct stat input_stat, dex_stat;
    7. char out_path[PKG_PATH_MAX];
    8. char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX];
    9. char *end;
    10. const char *input_file;
    11. char in_odex_path[PKG_PATH_MAX];
    12. int res, input_fd=-1, out_fd=-1;
    13. ...
    14. ...
    15. pid_t pid;
    16. pid = fork();
    17. if (pid == 0) {
    18. /* child -- drop privileges before continuing */
    19. if (setgid(uid) != 0) {
    20. ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
    21. exit(64);
    22. }
    23. if (setuid(uid) != 0) {
    24. ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
    25. exit(65);
    26. }
    27. // drop capabilities
    28. struct __user_cap_header_struct capheader;
    29. struct __user_cap_data_struct capdata[2];
    30. memset(&capheader, 0, sizeof(capheader));
    31. memset(&capdata, 0, sizeof(capdata));
    32. capheader.version = _LINUX_CAPABILITY_VERSION_3;
    33. if (capset(&capheader, &capdata[0]) < 0) {
    34. ALOGE("capset failed: %s\n", strerror(errno));
    35. exit(66);
    36. }
    37. if (set_sched_policy(0, SP_BACKGROUND) < 0) {
    38. ALOGE("set_sched_policy failed: %s\n", strerror(errno));
    39. exit(70);
    40. }
    41. if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) {
    42. ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno));
    43. exit(67);
    44. }
    45. if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) {
    46. run_dexopt(input_fd, out_fd, input_file, out_path);
    47. } else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) {
    48. if (is_patchoat) {
    49. run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set);
    50. } else {
    51. run_dex2oat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set,
    52. vm_safe_mode);
    53. }
    54. } else {
    55. exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */
    56. }
    57. exit(68); /* only get here on exec failure */
    58. } else {
    59. res = wait_child(pid);
    60. if (res == 0) {
    61. ALOGV("DexInv: --- END '%s' (success) ---\n", input_file);
    62. } else {
    63. ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res);
    64. goto fail;
    65. }
    66. }
    67. ut.actime = input_stat.st_atime;
    68. ut.modtime = input_stat.st_mtime;
    69. utime(out_path, &ut);
    70. close(out_fd);
    71. close(input_fd);
    72. return 0;
    73. fail:
    74. if (out_fd >= 0) {
    75. close(out_fd);
    76. unlink(out_path);
    77. }
    78. if (input_fd >= 0) {
    79. close(input_fd);
    80. }
    81. return -1;
    82. }

    由上面的代码可以发现,installd在做了些操作后,fork出了一个新的进程,根据虚拟机的类型为libdvmlibart分别执行run_dexoptrun_dex2oat(如果为is_patchoat,则是run_patchoat)操作。

    4. 更新权限信息

    dexopt操作执行完后,installNewPackageLI()方法就会走到updateSettingsLI()来更新设置信息,而更新设置信息主要是权限信息,所以直接来看updatePermissionsLPw();

    4.1 updatePermissionsLPw

    1. private void updatePermissionsLPw(String changingPkg,
    2. PackageParser.Package pkgInfo, int flags) {
    3. // Make sure there are no dangling permission trees.
    4. Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
    5. while (it.hasNext()) {
    6. final BasePermission bp = it.next();
    7. if (bp.packageSetting == null) {
    8. // We may not yet have parsed the package, so just see if
    9. // we still know about its settings.
    10. bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
    11. }
    12. if (bp.packageSetting == null) {
    13. Slog.w(TAG, "Removing dangling permission tree: " + bp.name
    14. + " from package " + bp.sourcePackage);
    15. it.remove();
    16. } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
    17. if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
    18. Slog.i(TAG, "Removing old permission tree: " + bp.name
    19. + " from package " + bp.sourcePackage);
    20. flags |= UPDATE_PERMISSIONS_ALL;
    21. it.remove();
    22. }
    23. }
    24. }
    25. // Make sure all dynamic permissions have been assigned to a package,
    26. // and make sure there are no dangling permissions.
    27. it = mSettings.mPermissions.values().iterator();
    28. while (it.hasNext()) {
    29. final BasePermission bp = it.next();
    30. if (bp.type == BasePermission.TYPE_DYNAMIC) {
    31. if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
    32. + bp.name + " pkg=" + bp.sourcePackage
    33. + " info=" + bp.pendingInfo);
    34. if (bp.packageSetting == null && bp.pendingInfo != null) {
    35. final BasePermission tree = findPermissionTreeLP(bp.name);
    36. if (tree != null && tree.perm != null) {
    37. bp.packageSetting = tree.packageSetting;
    38. bp.perm = new PackageParser.Permission(tree.perm.owner,
    39. new PermissionInfo(bp.pendingInfo));
    40. bp.perm.info.packageName = tree.perm.info.packageName;
    41. bp.perm.info.name = bp.name;
    42. bp.uid = tree.uid;
    43. }
    44. }
    45. }
    46. if (bp.packageSetting == null) {
    47. // We may not yet have parsed the package, so just see if
    48. // we still know about its settings.
    49. bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
    50. }
    51. if (bp.packageSetting == null) {
    52. Slog.w(TAG, "Removing dangling permission: " + bp.name
    53. + " from package " + bp.sourcePackage);
    54. it.remove();
    55. } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
    56. if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
    57. Slog.i(TAG, "Removing old permission: " + bp.name
    58. + " from package " + bp.sourcePackage);
    59. flags |= UPDATE_PERMISSIONS_ALL;
    60. it.remove();
    61. }
    62. }
    63. }
    64. // Now update the permissions for all packages, in particular
    65. // replace the granted permissions of the system packages.
    66. if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
    67. for (PackageParser.Package pkg : mPackages.values()) {
    68. if (pkg != pkgInfo) {
    69. grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,
    70. changingPkg);
    71. }
    72. }
    73. }
    74. if (pkgInfo != null) {
    75. grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);
    76. }
    77. }
    78. private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
    79. String packageOfInterest) {
    80. final PackageSetting ps = (PackageSetting) pkg.mExtras;
    81. if (ps == null) {
    82. return;
    83. }
    84. final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
    85. HashSet<String> origPermissions = gp.grantedPermissions;
    86. boolean changedPermission = false;
    87. if (replace) {
    88. ps.permissionsFixed = false;
    89. if (gp == ps) {
    90. origPermissions = new HashSet<String>(gp.grantedPermissions);
    91. gp.grantedPermissions.clear();
    92. gp.gids = mGlobalGids;
    93. }
    94. }
    95. if (gp.gids == null) {
    96. gp.gids = mGlobalGids;
    97. }
    98. final int N = pkg.requestedPermissions.size();
    99. for (int i=0; i<N; i++) {
    100. final String name = pkg.requestedPermissions.get(i);
    101. final boolean required = pkg.requestedPermissionsRequired.get(i);
    102. final BasePermission bp = mSettings.mPermissions.get(name);
    103. if (DEBUG_INSTALL) {
    104. if (gp != ps) {
    105. Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
    106. }
    107. }
    108. if (bp == null || bp.packageSetting == null) {
    109. if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
    110. Slog.w(TAG, "Unknown permission " + name
    111. + " in package " + pkg.packageName);
    112. }
    113. continue;
    114. }
    115. final String perm = bp.name;
    116. boolean allowed;
    117. boolean allowedSig = false;
    118. if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
    119. // Keep track of app op permissions.
    120. ArraySet<String> pkgs = mAppOpPermissionPackages.get(bp.name);
    121. if (pkgs == null) {
    122. pkgs = new ArraySet<>();
    123. mAppOpPermissionPackages.put(bp.name, pkgs);
    124. }
    125. pkgs.add(pkg.packageName);
    126. }
    127. final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
    128. if (level == PermissionInfo.PROTECTION_NORMAL
    129. || level == PermissionInfo.PROTECTION_DANGEROUS) {
    130. // We grant a normal or dangerous permission if any of the following
    131. // are true:
    132. // 1) The permission is required
    133. // 2) The permission is optional, but was granted in the past
    134. // 3) The permission is optional, but was requested by an
    135. // app in /system (not /data)
    136. //
    137. // Otherwise, reject the permission.
    138. allowed = (required || origPermissions.contains(perm)
    139. || (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
    140. } else if (bp.packageSetting == null) {
    141. // This permission is invalid; skip it.
    142. allowed = false;
    143. } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
    144. allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
    145. if (allowed) {
    146. allowedSig = true;
    147. }
    148. } else {
    149. allowed = false;
    150. }
    151. if (DEBUG_INSTALL) {
    152. if (gp != ps) {
    153. Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
    154. }
    155. }
    156. if (allowed) {
    157. if (!isSystemApp(ps) && ps.permissionsFixed) {
    158. // If this is an existing, non-system package, then
    159. // we can't add any new permissions to it.
    160. if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
    161. // Except... if this is a permission that was added
    162. // to the platform (note: need to only do this when
    163. // updating the platform).
    164. allowed = isNewPlatformPermissionForPackage(perm, pkg);
    165. }
    166. }
    167. if (allowed) {
    168. if (!gp.grantedPermissions.contains(perm)) {
    169. changedPermission = true;
    170. gp.grantedPermissions.add(perm);
    171. gp.gids = appendInts(gp.gids, bp.gids);
    172. } else if (!ps.haveGids) {
    173. gp.gids = appendInts(gp.gids, bp.gids);
    174. }
    175. } else {
    176. if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
    177. Slog.w(TAG, "Not granting permission " + perm
    178. + " to package " + pkg.packageName
    179. + " because it was previously installed without");
    180. }
    181. }
    182. } else {
    183. if (gp.grantedPermissions.remove(perm)) {
    184. changedPermission = true;
    185. gp.gids = removeInts(gp.gids, bp.gids);
    186. Slog.i(TAG, "Un-granting permission " + perm
    187. + " from package " + pkg.packageName
    188. + " (protectionLevel=" + bp.protectionLevel
    189. + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
    190. + ")");
    191. } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
    192. // Don't print warning for app op permissions, since it is fine for them
    193. // not to be granted, there is a UI for the user to decide.
    194. if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
    195. Slog.w(TAG, "Not granting permission " + perm
    196. + " to package " + pkg.packageName
    197. + " (protectionLevel=" + bp.protectionLevel
    198. + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
    199. + ")");
    200. }
    201. }
    202. }
    203. }
    204. if ((changedPermission || replace) && !ps.permissionsFixed &&
    205. !isSystemApp(ps) || isUpdatedSystemApp(ps)){
    206. // This is the first that we have heard about this package, so the
    207. // permissions we have now selected are fixed until explicitly
    208. // changed.
    209. ps.permissionsFixed = true;
    210. }
    211. ps.haveGids = true;
    212. }

    由上面两个方法可以看到,在apk的安装时PMS会将该app的所有权限都记录下来并更新到PMSmAppOpPermissionPackages成员变量里面,并判定是否授予该app请求的权限。

    4.2 完成安装

    还记得前面说过的在processPendingInstall方法在执行installPackageLi后会执行以下语句

    1. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
    2. // Pass responsibility to the Backup Manager. It will perform a
    3. // restore if appropriate, then pass responsibility back to the
    4. // Package Manager to run the post-install observer callbacks
    5. // and broadcasts.
    6. IBackupManager bm = IBackupManager.Stub.asInterface(
    7. ServiceManager.getService(Context.BACKUP_SERVICE));
    8. if (bm != null) {
    9. if (DEBUG_INSTALL) Log.v(TAG, "token " + token
    10. + " to BM for possible restore");
    11. try {
    12. bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
    13. } catch (RemoteException e) {
    14. // can't happen; the backup manager is local
    15. } catch (Exception e) {
    16. Slog.e(TAG, "Exception trying to enqueue restore", e);
    17. doRestore = false;
    18. }
    19. } else {
    20. Slog.e(TAG, "Backup Manager not found!");
    21. doRestore = false;
    22. }
    23. }

    我也不是很清楚为什么系统会调用IBackupManagerrestoreAtInstall方法,不过发现在BackupManagerServicerestoreAtInstall方法中会有以下代码:

    1. ...
    2. if (skip) {
    3. // Auto-restore disabled or no way to attempt a restore; just tell the Package
    4. // Manager to proceed with the post-install handling for this package.
    5. if (DEBUG) Slog.v(TAG, "Finishing install immediately");
    6. try {
    7. mPackageManagerBinder.finishPackageInstall(token);
    8. } catch (RemoteException e) { /* can't happen */ }
    9. }
    10. ...

    最终restoreAtInstall方法又会调用PMSfinishPackageInstall方法,而此方法最终会发送Intent.ACTION_PACKAGE_ADDED广播,apk的安装就到到此结束了。