This article is just a guide to the PkMS. It will not post a large chunk of code for analysis, but more based on method analysis of the implementation logic. In addition, the code is based on Android 11, which is quite different from the code before Android 10.

Content of this article

  1. How does the PkMS know the location of the APK
  2. The difference between system application and ordinary application
  3. Application scanning process and application information preservation

How does the PkMS know where the APK is

The answer is according to the path. For mobile phone users, the installed applications are placed in /data/app, while for system applications, they are distributed in various partitions, which can be simply regarded as directories, and /data is the data partition. The following partitions will be scanned, and only the priv-app and app directories will be scanned:

  1. Priv-app, app directory in the System partition/system/priv-app./system/app
  2. The product division
  3. Odm partition
  4. OEM partition
  5. Vendor partition
  6. System_ext partition
  7. Data partition, and finally scan

However, these partitions are not very strict implementation, do not involve the GMS test of the basic care, so where does APK exist? For example: Settings on/system_ext/priv – app/Settings/Settings. The apk, other partitions are similar, the analysis of application of the scanning process will also said. Here, why do we scan priv-app and app directories? Priv – app mean inside this directory are ring application, access privilege rights, the definition of permissions frameworks/base/core/res/AndroidManifest. Found in XML

The difference between system application and ordinary application

The answer is path. Applications in the data partition are common applications, and applications installed in other partitions are system applications. System applications cannot be uninstalled

Application scanning process

scanDirLI()

The parameters of scanDirLI are described.

  1. ScanDir: collection of application directories. For example, Settings/system_ext/priv-app
  2. ScanFlags: indicates the scanning flag, which is added when the system is usedSCAN_AS_SYSTEMFlag, plus if it’s a priv-app directorySCAN_AS_PRIVILGED
  3. PackageParser is the main utility class for parsing AndroidManifest.xml
  4. ExecutorService, the producer thread

ScanDirLI’s logic is simpler,

  1. In the above/system_ext/priv-appFor example, walk through each directory and APK in the directory
  2. Parse all directories and APK using ExecutorService(thread pool). See the PkMS Parse Package guide for details
  3. Get the ParsedPackage and make the calladdForInitLI()

addForInitLI()

The logic is quite complex, consider the situation to also want a lot of, some oneself also did not understand, just pick can say

  1. First, the logic of renaming the package name. In PkMS, all packages use the package name as the unique primary key, so the application may need to change the package name. PkMS solution is given with the < the original – package android: name = “com. Android. Oldpackagename” / > indicate the need to cover installation package names, but need to take into account many situation just the way they are

    1. What if the package name is changed multiple times
    2. The handling of applications that have previously installed the old package name
    3. Handling of applications with old package names that have not been installed before
    4. Processing of applications that have previously installed the current package name

    So what does PkMS do?

    1. OriginalPackages: originalPackages: originalPackages: originalPackages: originalPackages: originalPackages: originalPackages: originalPackages

      //ParsingPackageUtils.parseOriginalPackage()
      String orig = sa.getNonConfigurationString(
          R.styleable.AndroidManifestOriginalPackage_name,
          0);
      if(! pkg.getPackageName().equals(orig)) {if (pkg.getOriginalPackages().isEmpty()) {
              pkg.setRealPackage(pkg.getPackageName());
          }
          pkg.addOriginalPackage(orig);
      }
      
      Copy the code
    2. Then get originalPkgSetting based on realPkgName in addForInitLI()

    3. Next, determine whether to overwrite the installed application

    The PackageInstaller and PermissionController are designed to replace apps in the AOSP with GMS apps. They are not universal, and if they are tagged, they will still be considered as two apps

  2. What is an overwritten installation system application? The system application is updated and can be downloaded through the app store to cover the installation, but the system application is not uninstalled, but disable the system application, such as Google’s GMS application

    1. If the installed application is faulty, enable the disabled application again

    2. If the application isa system update, the disabled application needs to be scanned because the OTA upgrade may cause the system application to update apK. In this case, call scanPackageOnlyLI() to scan, which will be analyzed later

    3. Next, determine whether to reuse the system application based on the version of the disabled application and the installed application

  3. Handle signatures, which are required for installed applications

    1. This part of the AOSP is not written at all. The second part in the comment is not implemented yet
    // Verify certificates against what was last scanned. Force re-collecting certificate in two
    // special cases:
    // 1) when scanning system, force re-collect only if system is upgrading.
    // 2) when scannning /data, force re-collect only if the app is privileged (updated from
    // preinstall, or treated as privileged, e.g. due to shared user ID).
    final boolean forceCollect = scanSystemPartition ? mIsUpgrade
        : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
    Copy the code
    1. Whether to skip signature verification, this is used when overwriting installation
    // Full APK verification can be skipped during certificate collection, only if the file is
    // in verified partition, or can be verified on access (when apk verity is enabled). In both
    // cases, only data in Signing Block is verified instead of the whole file.
    // TODO(b/136132412): skip for Incremental installation
    final boolean skipVerify = scanSystemPartition
        || (forceCollect && canSkipForcedPackageVerification(parsedPackage));
    collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
    
    Copy the code
  4. We also deal with the reverse of step 3, where there is an installed application (data partition) and then an OTA upgrade that adds the system application (system or other partition), which is discussed in three scenarios

    1. If the signatures are different, uninstall the applications in the data partition
    2. If the version of the system application is higher, the application in the data partition is removed, but the data of the application is retained
    3. If the version number used by the system is lower, theshouldHideSystemAppSet to true to apply to the disable system below
  5. Call scanPackageNewLI() to continue the scan

  6. ReconcilePackagesLocked () is invoked for reconciliation

  7. Call commitReconciledScanResultLocked ()

