四大组件之Service(一)-Service启动过程

Service启动过程与Activity类似,了解了Activity启动之后来看Service就容易了,那么还是来简单过一下流程,先看一张整体流程图:

应用层startService 最终通过Binder IPC 到AMS:

Context关系以后再讲,这里其实我们都知道Context是个抽象类,真正干活的是ContextImpl. 由它执行真正的startService操作:

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

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
    try {
        ...
        ComponentName cn = ActivityManager.getService().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), requireForeground,
                        getOpPackageName(), user.getIdentifier());
        ...
}

这是典型的binder ipc过程了,话不多说。

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

@Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, String callingPackage, int userId)
        throws TransactionTooLargeException {
        ...
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, userId);
        ...
        return res;
    }
}

执行startServiceLocked:

frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
           int callingPid, int callingUid, String callingPackage, final int userId)
           throws TransactionTooLargeException {
     ...
       return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
   }
  ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
           boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
    ...
       String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
    ...
       return r.name;
   }

startServiceLocked 和startServiceInnerLocked 对应于Activity中的startActivityMayWait和startActivity的过程,无非也就是一些检验和初始化的工作。而startServiceInnerLocked方法中又调用了bringUpServiceLocked方法.

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
...
  final String procName = r.processName;
  ProcessRecord app;
  if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode,
                    mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } 
         ...
if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    "service", r.name, false, isolated, false)) == null) {
              ...
            }
          ...
        }
...     

}

该方法可以对比于Activity启动的startSpecificActivityLocked,也是一个分叉路,如果进程存在则调用realStartServiceLocked去schedule Service应用层的启动,如果不存在,则socket通知Zygote去fork进程,然后再回来schedule Service。Zygote去fork进程部分与Activity启动部分并无太大差别,那么直接来看startSpecificActivityLocked:

private final void realStartServiceLocked(ServiceRecord r,
       ProcessRecord app, boolean execInFg) throws RemoteException {
  ...
   try {
      ...
       app.thread.scheduleCreateService(r, r.serviceInfo,
               mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
               app.repProcState);
       r.postNotification();
       created = true;
   } catch (DeadObjectException e) {
     ...
   }
   ...
}

app.thread是IApplicationThread类型的,它的实现是ActivityThread的内部类ApplicationThread。

frameworks/base/core/java/android/app/ActivityThread.java
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);
}

到了ActivityThread的地界,那就是靠消息驱动运转的世界了,由H发送CREATE_SERVICE的消息,然后在handleMessage对应的case中执行的是handleCreateService

private void handleCreateService(CreateServiceData data) {
      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) {
         ...
          }
      }
      try {
          if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
          ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//4
          context.setOuterContext(service);
          Application app = packageInfo.makeApplication(false, mInstrumentation);
          service.attach(context, this, data.info.name, data.token, app,
                  ActivityManagerNative.getDefault());//5
          service.onCreate();//6
          mServices.put(data.token, service);//7
       ...
      } catch (Exception e) {
          ...
      }
  }

这里主要干两件事:

  • 将service load到内存

  • 通过Service的attach方法来初始化Service,然后走Service的onCreate方法,这样Service就启动了。

好了今天就简单地总结了下Service的启动过程,下篇接着看看Service的绑定过程。

参考:
http://gityuan.com/2016/03/06/start-service/
http://liuwangshu.cn/framework/component/2-service-start.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 224,983评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,354评论 3 403
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,216评论 0 367
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,061评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,073评论 6 400
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,541评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,906评论 3 428
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,881评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,428评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,460评论 3 346
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,578评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,176评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,913评论 3 339
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,348评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,490评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,142评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,650评论 2 366

推荐阅读更多精彩内容