takeaway

When the PMS note case reaches 106KB, you know something is wrong, and 叒叒叒 comes

As a result, I divided the article originally planned to end into the following three parts:

  • PMS1:Service initialization
  • PMS– 2:Some details of initialization
  • PMS– 3:Application Installation Process

The first two articles mainly comb through the PMS initialization process and some details of initialization; Finally, the installation process of the application is briefly combed.

Have you paid attention to the words? I’m sorry for those who want to learn PMS thoroughly and comprehensively. This series of articles only play a role of sorting out the main process.

Let’s take a look at the overall situation first, and then study it later when we meet relevant needs.

PackageManagerService

  • PMSThere are many analogies involved, and it takes time and effort to really master them
    • Related analogs:PackageRelated,SessionRelated,Settings, etc.
  • readingPMSThe method is a bit dismantledRussian nesting dollFeeling, layer upon layer…
  • The business logic is complex, and the execution of almost every method will be mixedpermissionsandThe userLogical judgment of

With that in mind, welcome to the world of PackageManagerService

To understandPackageManagerService

The PackageManagerService class has 24000 lines of code…

Android application management is mainly accomplished through the PackageManagerService. PackageManagerService installs, uninstalls, optimizes, and queries various APK packages.

Android applications can be divided into two categories: system applications and common applications:

  • System applicationIs located in/system/appand/system/priv-appApplications in directories
    • /system/priv-appfromThe Android 4.4Directories that store some low-level applications in the system, such as:Settings,SystemUIEtc.
    • /system/appStorage is some system level applications, such asCalendar,ContactsEtc.
  • Common applicationIs a user-installed application located in a directory/data/appUnder the

The PackageManagerService scans all APK files and Jar packages at startup and reads their information into memory so that the system can quickly find various application and component information at runtime.

  • If an unoptimized file is encountered during the scan, an optimization operation is performed.

    Android 5.0 introduced ART, which uses pre-ot (AOT) compilation, and Android 7.0 used a combination of AOT, just-in-time (JIT) compilation, and configuration file guided compilation to optimize application launch and execution efficiency

Without rushing to analyze the source code directly, let’s take a quick look at it from a usage perspective

