PackageManagerService(PMS for short, sometimes called PKMS to distinguish PowerManagerService) is one of the core services in Android system. It manages all work related to package, such as installing and uninstalling applications.

SyetemServer processing

Start the service during the SystemServer startup process

frameworks/base/services/java/com/android/server/SystemServer.java

private void run(a) {
    try{...// Create message Looper
         Looper.prepareMainLooper();
        // The dynamic library libandroid_servers.so is loaded
        System.loadLibrary("android_servers");
        performPendingShutdown();
        // Create the system Context
        createSystemContext();
        / / create SystemServiceManager
        mSystemServiceManager = new SystemServiceManager(mSystemContext);
        mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        SystemServerInitThreadPool.get();
    } finally {
        traceEnd(); 
    }
    try {
        traceBeginAndSlog("StartServices");
        // Start the boot service
        startBootstrapServices();
        // Start the core service
        startCoreServices();
        // Start other services
        startOtherServices();
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
        Slog.e("System"."* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
        Slog.e("System"."************ Failure starting system services", ex);
        throw ex;
    } finally{ traceEnd(); }... }Copy the code

As can be seen from the above, system services are divided into three types, namely boot service, core service and other services. The PMS to be understood in this paper belongs to boot service.

Guide services role
Installer A service class used when apK is installed. The Installer service is started before other system services can be started
ActivityManagerService Responsible for starting, switching and scheduling of four components.
PowerManagerService Calculate the system’s calculations relative to Power, and then decide how the system should react
LightsService Manage and display backlit leds
DisplayManagerService Used to manage all display devices
UserManagerService Multi-user mode management
SensorService Provide various sensor services for the system
PackageManagerService It is used to install, parse, delete, uninstall and so on apK
    private void startBootstrapServices(a) {
        // Start the Installer service
        Installer installer = mSystemServiceManager.startService(Installer.class);
        // AMS
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);
        
        //POWERMS
        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitPowerManagement");
        mActivityManagerService.initPowerManagement();
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        mSystemServiceManager.startService(LightsService.class);
        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
        mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);

        // Only run "core" apps if we're encrypting the device.
        // indicates that the device is encrypted, in which case the value of mOnlyCore is true, which means that only "core" programs are run to create a minimal startup environment.
        String cryptState = SystemProperties.get("vold.decrypt");

        mIsAlarmBoot = SystemProperties.getBoolean("ro.alarm_boot".false);
        if (ENCRYPTING_STATE.equals(cryptState)) {
            Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
            mOnlyCore = true;
        } else if (ENCRYPTED_STATE.equals(cryptState)) {
            Slog.w(TAG, "Device encrypted - only parsing core apps");
            mOnlyCore = true;
        } else if (mIsAlarmBoot) {
            mOnlyCore = true;
        }

        if (RegionalizationEnvironment.isSupported()) {
            Slog.i(TAG, "Regionalization Service");
            RegionalizationService regionalizationService = new RegionalizationService();
            ServiceManager.addService("regionalization", regionalizationService);
        }

        // Start the package manager.
        / / start the PMS
        traceBeginAndSlog("StartPackageManagerService");
        / / create the PMSmPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode ! = FactoryTest.FACTORY_TEST_OFF, mOnlyCore);// Indicates whether the PMS is started for the first time. This parameter is used when the WMS is created
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

        if(! mOnlyCore) {boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt".false);
            if(! disableOtaDexopt) { traceBeginAndSlog("StartOtaDexOptService");
                try {
                    OtaDexoptService.main(mSystemContext, mPackageManagerService);
                } catch (Throwable e) {
                    reportWtf("starting OtaDexOptService", e);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
                }
            }
        }

        traceBeginAndSlog("StartUserManagerService");
        mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        AttributeCache.init(mSystemContext);
        mActivityManagerService.setSystemProcess();
        startSensorService();
    }
Copy the code

PMS

