返回顶部
首页 > 资讯 > 移动开发 >【Android话题-5.1应用相关】说说service的启动原理
  • 557
分享到

【Android话题-5.1应用相关】说说service的启动原理

service启动Android 2022-06-06 13:06:40 557人浏览 独家记忆
摘要

考察内容: service启动有哪几种方式? service启动过程中主要流程有哪些? service启动过程涉及哪些参与者,通信过程是怎样的?

考察内容:

service启动有哪几种方式? service启动过程中主要流程有哪些? service启动过程涉及哪些参与者,通信过程是怎样的? Service启动原理 用startService启动Service:
@Override
public ComponentName startService(Intent service) {
  return startServiceCommon(service, mUser);
}
ComponentName startServiceCommon(Intent service, ...){
  ComponentName cn = ActivityManagerNative.getDefault()
    .startService(mMainThread.getApplicationThread(), service, ...);
  return cn;
}

AMS中的处理:

ComponentName startService(IApplicationThread caller, Intent service, ...){
  ComponentName res = mServices.startServiceLocked(caller, service, ...);
  return res;
}

根据intent 查询service Record对象:
每个应用端的Service在AMS中都对应一个ServiceRecore对象

ComponentName startServiceLocked(Intent service, ...){
  ServiceLookupResult res = retrieveServiceLocked(service, ...);
  ServiceRecord r = res.record;
  ...
  //查到ServiceRecord之后new了一个StartItem并加到pendingStart里面,
  //为后面调用onStartCommand准备
  r.pendingStart.add(new ServiceRecord.StartItem(r, ...));
  ...
  return startServiceInnerLocked(smap, service, r, ...);
}
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ...){
  bringUpServiceLocked(r, service.getFlags(), callerFg, false);
}
final String bringUpServiceLocked(ServiceRecord r, ...){
  if(r.app != null && r.app.thread != null) {
    //如果Service已经启动了,就调用下面这个函数,
    //它将触发应用端的onStartCommand
    sendServiceArgsLocked(r, ...);
    return null;
  }
  //Service还没启动的情况:
  ProcessRecord app = mAm.getProcessRecordLocked(procName, ...);
  if(app != null && app.thread != null){
    //如果Service所在的进程已经启动了,真正启动Service
    //r.app就是在下面这个函数中设置的
    realStartServiceLocked(r, app, execInFg);
    return null;
  }
  //Service所在进程没有启动或者虽然已经启动但还没就绪的情况:
  if(app == null){
    //app进程还没启动,启动进程
    app = mAm.startProcessLocked(procName, ...);
  }
  if(!mPendingServices.contains(r)){
    //把ServiceRecord加到pending列表里面,等待进程启动后再处理
    mPendingServices.add(r);
  }
  ...
}

进程启动的流程图:
在这里插入图片描述