In an application, if you want to use the PackageManagerService, you usually call the getPackageManager() method of the Context, which looks like this:

    public PackageManager getPackageManager(a) {
        if(mPackageManager ! =null) {
            return mPackageManager;
        }
        IPackageManager pm = ActivityThread.getPackageManager();
        if(pm ! =null) {
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }
Copy the code

Call to ActivityThread. GetPackageManager () method:

    public static IPackageManager getPackageManager(a) {
        if(sPackageManager ! =null) {
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        sPackageManager = IPackageManager.Stub.asInterface(b);
        return sPackageManager;
    }
Copy the code

You can see from the code for the two getPackageManager() methods:

  • Returns the ApplicationPackageManager object, the object created using the IPackageManager object as a parameter

    • IPackageManagerThe object isPackageManagerServicetheBinderProxy objects
  • ApplicationPackageManager inherited from PackageManager, defined in the PackageManager applications can access all the interface PackageManagerService

PackageManager relationship diagram is as follows:

For the PackageManagerService class, there are two important member variables:

  • MInstallerService: Instance object of the PackageInstallerService class. Android uses PackageInstallerService to manage the application installation process.

    • PackageInstallerServiceIs also aBinderService, the corresponding proxy object isPackageInstaller
  • MInstaller: Instance object of the Installer class. The class structure is relatively simple, with an IInstalld mInstalld variable called by Binder to communicate with the InstalLD process

    • Actually in the systemapkFile format conversion, the establishment of data directory and other work are finally byinstalldProcess to complete

The relationship between these objects is shown below:

SettingsClasses andpackages.xml

Before we start analyzing The PackageManagerService, we need to take a look at the Settings class, which holds Settings related to the PackageManagerService that will be used when parsing the application.

First take a look at the com. Android. Server. PM. Settings class constructor:

    Settings(File dataDir, PermissionSettings permission, Object lock) {
        // omit permission related processing.// Create a system directory under the data directory
        mSystemDir = new File(dataDir, "system");
        mSystemDir.mkdirs();
        // Set the directory property to 0775
        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); .// Deprecated: Needed for migration
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
    }
Copy the code

The constructor of the Settings class creates a system directory in the /data directory to hold some system configuration files. Create 5 File objects in directory /data/system:

  • packages.xml: Records information about all installed applications in the system, including basic information, signatures, and permissions.
  • packages-backup.xml:packages.xmlBackup of files
  • packages.list: Stores common application data directories anduidInformation such as
  • packages-stopped.xml: Records the information about the applications that are forced to stop. When the system forcibly stops an application, the application information is recorded in a file
  • packages-stopped-backup.xml:packages-stopped.xmlBackup of files

Packs-backup. XML and packs-stopped -backup. XML are backup files. The logic for backing up files is:

  • When Android filespackages.xmlandpackages-stopped.xmlThey are backed up before writing
  • If the file is successfully written, delete the backup file
  • If the system fails to write data and needs to read the two files after the system restarts, the contents of the backup files will be used because the original files may be damaged.

PackageManagerService starts with PackageManagerService.

    <package name="com.android.providers.telephony" codePath="/system/priv-app/TelephonyProvider" nativeLibraryPath="/system/priv-app/TelephonyProvider/lib" publicFlags="1007402501" privateFlags="8" ft="11e8dc5d800" it="11e8dc5d800" ut="11e8dc5d800" version="28" sharedUserId="1001" isOrphaned="true">
        <sigs count="1" schemeVersion="3">
            <cert index="0" />
        </sigs>
        <perms>
            <item name="android.permission.USE_RESERVED_DISK" granted="true" flags="0" />
            <item name="android.permission.INTERACT_ACROSS_USERS_FULL" granted="true" flags="0" />
            <item name="android.permission.INTERACT_ACROSS_USERS" granted="true" flags="0" />
            <item name="android.permission.MODIFY_PHONE_STATE" granted="true" flags="0" />
        </perms>
        <proper-signing-keyset identifier="1" />
    </package>
Copy the code

The tag in the file represents the basic information, signature, and declared permissions of an application. In terms of content, it basically parses the contents of Androidmanifest.xml.

Let’s take a look at the main attributes and tags:

  • nameIndicates the package name of the application
  • codePathsaidapkLocation of file
  • nativeLibraryPathAppliednativeThe storage path of the library
  • itIndicates the application installation time
  • utIndicates the time of the last modification
  • versionIndicates the version number of the application
  • sharedUserIdIndicates the user ID used by the application for sharing
  • userIdIndicates the ID of the user to which the application belongs
  • <sign/>Indicates the signature of the application
    • attributecountIndicates how many certificates are contained in the tag
    • The label<cert/>Indicates the value of a specific certificate
  • <perms/>Indicates the permission that the application claims to use
    • Each subtag<item/>Represents a permission

In addition to the tag, the following tags may exist in packes.xml:

  • <updated-package/>: Records the system application upgrade. When an application with the same package name and a higher version number is installed,AndroidInformation about overwritten system applications is recorded through this label.
  • <renamed-package/>: Records the change of the application package name.
    • The package name of the application is usually inAndroidManifest.xmlUsing attributes inpackageTo specify at the same timeAndroidManifest.xmlCan also be used<original-package>To specify the original package name, in this case:
      • If an application of an earlier version with the same package name as the original application exists on the device, the upgrade overwrites the original application.
      • You end up running the newly installed application with the same package name as the original application at runtime.Androidthrough<renamed-package/>Tag to record this change of name.
  • <cleaning-package/>: Is used to record information about applications that have been deleted but the data directory remains temporarily

For the and
tags, the parsed data is saved in the PackageSetting object. The inheritance diagram of the PackageSetting class is as follows:

  • PackageSettinginheritedPackageSettingBaseClass,PackageSettingBaseAnd inheritedSettingBaseclass
    • The basic application information is saved inPackageSettingBaseClass in a member variable
    • The declared permissions are saved inSettingBasethemPermissionStateIn the
  • The signature information is saved inSharedUserSettingClass member variablessignatures
  • classSharedUserSettingUsed to describe having the samesharedUserIdApplication information of
    • Its member variablespackagesIs used to save all with the samesharedUserIdA collection of application objects
    • The signatures of these applications are the same, so only one member variable is requiredsignaturesCan be saved

The PackageSetting objects representing the tag are stored in the Settings member variable mPackages, defined as follows:

final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
Copy the code

The PackageSetting objects representing the tag
are stored in the Settings member variable mDisabledSysPackages, defined as follows:

private final ArrayMap<String, PackageSetting> mDisabledSysPackages = new ArrayMap<String, PackageSetting>();
Copy the code

The PackageSetting object representing the tag
will be stored in the Settings member variable mpackagestobecshaping, defined as follows:

final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>();
Copy the code

The PackageSetting object representing the tag < design-package /> is stored in the Settings member variable mRenamedPackages, defined as follows:

private final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>();
Copy the code

These four objects are often encountered in the PackageManagerService, so keep them in mind for later understanding

PackageManagerServiceThe initialization

With that in mind, let’s look at the initialization process of the PackageManagerService.

The PackageManagerService is initialized in SystemServer, with some processing done in startBootstrapServices() and startOtherServices(), respectively. The relevant codes are as follows:

private void startBootstrapServices(a) {...// Start installd. PMS depends on this serviceInstaller installer = mSystemServiceManager.startService(Installer.class); .// Determine whether vold.decrypt is set to encrypted
    // mOnlyCore=true indicates the encryption state, which can only process system applications
    // In general mOnlyCore is false
    String cryptState = SystemProperties.get("vold.decrypt");
    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;
    }
    Call main() to initialize the PMSmPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode ! = FactoryTest.FACTORY_TEST_OFF, mOnlyCore); mFirstBoot = mPackageManagerService.isFirstBoot(); .// If the device is not encrypted, try starting OtaDexoptService
    // OtaDexoptService is A service for A/B updates, using PMS
    if(! mOnlyCore) {boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt".false);
        if(! disableOtaDexopt) { OtaDexoptService.main(mSystemContext, mPackageManagerService); }}... }private void startOtherServices(a) {
    if(! mOnlyCore) { ......// Perform dex optimizationmPackageManagerService.updatePackagesIfNeeded(); }...// Perform disk maintenancemPackageManagerService.performFstrimIfNeeded(); .// The PMS is ready
    mPackageManagerService.systemReady();
}
Copy the code

The main() method of the PackageManagerService is used to start the PackageManagerService

PackageManagerServicethemain()methods

The main() method reads as follows:

    public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // Self-check for initial settings.
        PackageManagerServiceCompilerMapping.checkProperties();
        Create a PackageManagerService object
        PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore);
        // Enable some system applications
        m.enableSystemUserPackages();
        // Add the service to the ServiceManager
        // Include package and package_native
        ServiceManager.addService("package", m);
        final PackageManagerNative pmn = m.new PackageManagerNative(a);
        ServiceManager.addService("package_native", pmn);
        return m;
    }
