Android Service启动过程完整分析

刚开始学习Service的时候以为它是一个线程的封装,也可以执行耗时操作。其实不然,Service是运行在主线程的。直接执行耗时操作是会阻塞主线程的。长时间就直接ANR了。

我们知道Service可以执行一些后台任务,是后台任务不是耗时的任务,后台和耗时是有区别的喔。
这样就很容易想到音乐播放器,天气预报这些应用是要用到Service的。当然如果要在Service中执行耗时操作的话,开个线程就可以了。

关于Service的运行状态有两种,启动状态和绑定状态,两种状态可以一起。
启动一个Service只需调用Context的startService方法,传进一个Intent即可。看起来好像很简单的说,那是因为Android为了方便开发者,做了很大程度的封装。那么你真的有去学习过Service是怎么启动的吗?Service的onCreate方法回调前都做了哪些准备工作?

先上一张图大致了解下,灰色背景框起来的是同一个类中的方法,如下图:

那接下来就从源码的角度来分析Service的启动过程。

当然是从Context的startService方法开始,Context的实现类是ContextImpl,那么我们就看到ContextImpl的startService方法即可,如下:

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

会转到startServiceCommon方法,那跟进startServiceCommon方法方法瞧瞧。

private ComponentName startServiceCommon(Intent service, UserHandle user) {
  try {
    validateServiceIntent(service);
    service.prepareToLeaveProcess();
    ComponentName cn = ActivityManagerNative.getDefault().startService(
      mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
            getContentResolver()), getOpPackageName(), user.getIdentifier());

  //代码省略

    return cn;
  } catch (RemoteException e) {
    throw new RuntimeException("Failure from system", e);
  }
}

可以看到调用了ActivityManagerNative.getDefault()的startService方法来启动Service,ActivityManagerNative.getDefault()是ActivityManagerService,简称AMS。

那么现在启动Service的过程就转移到了ActivityManagerService,我们关注ActivityManagerService的startService方法即可,如下:

@Override
public ComponentName startService(IApplicationThread caller, Intent service,
    String resolvedType, String callingPackage, int userId)
    throws TransactionTooLargeException {

   //代码省略

  synchronized(this) {
    final int callingPid = Binder.getCallingPid();
    final int callingUid = Binder.getCallingUid();
    final long origId = Binder.clearCallingIdentity();
    ComponentName res = mServices.startServiceLocked(caller, service,
        resolvedType, callingPid, callingUid, callingPackage, userId);
    Binder.restoreCallingIdentity(origId);
    return res;
  }
}

在上述的代码中,调用了ActiveServices的startServiceLocked方法,那么现在Service的启动过程从AMS转移到了ActiveServices了。

继续跟进ActiveServices的startServiceLocked方法,如下:

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
    int callingPid, int callingUid, String callingPackage, int userId)
    throws TransactionTooLargeException {

  //代码省略

  ServiceLookupResult res =
    retrieveServiceLocked(service, resolvedType, callingPackage,
        callingPid, callingUid, userId, true, callerFg);

  //代码省略

  ServiceRecord r = res.record;

  //代码省略

  return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}

在startServiceLocked方法中又会调用startServiceInnerLocked方法,

我们瞧瞧startServiceInnerLocked方法,

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
    boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
  ProcessStats.ServiceState stracker = r.getTracker();
  if (stracker != null) {
    stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
  }
  r.callStart = false;
  synchronized (r.stats.getBatteryStats()) {
    r.stats.startRunningLocked();
  }
  String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);

  //代码省略

  return r.name;
}

startServiceInnerLocked方法内部调用了bringUpServiceLocked方法,此时启动过程已经快要离开ActiveServices了。继续看到bringUpServiceLocked方法。如下:

