Android PackageManagerService流程详细分析(三)之PackageHandler

再回到(一),看到在SystemServer.java有这样一行代码:

 pm = PackageManagerService.main(context, installer,
                   factoryTest != SystemServer.FACTORY_TEST_OFF,
                   onlyCore);

PackageManagerService服务main函数如下:

  public static final IPackageManager main(Context context, Installer installer,
          boolean factoryTest, boolean onlyCore) {
      PackageManagerService m = new PackageManagerService(context, installer,
              factoryTest, onlyCore);
      ServiceManager.addService("package", m);
      return m;
  }

而PackageManagerService构造函数的代码如下:

public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) 
{
    // 前面省略...

    // 上一节重点讨论过
    mInstaller = installer;

    synchronized (mInstallLock) {
    // writer
    synchronized (mPackages) {
    mHandlerThread.start();
    // 本节分析内容
    mHandler = new PackageHandler(mHandlerThread.getLooper());

    readPermissions();

    } 

    // 后面省略...
}

PackageHandler用来处理安装apk等过程中的各种消息,后面讲到apk安装的时候会涉及。下面分两步走:

  • 1、先看看他的源代码
class PackageHandler extends Handler {
   private boolean mBound = false;
   final ArrayList<HandlerParams> mPendingInstalls =
       new ArrayList<HandlerParams>();

   private boolean connectToService() {
       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.bindService(service, mDefContainerConn,
               Context.BIND_AUTO_CREATE, UserHandle.USER_OWNER)) {
           Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
           mBound = true;
           return true;
       }
       Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
       return false;
   }

   private void disconnectService() {
       mContainerService = null;
       mBound = false;
       Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
       mContext.unbindService(mDefContainerConn);
       Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
   }

   PackageHandler(Looper looper) {
       super(looper);
   }

   public void handleMessage(Message msg) {
       try {
           doHandleMessage(msg);
       } finally {
           Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
       }
   }

   void doHandleMessage(Message msg) {
       switch (msg.what) {
           case INIT_COPY: {
               if (DEBUG_INSTALL) Slog.i(TAG, "init_copy");
               HandlerParams params = (HandlerParams) msg.obj;
               int idx = mPendingInstalls.size();
               if (DEBUG_INSTALL) Slog.i(TAG, "idx=" + idx);
               // If a bind was already initiated we dont really
               // need to do anything. The pending install
               // will be processed later on.
               if (!mBound) {
                   // If this is the only one pending we might
                   // have to bind to the service again.
                   if (!connectToService()) {
                       Slog.e(TAG, "Failed to bind to media container service");
                       params.serviceError();
                       return;
                   } else {
                       // Once we bind to the service, the first
                       // pending request will be processed.
                       mPendingInstalls.add(idx, params);
                   }
               } else {
                   mPendingInstalls.add(idx, params);
                   // Already bound to the service. Just make
                   // sure we trigger off processing the first request.
                   if (idx == 0) {
                       mHandler.sendEmptyMessage(MCS_BOUND);
                   }
               }
               break;
           }
           case MCS_BOUND: {
               if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
               if (msg.obj != null) {
                   mContainerService = (IMediaContainerService) msg.obj;
               }
               if (mContainerService == null) {
                   // Something seriously wrong. Bail out
                   Slog.e(TAG, "Cannot bind to media container service");
                   for (HandlerParams params : mPendingInstalls) {
                       // Indicate service bind error
                       params.serviceError();
                   }
                   mPendingInstalls.clear();
               } else if (mPendingInstalls.size() > 0) {
                   HandlerParams params = mPendingInstalls.get(0);
                   if (params != null) {
                       if (params.startCopy()) {
                           // We are done... look for more work or to
                           // go idle.
                           if (DEBUG_SD_INSTALL) Log.i(TAG,
                                   "Checking for more work or unbind...");
                           // Delete pending install
                           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);
                                   // Unbind after a little delay, to avoid
                                   // continual thrashing.
                                   sendMessageDelayed(ubmsg, 10000);
                               }
                           } else {
                               // There are more pending requests in queue.
                               // Just post MCS_BOUND message to trigger processing
                               // of next pending install.
                               if (DEBUG_SD_INSTALL) Log.i(TAG,
                                       "Posting MCS_BOUND for next woek");
                               mHandler.sendEmptyMessage(MCS_BOUND);
                           }
                       }
                   }
               } else {
                   // Should never happen ideally.
                   Slog.w(TAG, "Empty queue");
               }
               break;
           }
           case MCS_RECONNECT: {
               if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect");
               if (mPendingInstalls.size() > 0) {
                   if (mBound) {
                       disconnectService();
                   }
                   if (!connectToService()) {
                       Slog.e(TAG, "Failed to bind to media container service");
                       for (HandlerParams params : mPendingInstalls) {
                           // Indicate service bind error
                           params.serviceError();
                       }
                       mPendingInstalls.clear();
                   }
               }
               break;
           }
           case MCS_UNBIND: {
               // If there is no actual work left, then time to unbind.
               if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");

               if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
                   if (mBound) {
                       if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");

                       disconnectService();
                   }
               } else if (mPendingInstalls.size() > 0) {
                   // There are more pending requests in queue.
                   // Just post MCS_BOUND message to trigger processing
                   // of next pending install.
                   mHandler.sendEmptyMessage(MCS_BOUND);
               }

               break;
           }
           case MCS_GIVE_UP: {
               if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries");
               mPendingInstalls.remove(0);
               break;
           }
           case SEND_PENDING_BROADCAST: {
               String packages[];
               ArrayList<String> components[];
               int size = 0;
               int uids[];
               Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
               synchronized (mPackages) {
                   if (mPendingBroadcasts == null) {
                       return;
                   }
                   size = mPendingBroadcasts.size();
                   if (size <= 0) {
                       // Nothing to be done. Just return
                       return;
                   }
                   packages = new String[size];
                   components = new ArrayList[size];
                   uids = new int[size];
                   Iterator<Map.Entry<String, ArrayList<String>>>
                           it = mPendingBroadcasts.entrySet().iterator();
                   int i = 0;
                   while (it.hasNext() && i < size) {
                       Map.Entry<String, ArrayList<String>> ent = it.next();
                       packages[i] = ent.getKey();
                       components[i] = ent.getValue();
                       PackageSetting ps = mSettings.mPackages.get(ent.getKey());
                       uids[i] = (ps != null) ? ps.appId : -1;
                       i++;
                   }
                   size = i;
                   mPendingBroadcasts.clear();
               }
               // Send broadcasts
               for (int i = 0; i < size; i++) {
                   sendPackageChangedBroadcast(packages[i], true, components[i], uids[i]);
               }
               Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
               break;
           }
           case START_CLEANING_PACKAGE: {
               Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
               final String packageName = (String)msg.obj;
               final int userId = msg.arg1;
               final boolean andCode = msg.arg2 != 0;
               synchronized (mPackages) {
                   if (userId == UserHandle.USER_ALL) {
                       int[] users = sUserManager.getUserIds();
                       for (int user : users) {
                           mSettings.addPackageToCleanLPw(
                                   new PackageCleanItem(user, packageName, andCode));
                       }
                   } else {
                       mSettings.addPackageToCleanLPw(
                               new PackageCleanItem(userId, packageName, andCode));
                   }
               }
               Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
               startCleaningPackages();
           } break;
           case POST_INSTALL: {
               if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
               PostInstallData data = mRunningInstalls.get(msg.arg1);
               mRunningInstalls.delete(msg.arg1);
               boolean deleteOld = false;

               if (data != null) {
                   InstallArgs args = data.args;
                   PackageInstalledInfo res = data.res;

                   if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                       res.removedInfo.sendBroadcast(false, true, false);
                       Bundle extras = new Bundle(1);
                       extras.putInt(Intent.EXTRA_UID, res.uid);
                       // Determine the set of users who are adding this
                       // package for the first time vs. those who are seeing
                       // an update.
                       int[] firstUsers;
                       int[] updateUsers = new int[0];
                       if (res.origUsers == null || res.origUsers.length == 0) {
                           firstUsers = res.newUsers;
                       } else {
                           firstUsers = new int[0];
                           for (int i=0; i<res.newUsers.length; i++) {
                               int user = res.newUsers[i];
                               boolean isNew = true;
                               for (int j=0; j<res.origUsers.length; j++) {
                                   if (res.origUsers[j] == user) {
                                       isNew = false;
                                       break;
                                   }
                               }
                               if (isNew) {
                                   int[] newFirst = new int[firstUsers.length+1];
                                   System.arraycopy(firstUsers, 0, newFirst, 0,
                                           firstUsers.length);
                                   newFirst[firstUsers.length] = user;
                                   firstUsers = newFirst;
                               } else {
                                   int[] newUpdate = new int[updateUsers.length+1];
                                   System.arraycopy(updateUsers, 0, newUpdate, 0,
                                           updateUsers.length);
                                   newUpdate[updateUsers.length] = user;
                                   updateUsers = newUpdate;
                               }
                           }
                       }
                       sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                               res.pkg.applicationInfo.packageName,
                               extras, null, null, firstUsers);
                       final boolean update = res.removedInfo.removedPackage != null;
                       if (update) {
                           extras.putBoolean(Intent.EXTRA_REPLACING, true);
                       }
                       sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                               res.pkg.applicationInfo.packageName,
                               extras, null, null, updateUsers);
                       if (update) {
                           sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                                   res.pkg.applicationInfo.packageName,
                                   extras, null, null, updateUsers);
                           sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                                   null, null,
                                   res.pkg.applicationInfo.packageName, null, updateUsers);
                       }
                       if (res.removedInfo.args != null) {
                           // Remove the replaced package's older resources safely now
                           deleteOld = true;
                       }

                       // Log current value of "unknown sources" setting
                       EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
                           getUnknownSourcesSettings());
                   }
                   // Force a gc to clear up things
                   Runtime.getRuntime().gc();
                   // We delete after a gc for applications on sdcard.
                   if (deleteOld) {
                       synchronized (mInstallLock) {
                           res.removedInfo.args.doPostDeleteLI(true);
                       }
                   }
                   if (args.observer != null) {
                       try {
                           args.observer.packageInstalled(res.name, res.returnCode);
                       } catch (RemoteException e) {
                           Slog.i(TAG, "Observer no longer exists.");
                       }
                   }
               } else {
                   Slog.e(TAG, "Bogus post-install token " + msg.arg1);
               }
           } break;
           case UPDATED_MEDIA_STATUS: {
               if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");
               boolean reportStatus = msg.arg1 == 1;
               boolean doGc = msg.arg2 == 1;
               if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc);
               if (doGc) {
                   // Force a gc to clear up stale containers.
                   Runtime.getRuntime().gc();
               }
               if (msg.obj != null) {
                   @SuppressWarnings("unchecked")
                   Set<AsecInstallArgs> args = (Set<AsecInstallArgs>) msg.obj;
                   if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
                   // Unload containers
                   unloadAllContainers(args);
               }
               if (reportStatus) {
                   try {
                       if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back");
                       PackageHelper.getMountService().finishMediaUpdate();
                   } catch (RemoteException e) {
                       Log.e(TAG, "MountService not running?");
                   }
               }
           } break;
           case WRITE_SETTINGS: {
               Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
               synchronized (mPackages) {
                   removeMessages(WRITE_SETTINGS);
                   removeMessages(WRITE_PACKAGE_RESTRICTIONS);
                   mSettings.writeLPr();
                   mDirtyUsers.clear();
               }
               Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
           } break;
           case WRITE_PACKAGE_RESTRICTIONS: {
               Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
               synchronized (mPackages) {
                   removeMessages(WRITE_PACKAGE_RESTRICTIONS);
                   for (int userId : mDirtyUsers) {
                       mSettings.writePackageRestrictionsLPr(userId);
                   }
                   mDirtyUsers.clear();
               }
               Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
           } break;
           case CHECK_PENDING_VERIFICATION: {
               final int verificationId = msg.arg1;
               final PackageVerificationState state = mPendingVerification.get(verificationId);

               if ((state != null) && !state.timeoutExtended()) {
                   final InstallArgs args = state.getInstallArgs();
                   Slog.i(TAG, "Verification timed out for " + args.packageURI.toString());
                   mPendingVerification.remove(verificationId);

                   int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;

                   if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) {
                       Slog.i(TAG, "Continuing with installation of "
                               + args.packageURI.toString());
                       state.setVerifierResponse(Binder.getCallingUid(),
                               PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
                       broadcastPackageVerified(verificationId, args.packageURI,
                               PackageManager.VERIFICATION_ALLOW,
                               state.getInstallArgs().getUser());
                       try {
                           ret = args.copyApk(mContainerService, true);
                       } catch (RemoteException e) {
                           Slog.e(TAG, "Could not contact the ContainerService");
                       }
                   } else {
                       broadcastPackageVerified(verificationId, args.packageURI,
                               PackageManager.VERIFICATION_REJECT,
                               state.getInstallArgs().getUser());
                   }

                   processPendingInstall(args, ret);
                   mHandler.sendEmptyMessage(MCS_UNBIND);
               }
               break;
           }
           case PACKAGE_VERIFIED: {
               final int verificationId = msg.arg1;

               final PackageVerificationState state = mPendingVerification.get(verificationId);
               if (state == null) {
                   Slog.w(TAG, "Invalid verification token " + verificationId + " received");
                   break;
               }

               final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj;

               state.setVerifierResponse(response.callerUid, response.code);

               if (state.isVerificationComplete()) {
                   mPendingVerification.remove(verificationId);

                   final InstallArgs args = state.getInstallArgs();

                   int ret;
                   if (state.isInstallAllowed()) {
                       ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                       broadcastPackageVerified(verificationId, args.packageURI,
                               response.code, state.getInstallArgs().getUser());
                       try {
                           ret = args.copyApk(mContainerService, true);
                       } catch (RemoteException e) {
                           Slog.e(TAG, "Could not contact the ContainerService");
                       }
                   } else {
                       ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
                   }

                   processPendingInstall(args, ret);

                   mHandler.sendEmptyMessage(MCS_UNBIND);
               }

               break;
           }
       }
   }
}