A constructor

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

 public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // Self-check for initial settings.
        PackageManagerServiceCompilerMapping.checkProperties();
			  // Initialize the PMS
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        m.enableSystemUserPackages();
        // Register the package service with the ServiceManager manager
        ServiceManager.addService("package", m);
        return m;
    }
Copy the code

The PMS construction method consists of more than 700 lines. In the code, the PMS construction process is divided into five phases, and each phase uses eventLog. writeEvent to print system logs.

  1. BOOT_PROGRESS_PMS_START (start phase)
  2. BOOT_PROGRESS_PMS_SYSTEM_SCAN_START (Scan system phase)
  3. BOOT_PROGRESS_PMS_DATA_SCAN_START (Scan Data partition phase)
  4. BOOT_PROGRESS_PMS_SCAN_END (scan end phase)
  5. BOOT_PROGRESS_PMS_READY

1. The beginning

BOOT_PROGRESS_PMS_START

   public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // Prints the start log
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                SystemClock.uptimeMillis());

        if (mSdkVersion <= 0) {
            Slog.w(TAG, "**** ro.build.version.sdk not set!");
        }

        mContext = context;

        mPermissionReviewRequired = context.getResources().getBoolean(
                R.bool.config_permissionReviewRequired);

        mFactoryTest = factoryTest;
        mOnlyCore = onlyCore;
        // Used to store information about the screen
        mMetrics = new DisplayMetrics();
        // Create Settings object (1)
        mSettings = new Settings(mPackages);
        // Add system, phone, log, NFC, Bluetooth, shell shareUserId to mSettings;
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); . mInstaller = installer;// Create the Dex optimization tool class
        mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
                "*dexopt*");
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

        mOnPermissionChangeListeners = new OnPermissionChangeListeners(
                FgThread.get().getLooper());

        getDefaultDisplayMetrics(context, mMetrics);
        // Get the global system configuration information
        SystemConfig systemConfig = SystemConfig.getInstance();
     		// Get the global groupId
        mGlobalGids = systemConfig.getGlobalGids();
     		// Obtain system permission
        mSystemPermissions = systemConfig.getSystemPermissions();
        mAvailableFeatures = systemConfig.getAvailableFeatures();

        mProtectedPackages = new ProtectedPackages(mContext);

        // Lock required to install APK to protect all access to Installd.
        synchronized (mInstallLock) {
        // Update APK locks to protect parsed packages in memory
        synchronized (mPackages) {
            // Create the background thread ServiceThread
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            // Create a message queue with PackageHandler bound to ServiceThread
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            mProcessLoggingHandler = new ProcessLoggingHandler();
            // Add PackageHandler to Watchdog's detection set
            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);

            mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);
  					
            // Create directories in the Data partition
            File dataDir = Environment.getDataDirectory();
            mAppInstallDir = new File(dataDir, "app");
            mAppLib32InstallDir = new File(dataDir, "app-lib");
            mEphemeralInstallDir = new File(dataDir, "app-ephemeral");
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
            mRegionalizationAppInstallDir = new File(dataDir, "app-regional");

            // Create a multi-user management service
            sUserManager = new UserManagerService(context, this, mPackages);

            mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
   					
          	// Parse the information of the packes. XML file and save it in the corresponding field of the Settings. The packes.xml file records information about all installed applications in the system, including basic information, signatures, and permissions. If packes.xml has installed application information, the readLPw method returns true and mFirstBoot is false, indicating that the PMS was not started for the first time.mFirstBoot = ! mSettings.readLPw(sUserManager.getUsers(false));

Copy the code

In the beginning, many key objects in the PMS are created and assigned to member variables in the PMS

mSettings

Used to save dynamic Settings for all packages.

Settings(Object lock) {
    this(Environment.getDataDirectory(), lock);
}

Settings(File dataDir, Object lock) {
    mLock = lock;

    mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);

    mSystemDir = new File(dataDir, "system");
    mSystemDir.mkdirs(); / / create/data/system
    FileUtils.setPermissions(mSystemDir.toString(),
           FileUtils.S_IRWXU|FileUtils.S_IRWXG
           |FileUtils.S_IROTH|FileUtils.S_IXOTH,
           -1, -1);
    mSettingsFilename = new File(mSystemDir, "packages.xml");
    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
    mPackageListFilename = new File(mSystemDir, "packages.list");
    FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

    mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
    mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}
