欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

AndroidService完整实现流程分析,

来源: 开发者 投稿于  被查看 7380 次 评论:187

AndroidService完整实现流程分析,


目录
  • 前言
  • 一.APP侧启动Service
    • 1.1 前台和后台启动
    • 1.2startServiceCommon
  • 二.系统侧分发处理Service的启动逻辑
    • 2.1 AMS接受启动service的通知
    • 2.2realStartServiceLocked流程
  • 三.系统侧通知APP启动Service
    • 四.总结

      前言

      一开始的目标是解决各种各样的ANR问题的,我们知道,ANR总体上分有四种类型,这四种类型有三种是和四大组件相对应的,所以,如果想了解ANR发生的根因,对安卓四大组件的实现流程是必须要了解的,都不明白ANR如何触发的,怎么能完美的解决ANR的问题呢?

      所以会写一系列的文章,来分析四大组建的实现原理,同时也顺带讲解四种类型的ANR是如何发生的。

      本篇主要介绍service的完整实现流程,下一篇文章介绍Service中的ANR是如何产生的。

      一.APP侧启动Service

      其实启动service和启动Activity是很相似的,都是APP通知系统侧,由系统侧完成的整个流程。

      1.1 前台和后台启动

      无论是Activity,还是service,还是Application,都继承自Context的抽象类,所以可以使用Context的各种功能,就比如这了要介绍的启动前台/后台service。

      Context在安卓中,使用了一种典型的代理模式,我们调用的startService或者startForegroundService方法,最终都会委托给ContextImpl中的startService和startForegroundService来处理的。我们就来看下ContextImpl中的这两个方法:

      @Override
          public ComponentName startService(Intent service) {
              warnIfCallingFromSystemProcess();
              return startServiceCommon(service, false, mUser);
          }
          @Override
          public ComponentName startForegroundService(Intent service) {
              warnIfCallingFromSystemProcess();
              return startServiceCommon(service, true, mUser);
          }

      果然和我猜测的差不多,无论前台还是后台启动,其实最终都会走到一个方法中,只是配置参数的区别而已。最终都会走执行startServiceCommon方法。

      1.2startServiceCommon

      该方法中,通过binder通知系统的AMS完成对应的service的启动操作:

       ComponentName cn = ActivityManager.getService().startService(
                          mMainThread.getApplicationThread(), service,
                          service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                          getOpPackageName(), getAttributionTag(), user.getIdentifier());

      接下来,我们就看下系统侧是如何处理Service启动流程的。

      二.系统侧分发处理Service的启动逻辑

      系统侧的处理我主要分为3块来讲:

      1.系统接受APP侧的通知并转发

      2.系统侧委托ActiveServices负责完成的处理流程

      3.收到APP侧执行完成的回调,进行收尾操作

      2.1 AMS接受启动service的通知

      APP侧持有system_server进程的binder,上面讲到,它会通过binder方法startService完成对系统侧的通知。所以AMS的startService会收到这个通知。

      我们看下代码,发现AMS会把整个service的逻辑全部交由ActiveServices来处理,代码如下:

       try {
                      res = mServices.startServiceLocked(caller, service,
                              resolvedType, callingPid, callingUid,
                              requireForeground, callingPackage, callingFeatureId, userId);
                  } finally {
                      Binder.restoreCallingIdentity(origId);
                  }

      系统代码startServiceLocked方法中,代码虽然很长,但是却遵循着一个不变的宗旨:位语句,即前面处理各种异常的分支逻辑,把核心流程留到方法的最终来处理。

      所以我们直接看startServiceLocked方法的最后一部分即可:

      final ComponentName realResult =
                      startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
                      allowBackgroundActivityStarts, backgroundActivityStartsToken);

      startServiceInnerLocked方法中,处理逻辑也是比较简单的,最终会交给bringUpServiceLocked方法来进行处理。而bringUpServiceLocked方法中则最终会交给realStartServiceLocked完成整个流程。好像系统代码都喜喜欢用realStart,Activity启动的流程中也有一个方法叫realStartActivity。

      2.2realStartServiceLocked流程

      realStartServiceLocked方法中,我们总结为三个流程:

      1.bumpServiceExecutingLocked,启动超时检查。

      2.thread.scheduleCreateService通知APP一侧去创建Service。

      3.sendServiceArgsLocked通知APP执行Service的生命流程。

      private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
                  IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
                  boolean enqueueOomAdj) throws RemoteException {
              //1.启动超时检查
              bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */);
              ...
              //2.通知APP创建service
                  thread.scheduleCreateService(r, r.serviceInfo,
                          mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                          app.mState.getReportedProcState());
                  r.postNotification();
                  created = true;
              ...
              //3.通知执行service生命流程
              sendServiceArgsLocked(r, execInFg, true);
             ...
          }

      三.系统侧通知APP启动Service

      一般情况下,APP侧会收到系统侧发过来两种类型的通知,

      第一种:创建Service的任务通知

      第二种:执行Service生命流程的通知,通知Service执行onStartCommand方法。

      ApplicationThread接受通知并创建Service

      系统侧持有APP侧的binder,会通过scheduleCreateService这个binder方法通知APP一侧进行相应的操作。而APP侧,完成这个工作接收的就是ApplicationThread中的scheduleCreateService方法。该方法收到通知后,通过handler切换到主线程处理:

       public final void scheduleCreateService(IBinder token,
                      ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
                  updateProcessState(processState, false);
                  CreateServiceData s = new CreateServiceData();
                  s.token = token;
                  s.info = info;
                  s.compatInfo = compatInfo;
                  sendMessage(H.CREATE_SERVICE, s);
              }

      handle中,会切换到主线程执行ActivityThread的handleCreateService方法。

      主要执行了如下的几段逻辑:

      1.如果是首次创建App进程的话,则需要重新创建Application;

      2.创建Service对象;

      3.调用service的attach方法进行关联;

      4.调用service的onCreate生命周期方法;

      5.创建完成后,通过serviceDoneExecuting通知系统侧创建完成。

      try {
                  if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
                  Application app = packageInfo.makeApplication(false, mInstrumentation);
                  final java.lang.ClassLoader cl;
                  if (data.info.splitName != null) {
                      cl = packageInfo.getSplitClassLoader(data.info.splitName);
                  } else {
                      cl = packageInfo.getClassLoader();
                  }
                  service = packageInfo.getAppFactory()
                          .instantiateService(cl, data.info.name, data.intent);
                  ContextImpl context = ContextImpl.getImpl(service
                          .createServiceBaseContext(this, packageInfo));
                  if (data.info.splitName != null) {
                      context = (ContextImpl) context.createContextForSplit(data.info.splitName);
                  }
                  if (data.info.attributionTags != null && data.info.attributionTags.length > 0) {
                      final String attributionTag = data.info.attributionTags[0];
                      context = (ContextImpl) context.createAttributionContext(attributionTag);
                  }
                  // Service resources must be initialized with the same loaders as the application
                  // context.
                  context.getResources().addLoaders(
                          app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
                  context.setOuterContext(service);
                  service.attach(context, this, data.info.name, data.token, app,
                          ActivityManager.getService());
                  service.onCreate();
                  mServicesData.put(data.token, data);
                  mServices.put(data.token, service);
                  try {
                      ActivityManager.getService().serviceDoneExecuting(
                              data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                  } catch (RemoteException e) {
                      throw e.rethrowFromSystemServer();
                  }
              }

      ApplicationThread接受通知并执行Service的生命流程

      同样的,这里完成接受的是,仍然是ApplicationThread中的方法。这个流程中的接受方法是scheduleServiceArgs方法。

      ApplicationThread中,收到通知后,通过handler把任务转交到主线程。

       public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
                  List<ServiceStartArgs> list = args.getList();
                  for (int i = 0; i < list.size(); i++) {
                      ServiceStartArgs ssa = list.get(i);
                      ServiceArgsData s = new ServiceArgsData();
                      s.token = token;
                      s.taskRemoved = ssa.taskRemoved;
                      s.startId = ssa.startId;
                      s.flags = ssa.flags;
                      s.args = ssa.args;
                      sendMessage(H.SERVICE_ARGS, s);
                  }
              }

      接下来handler中切换到主线程会执行ActivityThread的handleServiceArgs方法。

      handleServiceArgs方法主要会完成以下几件事:

      1.找到对应的service,调用起onStartCommand方法;

      2.通知系统侧回调完成。

      private void handleServiceArgs(ServiceArgsData data) {
              CreateServiceData createData = mServicesData.get(data.token);
              Service s = mServices.get(data.token);
              if (s != null) {
                  try {
                      if (data.args != null) {
                          data.args.setExtrasClassLoader(s.getClassLoader());
                          data.args.prepareToEnterProcess(isProtectedComponent(createData.info),
                                  s.getAttributionSource());
                      }
                      int res;
                      if (!data.taskRemoved) {
                          res = s.onStartCommand(data.args, data.flags, data.startId);
                      } else {
                          s.onTaskRemoved(data.args);
                          res = Service.START_TASK_REMOVED_COMPLETE;
                      }
                      QueuedWork.waitToFinish();
                      try {
                          ActivityManager.getService().serviceDoneExecuting(
                                  data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                      } catch (RemoteException e) {
                          throw e.rethrowFromSystemServer();
                      }
                  } catch (Exception e) {
                      if (!mInstrumentation.onException(s, e)) {
                          throw new RuntimeException(
                                  "Unable to start service " + s
                                  + " with " + data.args + ": " + e.toString(), e);
                      }
                  }
              }
          }

      发我们发现,不论是创建service,还是通知执行service的生命流程,最终都执行了一个完成的通知,这有何意图呢?是的,这个意图就是和ANR相关的,我们下一章来讲了。

      四.总结

      前面一一讲了实现的原理,我们最后再来做一个总结,尽量用一张图+几句话的方式来概括。

      1.无论前台启动还是后台启动,最终都会走到ContextImpl这个最终实现类中的方法,完成和AMS的交互。

      2.AMS中主要是ActiveServices完成的整个流程。其核心方法是realStartServiceLocked。

      他首先启动一个延时消息,通过延时消息进行超时的监测。

      然后通知APP去生成Service。

      通知APP侧去完成Service的生命周期流程onStartCommand。

      3.收到APP侧执行完成的通知后,则取消注册延时消息。

      到此这篇关于Android Service完整实现流程分析的文章就介绍到这了,更多相关Android Service内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程!

      用户评论