Related articles Android package management mechanism series

preface

PackageInstaller installs APK and sends the APK information to the PMS. So how does PMS handle this? This article will give you the answer.

1.PackageHandler processes installation messages

After APK information is handed over to the PMS, the PMS sends messages to the PackageHandler to drive APK replication and installation. Let’s start by looking at the sequence diagram of how the PackageHandler calls the installation messages.

Continue with the code logic from the previous article to look at PMS’s installStage methods. frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

 void installStage(String packageName, File stagedDir, String stagedCid,
            IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
            String installerPackageName, int installerUid, UserHandle user,
            Certificate[][] certificates) {...final Message msg = mHandler.obtainMessage(INIT_COPY);/ / 1
        final int installReason = fixUpInstallReason(installerPackageName, installerUid,
                sessionParams.installReason);
        final InstallParams params = new InstallParams(origin, null, observer,
                sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
                verificationInfo, user, sessionParams.abiOverride,
                sessionParams.grantedRuntimePermissions, certificates, installReason);/ / 2
        params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params)); msg.obj = params; . mHandler.sendMessage(msg);/ / 3
    }
Copy the code

Create InstallParams in comment 2, which corresponds to the package’s installation data. A message of type INIT_COPY is created in comment 1, and InstallParams is sent via message in comment 3.

1.1 Handling of INIT_COPY messages

The code for handling messages of type INIT_COPY is shown below. frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#PackageHandler

        void doHandleMessage(Message msg) {
            switch (msg.what) {
                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    int idx = mPendingInstalls.size();
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ":" + params);
                    //mBound is used to identify whether a service is bound. The default value is false
                    if(! mBound) {/ / 1
                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                System.identityHashCode(mHandler));
                        // If the service is not bound, rebind it. Inside the connectToService method mBound is set to true if the binding succeeds
                        if(! connectToService()) {/ / 2
                            Slog.e(TAG, "Failed to bind to media container service");
                            params.serviceError();
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                    System.identityHashCode(mHandler));
                            if(params.traceMethod ! =null) {
                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
                                        params.traceCookie);
                            }
                            // If the binding fails, return
                            return;
                        } else {
                            // Add the request to mpendingMouse of type ArrayList. Waits for processingmPendingInstalls.add(idx, params); }}else {
                    // The service has been bound
                        mPendingInstalls.add(idx, params);
                        if (idx == 0) {
                            mHandler.sendEmptyMessage(MCS_BOUND);/ / 3}}break; }... }}}Copy the code

PackageHandler inherits from Handler, which is defined in the PMS. The doHandleMessage method is used to handle messages of various types to see how messages of type INIT_COPY are handled. MBound in comment 1 is used to indicate whether DefaultContainerService is bound. The default value is false. DefaultContainerService is a service that checks and copies removable files. This is a time-consuming operation, so DefaultContainerService does not run in the same process as PMS. It runs in com.android. defContainer and communicates with PMS via IMediaContainerService, as shown in the figure below.

The connectToService method at note 2 is used to bind DefaultContainerService, and the MCS_BOUND message at note 3 triggers processing of the first installation request. Look at the connectToService method in comment 2: **frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#PackageHandler **

  private boolean connectToService(a) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
                    " DefaultContainerService");
            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
            if (mContext.bindServiceAsUser(service, mDefContainerConn,
                    Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {/ / 1
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                mBound = true;/ / 2
                return true;
            }
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            return false;
        }
Copy the code

MBound is set to true in comment 2 if DefaultContainerService is successfully bound. The bindServiceAsUser method in comment 1 passes in mDefContainerConn. The logic of the bindServiceAsUser method is similar to that of calling bindService. Once the service has established a connection, Will call onServiceConnected method: * * frameworks/base/services/core/Java/com/android/server/PM/PackageManagerService. Java * *

  class DefaultContainerConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
            final IMediaContainerService imcs = IMediaContainerService.Stub
                    .asInterface(Binder.allowBlocking(service));
            mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, Object));/ / 1
        }
        public void onServiceDisconnected(ComponentName name) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected"); }}Copy the code

