【Android话题-5.1应用相关】说说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<IBinder, Service>
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)参考下图:在这里插入图片描述
发布了119 篇原创文章 · 获赞 28 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/menghaocheng/article/details/104595958