Copy the code

Here mSystemDir refers to the directory /data/system, in which there are the following five files:

file function
packages.xml Record all app installation information
packages-backup.xml Backup file
packages-stopped.xml Records the files that the system was forced to stop
packages-stopped-backup.xml Backup file
packages.list Record application data

mInstaller

Installer inherits from SystemService and is a system boot service like PMS and AMS. Many PMS operations are performed by Installer, such as APK installation and uninstallation. The Installer communicates with instalLD through the socket and the InstalLD at the Nativie layer performs the specific operations.

systemConfig

Used to get global system configuration information. For example, system permissions can be obtained through SystemConfig.

mPackageDexOptimizer

Dex optimized tool class.

MHandler (PackageHandler type)

PackageHandler inherits from Handler. PMS uses PackageHandler to drive APK replication and installation. The message queue processed by the PackageHandler can cause the system to freeze if it gets too busy, so add it to the Watchdog’s monitoring set. Watchdog is mainly used for two purposes. One is to periodically detect whether the system’s key services (AMS and WMS, etc.) are likely to be deadlocked, and the other is to periodically detect whether the message queue of the thread is in the working state for a long time (possibly blocked waiting for a long time). If these problems occur, the Watchdog saves the logs and, if necessary, kills its own process, the SystemServer process.

SUserManager (UserManagerService type)

Multi-user management services.

2. Scanning the system

// Displays system scanning logs
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                    startTime);

// Set flag to monitor and not change apk file paths when
// scanning install directories.
final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;

final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");

if (bootClassPath == null) {
  Slog.w(TAG, "No BOOTCLASSPATH found!");
}

if (systemServerClassPath == null) {
  Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}

final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
final String[] dexCodeInstructionSets =
  getDexCodeInstructionSets(
  allInstructionSets.toArray(new String[allInstructionSets.size()]));

