Android 9.0 PM机制系列(三)PMS处理APK的安装

前言

在上一篇文章 Android9.0 PM机制系列(二)PackageInstaller安装APK中,我们学习了PackageInstaller是如何安装APK的,最后会将APK的信息交由PMS处理。那么PMS是如何处理的呢?这篇文章会给你答案。

1.PackageHandler处理安装消息

接着上一篇文章的代码逻辑来查看PMS的installStage方法。
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

void installStage(String packageName, File stagedDir,
           IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
           String installerPackageName, int installerUid, UserHandle user,
           PackageParser.SigningDetails signingDetails) {
   
       ...
       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, signingDetails, installReason);//2
       params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
       msg.obj = params;
       ...
       mHandler.sendMessage(msg);//3
   }

注释2处创建InstallParams,它对应于包的安装数据。注释1处创建了类型为INIT_COPY的消息,在注释3处将InstallParams通过消息发送出去。

1.1 对INIT_COPY的消息的处理

处理INIT_COPY类型的消息的代码如下所示。
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用于标识是否绑定了服务,默认值为false
           if (!mBound) {
   //1
               //如果没有绑定服务,重新绑定,connectToService方法内部如果绑定成功会将mBound置为true
               if (!connectToService()) {
   //2
                   params.serviceError();
                   //绑定服务失败则return
                   return;
               } else {
   
                   //绑定服务成功,将请求添加到ArrayList类型的mPendingInstalls中,等待处理
                   mPendingInstalls.add(idx, params);
               }
           } else {
   //已经绑定服务
               mPendingInstalls.add(idx, params);
               if (idx == 0) {
   
                   mHandler.sendEmptyMessage(MCS_BOUND);//3
               }
           }
           break;
       }
   ....
   }
}
  1. PackageHandler继承自Handler,它被定义在PMS中,doHandleMessage方法用于处理各个类型的消息,来查看对INIT_COPY类型消息的处理。注释1处的mBound用于标识是否绑定了DefaultContainerService,默认值为false。
  2. DefaultContainerService是用于检查和复制可移动文件的服务,这是一个比较耗时的操作,因此DefaultContainerService没有和PMS运行在同一进程中,它运行在com.android.defcontainer进程,通过IMediaContainerService和PMS进行IPC通信,如下图所示。
    在这里插入图片描述
  3. 注释2处的connectToService方法用来绑定DefaultContainerService,注释3处发送MCS_BOUND类型的消息,触发处理第一个安装请求。查看注释2处的connectToService方法:

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

private boolean connectToService() {
   
    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;
}
  1. 注释2处如果绑定DefaultContainerService成功,mBound会置为ture 。
  2. 注释1处的bindServiceAsUser方法会传入mDefContainerConn,bindServiceAsUser方法的处理逻辑和我们调用bindService是类似的,服务建立连接后,会调用onServiceConnected方法:
class DefaultContainerConnection implements ServiceConnection {
   
      public void onServiceConnected(ComponentName name, IBinder service) {
   
          final IMediaContainerService imcs = IMediaContainerService.Stub
                  .asInterface(Binder.allowBlocking(service));
          mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));//1
      }
      public void onServiceDisconnected(ComponentName name) {
   
          if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
      }
  }

注释1处发送了MCS_BOUND类型的消息,与PackageHandler.doHandleMessage方法的注释3处不同的是,这里发送消息带了Object类型的参数,这里会对这两种情况来进行讲解,一种是消息不带Object类型的参数,一种是消息带Object类型的参数。

1.2 对MCS_BOUND类型的消息的处理

消息不带Object类型的参数
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java$PackageHandler

case MCS_BOUND: {
   
    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
    if (msg.obj != null) {
   //1
        mContainerService = (IMediaContainerService) msg.obj;//2
    }
    if (mContainerService == null) {
   //3
        if (!mBound) {
   //4
              Slog.e(TAG, "Cannot bind to media container service");
              for (HandlerParams params : mPendingInstalls) {
   
                  params.serviceError();//5
                  return;
              }   
              //绑定失败,清空安装请求队列
              mPendingInstalls.clear();
           } else {
   
             //继续等待绑定服务
              Slog.w(TAG, "Waiting to connect to media container service");
           }
    } else if (mPendingInstalls.size() > 0) {
   
      ...
    } else {
   
           Slog.w(TAG, "Empty queue");
           }
    break;
}
  1. 如果消息不带Object类型的参数,就无法满足注释1处的条件,注释2处的IMediaContainerService类型的mContainerService也无法被赋值,这样就满足了注释3处的条件。
  2. 如果满足注释4处的条件,说明还没有绑定服务,而此前已经在PackageHandler.doHandleMessage方法的注释2处调用绑定服务的方法了,这显然是不正常的,因此在注释5处负责处理服务发生错误的情况。如果不满足注释4处的条件,说明已经绑定服务了,就会打印出系统log,告知用户等待系统绑定服务。

消息带Object类型的参数

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.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
              if (params.startCopy()) {
   //4
                  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) {
   
                      //如果没有安装请求了,发送解绑服务的请求
                          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);//5
                  }
              }
              Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
          }else {
   
          Slog.w(TAG, "Empty queue");//6
      }
    break;
}
  1. 如果MCS_BOUND类型消息带Object类型的参数就不会满足注释1处的条件,就会调用注释2处的判断,如果安装请求数不大于0就会打印出注释6处的log,说明安装请求队列是空的。安装完一个APK后,就会在注释5处发出MSC_BOUND消息,继续处理剩下的安装请求直到安装请求队列为空。
  2. 注释3处得到安装请求队列第一个请求HandlerParams ,如果HandlerParams
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值