scanPackageNewLI()

It is important to note that this method is not only used during startup scanning, but also when installing the application

  1. Rename the package again, this should be related to the installation, when I test the overwrite installation system application is valid, the normal application is not valid, will be considered as two applications
  2. calladjustFlags()To readjustscanFlags, can be divided into the following situations
    1. The application that renames the package name application or overrides the installation is the system application, and scanFlags is added to itSCAN_AS_SYSTEMAnd possibly other flags
    2. If the Privilege application is included in sharedUserId, the application being scanned must be added as wellSCAN_AS_PRIVILEGED
  3. To obtainSharedUserSettingAt theaddForInitLI()Obtained once for scanning disabledPkgSetting
  4. buildScanRequestAnd callscanPackageOnlyLI()To obtainScanResult

scanPackageOnlyLI()

The main logic in this section is to update the interpretation of packageSetting and library

  1. Determine if you need to get the ABI (needToDeriveAbi), if packageSetting, if the application is installed, there is no need to change the cpuAbi, and if not, parse the native library
  2. Get the

    tag. I don’t know what it is. I haven’t seen it yet
  3. Update or create a newPackageSetting, there are two types of creation, the first installation of the application or factory restore boot
  4. According to the first stepneedToDeriveAbiGet the type of abi and set it in PackageSetting. Another thing is to parse the native SO library in APK and get the path to the corresponding SO library. Here is aSCAN_NEW_INSTALLFlag, this is for installation, scan will not cause this problem
  5. Set the timestamp of the installation, primarily the first and current installation. The use of this property is unknown at this time
  6. createScanResultAnd return

reconcilePackagesLocked()

Let’s start with a few parameters:

  1. ReconcileRequestAllPackages ->mPackages, scannedPackages->scanPackageOnlyLI() SharedLibrarySource ->mSharedLibraries will push only after being parsed
  2. KeySetManagerServiceSignature Management Service

ReconcilePackagesLocked () is also invoked by the process that installed the application, so some of the arguments from ReconcileRequest are for them, and the main function of this method is to verify signatures

  1. First check whether the signature needs to be updatedksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)This is not very understandable, the signature can be updated?
  2. callverifySignatures()Verify signature
  3. The last generationReconciledPackageAnd return

commitReconciledScanResultLocked()

This is also a method that is called both when you install the application and when you scan the application. Let’s just look at the scanning case

  1. Dealing with PackageSetting, this part of the logic is mixed up with the installation application, mainly including
    1. SharedUserSetting, this is usually only overridden if the sharedUserId has changed
    2. The logics for renaming packages are updated when the installation renames the package
  2. Write PackageSetting into package-restrictions. XML, which stores the four major components: disabled and Enabled
  3. The last callcommitPackageSettings()Proceed to the last step

commitPackageSettings()

  1. Determine if there is a vendor defined ResolveActivity(config_customResolverActivityProperty), if anysetUpCustomResolverActivity()When you set the ResolveActivity to be custom, the ResolveActivity handles unspecified tasksandroid.action.Viewthe
  2. Handle the ResolveActivity, specifying the framework ResolveActivity if none is available
  3. Update SharedLibraries, which is unfamiliar
  4. Check whether the Frozen application is required. If yes but no Frozen is available, exit the installation. The Frozen application is not required in the following cases
    1. SCAN_BOOTING, at boot time, because there are no applications to boot
    2. SCAN_DONT_KILL_APP, install does not kill the app, this is usually either specified in PkMS or at ADB installation time
    3. SCAN_IGNORE_FROZEN, ignore FROZEN, this option is not even specified by ADB, it may be the code left behind
  5. callmSettings.insertPackageSettingLPw().This is not the place to update packages.xml, just put the pkgSetting in settings.mpackages
  6. Put AndroidPackage in mPackages
  7. Update application information for KeySetManagerService, a service that manages signatures
  8. Add custom Permission and PermissionGroup to PermissionManagerService
  9. Add protected broadcasts, not for installation applications, but for system applications, such as teleservice, etc
  10. Update permissions for applications that have applied for these permissions. Note that these permissions are also defined by the application

What needs to be done after the scan is done

  1. Delete the deleted system applications and disable the disable applications
  2. callPermissionManagerService.updateAllPermissions()Update permissions, which are not performed until all application scans have been completed
  3. Create a directory for the application data store. Note that this operation is only for System core applications (such as SystemUI). Applications under data have multiple users and each data application is for a single user.
  4. Finally, the PackageSetting, permission and signature fingerprint were written into PackageSetting. XML. I think this design should be to avoid shutdown in the middle, so that writing all the information at once can minimize shutdown in half