Copy the code

The main() method is relatively simple and mainly carries out:

  • createPackageManagerServiceobject
    • Core objects, need detailed analysis
  • createPackageManagerNativeObject that simply provides three functional interfaces
    • String[] getNamesForUids
    • String getInstallerForPackage
    • long getVersionCodeForPackage
  • Then add two objects toServiceManager

Let’s focus on the creation of the PackageManagerService, the constructor.

PackageManagerServiceThe construction method of

PackageManagerService has a long constructor. According to the constructor, EventLogTags can be divided into five stages:

    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {... EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis()); . EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime); . EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); . EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); . EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); . }Copy the code

BOOT_PROGRESS_PMS_START

The BOOT_PROGRESS_PMS_START phase mainly performs:

  • createDisplayMetricsObjects, SettingsInstallerreference
  • createPermissionManagerobject
  • According to thepermissionInformation to createSettingsObject and add sectionsuidinformation
  • createDexManagerObject trackingdexusage
  • createSystemConfigObject is used to obtain system configuration information, such as the list of shared libraries and permissions
  • createPackageHandlerObject, which is actually aHandlerThreadClass and add toWatchdog
  • For first startup, copy the precompiled file todatapartition

The specific code is as follows:

    // ###### BOOT_PROGRESS_PMS_START phase ######
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
    // Check the SDK version
    if (mSdkVersion <= 0) {
        Slog.w(TAG, "**** ro.build.version.sdk not set!");
    }
    mContext = context;
    // Whether the factory mode is used to check system functions
    // Some key escapes can be performed. The formal product is usually false
    mFactoryTest = factoryTest;
    // Whether to process only system applications, usually false
    mOnlyCore = onlyCore;
    // Create a DisplayMetrics object to store screen display information
    mMetrics = new DisplayMetrics();
    / / set the installer
    mInstaller = installer;
    // Create sub-components that provide services / data. Order here is important.
    synchronized (mInstallLock) {
    synchronized (mPackages) {
        // Expose private service for system components to use.
        // Add PackageManagerInternal to the local service
        LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
        // Initialize the multi-user management service
        sUserManager = newUserManagerService(......) ;// Initialize the permission management servicemPermissionManager = PermissionManagerService.create(......) ; mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();// Create a Settings object
        mSettings = newSettings(mPermissionManager.getPermissionSettings(), mPackages); }}// Add the SharedUserSetting object to the Settings using the addSharedUserLPw method
    // Packages with the same sharedUserId attribute can run in the same process, or they can read resources from each other
    // Add a total of 7 system uid: system, phone, log, NFC, Bluetooth, shell, SE
    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); .// Create a help class for dexopt
    mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
            "*dexopt*");
    DexManager.Listener dexManagerListener = DexLogger.getListener(this,
            installer, mInstallLock);
    // Create the DexManager to track the usage of the dex file
    mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock, dexManagerListener);
    // Create the ART management service
    mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
    mMoveCallbacks = newMoveCallbacks(FgThread.get().getLooper()); .// Get the default screen parameters
    getDefaultDisplayMetrics(context, mMetrics);
    // Create a SystemConfig object to store global system configuration informationSystemConfig systemConfig = SystemConfig.getInstance(); mAvailableFeatures = systemConfig.getAvailableFeatures(); .synchronized (mInstallLock) {
    // writer
    synchronized (mPackages) {
        // Create a thread to process messages and add it to Watchdog
        mHandlerThread = new ServiceThread(TAG,
                Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
        mHandlerThread.start();
        mHandler = newPackageHandler(mHandlerThread.getLooper()); . Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);// Create the instant application management module
        mInstantAppRegistry = new InstantAppRegistry(this);
        // Obtain the list of shared libraries in the system from systemConfig
        ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
        final int builtInLibCount = libConfig.size();
        for (int i = 0; i < builtInLibCount; i++) {
            String name = libConfig.keyAt(i);
            String path = libConfig.valueAt(i);
            addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
                    SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
        }
        // Open SELinux Policy file:
        // 1. /security/mac_permissions.xml
        // 2. /etc/security/mac_permissions.xmlSELinuxMMAC.readInstallPolicy(); .// Read the packes. XML file, parse it and store the data in mSettingsmFirstBoot = ! mSettings.readLPw(sUserManager.getUsers(false));
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

        // Clean up orphaned packages for which the code path doesn't exist.if (mFirstBoot) {
            // If it is the first startup
            // Request the Init process (via setProp)
            // Copy the precompiled dex to the data partitionrequestCopyPreoptedFiles(); }}}Copy the code

BOOT_PROGRESS_PMS_SYSTEM_SCAN_START

BOOT_PROGRESS_PMS_SYSTEM_SCAN_START phase:

  • Getting environment variablesBOOTCLASSPATHandSYSTEMSERVERCLASSPATHAnd system version information
  • Confirm the upgrade policy based on the version information
    • Android MPrevious versions required the logic to be fetched at run time
    • Android NPrevious versions need to be adjusted to first boot
  • scanningvendor.producttheoverlayDirectory to collect file information
  • scanningvendor.product.system.oemEqual partitionappandpriv-appDirectory to collect application information and save the collected information tomPackagesIn the
  • willPMSIn themPackagesThe collection andmSettingsIn themPackagesSet for comparison and filter out invalid applications
  • Delete temporary files and unused onesSharedUserSettingobject

The relevant codes are as follows:

        / / # # # # # # # # # # # # BOOT_PROGRESS_PMS_SYSTEM_SCAN_START stage
        long startTime = SystemClock.uptimeMillis();
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime);

        final String bootClassPath = System.getenv("BOOTCLASSPATH");
        final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH"); . File frameworkDir =new File(Environment.getRootDirectory(), "framework");
        finalVersionInfo ver = mSettings.getInternalVersion(); mIsUpgrade = ! Build.FINGERPRINT.equals(ver.fingerprint); .// For previous versions of Android M, upgrade system application permissions from installation to runtime
        mPromoteSystemApps = mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
        // In the case of Android N prior to the upgrade, the package should be treated as if it were the first startup
        mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
        mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
        // Save existing system packages before scanning. Apply for permissions again after system upgrade
        // 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); }}}// Prepare to parse the package cachemCacheDir = preparePackageParserCache(mIsUpgrade); .// Run scanDirTracedLI to scan the application information of the specified directory, including:
        / / vendor/overlay, / product/overlay
        // system/framework, system/priv-app, /system/app
        / / vendor/priv - app, / vendor/app
        // priv-app, / odM /app,
        / / product/priv - app, / product/app
        // Save the related application information to mPackages
        scanDirTracedLI(newFile(VENDOR_OVERLAY_DIR),...) ; scanDirTracedLI(newFile(PRODUCT_OVERLAY_DIR),...) ; .// Prune any system packages that no longer exist.
        final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
        // Stub packages must either be replaced with full versions in the /data
        // partition or be disabled.
        final List<String> stubSystemApps = new ArrayList<>();
        if(! mOnlyCore) {// do this first before mucking with mPackages for the "expecting better" case
            final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator();
            while (pkgIterator.hasNext()) {
                final PackageParser.Package pkg = pkgIterator.next();
                if(pkg.isStub) { stubSystemApps.add(pkg.packageName); }}// Loop through application information in msettings. mPackages
            final Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
            while (psit.hasNext()) {
                PackageSetting ps = psit.next();
                if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                    // Ignore common applications
                    continue;
                }
                // Note that mPackages are member variables in PMS
                // This directory contains the application information obtained by scanDir
                final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                if(scannedPkg ! =null) {
                    // If the mPackages application is to be upgraded, remove it from mPackages
                    // disable indicates the application indicated by the 
       tag
                    if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        // Remove from scan table mPackages
                        removePackageLI(scannedPkg, true);
                        // Add it to the mExpectingBetter collection
                        // This will be handled in the next stage
                        mExpectingBetter.put(ps.name, ps.codePath);
                    }
                    continue;
                }
                // There is no ps application information in mPackages
                // The application does not exist in the system
                // Check if it belongs to the 
       tag
                if(! mSettings.isDisabledSystemPackageLPr(ps.name)) {// Does not belong to the 
       tag, indicating that it is residual in packes.xml
                    // Delete the data
                    psit.remove();
                } else {
                    // The application belongs to the 
       tag
                    / / added to possiblyDeletedUpdatedSystemApps collection. possiblyDeletedUpdatedSystemApps.add(ps.name); }}}//delete tmp files
        deleteTempPackageFiles();
        final int cachedSystemApps = PackageParser.sCachedPackageReadCount.get();
        // Remove the SharedUserSetting object in mSettings that is not associated with any application
        mSettings.pruneSharedUsersLPw();
        final longsystemScanTime = SystemClock.uptimeMillis() - startTime; .Copy the code