Comments sent 1 MCS_BOUND types of messages, and PackageHandler. DoHandleMessage method comments 3, send the message here is with the parameters of the Object types, there will be for the two cases to explain, is a kind of news do not bring the parameters of the Object types, One is a message with a parameter of type Object.

1.2 Handling of MCS_BOUND messages

MCS_BOUND messages with no Object parameters

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

case MCS_BOUND: {
            if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
            if(msg.obj ! =null) {/ / 1
                mContainerService = (IMediaContainerService) msg.obj;/ / 2
                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                        System.identityHashCode(mHandler));
            }
            if (mContainerService == null) {/ / 3
                if(! mBound) {/ / 4
                      Slog.e(TAG, "Cannot bind to media container service");
                      for (HandlerParams params : mPendingInstalls) {
                          params.serviceError();/ / 5
                          Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                        System.identityHashCode(params));
                          if(params.traceMethod ! =null) {
                          Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
                           params.traceMethod, params.traceCookie);
                          }
                          return;
                      }   
                          // Failed to bind, empty the installation request queue
                          mPendingInstalls.clear();
                   } else {
                          // Continue to wait for the binding service
                          Slog.w(TAG, "Waiting to connect to media container service"); }}else if (mPendingInstalls.size() > 0) {...else {
                   Slog.w(TAG, "Empty queue");
                   }
            break;
        }
Copy the code

If the message does not take an Object parameter, the conditions at comment 1 cannot be met. The mContainerService of type IMediaContainerService at comment 2 cannot be assigned, thus satisfying the conditions at Comment 3. If meet the comment 4 condition, that is not binding, and had been in PackageHandler. DoHandleMessage method 2 place call the binding service method, this is obviously not normal, so there was an error in note 5 is responsible for handling service. If the conditions in comment 4 are not met, the service is bound and the system log is printed to tell the user to wait for the system to bind the service.

Message with the parameters of the Object types frameworks/base/services/core/Java/com/android/server/PM/PackageManagerService. Java

case MCS_BOUND: {
            if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
            if(msg.obj ! =null) {... }if (mContainerService == null) {/ / 1. }else if (mPendingInstalls.size() > 0) {/ / 2
                          HandlerParams params = mPendingInstalls.get(0);/ / 3
                        if(params ! =null) {
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                    System.identityHashCode(params));
                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                            if (params.startCopy()) {/ / 4
                                if (DEBUG_SD_INSTALL) Log.i(TAG,
                                        "Checking for more work or unbind...");
                                 // If APK is installed successfully, delete the installation request
                                if (mPendingInstalls.size() > 0) {
                                    mPendingInstalls.remove(0);
                                }
                                if (mPendingInstalls.size() == 0) {
                                    if (mBound) {
                                    // If no more requests are installed, send a request to unbind the service
                                        if (DEBUG_SD_INSTALL) Log.i(TAG,
                                                "Posting delayed MCS_UNBIND");
                                        removeMessages(MCS_UNBIND);
                                        Message ubmsg = obtainMessage(MCS_UNBIND);
                                        sendMessageDelayed(ubmsg, 10000); }}else {
                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
                                            "Posting MCS_BOUND for next work");
                                   If there are additional installation requests, then send an MCS_BOUND message to continue processing the remaining installation requests
                                    mHandler.sendEmptyMessage(MCS_BOUND);/ / 5
                                }
                            }
                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                        }else {
                        Slog.w(TAG, "Empty queue");/ / 6
                    }
            break;
        }
Copy the code

