iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Android Service的启动过程分析
  • 501
分享到

Android Service的启动过程分析

androidserviceservice启动Android 2022-06-06 01:06:50 501人浏览 安东尼
摘要

Android Service的启动过程分析 刚开始学习Service的时候以为它是一个线程的封装,也可以执行耗时操作。其实不然,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呀。会有那种感觉,就是这里没错了。当然如果陷入胡同了也要兜出来。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

您可能感兴趣的文章:Android Service类与生命周期详细介绍详解Android中的ServiceAndroid IntentService详解及使用实例Android 如何保证service在后台不被killandroid使用NotificationListenerService监听通知栏消息Android实现微信自动向附近的人打招呼(AccessibilityService)Android AccessibilityService实现微信抢红包插件Android Service中使用Toast无法正常显示问题的解决方法Android基于service实现音乐的后台播放功能示例


--结束END--

本文标题: Android Service的启动过程分析

本文链接: https://www.lsjlt.com/news/21870.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android Service启动流程刨析
    强调一下阅读系统源码,起码要对进程间通信要了解,对binder机制非常非常清楚,binder就是指南针,要不然你会晕头转向;强行阅读,就容易睡着。 Service启动先来一张图感受一...
    99+
    2022-11-13
    Android Service Android Service启动
  • 详细分析Android-Zygote的启动过程
    目录创建Socket启动SystemServer等待AMSAndroid系统中,DVM,ART,应用程序进程和运行系统的关键服务的SystemServer进程都是Zygote创建的。...
    99+
    2024-04-02
  • Android组件Activity的启动过程深入分析
    目录前言源码分析总结前言 Activity是Android中一个很重要的概念,堪称四大组件之首,关于Activity有很多内容,比如生命周期和启动Flags,这二者想要说清楚,恐怕又...
    99+
    2023-05-15
    Android Activity启动过程 Android Activity启动方法
  • android性能优化之启动过程的示例分析
    小编给大家分享一下android性能优化之启动过程的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、应用的启动方式通常来说,启动方式分为两种:冷启动和热...
    99+
    2023-05-30
    android
  • Linux启动过程的示例分析
    这篇文章主要为大家展示了“Linux启动过程的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Linux启动过程的示例分析”这篇文章吧。Linux启动过程详细介绍启动第一步--加载BIOS...
    99+
    2023-06-09
  • Android Service启动绑定流程详解
    目录前言一、Service 的启动流程二、Service的绑定三、Service的Context总结前言 本文基于Android 11,参考《Android进阶解密》一书资料。了解...
    99+
    2023-03-08
    Android  Service启动绑定流程 Android Service
  • RAC各个进程启动的过程分析
    RAC各个进程启动的过程分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。 ohasd无法kill,一旦kil...
    99+
    2024-04-02
  • Angularjs中启动过程的示例分析
    这篇文章主要介绍Angularjs中启动过程的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!启动过程(v1.3.9)步骤一用自执行函数的形式让整个代码在加载完成之后立即执行i...
    99+
    2024-04-02
  • Linux中开机启动的过程分析
    这篇文章主要介绍了Linux中开机启动的过程分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。最初始阶段当我们打开计算机电源,计算机会自动从主板的BIOS(Basic Inp...
    99+
    2023-06-13
  • Android Service启动绑定流程是什么
    这篇文章主要介绍了Android Service启动绑定流程是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android Service启动绑定流程是什么文章都会有所收获,下面我们一起...
    99+
    2023-07-05
  • 如何在Android中启动Service
    如何在Android中启动Service?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Android Service的启动过程分析启动一个Service只需调用...
    99+
    2023-05-31
    android service roi
  • Android系统启动(四) — Launcher 启动过程
    1 Launcher 概述 系统启动的最后一步是启动一个应用程序来显示系统中已经安装的应用程序,这个应用程序就叫做 Launcher。Launcher 在启动过程中会请求 PackageManager...
    99+
    2023-09-04
    android java 开发语言
  • SpringBoot启动过程逐步分析讲解
    springboot启动是通过一个main方法启动的,代码如下 @SpringBootApplication public class Application { publi...
    99+
    2023-01-06
    SpringBoot启动过程 SpringBoot启动过程原理 SpringBoot启动过程执行顺序
  • Android Activity启动过程详解
     Android系统启动篇 1,《android系统启动流程简介》 2,《android init进程启动流程》 3,《android zygote进程启动流程》 4,《Android SystemServer进程启动流程》 5,《andr...
    99+
    2023-09-02
    android
  • ​Android中bindService为什么不能远程启动Service
    在Android中,bindService方法是用于在应用程序组件(如Activity、Service、BroadcastRecei...
    99+
    2024-02-29
    ​Android
  • Linux系统开机后的启动过程分析
    本篇内容介绍了“Linux系统开机后的启动过程分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Linux的启动其实和windows的启动过...
    99+
    2023-06-13
  • Spring启动过程源码分析及简介
    目录1、BeanDefinition2、beanFactory3、BeanDefinitionReader4、ClassPathBeanDefinitionScanner5、Cond...
    99+
    2024-04-02
  • Android 抓取Trace 分析冷启动
    为了分析冷启动,我们需要抓取Trace文件,来帮助我们分析问题 我们使用adb命令来抓取Trace文件 抓取Trace文件 adb shell atrace -b 25600 --async_star...
    99+
    2023-10-03
    android
  • 详解Android系统启动过程
    目录计算机是如何启动的引导阶段加载内核阶段Android的启动过程init进程init.rc 文件service_manager 进程surface_flinger 进程media_...
    99+
    2024-04-02
  • Android Activity启动流程刨析
    目录前言一、Binder的基本理解二、Activity启动的双向IPC过程三、AMS服务注册前言 上篇文章写到 Service 的启动过程; 相对来说Activity的启动过程比Se...
    99+
    2022-11-13
    Android Activity启动 Android Activity
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作