BOOT_PROGRESS_PMS_DATA_SCAN_START

BOOT_PROGRESS_PMS_DATA_SCAN_START does the following:

  • Scanning user Directories/data/appand/data/app-privateUnder the application information and add tomPackagesIn the
  • traversepossiblyDeletedUpdatedSystemAppsCollection and remove them one by one fromSettingsIn thedisabledSystemPackageDelete from collection
    • possiblyDeletedUpdatedSystemAppsThe collection is stored in thepackages.xmlThe file is marked as<update-package/>, but the application file has not been found
    • If the application upgrade file exists in the user directory, change the permission of the application to common application
    • If no, clear the application data
  • traversemExpectingBetterCollection.
    • mExpectingBetterThe collection is stored in thepackages.xmlThe file is marked as<update-package/>The data is complete and cannot be started directly. Only the complete application in the user directory can be started
    • Based on the application name in the collection, from/data,/vendor,/systemWait for the directory search, find it and scan it tomPackagesIn the collection
  • readStorageManagerandSetupWizardPackage name that updates the dynamic library path for all applications

The specific code is as follows:

    if(! mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis());// Scan the /data/app directory to collect application information
        scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
        // Scan the /data/app-private directory to collect application information
        scanDirTracedLI(sDrmAppPrivateInstallDir, mDefParseFlags
                | PackageParser.PARSE_FORWARD_LOCK,
                scanFlags | SCAN_REQUIRE_KNOWN, 0);
        / / possiblyDeletedUpdatedSystemApps application is in the packages. In the XML file is has been upgraded system used by tag, but is not in the file
        // Check whether the upgrade file exists in the user directory
        for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
            PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
            // Remove the application from the 
       collection
            mSettings.removeDisabledSystemPackageLPw(deletedAppName);
            final String msg;
            if (deletedPkg == null) {
                // The upgrade file does not exist in the user installation directory
                msg = "Updated system package " + deletedAppName
                        + " no longer exists; removing its data";
            } else {
                // User space found the upgrade file, indicating that the files in the system directory may have been deleted
                // Therefore, remove the system attributes of the application and run it as a normal application
                msg = "Updated system package + " + deletedAppName
                        + " no longer exists; revoking system privileges";
                finalPackageSetting deletedPs = mSettings.mPackages.get(deletedAppName); deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM; }... }// The apps on the mExpectingBetter list come with an upgrade pack
        // They have been removed from the mPackages list and put into the mExpectingBetter list during the last parsing phase
        for (int i = 0; i < mExpectingBetter.size(); i++) {
            final String packageName = mExpectingBetter.keyAt(i);
            if(! mPackages.containsKey(packageName)) {final File scanFile = mExpectingBetter.valueAt(i);
                final @ParseFlags int reparseFlags;
                final @ScanFlags int rescanFlags;
                // Find the application from the following path
                if (FileUtils.contains(privilegedAppDir, scanFile)) {
                    .....
                } else if (FileUtils.contains(systemAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(privilegedVendorAppDir, scanFile)
                        || FileUtils.contains(privilegedOdmAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(vendorAppDir, scanFile)
                        || FileUtils.contains(odmAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(oemAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(privilegedProductAppDir, scanFile)) {
                    ......
                } else if (FileUtils.contains(productAppDir, scanFile)) {
                    ......
                } else {
                    // If not found, do nothing
                    continue;
                }
                mSettings.enableSystemPackageLPw(packageName);
                try {
                    // Scan and process the application
                    scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0.null);
                } catch (PackageManagerException e) {
                    Slog.e(TAG, "Failed to parse original system package: "+ e.getMessage()); }}}// At this point, the user space scan is almost complete
        // Decompress and install stub System AppdecompressSystemApplications(stubSystemApps, scanFlags); . } mExpectingBetter.clear();// Obtain the StorageManager package name
    mStorageManagerPackage = getStorageManagerPackageName();
    // Get SetupWizard package namemSetupWizardPackage = getSetupWizardPackageName(); .// Update the dynamic library path for all applications
    updateAllSharedLibrariesLPw(null); .// Now that we know all the packages we are keeping,
    // read and update their last usage times.
    mPackageUsage.read(mPackages);
    mCompilerStats.read();
Copy the code

BOOT_PROGRESS_PMS_SCAN_END

The BOOT_PROGRESS_PMS_SCAN_END phase mainly does:

  • checkSDKVersion: Updates application permissions
  • Check startup conditions (first normal startup, based onAndroid MNormal startup after upgrade) set the default preferred application
  • To obtainUUID_DEFAULTName of the core system application package on the volume and prepare related application data
  • Check whether it is the first startup after OTA. If yes, proceedcacheClean up the
  • Finally, themSettingUpdate data topackages.xmlIn the

The main code is as follows:

    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis());
    // If the SDK version of the platform has changed since the last time it started, the definition of permission may have changed as well
    // You need to grant the application permission again
    final booleansdkUpdated = (ver.sdkVersion ! = mSdkVersion); mPermissionManager.updateAllPermissions( StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(), mPermissionCallback); 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.
    // Set the default preferred application based on the criteria
    if(! onlyCore && (mPromoteSystemApps || mFirstBoot)) {for (UserInfo user : sUserManager.getUsers(true)) {
            mSettings.applyDefaultPreferredAppsLPw(this, user.id); applyFactoryDefaultBrowserLPw(user.id); primeDomainVerificationsLPw(user.id); }}...// Obtain a collection of core system application package names at UUID_DEFAULT
    List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,  UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */.true /* onlyCoreApps */);
    // Prepare application data for applications in the deferPackages collectionmPrepareAppDataFuture = SystemServerInitThreadPool.get().submit(...) ; .// If this is the first startup after OTA, the cache needs to be cleared
    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 freezeclearAppDataLIF(...) ; } } ver.fingerprint = Build.FINGERPRINT; }...// Save the mSettings content to packs.xml
    mSettings.writeLPr();
