AMS service管理

1 上回書說(shuō)道 
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting)

     已經(jīng)解釋了retrieveServiceLocked 函數(shù)還沒(méi)有詳細(xì)分析. 繼續(xù)后續(xù)流程

1 后面執(zhí)行的情況是如果沒(méi)有其他使用者調(diào)用了startService,說(shuō)明這個(gè)服務(wù)還沒(méi)有起來(lái)或者已經(jīng)stop了, 并且當(dāng)前調(diào)用者不是前臺(tái)應(yīng)用,還要檢查當(dāng)前調(diào)用者是否有啟動(dòng)應(yīng)用的能力,是什么樣的能力呢
   1 檢查對(duì)應(yīng)service(注意是service)的啟動(dòng)能模式
       int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
                   int callingPid, boolean alwaysRestrict, boolean disabledOnly)
            檢查啟動(dòng)模式雖然不是我這次主要分析問(wèn)題的原點(diǎn),但是為了更好的掌握android的進(jìn)程管理還是需要分析的
            1 從存貨的進(jìn)程里面找到service的uid所對(duì)應(yīng)的UidRecord
            2 判斷uid狀態(tài), 對(duì)三種情況進(jìn)一步處理, 包括uidRec == null(進(jìn)程沒(méi)有啟動(dòng)), alwaysRestrict永遠(yuǎn)限制(對(duì)應(yīng)進(jìn)程雖然啟動(dòng)了還是非得要檢查(無(wú)理取鬧模式), uidRec.idle), 應(yīng)用處于idle狀態(tài)(在后臺(tái)長(zhǎng)時(shí)間不活躍)
               1 首先獲取到應(yīng)用是不是ephemeral(短暫的還不知道是干嘛的應(yīng)用)
               2 如果是短暫的直接返回ActivityManager.APP_START_MODE_DISABLED(不允許啟動(dòng))
               3 對(duì)不不是短暫進(jìn)程的做如下處理
                  1 如果沒(méi)有指定disabledOnly 則返回APP_START_MODE_NORMAL,由此可見只有ephemeral進(jìn)程是被DISABLE的. 
                  2 獲取startMode 對(duì)于要求嚴(yán)格限制的appRestrictedInBackgroundLocked 函數(shù)進(jìn)行處理
                  int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk)
                       1如果應(yīng)用的targetSdk 在Android o以上 返回APP_START_MODE_DELAYED_RIGID (看來(lái)是嚴(yán)格檢查,注釋中說(shuō)在android o以上要檢查后臺(tái)啟動(dòng)情況,由此可見返回這個(gè)后面還會(huì)檢查后臺(tái)情況)
                       2 對(duì)于o以下的應(yīng)用使用AppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
                                       uid, packageName) 檢查是否可以在后臺(tái)運(yùn)行,又返回三種情況
                  3 不嚴(yán)格的檢查
                  int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk)             
                        1 常駐應(yīng)用返回APP_START_MODE_NORMAL
                        2  在后臺(tái)運(yùn)行白名單返回APP_START_MODE_NORMAL
                        3 在idle白名單 返回APP_START_MODE_NORMAL
                        4 使用appRestrictedInBackgroundLocked 嚴(yán)格的的檢查
                  4 經(jīng)過(guò)2,3 對(duì)startmode的檢查后返回的結(jié)果有如下幾種 0:APP_START_MODE_NORMAL 正常啟動(dòng)
                       1:APP_START_MODE_DELAYED 延遲啟動(dòng) 2:APP_START_MODE_DELAYED_RIGID 嚴(yán)格的錯(cuò)誤,可能還需需要繼續(xù)檢查 . 對(duì)于禁用的情況這里是不包含的,看來(lái)這和引用包是兩個(gè)改建
                  5 獲取startMode后,APP_START_MODE_DELAYED 比較特殊,檢查應(yīng)用沒(méi)有在后臺(tái) 返回APP_START_MODE_NORMAL
                  6 其他類型直接返回
            3 不滿足2狀態(tài)的直接返回 APP_START_MODE_NORMAL
            4 對(duì)于檢查啟動(dòng)類型后 如果是APP_START_MODE_DELAYED直接返回null,其他返回ComponentName("?", "app is in background uid " + uidRec)
            5 由此可見,可以正常啟動(dòng)service的模式只有APP_START_MODE_NORMAL, 我們以后有機(jī)會(huì)分析啟動(dòng)限制
 
    2 checkGrantUriPermissionFromIntentLocked 檢查intent里面攜帶的url權(quán)限
        這個(gè)應(yīng)該是返回需要授權(quán)的uri信息
    3 權(quán)限審查,如果開啟了這個(gè)選項(xiàng)只允許前臺(tái)應(yīng)用啟動(dòng)服務(wù),并且還需要彈出頁(yè)面由用戶手動(dòng)同意權(quán)限,后臺(tái)啟動(dòng)則直接不允許
    4 設(shè)置 ServiceRecord的一些信息用于啟動(dòng)service(注意這里有兩種情況service已經(jīng)啟動(dòng)和還沒(méi)有啟動(dòng))
     設(shè)置的有 1 r.lastActivity 最后活躍時(shí)間 2 r.startRequested = true 需要啟動(dòng)(都到這里了可定需要啟動(dòng)拉)
     3  r.delayedStop = false 不用延遲關(guān)閉了 不需要關(guān)閉, 4 r.fgRequired = fgRequired是否需要作為前臺(tái)服務(wù).
     5 r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
       service, neededGrants, callingUid)) 添加到pendingStarts表示一次沒(méi)有處理的啟動(dòng)請(qǐng)求
    5 獲取ServiceRecord所屬的user的ServiceMap,做一些用戶界別的檢查 主要是針對(duì) 調(diào)用者不是前臺(tái)進(jìn)程,啟動(dòng)的也不是前臺(tái)服務(wù),并且user已經(jīng)啟動(dòng)的情況, user沒(méi)有啟動(dòng)的情況前面已經(jīng)跳過(guò)了 
        1 看看service對(duì)應(yīng)的進(jìn)程有沒(méi)有啟動(dòng) 
            1對(duì)于service進(jìn)程優(yōu)先級(jí)太低proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER 或者service進(jìn)程沒(méi)有啟動(dòng)的 這種情況對(duì)service啟動(dòng)就會(huì)嚴(yán)加限制. 我們來(lái)看看怎么限制
                1  延遲啟動(dòng)的直接返回(因?yàn)樵瓉?lái)啟動(dòng)的時(shí)候也是這種情況,服務(wù)在后臺(tái), 現(xiàn)在可定還是延遲狀態(tài),所以不用重新設(shè)置了,直接返回)
                2 后臺(tái)正在運(yùn)行的服務(wù)已經(jīng)超出了最大限制,把這個(gè)服務(wù)添加到smap.mDelayedStartList 中并且設(shè)置r.delayed = true,返回. 由此可見后臺(tái)服務(wù)限制還是比較嚴(yán)格的
                3 如果不滿足1,2 說(shuō)明還可以啟動(dòng)服務(wù),設(shè)置addToStarting=true
            2 proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE 也就是服務(wù)中本來(lái)也有服務(wù)運(yùn)行,直接設(shè)置 addToStarting = true
        2 現(xiàn)在可以看到在1里面淘汰了延遲啟動(dòng)的服務(wù),放到了延遲列表里就返回了, 另外對(duì)于service進(jìn)程優(yōu)先級(jí)低于PROCESS_STATE_SERVICE的或者進(jìn)程還沒(méi)有啟動(dòng)的設(shè)置addToStarting = true;
          addToStarting的情況包含一下幾種: 1 進(jìn)程優(yōu)先級(jí)比較高  2 前臺(tái)進(jìn)程啟動(dòng)的服務(wù) 3后臺(tái)進(jìn)程啟動(dòng)的前臺(tái)服務(wù). 或者user都沒(méi)有啟動(dòng)(這種情況不大可能,前邊已經(jīng)檢查過(guò)了)
     6 ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting) 真正啟動(dòng)服務(wù)或者執(zhí)行startcommand的過(guò)程,注意前邊分析的參數(shù)我們后面再去分析. 