PackageHandler类的源代码主要关注doHandleMessage对各种消息的处理,因为在安装apk的时候,会发消息来到这里处理,下面就接着讲下安装apk的时候,是怎么发消息来到这里处理的。

  • 2、接着看看安装apk的时候是怎么样调用他的

下面就以商城下载apk安装过程中,怎么发消息去到PackageHandler类的。安装的时候最终会调用到这个函数:
installPackageWithVerificationAndEncryption(…)

先看看Log日志:
《Android PackageManagerService流程详细分析(三)之PackageHandler》

依据Log日志协助,分析流程如下:
《Android PackageManagerService流程详细分析(三)之PackageHandler》
看到05726-05729行,是不是很熟悉了,就是发送消息给PackageHandler类处理了。

下面是PackageHandler类处理消息函数doHandleMessage函数的代码片段:
《Android PackageManagerService流程详细分析(三)之PackageHandler》

接着往下:
《Android PackageManagerService流程详细分析(三)之PackageHandler》

进入startCopy:
《Android PackageManagerService流程详细分析(三)之PackageHandler》

调用handleReturnCode:
《Android PackageManagerService流程详细分析(三)之PackageHandler》

进入processPendingInstall:
《Android PackageManagerService流程详细分析(三)之PackageHandler》

进入installPackageLI,其中包含代码片段如下:
《Android PackageManagerService流程详细分析(三)之PackageHandler》

进入installNewPackageLI函数:
《Android PackageManagerService流程详细分析(三)之PackageHandler》

最后进入scanPackageLI重载函数;本节主要介绍了PackageHandler类是怎么配合apk安装的。

    原文作者:Rjdeng
    原文地址: https://blog.csdn.net/rjdeng/article/details/49585125
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