/** * Ensure all external libraries have had dexopt run on them. */
if (mSharedLibraries.size() > 0) {
  // NOTE: For now, we're compiling these system "shared libraries"
  // (and framework jars) into all available architectures. It's possible
  // to compile them only when we come across an app that uses them (there's
  // already logic for that in scanPackageLI) but that adds some complexity.
  for (String dexCodeInstructionSet : dexCodeInstructionSets) {
    for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
      final String lib = libEntry.path;
      if (lib == null) {
        continue;
      }

      try {
        // Shared libraries do not have profiles so we perform a full
        // AOT compilation (if needed).
        int dexoptNeeded = DexFile.getDexOptNeeded(
          lib, dexCodeInstructionSet,
          getCompilerFilterForReason(REASON_SHARED_APK),
          false /* newProfile */);
        if(dexoptNeeded ! = DexFile.NO_DEXOPT_NEEDED) { mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet, dexoptNeeded, DEXOPT_PUBLIC/*dexFlags*/, getCompilerFilterForReason(REASON_SHARED_APK), StorageManager.UUID_PRIVATE_INTERNAL, SKIP_SHARED_LIBRARY_CHECK); }}catch (FileNotFoundException e) {
        Slog.w(TAG, "Library not found: " + lib);
      } catch (IOException | InstallerException e) {
        Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "+ e.getMessage()); }}}}// Create framework directory in /system
File frameworkDir = new File(Environment.getRootDirectory(), "framework");

finalVersionInfo ver = mSettings.getInternalVersion(); mIsUpgrade = ! Build.FINGERPRINT.equals(ver.fingerprint);// when upgrading from pre-M, promote system app permissions from install to runtime
mPromoteSystemApps =
  mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;

// When upgrading from pre-N, we need to handle package extraction like first boot,
// as there is no profiling data available.
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;

mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;

// save off the names of pre-existing system packages prior to scanning; we don't
// want to automatically grant runtime permissions for new system apps
if (mPromoteSystemApps) {
  Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
  while (pkgSettingIter.hasNext()) {
    PackageSetting ps = pkgSettingIter.next();
    if(isSystemApp(ps)) { mExistingSystemPackages.add(ps.name); }}}// Collect vendor overlay packages. (Do this before scanning any apps.)
// For security and version matching reason, only consider
// overlay packages if they reside in the right directory.
String overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PROPERTY);
 // Scan files in /vendor/overlay directory
if(! overlayThemeDir.isEmpty()) { scanDirTracedLI(new File(VENDOR_OVERLAY_DIR, overlayThemeDir), mDefParseFlags
                  | PackageParser.PARSE_IS_SYSTEM
                  | PackageParser.PARSE_IS_SYSTEM_DIR
                  | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
}
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags
                | PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR
                | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

// Find base frameworks (resource packages without code).
// Collect package name: /system/framework
scanDirTracedLI(frameworkDir, mDefParseFlags
                | PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR
                | PackageParser.PARSE_IS_PRIVILEGED,
                scanFlags | SCAN_NO_DEX, 0);

// Collected privileged system packages.
// Collect the private system package name: /system/priv-app
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirTracedLI(privilegedAppDir, mDefParseFlags
                | PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR
                | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);

// Collect ordinary system packages.
// Collect common system package names: /system/app
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirTracedLI(systemAppDir, mDefParseFlags
                | PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

// Collect all vendor packages.
// Collect all vendor package names: /vendor/app
File vendorAppDir = new File("/vendor/app");
try {
  vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
  // failed to look up canonical path, continue with original one
}
scanDirTracedLI(vendorAppDir, mDefParseFlags
                | PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

// Collect all OEM packages.
Collect all OEM package names: / OEM /app
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirTracedLI(oemAppDir, mDefParseFlags
                | PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

// Collect all Regionalization packages form Carrier's res packages.
if (RegionalizationEnvironment.isSupported()) {
  Log.d(TAG, "Load Regionalization vendor apks");
  final List<File> RegionalizationDirs =
    RegionalizationEnvironment.getAllPackageDirectories();
  for (File f : RegionalizationDirs) {
    File RegionalizationSystemDir = new File(f, "system");
    // Collect packages in <Package>/system/priv-app
    scanDirLI(new File(RegionalizationSystemDir, "priv-app"),
              PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR
              | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
    // Collect packages in <Package>/system/app
    scanDirLI(new File(RegionalizationSystemDir, "app"),
              PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,
              scanFlags, 0);
    // Collect overlay in <Package>/system/vendor
    scanDirLI(new File(RegionalizationSystemDir, "vendor/overlay"),
              PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,
              scanFlags | SCAN_TRUSTED_OVERLAY, 0); }}// Prune any system packages that no longer exist.
// This list represents system apps that may have upgrade packs
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
if(! mOnlyCore) { Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();while (psit.hasNext()) {
    PackageSetting ps = psit.next();

    /* * If this is not a system app, it can't be a * disable system app. */
    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
      continue;
    }

    /* * If the package is scanned, it's not erased. */
    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
    if(scannedPkg ! =null) {
      /* * If the system app is both scanned and in the * disabled packages list, then it must have been * added via OTA. Remove it from the currently * scanned package so the previously user-installed * application can be scanned. */
      if (mSettings.isDisabledSystemPackageLPr(ps.name)) {  / / 1
        logCriticalInfo(Log.WARN, "Expecting better updated system app for "
                        + ps.name + "; removing system app. Last known codePath="
                        + ps.codePathString + ", installStatus=" + ps.installStatus
                        + ", versionCode=" + ps.versionCode + "; scanned versionCode="
                        + scannedPkg.mVersionCode);
        // Remove the PackageSetting App from the PMS mPackages
        removePackageLI(scannedPkg, true);
        // Add the path to the upgrade package to the mExpectingBetter list
        mExpectingBetter.put(ps.name, ps.codePath);
      }

      continue;
    }

    if(! mSettings.isDisabledSystemPackageLPr(ps.name)) { psit.remove(); logCriticalInfo(Log.WARN,"System package " + ps.name
                      + " no longer exists; it's data will be wiped");
      // Actual deletion of code and data will be handled by later
      // reconciliation step
    } else {
      final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
      // The system App upgrade package information is in mDisabledSysPackages, but the upgrade package is not found
      if (disabledPs.codePath == null| |! disabledPs.codePath.exists()) {/ / 2possiblyDeletedUpdatedSystemApps.add(ps.name); }}}}//look for any incomplete package installations
// Clean up all packages that are not installed completely
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
for (int i = 0; i < deletePkgsList.size(); i++) {
  // Actual deletion of code and data will be handled by later
  // reconciliation step
  final String packageName = deletePkgsList.get(i).name;
  logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);
  synchronized(mPackages) { mSettings.removePackageLPw(packageName); }}//delete tmp files
// Delete temporary files
deleteTempPackageFiles();

// Remove any shared userIDs that have no associated packages
mSettings.pruneSharedUsersLPw();
Copy the code

The main tasks in the system scanning phase are as follows:

  1. Create /system subdirectories, such as /system/framework, /system/priv-app, /system/app, and so on
  2. Scan system files, such as /vendor/overlay, /system/framework, /system/app, etc.
  3. Perform subsequent operations on scanned system files.

The third point is that there are three situations for an OTA upgrade of a system App:

  • There is no update of APP in this system.
  • The APP of this system has been updated.
  • This system APP has been deleted in the new OTA version.

When the system App is updated, PMS stores the system App’s upgrade PackageSetting data (PackageSetting) into the mDisabledSysPackages list of Settings (see the PMS replaceSystemPackageLIF method for details). The type of mDisabledSysPackages is ArrayMap

. MDisabledSysPackages of information will be preserved by the PMS to packages. The XML in the < updated – package > tag under writeDisabledSysPackageLPr method (see specific Settings).
,>

Note 1 indicates that the system App has an upgrade package, so remove the PackageSetting of the system App from the mDisabledSysPackages list, and add the path of the upgrade package of the system App to the mExpectingBetter list. MExpectingBetter is of type ArrayMap

to wait for further processing.
,>

2 place if the system App updates information is stored in mDisabledSysPackages list, but have not found this upgrade packages exist, then add it to the list of possiblyDeletedUpdatedSystemApps, Meaning “system App updates may be deleted”, is “may”, because the system haven’t scan Data partition, can only temporarily put possiblyDeletedUpdatedSystemApps list, wait until after scanning the Data partition to do processing.

3. Data partition scanning phase

// If the device is not encrypted, start scanning the Data partition
if(! mOnlyCore) {// Prints the Data partition scanning phase logs
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
    // Scan files in /data/app
    scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
    // Scan files in /data/app-private
    scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
                    | PackageParser.PARSE_FORWARD_LOCK,
                    scanFlags | SCAN_REQUIRE_KNOWN, 0);
    // Scan the files under /data/app-ephemeral
    scanDirLI(mEphemeralInstallDir, mDefParseFlags
              | PackageParser.PARSE_IS_EPHEMERAL,
              scanFlags | SCAN_REQUIRE_KNOWN, 0);

    /** * Remove disable package settings for any updated system * apps that were removed via an OTA. If they're not a * previously-updated app, remove them completely. * Otherwise, Just revoke their system - level permissions. * * * / processing possiblyDeletedUpdatedSystemApps list
    for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
      PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
      mSettings.removeDisabledSystemPackageLPw(deletedAppName);

      String msg;
      if (deletedPkg == null) {
        //1 If the package information of this system App is not in the variable mPackages of PMS, it indicates residual App information, and its data will be deleted later
        msg = "Updated system package " + deletedAppName
          + " no longer exists; it's data will be wiped";
        // Actual deletion of code and data will be handled by later
        // reconciliation step
      } else {
        //2 If the system App is in mPackages, it exists in the Data partition and does not belong to the system App, then remove the system permission of the system App.
        msg = "Updated system app + " + deletedAppName
          + " no longer present; removing system privileges for "
          + deletedAppName;

        deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;

        PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
        deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
      }
      logCriticalInfo(Log.WARN, msg);
    }

    /** * Make sure all system apps that we expected to appear on * the userdata partition actually showed up. If they never  * appeared, crawl back and revive the system version. */
     // Iterate over the mExpectingBetter list
    for (int i = 0; i < mExpectingBetter.size(); i++) {
      final String packageName = mExpectingBetter.keyAt(i);
      if(! mPackages.containsKey(packageName)) {// Get the upgrade package path of the system App
        final File scanFile = mExpectingBetter.valueAt(i);

        logCriticalInfo(Log.WARN, "Expected better " + packageName
                        + " but never showed up; reverting to system");
 
        
        //3 Set scan resolution parameters based on the directory where the App resides
        int reparseFlags = mDefParseFlags;
        if (FileUtils.contains(privilegedAppDir, scanFile)) {
          reparseFlags = PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR
            | PackageParser.PARSE_IS_PRIVILEGED;
        } else if (FileUtils.contains(systemAppDir, scanFile)) {
          reparseFlags = PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR;
        } else if (FileUtils.contains(vendorAppDir, scanFile)) {
          reparseFlags = PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR;
        } else if (FileUtils.contains(oemAppDir, scanFile)) {
          reparseFlags = PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR;
        } else {
          Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
          continue;
        }

        //4 Add packageName to mPackages in mSettings
        mSettings.enableSystemPackageLPw(packageName);

        try {
          //5 Scan the upgrade package of the system App
          scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0.null);
        } catch (PackageManagerException e) {
          Slog.e(TAG, "Failed to parse original system package: "+ e.getMessage()); }}}}// Clear the mExpectingBetter list
  mExpectingBetter.clear();
Copy the code

In the phase of scanning Data partition, the following things are done:

  1. Scan files in /data/app and /data/app-private.
  2. Traverse possiblyDeletedUpdatedSystemApps list, note 1 place if the system of App package information is not in the PMS variable mPackages, that is remaining App information, the follow-up data will delete it. Note 2: If the package information of this system App is in mPackages, it indicates that it exists in the Data partition and does not belong to the system App, so remove its system permission.
  3. Go through the mExpectingBetter list. In Note 3, set the resolution parameters of the scan according to the directory where the system App is located. In the method in Note 4, the PackageSetting data corresponding to packageName will be added to the mPackages of mSettings. Note 5 scans the upgrade package of the system App and clears the mExpectingBetter list.

4. End of scan

// Prints the scan end logs
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());

            // If the platform SDK has changed since the last time we booted,
            // we need to re-grant app permission to catch any new ones that
            // appear. This is really a hack, and means that apps can in some
            // cases get permissions that the user didn't initially explicitly
            // allow... it would be nice to have some better way to handle
            // this situation.
            // If the SDK versions are inconsistent, the permissions need to be updated
            int updateFlags = UPDATE_PERMISSIONS_ALL;
            if(ver.sdkVersion ! = mSdkVersion) { Slog.i(TAG,"Platform changed from " + ver.sdkVersion + " to "
                        + mSdkVersion + "; regranting permissions for internal storage");
                updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
            }
            updatePermissionsLPw(null.null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
            ver.sdkVersion = mSdkVersion;

            // If this is the first boot or an update from pre-M, and it is a normal
            // boot, then we need to initialize the default preferred apps across
            // all defined users.
   					// If it is the first startup or the first startup after the Android M upgrade, all user-defined default preferred apps need to be initialized
            if(! onlyCore && (mPromoteSystemApps || mFirstBoot)) {for (UserInfo user : sUserManager.getUsers(true)) {
                    mSettings.applyDefaultPreferredAppsLPw(this, user.id); applyFactoryDefaultBrowserLPw(user.id); primeDomainVerificationsLPw(user.id); }}// Prepare storage for system users early in the boot process,
            // Because core system applications such as Setup Provider and SystemUI cannot wait for the user to start
            final int storageFlags;
            if (StorageManager.isFileEncryptedNativeOrEmulated()) {
                storageFlags = StorageManager.FLAG_STORAGE_DE;
            } else {
                storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
            }
            reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM,
                    storageFlags);

            // If this is first boot after an OTA, and a normal boot, then
            // we need to clear code cache directories.
            // Note that we do *not* clear the application profiles. These remain valid
            // across OTAs and are used to drive profile verification (post OTA) and
            // profile compilation (without waiting to collect a fresh set of profiles).
 						// The first startup after OTA clears the code cache directory
            if(mIsUpgrade && ! onlyCore) { Slog.i(TAG,"Build fingerprint changed; clearing code caches");
                for (int i = 0; i < mSettings.mPackages.size(); i++) {
                    final PackageSetting ps = mSettings.mPackages.valueAt(i);
                    if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
                        // No apps are running this early, so no need to freeze
                        clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
                                StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE
                                        | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
                    }
                }
                ver.fingerprint = Build.FINGERPRINT;
            }

            checkDefaultBrowser();

            // When permissions and other defaults are updated, the information is cleared
            mExistingSystemPackages.clear();
            mPromoteSystemApps = false;

            // All the changes are done during package scanning.
            ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;

            // Save the contents of Settings to packs.xml
            mSettings.writeLPr();