在分析startServiceInnerLocked函數(shù)前我們還是老老實(shí)實(shí)的分析retrieveServiceLocked函數(shù),看看如何分獲取service記錄. 這里我們猜想它如何實(shí)現(xiàn). 肯定是對(duì)于已經(jīng)啟動(dòng)的或者已經(jīng)請(qǐng)求啟動(dòng)的(延遲啟動(dòng))直接拿出來(lái)ServiceRecord, 對(duì)于沒(méi)有啟動(dòng)的service通過(guò)pms找到組件,檢查一系列權(quán)限,之后創(chuàng)建serviceRecord的過(guò)程,我們帶著猜測(cè)進(jìn)去看下
1 找到正確的調(diào)用者userid,分析多用戶時(shí)候再去分析它
2 獲取user下的ServiceMap
3 從intent中獲取要啟動(dòng)的ComponentName
4 ServiceMap里面有兩個(gè)集合,用于存放當(dāng)前user下的用戶信息
    final ArrayMap<ComponentName, ServiceRecord> mServicesByName = new ArrayMap<>();
            final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = new ArrayMap<>();
   mServicesByName 是根據(jù)ComponentName 進(jìn)行查詢ServiceRecord, 而mServicesByIntent 則根據(jù)intent信息進(jìn)程查詢