AMS通过Socket向ZyGote发起启动进程的请求 Zygote收到请求之后就会启动进程 应用进程向AMS发起attachApplication的binder调用,把自己的binder对象注册到AMS(注册完之后对于AMS来说这个应用就算是就绪了) 通过应用进程注册过来的applicationThread向应用端发起bindApplication调用,主应用初始化application(这步完事后AMS就可以处理Pending的组件了) AMS中处理attachApplication的函数:
boolean attachApplicationLocked(IApplicationThread thread, ...) {
  ...
  mServices.attachApplicationLocked(app, processName);
  ...
  return true;
}
//处理pending的Service
boolean attachApplicationLocked(ProcessRecord proc, ...){
  for(int i = 0; i < mPendingServices.size(); i++){
    sr = mPendingServices.get(i);
    ...
    mPendingServices.remove(i--);
    //对每一个pending的service调用realStartServiceLocked函数真正启动service
    realStartServiceLocked(sr, proc, ...);
  }
  ...
}
void realStartServiceLocked(ServiceRecord r, ProcessRecord app, ...){
  r.app = app;
  ...
  //向应用端发起IPC调用,应用收到后就会创建Service,执行应用里的onCreate回调
  //参数r其实是一个binder对象: final class ServiceRecord extends Binder{}
  //这是要存在应用端的,应用端有一个用来保存service对象的map,这里的r就是key
  app.thread.scheduleCreateService(r, r.serviceInfo, ...);
  ...
  //触发应用端Service的onStartCommand
  sendServiceArgsLocked(r, ...);
}
应用端是如何处理AMS发过来的CreateServicd请求的:
private void handleCreateService(CreateServiceData data){
  //先拿到loadedApk
  LoadedApk packageInfo = getPackageInfoNoCheck(...);
  //加载Service类,并通过newInstance调用其构造函数,从而获得Service对象
  Service service = (Service)cl.loadClass(data.info.name).newInstance();
  //给这个Service创建一个Context对象
  ContextImpl context = ContextImpl.createAppContext(this, ...);
  //获取Application,这个application是在应用启动的时候创建的
  Application app = packageInfo.makeApplication(flase, ...);
  //给service赋予上下文
  service.attach(context, this, ...);
  //执行Service的生命周期
  service.onCreate();
  mServices.put(data.token, service);
  ...
}
mServices是一个map:
ArrayMap
private final void sendServiceArgsLocked(ServiceRecord r, ){
  while(r.pendingStarts.size() > 0){
    //取出每一个pending的startItem
    StartItem si = r.pendingStarts.remove(0);
    ...
    //向应用端发起IPC调用
    r.app.thread.scheduleServiceArgs(r, ...);
  }
}
AMS是如何触发应用端Service的onStartCommand的

AMS调用r.app.thread.scheduleServiceArgs(r, …)后,应用端的处理:

public final void scheduleServiceArgs(IBinder token, ...) {
  //封装了一个ServiceArgsData对象
  ServiceArgsData s = new ServiceArgsData();
  ...
  //丢到应用的主线程去处理
  sendMessage(H.SERVICE_ARGS, s);
}
//应用端主线程的处理:
private void handleServiceArgs(ServiceArgsData data) {
  //首先从mServices中把Service对象取出来。mService是一个map,其中:
  //key就是AMS中的ServiceRecord的对象
  //value就是应用端的Service对象
  //data.token就是AMS中的ServiceRecord对象
  Service s = mServices.get(data.token);
  if(s != null){
    ...
    //调用Service的onStartCommand
    s.onStartCommand(data.args, data.flags, data.startId);
    ...
  }
}
总结Service启动的流程:

在这里插入图片描述
AMS端:

先看Service启动了没有:如果启动了就直接发指令,让应用端执行onStartCommand() 如果Service没有启动,就看它所在进程启动了没有:如果已经启动,就去启动Service,等Service启动了之后再发送指令让其执行onStartCommand 如果进程没有启动就去启动进程,等进程启动后再启动Service

应用端:

先创建Service对象 再赋予上下文 最后调用生命周期onCreate() 用bindService启动Service

启动Service还有另一种情况:bindService的时候带上BIND_AUTO_CREATE标记

int bindServiceLocked(IApplicationThread caller, ...){
  ...
  if((flags & Context.BIND_AUTO_CREATE) != 0){
    //如果带上BIND_AUTO_CREATE标记
    bringUpServiceLocked(s, ...);
  }
  ...
}
binderService和startService的区别: binderService不会触发应用端的onStartCommand函数 因为binderService没有把ServiceRecord加到mPendingStart队列中 回归:说说service的启动原理 service启动有几种方式?
a) startService
b) bindService带BIND_AUTO_CREATE service启动过程主要流程有哪些?
a)AMS端:
1)先看Service启动了没有:如果启动了就直接发指令,让应用端执行onStartCommand()
2)如果Service没有启动,就看它所在进程启动了没有:如果已经启动,就去启动Service,等Service启动了之后再发送指令让其执行onStartCommand
3)如果进程没有启动就去启动进程,等进程启动后再启动Service

b)应用端:
1)先创建Service对象
2)再赋予上下文
3)最后调用生命周期onCreate()

service启动过程中有哪些参与者,通信过程是怎样的?
a)参考下图:在这里插入图片描述
作者:menghaocheng


--结束END--

本文标题: 【Android话题-5.1应用相关】说说service的启动原理

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

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

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作