Copy the code

At the end of scanning, the following things are done:

  1. If the SDK version of the current platform is different from the SDK version of the last startup, update the APK authorization.
  2. If it is the first startup or the first startup after an Android M upgrade, you need to initialize all user-defined default preferred apps.
  3. The first startup after the OTA upgrade clears the code cache directory.
  4. Save the Settings contents to packs.xml so that the PMS will read the previously saved Settings contents when it is created again later.

5. Preparation

// Prints the preparation logs
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                    SystemClock.uptimeMillis());

if(! mOnlyCore) { mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr(); mRequiredInstallerPackage = getRequiredInstallerLPr(); mRequiredUninstallerPackage = getRequiredUninstallerLPr(); mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr(); mIntentFilterVerifier =new IntentVerifierProxy(mContext,
                                                    mIntentFilterVerifierComponent);
    mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
      PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES);
    mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
      PackageManager.SYSTEM_SHARED_LIBRARY_SHARED);
} else {
    mRequiredVerifierPackage = null;
    if (mOnlyPowerOffAlarm) {
      mRequiredInstallerPackage = getRequiredInstallerLPr();
    } else {
      mRequiredInstallerPackage = null;
    }
    mRequiredUninstallerPackage = null;
    mIntentFilterVerifierComponent = null;
    mIntentFilterVerifier = null;
    mServicesSystemSharedLibraryPackageName = null;
    mSharedSystemSharedLibraryPackageName = null;
}

// Create PackageInstallerService to manage the installation session service, which assigns a SessionId to each installation process
mInstallerService = new PackageInstallerService(context, this);

// Do a garbage collection
untime.getRuntime().gc();

// The initial scanning above does many calls into installd while
// holding the mPackages lock, but we're mostly interested in yelling
// once we have a booted system.
mInstaller.setWarnIfHeld(mPackages);

/ / will PackageManagerInternalImpl (PackageManager local service) added to the LocalServices, LocalServices used to store run local services in the current process
LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
Copy the code

conclusion

PMS is a boot service started by SyetemServer

PMS startup is divided into five phases

  1. BOOT_PROGRESS_PMS_START (start phase)
  2. BOOT_PROGRESS_PMS_SYSTEM_SCAN_START (Scan system phase)
  3. BOOT_PROGRESS_PMS_DATA_SCAN_START (Scan Data partition phase)
  4. BOOT_PROGRESS_PMS_SCAN_END (scan end phase)
  5. BOOT_PROGRESS_PMS_READY

link

Android system – Package management mechanism (1)PMS service startup

Android – Package management (2)PackageInstaller Installs APK

Android system – package management mechanism (3)PMS process APK installation

Android – Installd daemon