5  如果指定了ComponentName 看看mServicesByName里面是否已經(jīng)存在了對(duì)應(yīng)的ServiceRecord,如果存在取出來(lái)(這種找法是相當(dāng)準(zhǔn)確的)
6 如果通過(guò)ComponentName沒(méi)有找到ServiceRecord并且isBindExternal(代表綁定外部服務(wù),是綁定service時(shí)候根據(jù)傳遞的flags去設(shè)置的),  根據(jù)intent找一下,由此可見如果要綁定外部服務(wù),找到服務(wù)后可定會(huì)被放到mServicesByName集合中去.
  這里我們來(lái)介紹isBindExternal參數(shù)的來(lái)歷
  這里解釋下isBindExternal,在綁定服務(wù)的時(shí)候如果指定了BIND_EXTERNAL_SERVICE這個(gè)標(biāo)志,代表要綁定的服務(wù)必須運(yùn)行在沙盒進(jìn)程中, 并且設(shè)置了externalService=true,另外如果service指定了 externalService=true 也必須使用BIIND_EXTERNAL_SERVICE綁定, 而且還要求service被導(dǎo)出 要求挺多的哈
7 了解了isBindExternal的上述需求我們繼續(xù)向下分析
8 如果一個(gè)聲明了FLAG_EXTERNAL_SERVICE的服務(wù)運(yùn)行在自己的進(jìn)程中,其他服務(wù)不能綁定它,所以設(shè)置找到的ServiceRecord為null,再去創(chuàng)建新的實(shí)例(這里當(dāng)然也有可能還沒(méi)有對(duì)應(yīng)的serviceRecord)
9 這里所描述的情況就是沒(méi)有找到對(duì)應(yīng)的ServiceRecord,因?yàn)檫@我們要啟動(dòng)的service并沒(méi)有啟動(dòng). 
   1 使用PMS解析對(duì)應(yīng)的service信息ResolveInfo
   2 如果沒(méi)有找到對(duì)應(yīng)的serice信息則返回null不去處理
   3 后面的情況是通過(guò)pms找到的對(duì)應(yīng)的service,進(jìn)行一些檢查后創(chuàng)建ServiceRecord的過(guò)程我們?cè)敿?xì)分析
       1 創(chuàng)建ComponentName
       2 對(duì)FLAG_EXTERNAL_SERVICE進(jìn)行檢查,前面說(shuō)了綁定外部服務(wù)如果傳遞了BIND_EXTERNAL_SERVICE標(biāo)志,要慢如如下條件, 首先服務(wù)應(yīng)該被導(dǎo)出, 另外服務(wù)必須是在獨(dú)立的進(jìn)程中運(yùn)行, 滿足這兩條之后就可以為service的intent添加ComponentName信息了,這和我們前面分析的綁定外部服務(wù)必定要放在mServicesByName中是一致的. 另外如果沒(méi)有使用了BIND_EXTERNAL_SERVICE,則會(huì)拋出異常 . 到這里我們可以總結(jié)下EXTERNAL_SERVICE的特性. 1 運(yùn)行在沙盒進(jìn)程中 2 自己應(yīng)用擁有一個(gè)實(shí)例,其他應(yīng)用擁有一個(gè)實(shí)例.  這里有一個(gè)疑問(wèn),是不是產(chǎn)生多個(gè)ServiceRecord?  如何解決差到多個(gè)實(shí)例的情況?
       3 這樣對(duì)于外部服務(wù)的特殊處理也執(zhí)行完成了
       4 對(duì)于多用戶的處理,如果調(diào)用者的userid>0 也就是說(shuō)不是系統(tǒng)用戶,則判斷要啟動(dòng)的服務(wù)是不是singleton的,如果是單例的則不需要在userid下創(chuàng)建ServiceRecord(只需要在user_system下創(chuàng)建就可以了).  重新設(shè)置查到的serviceInfo到系統(tǒng)用戶
       5 再次再新的用戶的ServiceMap下查找是由存在已經(jīng)運(yùn)行起來(lái)的service. 
       6 如果還是沒(méi)有查到的話可代表確實(shí)該service還沒(méi)有啟動(dòng)或者沒(méi)有延遲啟動(dòng). 
       7 對(duì)于沒(méi)有找到的情況如果指定了createIfNeeded就創(chuàng)建一個(gè)ServiceRecord(這里需要說(shuō)明下createIfNeeded參數(shù),在請(qǐng)求啟動(dòng)service的時(shí)候和binderservice的時(shí)候都會(huì)設(shè)置成true,要求創(chuàng)建ServiceRecord,啟動(dòng)的時(shí)候比較容易分析,binder的時(shí)候?yàn)槭裁床皇侵付ˋutoCreate的時(shí)候才去創(chuàng)建???????? 我們后面一定會(huì)弄明白這一點(diǎn))
       現(xiàn)在來(lái)看看創(chuàng)建ServiceRecord的過(guò)程. 
            1 創(chuàng)建一個(gè)BatteryStatsImpl 用于通知電池服務(wù)service運(yùn)行情況方便統(tǒng)計(jì)
            2 創(chuàng)建ServiceRecord new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res)
            3 創(chuàng)建ServiceRestarter,把ServiceRecord放到這個(gè)Starter中去,看來(lái)是雙向關(guān)系呀
            4  smap.mServicesByName.put(name, r);
                                smap.mServicesByIntent.put(filter, r); 添加到集合
            5 如果mPendingServices中存在這個(gè)service,移除它,(mPendingServices) 是等待進(jìn)程起起來(lái)再啟動(dòng)服務(wù)的,這里移除它就可以和當(dāng)前這次請(qǐng)求統(tǒng)一處理,說(shuō)不定進(jìn)程已經(jīng)起來(lái)了. 我想這種情況是不會(huì)出現(xiàn)的,為什么呢,因?yàn)樾聞?chuàng)建的serviceRecord,怎么會(huì)和出現(xiàn)在這個(gè)列表中呢???
       8 到這里對(duì)于一開始沒(méi)有找到相應(yīng)的ServiceRecord要么使用新的userid找到了,要么已經(jīng)創(chuàng)建了,要么就是沒(méi)一些異常情況返回了. 或者就是找到了但是不能創(chuàng)建(stop的時(shí)候)
       9 下面一段就是對(duì)找到ServiceRecord的情況做出處理
          1首先檢查權(quán)限和導(dǎo)出選項(xiàng),錯(cuò)誤設(shè)置ServiceLookupResult(null, "not exported from uid "
                                      + r.appInfo.uid)
          2 如果使用mAm價(jià)差通過(guò)了再次使用AppOpsManager檢查權(quán)限
          3 權(quán)限檢查失敗都會(huì)返回錯(cuò)誤
          4 防火墻檢查權(quán)限
          5 所有權(quán)限通通過(guò)返回爭(zhēng)取的 ServiceLookupResult(r, null)
       10 最后可能會(huì)返回錯(cuò)誤的 ServiceLookupResult(null, errMsg), null, 正確的ServiceLookupResult(r, null)          檢查的還挺多哈,不過(guò)和我們猜想的一樣啊


