Android Service的启动过程分析

Android Service的启动过程分析

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

我们知道Service可以执行一些后台任务,是后台任务不是耗时的任务,后台和耗时是有区别的喔。

这样就很容易想到音乐播放器,天气预报这些应用是要用到Service的。当然如果要在Service中执行耗时操作的话,开个线程就可以了。

关于Service的运行状态有两种,启动状态和绑定状态,两种状态可以一起。

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

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

Service启动过程

那接下来就从源码的角度来分析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中使用Toast无法正常显示问题的解决方法

    本文实例讲述了Android Service中使用Toast无法正常显示问题的解决方法.分享给大家供大家参考,具体如下: 在做Service简单练习时,在Service中的OnCreate.OnStart.OnDestroy三个方法中都像在Activity中同样的方法调用了Toast.makeText,并在Acitivy中通过两个按钮来调用该服务的onStart和onDestroy方法: DemoService代码如下: @Override public void onCreate() { su

  • android使用NotificationListenerService监听通知栏消息

    NotificationListenerService是通过系统调起的服务,在应用发起通知时,系统会将通知的应用,动作和信息回调给NotificationListenerService.但使用之前需要引导用户进行授权.使用NotificationListenerService一般需要下面三个步骤. 注册服务 首先需要在AndroidManifest.xml对service进行注册. <service android:name=".NotificationCollectorService&q

  • Android实现微信自动向附近的人打招呼(AccessibilityService)

    学习功能强大的AccessibilityService!!! 以下是本人根据自动抢红包的实现思路敲的用于微信自动向附近的人打招呼的核心代码 public class AutoService extends AccessibilityService implements View.OnClickListener { private static final String TAG = "test"; /** * 微信的包名 */ static final String WECHAT_PAC

  • Android 如何保证service在后台不被kill

    Android 其实无法做多绝对的不被后台kill掉,我们只能尽量使用一些操作提升不被kill的机会. 一.onStartCommand方法,返回START_STICKY START_STICKY 在运行onStartCommand后service进程被kill后,那将保留在开始状态,但是不保留那些传入的intent.不久后service就会再次尝试重新创建,因为保留在开始状态,在创建     service后将保证调用onstartCommand.如果没有传递任何开始命令给service,那将

  • Android AccessibilityService实现微信抢红包插件

    在你的手机更多设置或者高级设置中,我们会发现有个无障碍的功能,很多人不知道这个功能具体是干嘛的,其实这个功能是为了增强用户界面以帮助残障人士,或者可能暂时无法与设备充分交互的人们 它的具体实现是通过AccessibilityService服务运行在后台中,通过AccessibilityEvent接收指定事件的回调.这样的事件表示用户在界面中的一些状态转换,例如:焦点改变了,一个按钮被点击,等等.这样的服务可以选择请求活动窗口的内容的能力.简单的说AccessibilityService就是一个后

  • Android IntentService详解及使用实例

    Android IntentService详解 一.IntentService简介 IntentService是Service的子类,比普通的Service增加了额外的功能.先看Service本身存在两个问题: Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中: Service也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务: 二.IntentService特征 会创建独立的worker线程来处理所有的Intent请求: 会创建独立的wor

  • Android Service类与生命周期详细介绍

    Android  Service类与生命周期 Service是Android四大组件与Activity最相似的组件,都代表可执行的程序,区别在于Service一直在后台运行且没有用户界面. 1.Service的类图和生命周期 先来看看Service的类图: 接下来看看Service的生命周期: 2.开发Service (1)开发Service需要两步: 第1步:定义子类,继承Service 第2步:在AndroidManifest.xml文件中配置Service (2)创建Service pub

  • Android基于service实现音乐的后台播放功能示例

    本文实例讲述了Android基于service实现音乐的后台播放功能.分享给大家供大家参考,具体如下: Service是一个生命周期长且没有用户界面的程序,当程序在各个activity中切换的时候,我们可以利用service来实现背景音乐的播放,即使当程序退出到后台的时候,音乐依然在播放.下面我们给出具体例子的实现: 当然,首先要在资源文件夹中添加一首MP3歌曲: 要实现音乐的播放,需要在界面中放置两个按钮,用来控制音乐的播放和停止,通过使用startService和stopService来实现

  • 详解Android中的Service

    Service简介: Service是被设计用来在后台执行一些需要长时间运行的操作. Android由于允许Service在后台运行,甚至在结束Activity后,因此相对来说,Service相比Activity拥有更高的优先级. 创建Service: 要创建一个最基本的Service,需要完成以下工作:1)创建一个Java类,并让其继承Service 2)重写onCreate()和onBind()方法 其中,onCreate()方法是当该Service被创建时执行的方法,onBind()是该S

  • Android Service的启动过程分析

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

  • android Service基础(启动服务与绑定服务)

    Service是Android中一个类,它是Android 四大组件之一,使用Service可以在后台执行耗时的操作(注意需另启子线程),其中Service并不与用户产生UI交互.其他的应用组件可以启动Service,即便用户切换了其他应用,启动的Service仍可在后台运行.一个组件可以与Service绑定并与之交互,甚至是跨进程通信.通常情况下Service可以在后台执行网络请求.播放音乐.执行文件读写操作或者与contentprovider交互等. 本文主要讲述service服务里的启动与

  • Android Service启动过程完整分析

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

  • android Service基础(启动服务与绑定服务)

         Service是Android中一个类,它是Android 四大组件之一,使用Service可以在后台执行耗时的操作(注意需另启子线程),其中Service并不与用户产生UI交互.其他的应用组件可以启动Service,即便用户切换了其他应用,启动的Service仍可在后台运行.一个组件可以与Service绑定并与之交互,甚至是跨进程通信.通常情况下Service可以在后台执行网络请求.播放音乐.执行文件读写操作或者与contentprovider交互等.   本文主要讲述service

  • Android Service启动流程刨析

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

  • Android Service启动绑定流程详解

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

  • Android Service绑定过程完整分析

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

  • Android Service(不和用户交互应用组件)案例分析

    Service是在一段不定的时间运行在后台,不和用户交互应用组件.每个Service必须在manifest中 通过<service>来声明.可以通过contect.startservice和contect.bindserverice来启动. Service和其他的应用组件一样,运行在进程的主线程中.这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现. service的两种模式 本地服务 Local Service 用于应用程序内部. 它可以启动并运行,直至有人停止了它或

  • Android Service服务详细介绍及使用总结

    Android Service服务详解 一.Service简介 Service是android 系统中的四大组件之一(Activity.Service.BroadcastReceiver. ContentProvider),它跟Activity的级别差不多,但不能页面显示只能后台运行,并且可以和其他组件进行交互.service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变

  • Android Service详解及示例代码

    Android Service 详细介绍: 1.Service的概念 2.Service的生命周期 3.实例:控制音乐播放的Service 一.Service的概念 Service是Android程序中四大基础组件之一,它和Activity一样都是Context的子类,只不过它没有UI界面,是在后台运行的组件. 二.Service的生命周期 Service对象不能自己启动,需要通过某个Activity.Service或者其他Context对象来启动.启动的方法有两种,Context.startS

随机推荐