If an MCS_BOUND message with an Object parameter does not satisfy the conditions in comment 1, the judgment in comment 2 is invoked. If the number of install requests does not exceed zero, the log in comment 6 is printed, indicating that the install request queue is empty. Once an APK is installed, an MSC_BOUND message is sent at comment 5 to continue processing the remaining install requests until the install request queue is empty. If HandlerParams is not null, the startCopy method of HandlerParams at comment 4 is called to start the process of copying APK.

2. Copy the APK

Let’s start by looking at the sequence diagram of the copied APK.

HandlerParams is an abstract class in PMS. Its implementation class is InstallParams, an internal class of PMS. The startCopy method for HandlerParams is shown below. frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#HandlerParams

 final boolean startCopy(a) {
            boolean res;
            try {
                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ":" + this);
                // The startCopy method is aborted after four attempts
                if (++mRetries > MAX_RETRIES) {/ / 1
                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                    mHandler.sendEmptyMessage(MCS_GIVE_UP);/ / 2
                    handleServiceError();
                    return false;
                } else {
                    handleStartCopy();/ / 3
                    res = true; }}catch (RemoteException e) {
                if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
                mHandler.sendEmptyMessage(MCS_RECONNECT);
                res = false;
            }
            handleReturnCode();/ / 4
            return res;
        }
Copy the code

The mRetries in comment 1 is used to record the number of times the startCopy method is called. The startCopy method is automatically incremented and the request is aborted if it is called more than four times: Delete the first install request (this one) from the Install queue mpendingMouse by sending a message of type MCS_GIVE_UP at comment 2. Note 4 deals with the logic of installing APK after copying APK, as mentioned again in section 3. Note 3 calls the abstract method handleStartCopy, which is implemented in InstallParams as shown below. frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#InstallParams

     public void handleStartCopy(a) throws RemoteException {...// Determine the APK installation location. OnSd: Install to SD card, onInt: internal storage i.e. Data partition, ephemeral: install to temporary storage (Instant Apps installation)
            final booleanonSd = (installFlags & PackageManager.INSTALL_EXTERNAL) ! =0;
            final booleanonInt = (installFlags & PackageManager.INSTALL_INTERNAL) ! =0;
            final booleanephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) ! =0;
            PackageInfoLite pkgLite = null;
            if (onInt && onSd) {
              // APK cannot be installed on both SD card and Data partition
                Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
              Instant Apps cannot be installed on the SD card
            } else if (onSd && ephemeral) {
                Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else {
                 // Get a small amount of information about APK
                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                        packageAbiOverride);/ / 1
                if (DEBUG_EPHEMERAL && ephemeral) {
                    Slog.v(TAG, "pkgLite for install: "+ pkgLite); }...if (ret == PackageManager.INSTALL_SUCCEEDED) {
                 // Determine the installation position
                int loc = pkgLite.recommendedInstallLocation;
                if(loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) { ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;  }else if(loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) { ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; }... }else{
                  loc = installLocationPolicy(pkgLite);/ / 2. }}// Create InstallArgs object according to InstallParams
            final InstallArgs args = createInstallArgs(this);/ / 3
            mArgs = args;
            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                   ...
                if(! origin.existing && requiredUid ! = -1
                        && isVerificationEnabled(
                              verifierUser.getIdentifier(), installFlags, installerUid)) {
                      ...
                } else{
                    ret = args.copyApk(mContainerService, true);/ / 4
                }
            }
            mRet = ret;
        }

Copy the code

The handleStartCopy method has a lot of code, and here are the key sections. Note 1 calls the getMinimalPackageInfo method of DefaultContainerService across processes through IMediaContainerService, which parses APK lightly and gets a small amount of APK information. The reason for light parsing is that you don’t need to get all the APK information; the small amount of APK information is encapsulated in PackageInfoLite. Next determine the location of the APK installation in comment 2. Note 3 creates InstallArgs, an abstract class that defines the installation logic of APK, such as copying and renaming APK. InstallArgs has three subclasses, all defined in PMS, as shown in the figure below.

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

   private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {...try {
                final booleanisEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) ! =0;
                // Create a temporary file storage directory
                final File tempDir =
                        mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);/ / 1
                codeFile = tempDir;
                resourceFile = tempDir;
            } catch (IOException e) {
                Slog.w(TAG, "Failed to create copy file: " + e);
                returnPackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; }...int ret = PackageManager.INSTALL_SUCCEEDED;
            ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);/ / 2.return ret;
        }
