What does the PackageManagerService do when it starts?

  1. Execute the PackageManagerService main static method;
  2. Call the PackageManagerService isFirstBoot() method;
  3. Call PackageManagerService class getUsageStatsIfNoPackageUsageInfo () method;
  4. Call the PackageManagerService class performBootDexOpt() method;
  5. Call the PackageManagerService class systemReady() method.

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

public final class SystemServer {...privatePackageManagerService mPackageManagerService; ./** * The main entry point from zygote. */
    public static void main(String[] args) {
        new SystemServer().run();
    }

    public SystemServer(a) {
        // Check for factory test mode.
        mFactoryTestMode = FactoryTest.getMode();
    }

    private void run(a) {...// Start services.
        try {
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
        } catch (Throwable ex) {
            Slog.e("System"."* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
            Slog.e("System"."************ Failure starting system services", ex);
            throwex; }... }...private void startBootstrapServices(a) {...// Wait for Installd to finish booting so that it has a chance to create key directories with appropriate permissions, such as /data/user.
        // We need to do this before initializing the other services.Installer installer = mSystemServiceManager.startService(Installer.class); .// Start the package manager.
        Slog.i(TAG, "Package Manager"); mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode ! = FactoryTest.FACTORY_TEST_OFF, mOnlyCore); mFirstBoot = mPackageManagerService.isFirstBoot(); . }...private void startCoreServices(a) {...// UsageStatsService is updated after it becomes available, before performBootDexOpt.mPackageManagerService.getUsageStatsIfNoPackageUsageInfo(); . }...private void startOtherServices(a) {...try {
            mPackageManagerService.performBootDexOpt();
        } catch (Throwable e) {
            reportWtf("performing boot dexopt", e); }...try {
            mPackageManagerService.systemReady();
        } catch (Throwable e) {
            reportWtf("making Package Manager Service ready", e); }... }... }Copy the code

In the main() static method:

  1. Create the PackageManagerService object.
  2. Register it with the ServiceManager ServiceManager using the “package” registration field. Then you can query the “package” string to obtain the PackageManagerService.

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

public class PackageManagerService extends IPackageManager.Stub {...public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        ServiceManager.addService("package", m);
        returnm; }... }Copy the code

The PackageManagerService constructor does a number of things including adding special user names and uIds and associating them, and getting various paths (/data/data, /data/app, /data/app-lib, /data/app-asec…). , all external libraries run dexopt, files in the framework path run dexopt (except framework-res.apk and core-libart.jar), scan various software packages (vendor Overlay package, base) Framework (codeless resource packs), privileged System packages, common system packages, vendor packages, OEM packages), processing all system packages that no longer exist, cleaning up any incomplete package installations, removing all shared user ids that are not associated with packages…

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

public class PackageManagerService extends IPackageManager.Stub {...public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {... mContext = context; mFactoryTest = factoryTest; mOnlyCore = onlyCore; mLazyDexOpt ="eng".equals(SystemProperties.get("ro.build.type"));
        mMetrics = new DisplayMetrics();
        mSettings = new Settings(mPackages);
        // Add special user names and UID associations, such as "android.uid. System "and process.system_uid associations
        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; mPackageDexOptimizer =new PackageDexOptimizer(this);
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

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

        getDefaultDisplayMetrics(context, mMetrics);

        SystemConfig systemConfig = SystemConfig.getInstance();
        mGlobalGids = systemConfig.getGlobalGids();
        mSystemPermissions = systemConfig.getSystemPermissions();
        mAvailableFeatures = systemConfig.getAvailableFeatures();

        synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
            // Return path: /data
            File dataDir = Environment.getDataDirectory();
            mAppDataDir = new File(dataDir, "data");
            mAppInstallDir = new File(dataDir, "app");
            mAppLib32InstallDir = new File(dataDir, "app-lib");
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            mUserAppDataDir = new File(dataDir, "user");
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