private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
    boolean whileRestarting) throws TransactionTooLargeException {

    //代码省略

    if (app != null && app.thread != null) {
      try {
        app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
        realStartServiceLocked(r, app, execInFg);
        return null;
      } 

    //代码省略

    return null;
}

省略了大部分if判断,相信眼尖的你一定发现了核心的方法,那就是
realStartServiceLocked,没错,看名字就像是真正启动Service。那么事不宜迟跟进去探探吧。如下:

private final void realStartServiceLocked(ServiceRecord r,
    ProcessRecord app, boolean execInFg) throws RemoteException {

  //代码省略

  boolean created = false;
  try {

    //代码省略
    app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
    app.thread.scheduleCreateService(r, r.serviceInfo,
        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
        app.repProcState);
    r.postNotification();
    created = true;
  } catch (DeadObjectException e) {
    Slog.w(TAG, "Application dead when creating service " + r);
    mAm.appDiedLocked(app);
    throw e;
  } 

  //代码省略

  sendServiceArgsLocked(r, execInFg, true);

  //代码省略

}

找到了。app.thread调用了scheduleCreateService来启动Service,而app.thread是一个ApplicationThread,也是ActivityThread的内部类。此时已经到了主线程。
那么我们探探ApplicationThread的scheduleCreateService方法。如下:

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);
}

对待启动的Service组件信息进行包装,然后发送了一个消息。我们关注这个CREATE_SERVICE消息即可。

public void handleMessage(Message msg) {

    //代码省略

    case CREATE_SERVICE:
      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
      handleCreateService((CreateServiceData)msg.obj);
      Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
      break;

    //代码省略

}

在handleMessage方法中接收到这个消息,然后调用了handleCreateService方法,跟进handleCreateService探探究竟:

private void handleCreateService(CreateServiceData data) {
  // If we are getting ready to gc after going to the background, well
  // we are back active so skip it.
  unscheduleGcIdler();

  LoadedApk packageInfo = getPackageInfoNoCheck(
      data.info.applicationInfo, data.compatInfo);
  Service service = null;
  try {
    java.lang.ClassLoader cl = packageInfo.getClassLoader();
    service = (Service) cl.loadClass(data.info.name).newInstance();
  } catch (Exception e) {
    if (!mInstrumentation.onException(service, e)) {
      throw new RuntimeException(
        "Unable to instantiate service " + data.info.name
        + ": " + e.toString(), e);
    }
  }

  try {
    if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
    context.setOuterContext(service);

    Application app = packageInfo.makeApplication(false, mInstrumentation);
    service.attach(context, this, data.info.name, data.token, app,
        ActivityManagerNative.getDefault());
    service.onCreate();
    mServices.put(data.token, service);
    try {
      ActivityManagerNative.getDefault().serviceDoneExecuting(
          data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
    } catch (RemoteException e) {
      // nothing to do.
    }
  } catch (Exception e) {
    if (!mInstrumentation.onException(service, e)) {
      throw new RuntimeException(
        "Unable to create service " + data.info.name
        + ": " + e.toString(), e);
    }
  }
}

终于击破,这个方法很核心的。一点点分析

首先获取到一个LoadedApk对象,在通过这个LoadedApk对象获取到一个类加载器,通过这个类加载器来创建Service。如下:

java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();

接着调用ContextImpl的createAppContext方法创建了一个ContextImpl对象。

之后再调用LoadedApk的makeApplication方法来创建Application,这个创建过程如下:

public Application makeApplication(boolean forceDefaultAppClass,
    Instrumentation instrumentation) {
  if (mApplication != null) {
    return mApplication;
  }

  Application app = null;

  String appClass = mApplicationInfo.className;
  if (forceDefaultAppClass || (appClass == null)) {
    appClass = "android.app.Application";
  }

  try {
    java.lang.ClassLoader cl = getClassLoader();
    if (!mPackageName.equals("android")) {
      initializeJavaContextClassLoader();
    }
    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
    app = mActivityThread.mInstrumentation.newApplication(
        cl, appClass, appContext);
    appContext.setOuterContext(app);
  } catch (Exception e) {
    if (!mActivityThread.mInstrumentation.onException(app, e)) {
      throw new RuntimeException(
        "Unable to instantiate application " + appClass
        + ": " + e.toString(), e);
    }
  }
  mActivityThread.mAllApplications.add(app);
  mApplication = app;

  if (instrumentation != null) {
    try {
      instrumentation.callApplicationOnCreate(app);
    } catch (Exception e) {
      if (!instrumentation.onException(app, e)) {
        throw new RuntimeException(
          "Unable to create application " + app.getClass().getName()
          + ": " + e.toString(), e);
      }
    }
  }

  // Rewrite the R 'constants' for all library apks.
  SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
      .getAssignedPackageIdentifiers();
  final int N = packageIdentifiers.size();
  for (int i = 0; i < N; i++) {
    final int id = packageIdentifiers.keyAt(i);
    if (id == 0x01 || id == 0x7f) {
      continue;
    }

    rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
  }

  return app;
}

当然Application是只有一个的,从上述代码中也可以看出。

在回来继续看handleCreateService方法,之后service调用了attach方法关联了ContextImpl和Application等

最后service回调了onCreate方法,

service.onCreate();
mServices.put(data.token, service);

并将这个service添加进了一个了列表进行管理。

至此service启动了起来,以上就是service的启动过程。

你可能还想要知道onStartCommand方法是怎么被回调的?可能细心的你发现了在ActiveServices的realStartServiceLocked方法中,那里还有一个sendServiceArgsLocked方法。是的,那个就是入口。

那么我们跟进sendServiceArgsLocked方法看看onStartCommand方法是怎么回调的。

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
    boolean oomAdjusted) throws TransactionTooLargeException {
  final int N = r.pendingStarts.size();

    //代码省略

    try {

    //代码省略

      r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
    } catch (TransactionTooLargeException e) {
      if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large: intent="
          + si.intent);
      caughtException = e;
    } catch (RemoteException e) {
      // Remote process gone... we'll let the normal cleanup take care of this.
      if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);
      caughtException = e;
    } 

    //代码省略
}