這里我們已經(jīng)對(duì)找到和創(chuàng)建ServiceRecord的過(guò)程進(jìn)行分析了,也分析了找到后對(duì)啟動(dòng)限制的檢查,我們?cè)俅慰偨Y(jié)一下
1 首先對(duì)user,權(quán)限進(jìn)行檢查,還有啟動(dòng)服務(wù)是否合法
2 對(duì)后臺(tái)啟動(dòng)進(jìn)行檢查,主要包括進(jìn)程的啟動(dòng)模式和后臺(tái)進(jìn)程的個(gè)數(shù). 還留有一個(gè)疑問(wèn)addToStarting是干什么用的
我們總結(jié)下可以啟動(dòng)的條件
  不違反原則,權(quán)限滿足,用戶滿足, 前臺(tái)應(yīng)用啟動(dòng)服務(wù)或者啟動(dòng)前臺(tái)服務(wù)

到這里我們分析service真正啟動(dòng)和或者執(zhí)行的過(guò)程
startServiceInnerLocked(smap, service, r, callerFg, addToStarting)
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException 
1 獲取service追蹤者ServiceState,看類名稱是用于記錄service狀態(tài)的. 我們來(lái)看看如何獲取
public ServiceState getTracker() 
   1 tracker不為null,直接返回
   2  如果不是常駐進(jìn)程, 創(chuàng)建一個(gè) tracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
                       serviceInfo.applicationInfo.uid, serviceInfo.applicationInfo.versionCode,
                                           serviceInfo.processName, serviceInfo.name),這里可以看出來(lái)常駐進(jìn)程不需要追蹤. 
         ----> ProcStats->public ServiceState getServiceStateLocked(String packageName, int uid, int vers,
                     String processName, String className)
                      創(chuàng)建一個(gè)ServiceState找到對(duì)應(yīng)的service狀態(tài),沒(méi)有則創(chuàng)建一個(gè)嘍