            sUserManager = new UserManagerService(context, this, mInstallLock, mPackages); . mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), mSdkVersion, mOnlyCore); .// Set the monitor flag instead of changing the apk file path while scanning the installation directory.
            final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;

            final ArraySet<String> alreadyDexOpted = new ArraySet<String>();

            /** * adds everything in the boot classpath to the process file list, * because dexopt will be run during zygote startup if needed. * /
            final String bootClassPath = System.getenv("BOOTCLASSPATH");
            final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");

            if(bootClassPath ! =null) {
                String[] bootClassPathElements = splitString(bootClassPath, ':');
                for(String element : bootClassPathElements) { alreadyDexOpted.add(element); }}else {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }

            if(systemServerClassPath ! =null) {
                String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
                for(String element : systemServerClassPathElements) { alreadyDexOpted.add(element); }}else {
                Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
            }

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

            /** * Make sure all external libraries are running dexopt. * /
            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 {
                            int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
                            if(dexoptNeeded ! = DexFile.NO_DEXOPT_NEEDED) { alreadyDexOpted.add(lib); mInstaller.dexopt(lib, Process.SYSTEM_UID,true, dexCodeInstructionSet, dexoptNeeded, false); }}catch (FileNotFoundException e) {
                            Slog.w(TAG, "Library not found: " + lib);
                        } catch (IOException e) {
                            Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                    + e.getMessage());
                        }
                    }
                }
            }

            File frameworkDir = new File(Environment.getRootDirectory(), "framework");

            // We know that this file does not contain any code, so please do not do dexopt processing to avoid log overflow.
            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");

            // We know that this file is only part of the art startup classpath, so please do not do dexopt processing to avoid log overflow.
            alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");

            /** * There are many commands implemented in Java that * we currently need to run dexopt on, * so that we can run them from non-root user shell programs. * /
            String[] frameworkFiles = frameworkDir.list();
            if(frameworkFiles ! =null) {
                // TODO: We could compile these only for the most preferred ABI. We should
                // first double check that the dex files for these commands are not referenced
                // by other system apps.
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    for (int i=0; i<frameworkFiles.length; i++) {
                        File libPath = new File(frameworkDir, frameworkFiles[i]);
                        String path = libPath.getPath();
                        // Skip the file if we have already processed it.
                        if (alreadyDexOpted.contains(path)) {
                            continue;
                        }
                        If it is not of the type we need to process (dexopt), skip the file.
                        if(! path.endsWith(".apk") && !path.endsWith(".jar")) {
                            continue;
                        }
                        try {
                            int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
                            if(dexoptNeeded ! = DexFile.NO_DEXOPT_NEEDED) { mInstaller.dexopt(path, Process.SYSTEM_UID,true, dexCodeInstructionSet, dexoptNeeded, false); }}catch (FileNotFoundException e) {
                            Slog.w(TAG, "Jar not found: " + path);
                        } catch (IOException e) {
                            Slog.w(TAG, "Exception reading jar: " + path, e);
                        }
                    }
                }
            }

            ......

            // Collect vendor Overlay packages. (Do this before scanning any applications.)
            // For security and version matching reasons, overlay packages are only considered if they are located in VENDOR_OVERLAY_DIR
            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
            scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

            // Find the underlying framework (code free resource bundles).
            scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED,
                    scanFlags | SCAN_NO_DEX, 0);

            // Collect the privileged system package.
            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
            scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);

            // Collect common system software packages.
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

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

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

            if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
            mInstaller.moveFiles();

            // Prune all system packages that no longer exist.
            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 application, it cannot be a disabled system application. * /
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        continue;
                    }

                    /* * If the packet is scanned, it will not be deleted. * /
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    if(scannedPkg ! =null) {
                        /* * If the system application is scanned and in the banned package list, it must have been added via OTA. * Remove it from the currently scanned package so that applications installed by previous users can be scanned. * /
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                            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);
                            removePackageLI(ps, true);
                            mExpectingBetter.put(ps.name, ps.codePath);
                        }

                        continue;
                    }

                    if(! mSettings.isDisabledSystemPackageLPr(ps.name)) { psit.remove(); logCriticalInfo(Log.WARN,"System package " + ps.name
                                + " no longer exists; wiping its data");
                        removeDataDirsLI(null, ps.name);
                    } else {
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null| |! disabledPs.codePath.exists()) { possiblyDeletedUpdatedSystemApps.add(ps.name); }}}}// Find any incomplete package installations
            ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            / / clean up the list
            for(int i = 0; i < deletePkgsList.size(); i++) {
                cleanupInstallFailedPackage(deletePkgsList.get(i));
            }
            // Delete TMP files
            deleteTempPackageFiles();

            // Delete all share user ids that are not associated with software packages
            mSettings.pruneSharedUsersLPw();

            if(! mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); scanDirLI(mAppInstallDir,0, scanFlags | SCAN_REQUIRE_KNOWN, 0);

                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                        scanFlags | SCAN_REQUIRE_KNOWN, 0);

                /** * Remove the disable package Settings for all updated system applications that are removed over OTA. * If they are not previously updated applications, remove them completely. Otherwise, just revoke its system-level permissions. * /
                for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                    PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                    mSettings.removeDisabledSystemPackageLPw(deletedAppName);

                    String msg;
                    if (deletedPkg == null) {
                        msg = "Updated system package " + deletedAppName
                                + " no longer exists; wiping its data";
                        removeDataDirsLI(null, deletedAppName);
                    } else {
                        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 that all the system applications we expect to appear on the UserData partition actually appear. * /
                for (int i = 0; i < mExpectingBetter.size(); i++) {
                    final String packageName = mExpectingBetter.keyAt(i);
                    if(! mPackages.containsKey(packageName)) {final File scanFile = mExpectingBetter.valueAt(i);

                        logCriticalInfo(Log.WARN, "Expected better " + packageName
                                + " but never showed up; reverting to system");

                        final int reparseFlags;
                        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;
                        }

                        mSettings.enableSystemPackageLPw(packageName);

                        try {
                            scanPackageLI(scanFile, reparseFlags, scanFlags, 0.null);
                        } catch (PackageManagerException e) {
                            Slog.e(TAG, "Failed to parse original system package: "
                                    + e.getMessage());
                        }
                    }
                }
            }
            mExpectingBetter.clear();

            // Now that we know all shared libraries, update all clients to get the correct library path.
            updateAllSharedLibrariesLPw();

            for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                // NOTE: We ignore potential failures here during a system scan (like
                // the rest of the commands above) because there's precious little we
                // can do about it. A settings error is reported, though.
                adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */.false /* force dexopt */.false /* defer dexopt */.false /* boot complete */);
            }

            // Now we know all the packages to save, the last usage times to read and update them.
            mPackageUsage.readLP();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());
            Slog.i(TAG, "Time to scan packages: "
                    + ((SystemClock.uptimeMillis()-startTime)/1000f)
                    + " seconds");

            // If the platform SDK has changed since the last launch, we need to re-grant the application permissions to capture any new versions that appear.
            // This is a form of hacking, which means that the application can in some cases obtain permissions that the user did not initially explicitly allow...
            If only there were a better way to handle this situation.
            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 startup or update from pre-m, and it started normally,
            // We need to initialize the default preferred application in all defined users.
            if(! onlyCore && (mPromoteSystemApps || ! mRestoredSettings)) {for (UserInfo user : sUserManager.getUsers(true)) {
                    mSettings.applyDefaultPreferredAppsLPw(this, user.id); applyFactoryDefaultBrowserLPw(user.id); primeDomainVerificationsLPw(user.id); }}// If this is the first boot after the OTA and it is normal, then we need to clear 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)) {
                        deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
                    }
                }
                ver.fingerprint = Build.FINGERPRINT;
            }

            checkDefaultBrowser();

            Clear only after permissions and other default values have been updated
            mExistingSystemPackages.clear();
            mPromoteSystemApps = false;

            // All changes are made during the package scan.
            ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;

            // Can be downgraded to read
            mSettings.writeLPr();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                    SystemClock.uptimeMillis());

            mRequiredVerifierPackage = getRequiredVerifierLPr();
            mRequiredInstallerPackage = getRequiredInstallerLPr();

            mInstallerService = new PackageInstallerService(context, this);

            mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
            mIntentFilterVerifier = new IntentVerifierProxy(mContext,
                    mIntentFilterVerifierComponent);

        } // synchronized (mPackages)
        } // synchronized (mInstallLock)

        // Now, after opening each application zip, make sure they are refreshed.
        // Not really, but can be kept clean.
        Runtime.getRuntime().gc();

        // Expose private services for use by system components.
        LocalServices.addService(PackageManagerInternal.class, newPackageManagerInternalImpl()); }... }Copy the code