Copy the code

Note 1 is used to create temporary storage directory, such as/data/app/vmdl18300388. TMP, 18300388 of them were installed sessionId. Note 2 calls the copyPackage method of DefaultContainerService across processes through IMediaContainerService. This method copies the APK to the temporary storage directory in the process where the DefaultContainerService is located. Such as the/data/app/vmdl18300388. TMP/base. Apk. Now that the APK copy is complete, the APK installation process is ready.

3. Install the APK

As usual, we’ll start with a sequence diagram of the APK installation.

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

 void handleReturnCode(a) {
    if(mArgs ! =null) { processPendingInstall(mArgs, mRet); }}private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        mHandler.post(new Runnable() {
            public void run(a) {
                mHandler.removeCallbacks(this);
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.setReturnCode(currentStatus);
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = null;
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                    // Pre-installation processing
                    args.doPreInstall(res.returnCode);/ / 1
                    synchronized (mInstallLock) {
                        installPackageTracedLI(args, res);/ / 2
                    }
                    // Finish after installation
                    args.doPostInstall(res.returnCode, res.uid);/ / 3}... }}); }Copy the code

In the handleReturnCode method, only the processPendingInstall method is called. Note 1 is used to check the status of APK and ensure that the installation environment is reliable before installation. If not, the copied APK files will be cleared. Delete the installation related directories and files. Focus on the installPackageTracedLI method in comment 2, which internally calls the installPackageLI method of PMS. frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {... PackageParser pp =new PackageParser();
    pp.setSeparateProcesses(mSeparateProcesses);
    pp.setDisplayMetrics(mMetrics);
    pp.setCallback(mPackageParserCallback);
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
    final PackageParser.Package pkg;
    try {
        / / parsing APK
        pkg = pp.parsePackage(tmpPackageFile, parseFlags);/ / 1
    } catch (PackageParserException e) {
        res.setError("Failed parse during installPackageLI", e);
        return;
    } finally{ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); }... pp =null;
    String oldCodePath = null;
    boolean systemApp = false;
    synchronized (mPackages) {
        // Check whether the APK exists
        if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) ! =0) {
            String oldName = mSettings.getRenamedPackageLPr(pkgName);// Get the package name before it was renamed
            if(pkg.mOriginalPackages ! =null
                    && pkg.mOriginalPackages.contains(oldName)
                    && mPackages.containsKey(oldName)) {
                pkg.setPackageName(oldName);/ / 2
                pkgName = pkg.packageName;
                replace = true;// Set the flag bit to indicate a replacement installation
                if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
                        + oldName + " pkgName="+ pkgName); }... } PackageSetting ps = mSettings.mPackages.get(pkgName);// Check whether the Settings contains information about the APK to install, and if so, get the signature information
        if(ps ! =null) {/ / 3
            if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
            PackageSetting signatureCheckPs = ps;
            if (pkg.applicationInfo.isStaticSharedLibrary()) {
                SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
                if(libraryEntry ! =null) { signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk); }}// Check whether the signature is correct
            if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
                if(! checkUpgradeKeySetLP(signatureCheckPs, pkg)) { res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,"Package "
                            + pkg.packageName + " upgrade keys do not match the "
                            + "previously installed version");
                    return; }}... }int N = pkg.permissions.size();
        for (int i = N-1; i >= 0; i--) {
           // Iterate over each permission to process the permissionPackageParser.Permission perm = pkg.permissions.get(i); BasePermission bp = mSettings.mPermissions.get(perm.info.name); }}}if (systemApp) {
        if (onExternal) {
            // System APP cannot be replaced on SD card
            res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Cannot install updates to system apps on sdcard");
            return;
        } else if (instantApp) {
            // System APP cannot be replaced by Instant APP
            res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Cannot update a system app with an instant app");
            return; }}...// Rename temporary files
    if(! args.doRename(res.returnCode, pkg, oldCodePath)) {/ / 4
        res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
        return;
    }

    startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);

    try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
            "installPackageLI")) {
       
        if (replace) {/ / 5
         // Replace the installation. replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user, installerPackageName, res, args.installReason); }else {
        // Install new APKinstallNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, args.user, installerPackageName, volumeUuid, res, args.installReason); }}synchronized (mPackages) {
        final PackageSetting ps = mSettings.mPackages.get(pkgName);
        if(ps ! =null) {
            // Update the user to which the application belongs
            res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            ps.setUpdateAvailable(false /*updateAvailable*/); }... }}Copy the code