2 獲取后開始設(shè)置狀態(tài) stracker.setStarted
3 開啟電池最總
4 bringUpServiceLocked(r, service.getFlags(), callerFg, false, false) 從何函數(shù)的名字來(lái)看叫做調(diào)出服務(wù). 我們一會(huì)分析
5 對(duì)調(diào)出服務(wù)結(jié)果做處理,如果返回錯(cuò)誤也從這里返回錯(cuò)誤
6 如果r.startRequested 并且 addToStarting 說(shuō)明需要放到后臺(tái)啟動(dòng)的服務(wù)里面,看到了addToStarting的作用, 如果是第一次添加后臺(tái)服務(wù),還要smap.rescheduleDelayedStartsLocked() 我們也先不去分析. 
7 如果沒(méi)有請(qǐng)求啟動(dòng)或者不是啟動(dòng)后臺(tái)服務(wù), 并且是前臺(tái)服務(wù)或者前臺(tái)調(diào)用者使用   smap.ensureNotStartingBackgroundLocked(r); 函數(shù)做操作


我們先來(lái)分析bringUpServiceLocked(r, service.getFlags(), callerFg, false, false) 函數(shù),這應(yīng)該是服務(wù)啟動(dòng)的真正過(guò)程. 
1 首先如果r.app != null && r.app.thread != null的情況說(shuō)明服務(wù)已經(jīng)啟動(dòng),只要執(zhí)行startCommand就行了,使用sendServiceArgsLocked(r, execInFg, false)函數(shù)進(jìn)行執(zhí)行. 注意r.app實(shí)在啟動(dòng)服務(wù)的時(shí)候設(shè)置
    先來(lái)分析sendServiceArgsLocked 函數(shù).
    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
                boolean oomAdjusted) throws TransactionTooLargeException
          1 首先判斷是否真的有要啟動(dòng)的服務(wù),沒(méi)有則不需要處理 直接返回
          2 遍歷startService請(qǐng)求 r.pendingStarts, 注意這是一個(gè)for循環(huán),我們進(jìn)入循環(huán)中觀察
              1 拿出一個(gè)請(qǐng)求StartItem
              2 如果沒(méi)有指定intent,并且請(qǐng)求數(shù)量大于1 就跳過(guò),那么什么時(shí)候會(huì)intent為null呢? 猜想是bindService的時(shí)候,后面進(jìn)行實(shí)驗(yàn)
              3 設(shè)置派發(fā)時(shí)間 si.deliveredTime = SystemClock.uptimeMillis()
              4 增加r.deliveredStarts.add(si) 分發(fā)的請(qǐng)求
              5 si.deliveryCount++ 計(jì)數(shù)
              6 授權(quán)(對(duì)于授權(quán)這里還是值得分析的)
              7 bumpServiceExecutingLocked(r, execInFg, "start") 函數(shù)的名字很抽象,我不太能得出信息(通氣服務(wù)執(zhí)行???)  還是進(jìn)去看看吧
                  1 r.executeNesting嵌套數(shù)量為0,要?jiǎng)?chuàng)建一些信息
                      r.executeFg = fg 設(shè)置是否我前臺(tái)
                      stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now) 設(shè)置執(zhí)行狀態(tài)                      設(shè)置應(yīng)用信息
                         r.app.executingServices.add(r)
                         r.app.execServicesFg |= fg; 這里注意并不是說(shuō)服務(wù)是前臺(tái)服務(wù),而是前臺(tái)進(jìn)程調(diào)用的服務(wù)
                          if (r.app.executingServices.size() == 1) {
                                              scheduleServiceTimeoutLocked(r.app);
                                                              }
                              還要設(shè)置超時(shí)消息,這里需要注意一點(diǎn),前臺(tái)進(jìn)程調(diào)用的服務(wù)超時(shí)20s,后臺(tái)調(diào)用的超時(shí)2000s. 那么問(wèn)題來(lái)了后臺(tái)服務(wù)調(diào)用前臺(tái)應(yīng)用的服務(wù)怎么算? 做實(shí)驗(yàn)做實(shí)驗(yàn)
                  2 不是嵌套服務(wù)的話前邊的哪些信息已經(jīng)初始化了, 只是需要看一下是否要改變服務(wù)的屬性execServicesFg和服務(wù)的超時(shí)消息
                  3 r.executeFg |= fg;
                          r.executeNesting++;
                               r.executingStart = now; 更新三個(gè)狀態(tài)信息 感覺這里寫的比較啰嗦哈
               8 回到遍歷中,第一次遍歷更新oomadj,(注意當(dāng)前這次調(diào)用真正出發(fā)了服務(wù)的啟動(dòng),如果pendingStarts可能是有延遲的啟動(dòng),幸運(yùn)的是它們借助這次啟動(dòng)的東風(fēng)得意執(zhí)行)
               9 前邊處理了前臺(tái)服務(wù)調(diào)用的情況,這里處理的才是真正的前臺(tái)進(jìn)程,如果請(qǐng)求啟動(dòng)前臺(tái)服務(wù),并且r.fgWaiting說(shuō)明馬上可以啟動(dòng)前臺(tái)服務(wù)了(r.fgWaiting == true代表前臺(tái)服務(wù)已經(jīng)啟動(dòng)了,不需要重新處理).
                  1 如果當(dāng)前r.isForeground==false 說(shuō)明還沒(méi)有啟動(dòng)成前臺(tái)服務(wù),發(fā)送超時(shí)消息,否則設(shè)置r.fgRequired = false 表示前臺(tái)服務(wù)的請(qǐng)求已經(jīng)得到執(zhí)行
               10 處理完成前臺(tái)的小插曲,如果是前臺(tái)的請(qǐng)求,超時(shí)消息已經(jīng)發(fā)出去了,是箭在弦上不得不發(fā)了,我們就來(lái)看看怎么發(fā)
               11  如果大于 派發(fā)次數(shù)大于1 設(shè)置flags |= Service.START_FLAG_RETRY
               12 si.doneExecutingCount > 0 執(zhí)行返程次數(shù)大于0 設(shè)置flags |= Service.START_FLAG_REDELIVERY
               13 這兩個(gè)標(biāo)志還不太好理解分析客戶端執(zhí)行的時(shí)候再去分析
               14 把請(qǐng)求封裝成ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent)參數(shù),放到一個(gè)集合里,用于批量執(zhí)行. 
               15 這樣收集服務(wù)請(qǐng)求的過(guò)程就完成了
           3 前邊手機(jī)好的請(qǐng)求 我們封裝成ParceledListSlice用于序列化,slice.setInlineCountLimit(4) 設(shè)置一次最多傳送4個(gè)請(qǐng)求,如果太多ParceledListSlice封裝了一個(gè)binder調(diào)用獲取數(shù)據(jù)
           4 r.app.thread.scheduleServiceArgs(r, slice) 請(qǐng)求servie進(jìn)程執(zhí)行
           5 對(duì)錯(cuò)誤的處理 serviceDoneExecutingLocked(r, inDestroying, inDestroying)
             這一步驟還挺長(zhǎng),我們?nèi)シ治鲆幌?               1r.executeNesting-- 代表處理了一個(gè)請(qǐng)求,如果r.executeNesting <= 0 說(shuō)明是最后一個(gè)請(qǐng)求,這時(shí)候可能要去destory服務(wù)
               首先如果r.app != null 對(duì)app做一些清理工作 ,這正是我們發(fā)起請(qǐng)求時(shí)候設(shè)置的
                 r.app.execServicesFg = false;
                                 r.app.executingServices.remove(r);
                 如果沒(méi)有正在執(zhí)行的服務(wù) 移除服務(wù)消息
                如果還有其他服務(wù)在執(zhí)行,那么如果我們異常(執(zhí)行完成)的這個(gè)服務(wù)是一個(gè)前臺(tái)應(yīng)用掉漆的服務(wù),遍歷進(jìn)程中啟動(dòng)的其他服務(wù)看有沒(méi)有前臺(tái)應(yīng)用掉起來(lái)的,設(shè)置r.app.execServicesFg = true
                如果當(dāng)前服務(wù)正在銷毀的而過(guò)程中,從mDestroyingServices移除,綁定的數(shù)據(jù)清除
                更新oomadj
               2 更新狀態(tài), 不是常駐服務(wù)進(jìn)程的服務(wù)移除 更新白名單管理服務(wù),設(shè)置r.app == null
           6 拋出異常