Next, go to the isFirstBoot() method, which is very simple and just returns the mRestoredSettings flag (restore Settings), initialized in the PackageManagerService constructor.

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

public class PackageManagerService extends IPackageManager.Stub {...booleanmRestoredSettings; .@Override
    public boolean isFirstBoot(a) {
        return! mRestoredSettings; }... }Copy the code

GetUsageStatsIfNoPackageUsageInfo update () function focuses on the application for the last time at the end of the time, through the Package name derives from the mPackages PackageParser. Package object, and then update.

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

public class PackageManagerService extends IPackageManager.Stub {...public void getUsageStatsIfNoPackageUsageInfo(a) {
        if(! mPackageUsage.isHistoricalPackageUsageAvailable()) { UsageStatsManager usm = (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE);if (usm == null) {
                throw new IllegalStateException("UsageStatsManager must be initialized");
            }
            long now = System.currentTimeMillis();
            Map<String, UsageStats> stats = usm.queryAndAggregateUsageStats(now - mDexOptLRUThresholdInMills, now);
            for (Map.Entry<String, UsageStats> entry : stats.entrySet()) {
                String packageName = entry.getKey();
                PackageParser.Package pkg = mPackages.get(packageName);
                if (pkg == null) {
                    continue;
                }
                UsageStats usage = entry.getValue();
                // Update the time when the application was last used
                pkg.mLastPackageUsageTimeInMills = usage.getLastTimeUsed();
                mPackageUsage.mIsHistoricalPackageUsageAvailable = true; }}}... }Copy the code