The installPackageLI method has nearly 500 lines of code, and here is the main excerpt that does a few things:

  1. Create PackageParser to parse the APK.
  2. Check if the APK exists. If it does, get the Package name that was not previously renamed and assign it to a PKG of type PackageParser.Package at comment 1.
  3. In comment 3, if the Settings contains information about the APK to be installed, it indicates that the APK has been installed before. Therefore, you need to verify the APK signature information to ensure safe replacement.
  4. In April to a temporary file renaming, such as the aforementioned/data/app/vmdl18300388. TMP/base. The apk, renamed/data/app/package name – 1 / base. Apk. The newly named package name will have a suffix 1, which will add up every time you upgrade an existing App.
  5. There are two limitations in the update installation of system APP. One is that system APP cannot be replaced and installed on the SD card, and the other is that system APP cannot be replaced by Instant APP.
  6. ReplacePackageLIF is called in the case of a replacement installation. It also distinguishes between system APP and non-system APP. InstallNewPackageLIF is called in the case of a newly installed APK.

Here we use the newly installed APK as an example, calling the installNewPackageLIF method of PMS. frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

 private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
            int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
            PackageInstalledInfo res, int installReason) {...try {
            / / scan the APK
            PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
                    System.currentTimeMillis(), user);
            // Update Settings information
            updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                // After successful installation, prepare data for the newly installed application
                prepareAppDataAfterInstallLIF(newPackage);

            } else {
                // If the installation fails, delete the APK
                deletePackageLIF(pkgName, UserHandle.ALL, false.null,
                        PackageManager.DELETE_KEEP_DATA, res.removedInfo, true.null); }}catch (PackageManagerException e) {
            res.setError("Package couldn't be installed in " + pkg.codePath, e);
        }
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
Copy the code

InstallNewPackageLIF does three things:

  1. Scan the APK and store the APK information in newPackage of type PackageParser.Package. The information of a Package contains 1 Base APK and 0 or more split APKs.
  2. Update the Settings of the APK. Settings is used to save the dynamic Settings of all packages.
  3. Prepare the data for the newly installed application on success, and remove the APK on failure.

This is the APK installation process, no further analysis, interested students can continue to dig.

4. To summarize

This article mainly explains how PMS handles APK installation. There are several steps:

  1. When the PackageInstaller installs the APK, the APK information is processed by the PMS. The PMS sends messages to the PackageHandler to drive the APK replication and installation.
  2. The PMS sends messages of type INIT_COPY and MCS_BOUND, and controls PackageHandler to bind DefaultContainerService and copy APK.
  3. After the APK is copied, the APK installation process starts, including pre-installation check, APK installation, and post-installation finishing work.

Android Package Management Mechanism Android App Installation process analysis (based on Nougat) Application installation process


Here we share not only Android, Java and mobile front-end technologies, but also industry trends, technical information, experience and personal insights. Every month will strive to send book benefits to everyone.