可以看到onStartCommand方法回调过程和onCreate方法的是很相似的,都会转到app.thread。那么现在就跟进ApplicationThread的scheduleServiceArgs。
你也可能猜到了应该又是封装一些Service的信息,然后发送一个消息, handleMessage接收。是的,源码如下:

public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
  int flags ,Intent args) {
  ServiceArgsData s = new ServiceArgsData();
  s.token = token;
  s.taskRemoved = taskRemoved;
  s.startId = startId;
  s.flags = flags;
  s.args = args;

  sendMessage(H.SERVICE_ARGS, s);
}

public void handleMessage(Message msg) {

    //代码省略

    case SERVICE_ARGS:
      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
      handleServiceArgs((ServiceArgsData)msg.obj);
      Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
      break;

    //代码省略
}

咦,真的是这样。谜底应该就在handleServiceArgs方法了,那么赶紧瞧瞧,源码如下:

private void handleServiceArgs(ServiceArgsData data) {
  Service s = mServices.get(data.token);
  if (s != null) {
    try {
      if (data.args != null) {
        data.args.setExtrasClassLoader(s.getClassLoader());
        data.args.prepareToEnterProcess();
      }
      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 {
        ActivityManagerNative.getDefault().serviceDoneExecuting(
            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
      } catch (RemoteException e) {
        // nothing to do.
      }
      ensureJitEnabled();
    } catch (Exception e) {
      if (!mInstrumentation.onException(s, e)) {
        throw new RuntimeException(
            "Unable to start service " + s
            + " with " + data.args + ": " + e.toString(), e);
      }
    }
  }
}

可以看到回调了onStartCommand方法。

以上就是Service的启动过程的源码分析。

从中,我理解了Service的启动过程的同时,阅读源码的能力也提高了,分析源码的时候我没能力把每一个变量,每一个方法都搞懂,我关注的都是一些关键的字眼,比如这篇文章就是start呀,service呀。会有那种感觉,就是这里没错了。当然如果陷入胡同了也要兜出来。

这样的分析也能够摸清整体的过程,对于细节,等我有扎实的功底了在去研究吧。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android Service自启动注意事项分析

    本文实例分析了Android Service自启动注意事项.分享给大家供大家参考,具体如下: @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); if(intent == null) return; } @Override public void onDestroy() { super.onDestroy(); Intent intent = new Intent(

  • android开发教程之开机启动服务service示例

    个例子实现的功能是:1,安装程序后看的一个Activity程序界面,里面有个按钮,点击按钮就会启动一个Service服务,此时在设置程序管理里面会看的有个Activity和一个Service服务运行2,如果手机关机重启,会触发你的程序里面的Service服务,当然,手机启动后是看不到你的程序界面.好比手机里面自带的闹钟功能,手机重启看不到闹钟设置界面只是启动服务,时间到了,闹钟就好响铃提醒. 程序代码是: 首先要有一个用于开机启动的Activity,给你们的按钮设置OnClickListener

  • Android Service绑定过程完整分析

    通常我们使用Service都要和它通信,当想要与Service通信的时候,那么Service要处于绑定状态的.然后客户端可以拿到一个Binder与服务端进行通信,这个过程是很自然的. 那你真的了解过Service的绑定过程吗?为什么可以是Binder和Service通信? 同样的先看一张图大致了解一下,灰色背景框起来的是同一个类的方法,如下: 我们知道调用Context的bindService方法即可绑定一个Service,而ContextImpl是Context的实现类.那接下来就从源码的角度

  • Android中实现开机自动启动服务(service)实例

    最近在将 HevSocks5Client 移植到 Android 上了,在经过增加 signalfd 和 timerfd 相关的系统调用支持后,就可以直接使用 NDK 编译出 executable 了.直接的 native exectuable 在 Android 系统总还是不太方便用哦.还是做成一个 apk 吧,暂定只写一个 service 并开机自动启用,无 activity 的. Java 中调用 native 程序我选择使用 JNI 方式,直接在 JNI_OnLoad 方法中调用 pth

  • android中soap协议使用(ksoap调用webservice)

    如下面代码所示: 复制代码 代码如下: SoapObject request  = new SoapObject(serviceNamespace, methodName); SoapObject构造函数的两个参数含义为: serviceNamespace – 你的webservice的命名空间,既可以是 http://localhost:8088/flickrBuddy/services/Buddycast这样的,也可以是 urn:PI/DevCentral/SoapService这样的: m

  • Android Service 服务不被杀死的妙招

    Service是android 系统中的一种组件,它跟Activity的级别差不多,但是他不能自己运行,只能后台运行,并且可以和其他组件进行交互. Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,然后在onStartCommand方法中做一些处理. 从Android官方文档中,我们知道onStartCommand有4种int返回值,首先简单地讲讲int返回值的作用.

  • Android 启动 Service(startservice和bindservice) 两种方式的区别

    Android Service 生命周期可以促使移动设备的创新,让用户体验到最优越的移动服务,只有broadcast receivers执行此方法的时候才是激活的,当 onReceive()返回的时候,它就是非激活状态. 如果没有程序停止它或者它自己停止,service将一直运行.在这种模式下,service开始于调用Context.startService() ,停止于Context.stopService(). service可以通过调用Android Service 生命周期() 或 Se

  • 解析Android中如何做到Service被关闭后又自动启动的实现方法

    首先要说的是,用户可能把这种做法视为流氓软件.大部分时候,程序员也不想把软件做成流氓软件,没办法,领导说了算. 我们在使用某些Android应用的时候,可能会发现安装了某应用以后,会有一些服务也会随之运行.而且,这些服务每次都会随着手机开机而启动.有的服务做的更绝,当用户在运行的服务中手动停止该服务以后,过了一段时间,服务又自动运行了.虽然,从用户的角度来说,这种方式比较流氓.但是,从程序员的角度来说,这是如何做到的呢?经过研究,我发现有一种方式是可以实现的.下面就和大家分享. 先简单介绍,一会

  • Android实现开机自动启动Service或app的方法

    本文实例讲述了Android实现开机自动启动Service或app的方法.分享给大家供大家参考,具体如下: 第一步:首先创建一个广播接收者,重构其抽象方法 onReceive(Context context, Intent intent),在其中启动你想要启动的Service或app. import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; i

  • Android Service启动过程完整分析

    刚开始学习Service的时候以为它是一个线程的封装,也可以执行耗时操作.其实不然,Service是运行在主线程的.直接执行耗时操作是会阻塞主线程的.长时间就直接ANR了. 我们知道Service可以执行一些后台任务,是后台任务不是耗时的任务,后台和耗时是有区别的喔. 这样就很容易想到音乐播放器,天气预报这些应用是要用到Service的.当然如果要在Service中执行耗时操作的话,开个线程就可以了. 关于Service的运行状态有两种,启动状态和绑定状态,两种状态可以一起. 启动一个Servi

  • Android 系统服务TelecomService启动过程原理分析

    由于一直负责的是Android Telephony部分的开发工作,对于通信过程的上层部分Telecom服务以及UI都没有认真研究过.最近恰好碰到一个通话方面的问题,涉及到了Telecom部分,因而就花时间仔细研究了下相关的代码.这里做一个简单的总结.这篇文章,主要以下两个部分的内容: 什么是Telecom服务?其作用是什么? Telecom模块的启动与初始化过程: 接下来一篇文章,主要以实际通话过程为例,分析下telephony收到来电后如何将电话信息发送到Telecom模块以及Telecom是

  • Android Service启动流程刨析

    强调一下阅读系统源码,起码要对进程间通信要了解,对binder机制非常非常清楚,binder就是指南针,要不然你会晕头转向:强行阅读,就容易睡着. Service启动先来一张图感受一下 这张图能够说明一个大致的流程,但是服务的启动肯定不是这么简单,但是我们先简单的总结一下,逐渐深入.服务的启动形式有两种,startService()和 binderService(),我们看startService()这一种.startService是ContextWrapper里面的方法. ContextWra

  • ActivityManagerService之Service启动过程解析

    目录 缘由 启动 Service 宿主进程的启动 宿主进程创建 Service Service 接收参数 结束 缘由 我曾经任职于一家小公司,负责上层一切事务,而公司为了给客户(尤其是小客户)提供开发的便利,会强行去掉一些限制,其中就包括启动 Service 的限制. 本文来分析 Service 的整体启动流程,顺带也会提一提 Service 启动的一些限制.但是,读者请务必自行了解 Service 的启动方式,包括前台 Service 的启动,这些基本知识本文不会过多提及. 启动 Servic

  • SpringBoot启动过程逐步分析讲解

    springboot启动是通过一个main方法启动的,代码如下 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 从该方法我们一路跟进去,进入SpringApplication的构造函数,我们可以看到如下代码primarySources,为我们从run方法塞进来的

  • Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析

    在前面一篇文章Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路中,介绍了在Android系统中Binder进程间通信机制中的Server角色是如何获得Service Manager远程接口的,即defaultServiceManager函数的实现.Server获得了Service Manager远程接口之后,就要把自己的Service添加到Service Manager中去,然后把自己启动起来,等待Client的请求.

  • 通过实例解析android Activity启动过程

    注:只是说明启动activity的过程(ActivityThread如何与ActivityManagerService简称AmS进行进程间通信调用全过程),不解析android从zygote(受精卵)到整个系统服务的启动 具体来讲,启动activity的方式有以下几种: 在应用程序中startActivity()或startActivityForResult()方法启动指定activity 在HOME(桌面)程序中单击应用图标,启动新的activity 按"BACK"键结束当前acti

  • Android Service启动绑定流程详解

    目录 前言 一.Service 的启动流程 二.Service的绑定 三.Service的Context 总结 前言 本文基于Android 11,参考<Android进阶解密>一书资料.了解Service的启动和绑定流程,以及Service的Context创建过程. 由于基于分析流程,忽略很多细节分支.各位在看源码的时候,要尽可能忽略细节,分析整体流程之后,还有精力的话再去看细节.例如有些属性是在后面赋值的,如果在前面追究,难哦. 另:阅读这种流程需要很大的耐心和毅力.建议在心情愉悦想要学习

随机推荐