這里我們就分析完成了service已經(jīng)啟動(dòng),直接執(zhí)行startCommand的情況,不過(guò)我們還沒(méi)有分析客戶端如何執(zhí)行,來(lái)看一下

注意
new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent) 
   可能的flags 
   if (si.deliveryCount > 1) {
                   flags |= Service.START_FLAG_RETRY;
                               }
                                           if (si.doneExecutingCount > 0) {
                                                           flags |= Service.START_FLAG_REDELIVERY;
                                                                       }
客戶端的代碼在ActivityThread中
  兩個(gè)參數(shù) 1 IBinder token代代表AMS中的ServiceRecord. ParceledListSlice args代表參數(shù).
  遍歷啟動(dòng)請(qǐng)求,封裝成ServiceStartArgs,發(fā)送SERVICE_ARGS消息請(qǐng)求執(zhí)行. 

private void handleServiceArgs(ServiceArgsData data)  進(jìn)行處理
   根據(jù)ServiceRecord的binder對(duì)象從mServices找到對(duì)應(yīng)的service,主要調(diào)用的時(shí)候默認(rèn)服務(wù)已經(jīng)啟動(dòng)了, 所以只處理找到了服務(wù)的情況. 
      這里根據(jù) taskRemoved參數(shù)去做不同的處理,如果 taskRemoved 為false,則執(zhí)行onStartCommand 函數(shù)
      如果taskRemoved為true說(shuō)明是由于應(yīng)用的task被移除發(fā)起的請(qǐng)求, 如果設(shè)置了FLAG_STOP_WITH_TASK 則不會(huì)收到請(qǐng)求,只是簡(jiǎn)單的關(guān)閉服務(wù).  這可能是給應(yīng)用服務(wù)一個(gè)做事情的機(jī)會(huì)?
      服務(wù)完成后執(zhí)行ActivityManager.getService().serviceDoneExecuting(
                                  data.token, SERVICE_DONE_EXECUTING_START, data.startId, res) 