Copy the code

BOOT_PROGRESS_PMS_READY

The BOOT_PROGRESS_PMS_READY phase is simple. The method is as follows:

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); ./ / create PackageInstallerService
        mInstallerService = new PackageInstallerService(context, this); .// Get installed application information for each user and fill it in userPackages
        final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
        final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
        for (int userId : currentUserIds) {
            userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
        }
        // Add userPackages to mDexManager to track dex usagemDexManager.load(userPackages); .// Trigger garbage collectionRuntime.getRuntime().gc(); .Copy the code

PMSSummary of construction methods

The PackageManagerService constructor executes as follows:

  • Read the firstpackages.xmlFile contents, parsed and saved in member variablesmSettingsIn the.
    • This is equivalent to loading application status information from the last time the device was run
  • Then scan the application files in several partition directories on the device and save the scan results toPMSthemPackagesIn the.
    • This records application status information in the current system
  • The next step is to compare, readjust, and scan specific directories.
  • Finally, the application information is written backpackages.xmlfile

The call sequence diagram looks like this (some methods have been removed for brevity) :

startOtherServices()In thePMSoperation

As described earlier, in startOtherServices(), PMS also does the following three operations:

  • mPackageManagerService.updatePackagesIfNeeded(): Checks whether an update is requiredpackage
  • mPackageManagerService.performFstrimIfNeeded(): Deletes disk space
  • mPackageManagerService.systemReady(): Performs some default permission checks andpackageInformation update operations and status notifications of related services (*.systemReady())