Fstrim is used to reclaim (also called “trim”) all unused blocks on a mounted file system. This is useful for solid-state drives (SSDS) and thinly-provisioned storage devices. By default, fSTRIm will reclaim all unused blocks on the file system. However, the scope and size of the collection can be limited by options.

The performBootDexOpt() function does the following

  1. Determine whether disk maintenance is required, which is done with the fstrim command
  2. Package tuning is done by calling an overloaded version of the performBootDexOpt function by calling dexopt to optimize the core application, listening for pre-booted system applications, and recently used applications

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

public class PackageManagerService extends IPackageManager.Stub {...@Override
    public void performBootDexOpt(a) {
        enforceSystemOrRoot("Only the system can request dexopt be performed");

        // First, see if we need fSTRIm.
        try {
            IMountService ms = PackageHelper.getMountService();
            if(ms ! =null) {
                final boolean isUpgrade = isUpgrade();
                boolean doTrim = isUpgrade;
                // Perform disk maintenance immediately due to system update
                if (doTrim) {
                    Slog.w(TAG, "Running disk maintenance immediately due to system update");
                } else {
                    // The interval between fstrim execution. The default is three 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) {
                        final long timeSinceLast = System.currentTimeMillis() - ms.lastMaintenance();
                        // More than three days to trigger disk maintenance (doTrim = true)
                        if (timeSinceLast > interval) {
                            doTrim = true;
                            Slog.w(TAG, "No disk maintenance in " + timeSinceLast
                                    + "; running immediately"); }}}if (doTrim) {
                    // If it is not the first startup, the interface shows that the storage space is being optimized.
                    if(! isFirstBoot()) {try {
                            ActivityManagerNative.getDefault().showBootMessage(
                                    mContext.getResources().getString(
                                            R.string.android_upgrading_fstrim), true);
                        } catch (RemoteException e) {
                        }
                    }
                    // Run disk maintenance, which is done with the fstrim commandms.runMaintenance(); }}else {
                Slog.e(TAG, "Mount service unavailable!"); }}catch (RemoteException e) {
            // Can't happen; MountService is local
        }

        final ArraySet<PackageParser.Package> pkgs;
        synchronized (mPackages) {
            // Clear the delayed dexopt package in Set. Returns the contents of the dexopt Set before clearing (if not empty)
            pkgs = mPackageDexOptimizer.clearDeferredDexOptPackages();
        }

        if(pkgs ! =null) {
            // Sort applications by importance for dexopt sort.
            // If device space is low, important applications will be given higher priority.
            ArrayList<PackageParser.Package> sortedPkgs = new ArrayList<PackageParser.Package>();
            // Give priority to core applications.
            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                PackageParser.Package pkg = it.next();
                if (pkg.coreApp) {
                    if (DEBUG_DEXOPT) {
                        Log.i(TAG, "Adding core app " + sortedPkgs.size() + ":"+ pkg.packageName); } sortedPkgs.add(pkg); it.remove(); }}// Priority is given to listening on system applications that have been prebooted.
            Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
            ArraySet<String> pkgNames = getPackageNamesForIntent(intent);
            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                PackageParser.Package pkg = it.next();
                if (pkgNames.contains(pkg.packageName)) {
                    if (DEBUG_DEXOPT) {
                        Log.i(TAG, "Adding pre boot system app " + sortedPkgs.size() + ":"+ pkg.packageName); } sortedPkgs.add(pkg); it.remove(); }}// Filter out packages that have not been used recently.
            filterRecentlyUsedApps(pkgs);
            // Add all remaining applications.
            for (PackageParser.Package pkg : pkgs) {
                if (DEBUG_DEXOPT) {
                    Log.i(TAG, "Adding app " + sortedPkgs.size() + ":" + pkg.packageName);
                }
                sortedPkgs.add(pkg);
            }