另外這里我們可以解釋那連個(gè)flags了
public static final int START_FLAG_REDELIVERY = 0x0001 表示原來(lái)就指定過(guò)這個(gè)intent(因?yàn)檫@個(gè)服務(wù)項(xiàng)的doneExecutingCount大于0, 執(zhí)行stop前被殺死,這是重啟的過(guò)程)
public static final int START_FLAG_RETRY = 0x0002; 表示有些服務(wù)之前沒(méi)有發(fā)送出去,又進(jìn)行重新發(fā)送


我們這里先不去看服務(wù)執(zhí)行完成的serviceDoneExecuting函數(shù),先去分析啟動(dòng)過(guò)程中還沒(méi)看完的部分,前面值分析了服務(wù)已經(jīng)啟動(dòng)的情況



private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired) 
該函數(shù)我們之前已經(jīng)分析了service已經(jīng)啟動(dòng)的情況,這時(shí)候來(lái)分析還沒(méi)有請(qǐng)的情況,可想而知這里又會(huì)有兩種情況,一種是進(jìn)程還沒(méi)有啟動(dòng),另一種是進(jìn)程已經(jīng)啟動(dòng)了. 
1 如果當(dāng)前不是進(jìn)行服務(wù)的重新啟動(dòng),該服務(wù)在重新啟動(dòng)的列表里面就直接返回null,到重新啟動(dòng)時(shí)候會(huì)進(jìn)行處理
2 過(guò)了這種情況無(wú)論服務(wù)是重新啟動(dòng)還是不是沖洗你啟動(dòng)都可以執(zhí)行啟動(dòng)了,所以要從mRestartingServices中移除.
3 如果后臺(tái)服務(wù)已經(jīng)達(dá)到了上限,這個(gè)服務(wù)的請(qǐng)求要被延遲. 能到這里的話肯定是該服務(wù)已經(jīng)可以執(zhí)行,從這個(gè)用戶的mDelayedStartList中移除,設(shè)置r.delayed = false
4 如果service的所在的user已經(jīng)不存在,則使用bringDownServiceLocked(r) 搞什么鬼 應(yīng)該是關(guān)閉服務(wù)的過(guò)程,后續(xù)分析
5 啟動(dòng)了!!!!
6 如果服務(wù)不用運(yùn)行在沙盒進(jìn)程中
    1 獲取服務(wù)所在的進(jìn)程
    2 如果進(jìn)程正在運(yùn)行 使用realStartServiceLocked(r, app, execInFg) 來(lái)啟動(dòng)服務(wù),這里就可以直接返回了
7 處理沙盒進(jìn)程
     其實(shí)也沒(méi)啥處理 主要是對(duì)webview的處理,可見webview的重要之處
