Android PMS APP installation process

Warehouse URL: http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

1. PMS installation APP flow chart

insert image description here

2. File copy

PMS processing installation HandlerParams installation parameter flowchart

insert image description herePackageManagerService.java#installStage method introduction

1. An InstallParams object is created.
2. An INIT_COPY Message is created and sent.
3. InstallParams inherits from HandlerParams and is used to record the parameters for installing applications.
There is a member variable mArgs in InstallParams, which is an abstract type InstallArgs, which is mainly used to copy APK. The real implementation classes include: FileInstallArgs: used to complete the installation of
non-ASEC applications. The full name of ASEC is Android Secure External Cache
MoveInstallArgs: used to complete the mobile install of the installed app

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);
       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);
       params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
       msg.obj = params;
       ...
       //发送信息拷贝INIT_COPY 信息
       mHandler.sendMessage(msg);
   }

PackageManagerService.java#PackageHandler

connectToService(): A service for checking and copying removable files
Send MCS_BOUND information to trigger the processing of the first installation request

       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用于标识是否绑定了服务,默认值为false
                   if (!mBound) {
    
     
                       Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                               System.identityHashCode(mHandler));
                      //connectToService里面的DefaultContainerService是用于检查和复制可移动文件的服务
                       if (!connectToService()) {
    
      
                           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);
                           }
                           //绑定服务失败则return
                           return;
                       } else {
    
     
                           //绑定服务成功,将请求添加到ArrayList类型的mPendingInstalls中,等待处理
                           mPendingInstalls.add(idx, params);
                       }
                   } else {
    
      
                   //已经绑定服务
                       mPendingInstalls.add(idx, params);
                       if (idx == 0) {
    
       //5
                           //发送MCS_BOUND类型的消息,触发处理第一个安装请求
                           mHandler.sendEmptyMessage(MCS_BOUND);
                       }
                   }
                   break;
               }
               ....
               }
   }
}

MCS_BOUND process processing:

case MCS_BOUND: {
    
    
            if (mContainerService == null) {
    
             //判断是否已经绑定了服务
                if (!mBound) {
    
                //绑定服务的标识位,没有绑定成功
                      Slog.e(TAG, "Cannot bind to media container service");
                      for (HandlerParams params : mPendingInstalls) {
    
    
                          params.serviceError();
                          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;
                      }   
                          //绑定失败,清空安装请求队列
                          mPendingInstalls.clear();
                   } else {
    
                 // 绑定成功
                          //继续等待绑定服务
                          Slog.w(TAG, "Waiting to connect to media container service");
                   }
            } else if (mPendingInstalls.size() > 0) {
    
            //安装APK的队列
                          HandlerParams params = mPendingInstalls.get(0);   //安装队列有参数
                        if (params != null) {
    
    
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                    System.identityHashCode(params));
                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                            if (params.startCopy()) {
    
                   //HandlerParams开始拷贝
                                if (DEBUG_SD_INSTALL) Log.i(TAG,
                                        "Checking for more work or unbind...");
                                 //如果APK安装成功,删除本次安装请求
                                if (mPendingInstalls.size() > 0) {
    
    
                                    mPendingInstalls.remove(0);
                                }
                                if (mPendingInstalls.size() == 0) {
    
      //安装队列没有参数
                                    if (mBound) {
    
                //已经绑定服务,需要发送一个解绑MCS_UNBIND的message
                                    //如果没有安装请求了,发送解绑服务的请求
                                        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");
                                   //如果还有其他的安装请求,接着发送MCS_BOUND消息继续处理剩余的安装请求       
                                    mHandler.sendEmptyMessage(MCS_BOUND);
                                }
                            }
                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                        }else {
    
    
                        Slog.w(TAG, "Empty queue");
                    }
            break;
        }

PMS handles copying APP flow chart
DefaultContainerService: the class that actually handles copying APP files

insert image description herePackageManagerService.java#HandlerParams#startCopy

1. If the number of installation attempts exceeds 4 times, remove the installed list data
2. handleStartCopy: //Copy the APK file
3. handleReturnCode: //Start installing the APK

final boolean startCopy() {
    
    
           boolean res;
           try {
    
    
               if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
               //startCopy方法尝试的次数,超过了4次,就放弃这个安装请求
               if (++mRetries > MAX_RETRIES) {
    
    
                   Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                   mHandler.sendEmptyMessage(MCS_GIVE_UP);  //发送放弃安装信息
                   handleServiceError();
                   return false;
               } else {
    
    
                   handleStartCopy();      //复制APK文件
                   res = true;
               }
           } catch (RemoteException e) {
    
    
               if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
               mHandler.sendEmptyMessage(MCS_RECONNECT);
               res = false;
           }
           handleReturnCode();   //处理复制APK后的安装APK逻辑
           return res;
       }

PackageManagerService.java#InstallParams#handleStartCopy

1. Obtain part of the installation information of the APP
2. Obtain the installation location of the APP
3. Copy the APP by InstallArgs ----> Copy the APP by FileInstallArgs ----> DefaultContainerService copy the APP
InstallArgs as an abstract class, FileInstallArgs and MoveInstallArgs inherit InstallArgs
FileInstallArgs: Yes data/data/package name (system application)
MoveInstallArgs : used to handle the movement of the installed APK

public void handleStartCopy() throws RemoteException {
    
    
       ...
       //确定APK的安装位置。onSd:安装到SD卡, onInt:内部存储即Data分区,ephemeral:安装到临时存储(Instant Apps安装)            
       final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
       final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
       final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
       PackageInfoLite pkgLite = null;
       if (onInt && onSd) {
    
    
         // APK不能同时安装在SD卡和Data分区
           Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
           ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
         //安装标志冲突,Instant Apps不能安装到SD卡中
       } else if (onSd && ephemeral) {
    
    
           Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
           ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
       } else {
    
    
            //获取APK的少量的信息
           pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                   packageAbiOverride);
           if (DEBUG_EPHEMERAL && ephemeral) {
    
    
               Slog.v(TAG, "pkgLite for install: " + pkgLite);
           }
       ...
       if (ret == PackageManager.INSTALL_SUCCEEDED) {
    
    
            //判断安装的位置
           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);     //确定APP安装的位置
             ...
           }
       }
       //根据InstallParams创建InstallArgs对象
       final InstallArgs args = createInstallArgs(this);    InstallArgs作用时:复制和重命名APK
       mArgs = args;
       if (ret == PackageManager.INSTALL_SUCCEEDED) {
    
    
              ...
           if (!origin.existing && requiredUid != -1
                   && isVerificationEnabled(
                         verifierUser.getIdentifier(), installFlags, installerUid)) {
    
    
                 ...
           } else{
    
    
               ret = args.copyApk(mContainerService, true);     // InstallArgs开始复制APP
           }
       }
       mRet = ret;
   }


private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
    
    
        ...
         try {
    
    
             final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
             //创建临时文件存储目录
             final File tempDir =
                     mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
             codeFile = tempDir;
             resourceFile = tempDir;
         } catch (IOException e) {
    
    
             Slog.w(TAG, "Failed to create copy file: " + e);
             return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
         }
         ...
         int ret = PackageManager.INSTALL_SUCCEEDED;
         ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
         ...
         return ret;
     }

3. Install the APK

APP安装流程图

insert image description here

1. Check whether the environment is reliable before installation. If not, the copied APK file will be cleared.
2. installPackageTracedLI will internally call the installPackageLI method of PMS to install APP.
3. Handle the post-installation operation. If the installation is unsuccessful, delete the installation-related directories and files.

  final boolean startCopy() {
    
    
    ......
    handleStartCopy();  //APP文件复制拷贝
    .....
    //开始安装APP
  handleReturnCode();
  }
   void handleReturnCode() {
    
    
        ........
        if (mArgs != null) {
    
    
        processPendingInstall(mArgs, mRet);
      }
    }

    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
    
    
        mHandler.post(new Runnable() {
    
    
            public void run() {
    
    
                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) {
    
    
                    //安装前处理
                    args.doPreInstall(res.returnCode);
                    synchronized (mInstallLock) {
    
    
                        //开始安装
                        installPackageTracedLI(args, res);
                    }
                    //安装后收尾
                    args.doPostInstall(res.returnCode, res.uid);
                }
              ...
            }
        });
    }

Guess you like

Origin blog.csdn.net/qq_24252589/article/details/131353190