            // Filter packets that have not been used recently in lazy mode
            if (mLazyDexOpt) {
                filterRecentlyUsedApps(sortedPkgs);
            }

            int i = 0;
            int total = sortedPkgs.size();
            File dataDir = Environment.getDataDirectory();
            // Obtain the low storage space threshold
            long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
            if (lowThreshold == 0) {
                throw new IllegalStateException("Invalid low memory threshold");
            }
            for (PackageParser.Package pkg : sortedPkgs) {
                long usableSpace = dataDir.getUsableSpace();
                Dexopt is not run on other applications due to insufficient storage space
                if (usableSpace < lowThreshold) {
                    Log.w(TAG, "Not running dexopt on remaining apps due to low memory: " + usableSpace);
                    break;
                }
                // Complete the package optimizationperformBootDexOpt(pkg, ++i, total); }}}... }Copy the code
  1. If it is not the first startup, the interface displays xx/XX.
  2. The actual optimization is handled by calling the PackageDexOptimizer class performDexOpt

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

public class PackageManagerService extends IPackageManager.Stub {...private void performBootDexOpt(PackageParser.Package pkg, int curr, int total) {
        if (DEBUG_DEXOPT) {
            Log.i(TAG, "Optimizing app " + curr + " of " + total + ":" + pkg.packageName);
        }
        if(! isFirstBoot()) {try {
                // If it is not the first startup, the interface displays the application: xx/xx.
                ActivityManagerNative.getDefault().showBootMessage(
                        mContext.getResources().getString(R.string.android_upgrading_apk,
                                curr, total), true);
            } catch (RemoteException e) {
            }
        }
        PackageParser.Package p = pkg;
        synchronized (mInstallLock) {
            // The actual optimization is handled by calling the PackageDexOptimizer class performDexOpt
            mPackageDexOptimizer.performDexOpt(p, null /* Instruction set */.false /* Force dex */.false / * delay * /.true /* Includes dependencies */.false /* Start complete */); }}... }Copy the code

Dexopt is executed on all code paths and libraries of the specified package of the specified instruction set. PerformDexOptLI () is called inside the performDexOpt() method, and the Installer class dexopt is finally called inside the performDexOptLI() method to complete the actual optimization action.

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

final class PackageDexOptimizer {...int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
            boolean forceDex, boolean defer, boolean inclDependencies, boolean bootComplete) {
        ArraySet<String> done;
        if(inclDependencies && (pkg.usesLibraries ! =null|| pkg.usesOptionalLibraries ! =null)) {
            done = new ArraySet<String>();
            done.add(pkg.packageName);
        } else {
            done = null;
        }
        synchronized (mPackageManagerService.mInstallLock) {
            final boolean useLock = mSystemReady;
            if (useLock) {
                mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
                mDexoptWakeLock.acquire();
            }
            try {
                return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete, done);
            } finally {
                if(useLock) { mDexoptWakeLock.release(); }}}}private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
            boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {...final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
        for (String dexCodeInstructionSet : dexCodeInstructionSets) {
            ......
            for (String path : paths) {
                ......
                if(dexoptNeeded ! = DexFile.NO_DEXOPT_NEEDED) { ......final intret = mPackageManagerService.mInstaller.dexopt(path, sharedGid, ! pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet, dexoptNeeded, vmSafeMode, debuggable, oatDir, bootComplete); . }}... }... }... }Copy the code