8 下面所處理的情況就是進(jìn)程沒(méi)有啟動(dòng)或者是沙盒進(jìn)程的情況
   1 進(jìn)程沒(méi)有啟動(dòng),并且不需要重新檢查權(quán)限,直接啟動(dòng)進(jìn)程
   2 進(jìn)程啟動(dòng)失敗的情況 還是要執(zhí)行bringDownServiceLocked(r) 關(guān)掉服務(wù),啟動(dòng)成功如果是運(yùn)行在沙盒進(jìn)程中的服務(wù)設(shè)置r.isolatedProc = app
9 如果mPendingServices.contains(r) 添加到mPendingServices.add(r) 代表等待進(jìn)程啟動(dòng),但是這里就產(chǎn)生了一個(gè)疑問(wèn),為啥沙盒進(jìn)程還要等待?????
10 如果延遲stop,這里就執(zhí)行stop,為啥?? 設(shè)置為stop為false,不需要延遲關(guān)閉了,但是如果執(zhí)行了start,則還需要執(zhí)行stopServiceLocked(r) 這是搞什么????  stop的時(shí)候發(fā)現(xiàn)正在延遲啟動(dòng),要等到去啟動(dòng)服務(wù)了才去執(zhí)行stop(延遲執(zhí)行stop)



1 private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException 
   1 如果thread為null 拋出異常
   2 啟動(dòng)時(shí)間 設(shè)置
   3 添加到應(yīng)用ProcessRecord的services列表
   4 創(chuàng)建那些服務(wù)信息
   5 更新進(jìn)程lru列表
   6 更新前臺(tái)服務(wù)
   7 更新電池狀態(tài)
   8 app.thread.scheduleCreateService(r, r.serviceInfo,
                       mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo) 創(chuàng)建service
   9 發(fā)出前臺(tái)服務(wù)通知r.postNotification()
   10 沒(méi)有創(chuàng)建成功的情況下
       1執(zhí)行serviceDoneExecutingLocked(r, inDestroying, inDestroying)  我們之前已經(jīng)分析過(guò)
       2 已經(jīng)添加到了services列表要移除
       3 不在destorying列表 scheduleServiceRestartLocked(r, false) 重新啟動(dòng)
   11 設(shè)置whitelistManager 
   12 service create之后處理綁定請(qǐng)求
        來(lái)看下如何處理綁定請(qǐng)求
        requestServiceBindingsLocked(r, execInFg) 函數(shù)
            1 首先判斷進(jìn)程狀態(tài)不存在則返回false
            2  對(duì)于沒(méi)有綁定過(guò),或者要求重新綁定的并且真的有綁定請(qǐng)求的情況,合并請(qǐng)求參數(shù),調(diào)用r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                                    r.app.repProcState)執(zhí)行綁定請(qǐng)求, 請(qǐng)求完成后如果不是rebind, 設(shè)置i.requested = true
                 i.hasBound = true;
                                 i.doRebind = false;
                                 這樣就綁定完成了,出現(xiàn)錯(cuò)誤的時(shí)候都會(huì)執(zhí)行serviceDoneExecutingLocked(r, inDestroying, inDestroying) 來(lái)做清理工作
   13 private boolean updateServiceClientActivitiesLocked(ProcessRecord proc,
               ConnectionRecord modCr, boolean updateLru)  更新客戶端活躍狀態(tài)
               這里主要更新service所在進(jìn)程的proc.hasClientActivities變量,用于計(jì)算adj
   14 發(fā)送sendServiceArgsLocked(r, execInFg, true) 發(fā)送未執(zhí)行的請(qǐng)求
   15 如果要延遲啟動(dòng)的話,現(xiàn)在已經(jīng)不需要了,因?yàn)檎?qǐng)求都執(zhí)行完了,  從mDelayedStartList中移除,設(shè)置 r.delayed = false
   16 處理延遲stop


ActivityThread: 綁定過(guò)程
  private void handleBindService(BindServiceData data) 
  不是rebind的情況  調(diào)用s.onBind函數(shù)創(chuàng)建Binder對(duì)象 使用ctivityManager.getService().publishService(
                                    data.token, data.intent, binder) 發(fā)布對(duì)象
  rebind呢? 執(zhí)行serviceDoneExecuting 執(zhí)行onRebind函數(shù) 要弄清楚這一點(diǎn)要看unbindservice珊瑚

stopServiceLocked(r)
bringDownServiceLocked(r)
smap.rescheduleDelayedStartsLocked()
smap.ensureNotStartingBackgroundLocked(r)
scheduleServiceRestartLocked(r, false)
requestServiceBindingLocked(r, ibr, execInFg, false)
publishService
serviceDoneExecuting(

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容