So let’s look at it briefly

updatePackagesIfNeeded()

UpdatePackagesIfNeeded () checks whether packages need to be updated and dex optimized

The content of the method is as follows, with detailed notes:

    public void updatePackagesIfNeeded(a) {
        enforceSystemOrRoot("Only the system can request package update");

        // We need to re-extract after an OTA.
        boolean causeUpgrade = isUpgrade();

        // First boot or factory reset.
        boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;

        // We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
        boolean causePrunedCache = VMRuntime.didPruneDalvikCache();
        
        // If not: OTA, first startup, Upgrade to Android N, VM cache adjustment
        // Return directly
        if(! causeUpgrade && ! causeFirstBoot && ! causePrunedCache) {return;
        }
        List<PackageParser.Package> pkgs;
        synchronized (mPackages) {
            // Get the installed Package collection
            pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
        }
        final long startTime = System.nanoTime();
        // Perform the upgrade
        final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
                    causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
                    false /* bootComplete */); . }Copy the code

The actual method to perform the upgrade is performDexOptUpgrade().

    private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, ...) {...final int numberOfPackagesToDexopt = pkgs.size();
        for (PackageParser.Package pkg : pkgs) {
            numberOfPackagesVisited++;
            boolean useProfileForDexopt = false;
            if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) {
                // For the system APP, if it is the first startup or upgrade state
                // First check whether the application's Initial Preopt profiles exist
                if (profileFile.exists()) {
                    ......
                    // Copy the file with Installer if it existsmInstaller.copySystemProfile(profileFile.getAbsolutePath(), ...) ; }else {
                    // File does not exist, check application in 
       tag
                    PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
                    if(disabledPs ! =null && disabledPs.pkg.isStub) {
                        // If the tag exists and the application type is Stub, find the special path
                        String systemProfilePath = getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, "");
                        profileFile = newFile(systemProfilePath); . mInstaller.copySystemProfile(profileFile.getAbsolutePath(),...) ; }}}if(! PackageDexOptimizer.canOptimizePackage(pkg)) { ......// If the application does not support optimization, skip it
                continue; }...// The call to performDexOptTraced is disgusting
            // Trace the code, the last call is
            PackageDexOptimizer class dexOptPath function
            // The minstaller.dexopt () function is converted
            // Minstaller.dexopt () invokes installd service remotely with Binder
            performDexOptTraced(newDexoptOptions( pkg.packageName, pkgCompilationReason, dexoptFlags)); . }... }Copy the code