Finally, look at the PackageManagerService class systemReady() method.

  1. Verify that all PreferredActivity components actually exist
  2. If we upgrade, grant all default permissions before startup
  3. Monitor external capacity changes

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

public class PackageManagerService extends IPackageManager.Stub {...@Override
    public void systemReady(a) {
        mSystemReady = true;

        // When the system is ready, read the compatibility mode switch.
        boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
                mContext.getContentResolver(),
                android.provider.Settings.Global.COMPATIBILITY_MODE, 1) = =1;
        PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
        if (DEBUG_SETTINGS) {
            Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
        }

        int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;

        synchronized (mPackages) {
            // Verify that all PreferredActivity components actually exist.
            ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
            for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
                PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
                removed.clear();
                for (PreferredActivity pa : pir.filterSet()) {
                    if (mActivities.mActivities.get(pa.mPref.mComponent) == null) { removed.add(pa); }}if (removed.size() > 0) {
                    for (int r=0; r<removed.size(); r++) {
                        PreferredActivity pa = removed.get(r);
                        Slog.w(TAG, "Removing dangling preferred activity: "+ pa.mPref.mComponent); pir.removeFilter(pa); } mSettings.writePackageRestrictionsLPr( mSettings.mPreferredActivities.keyAt(i)); }}for (int userId : UserManagerService.getInstance().getUserIds()) {
                if(! mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) { grantPermissionsUserIds = ArrayUtils.appendInt( grantPermissionsUserIds, userId); } } } sUserManager.systemReady();// If we upgrade, grant all default permissions before startup.
        for (int userId : grantPermissionsUserIds) {
            mDefaultPermissionPolicy.grantDefaultPermissions(userId);
        }

        // Start any messages and wait for the system to be ready
        if(mPostSystemReadyMessages ! =null) {
            for (Message msg : mPostSystemReadyMessages) {
                msg.sendToTarget();
            }
            mPostSystemReadyMessages = null;
        }

        // Monitor external capacity changes
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        storage.registerListener(mStorageListener);

        mInstallerService.systemReady();
        mPackageDexOptimizer.systemReady();

        MountServiceInternal mountServiceInternal = LocalServices.getService(
                MountServiceInternal.class);
        mountServiceInternal.addExternalStoragePolicy(
                new MountServiceInternal.ExternalStorageMountPolicy() {
            @Override
            public int getMountMode(int uid, String packageName) {
                if (Process.isIsolated(uid)) {
                    return Zygote.MOUNT_EXTERNAL_NONE;
                }
                if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
                    return Zygote.MOUNT_EXTERNAL_DEFAULT;
                }
                if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
                    return Zygote.MOUNT_EXTERNAL_DEFAULT;
                }
                if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
                    return Zygote.MOUNT_EXTERNAL_READ;
                }
                return Zygote.MOUNT_EXTERNAL_WRITE;
            }

            @Override
            public boolean hasExternalStorage(int uid, String packageName) {
                return true; }}); }... }Copy the code