四大組件之Service(一)-Service啟動過程

Service啟動過程與Activity類似,了解了Activity啟動之后來看Service就容易了,那么還是來簡單過一下流程恨统,先看一張整體流程圖:

應(yīng)用層startService 最終通過Binder IPC 到AMS:

Context關(guān)系以后再講怪蔑,這里其實(shí)我們都知道Context是個抽象類,真正干活的是ContextImpl. 由它執(zhí)行真正的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;
    }
}

執(zhí)行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 對應(yīng)于Activity中的startActivityMayWait和startActivity的過程,無非也就是一些檢驗(yàn)和初始化的工作材泄。而startServiceInnerLocked方法中又調(diào)用了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沮焕,也是一個分叉路,如果進(jìn)程存在則調(diào)用realStartServiceLocked去schedule Service應(yīng)用層的啟動拉宗,如果不存在峦树,則socket通知Zygote去fork進(jìn)程辣辫,然后再回來schedule Service。Zygote去fork進(jìn)程部分與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類型的急灭,它的實(shí)現(xiàn)是ActivityThread的內(nèi)部類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的地界谷遂,那就是靠消息驅(qū)動運(yùn)轉(zhuǎn)的世界了葬馋,由H發(fā)送CREATE_SERVICE的消息,然后在handleMessage對應(yīng)的case中執(zhí)行的是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到內(nèi)存

  • 通過Service的attach方法來初始化Service肾扰,然后走Service的onCreate方法畴嘶,這樣Service就啟動了。

好了今天就簡單地總結(jié)了下Service的啟動過程集晚,下篇接著看看Service的綁定過程窗悯。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者甩恼。
  • 序言:七十年代末蟀瞧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子条摸,更是在濱河造成了極大的恐慌悦污,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钉蒲,死亡現(xiàn)場離奇詭異切端,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)顷啼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門踏枣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人钙蒙,你說我怎么就攤上這事茵瀑。” “怎么了躬厌?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵马昨,是天一觀的道長。 經(jīng)常有香客問我扛施,道長鸿捧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任疙渣,我火速辦了婚禮匙奴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘妄荔。我一直安慰自己泼菌,他們只是感情好谍肤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著灶轰,像睡著了一般谣沸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上笋颤,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音内地,去河邊找鬼伴澄。 笑死,一個胖子當(dāng)著我的面吹牛阱缓,可吹牛的內(nèi)容都是我干的非凌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼荆针,長吁一口氣:“原來是場噩夢啊……” “哼敞嗡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起航背,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤喉悴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后玖媚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箕肃,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年今魔,在試婚紗的時候發(fā)現(xiàn)自己被綠了勺像。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡错森,死狀恐怖吟宦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涩维,我是刑警寧澤殃姓,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站激挪,受9級特大地震影響辰狡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜垄分,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一宛篇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧薄湿,春花似錦叫倍、人聲如沸偷卧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽听诸。三九已至,卻和暖如春蚕泽,著一層夾襖步出監(jiān)牢的瞬間晌梨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工须妻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仔蝌,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓荒吏,卻偏偏與公主長得像敛惊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子绰更,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容