performFstrimIfNeeded()

PerformFstrimIfNeeded () is used to clean disks as follows:

    public void performFstrimIfNeeded(a) {
        enforceSystemOrRoot("Only the system can request fstrim");

        // Before everything else, see whether we need to fstrim.
        try {
            // Get the StorageManagerService object
            IStorageManager sm = PackageHelper.getStorageManager();
            if(sm ! =null) {
                boolean doTrim = false;
                // The interval between reading fstrim, default 3 days
                final long interval = android.provider.Settings.Global.getLong(
                        mContext.getContentResolver(),
                        android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL,
                        DEFAULT_MANDATORY_FSTRIM_INTERVAL);
                if (interval > 0) {
                    // Determine the interval
                    final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance();
                    if (timeSinceLast > interval) {
                        doTrim = true; }}if (doTrim) {
                    ......
                    // runMaintenance first sends an H_FSTRIM message to the Handler via sm
                    // The mVold object then calls the fSTRIm function of the vold process through bindersm.runMaintenance(); }}else {
                Slog.e(TAG, "storageManager service unavailable!"); }}catch (RemoteException e) {
            // Can't happen; StorageManagerService is local}}Copy the code

systemReady()

SystemReady () mainly performs permission-related updates, as well as some service state changes.

The relevant codes are as follows:

    @Override
    public void systemReady(a) {
        enforceSystemOrRoot("Only the system can claim the system is ready");
        mSystemReady = true; .// Omit a ContentObserver associated with InstantApp
        CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this, mContext.getContentResolver(), UserHandle.USER_SYSTEM); .// Obtain and set the compatibilityModeEnabled compatibility mode
        boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
                mContext.getContentResolver(),
                android.provider.Settings.Global.COMPATIBILITY_MODE, 1) = =1; PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled); .int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
        synchronized (mPackages) {
            // Check whether the PreferredActivity exists and clean up any that doesn't
            ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
            for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
                ......
            }
            // Check user permissions and add userids that are not default permissions to the set of grantPermissionsUserIds
            for (int userId : UserManagerService.getInstance().getUserIds()) {
                if(! mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) { grantPermissionsUserIds = ArrayUtils.appendInt( grantPermissionsUserIds, userId); } } } sUserManager.systemReady();// Set to default
        for (intuserId : grantPermissionsUserIds) { mDefaultPermissionPolicy.grantDefaultPermissions(userId); }...// Update permissions
        synchronized (mPackages) {
            mPermissionManager.updateAllPermissions(
                    StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
                    mPermissionCallback);
        }
        // Send systemReady notification
        if(mPostSystemReadyMessages ! =null) {
            for (Message msg : mPostSystemReadyMessages) {
                msg.sendToTarget();
            }
            mPostSystemReadyMessages = null;
        }
        // Register external storage device listener
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        storage.registerListener(mStorageListener);
        // Send systemReady notifications for associated services
        mInstallerService.systemReady();
        mDexManager.systemReady();
        mPackageDexOptimizer.systemReady();
        // Obtain the StorageManager service and add related status notification policiesStorageManagerInternal StorageManagerInternal = LocalServices.getService( StorageManagerInternal.class); StorageManagerInternal.addExternalStoragePolicy(...) ;// Now that we're mostly running, clean up stale users and apps
        sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
        reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
        // Send the systemReady notification to the PermissionManagermPermissionManager.systemReady(); . }Copy the code

By now, the main process of PMS initialization has been sorted out. The whole process is quite long and many details have been ignored. Next, we will look at the details of PMS initialization from three aspects:

  • permissionFile processing
  • Application directory scanning process
  • APKFile parsing process

The next article dives into Android (X) PMS-2- some details of initialization