Android Service原理分析之startService(一)

1. Service概述java

Service做爲Android四大組件之一,在開發過程當中很是經常使用,它雖然沒有ui,可是一樣能夠在後臺作不少重要的事情,咱們平時使用啓動service主要經過startService以及bindService來啓動service以便已經相關操做。本文將介紹startService的原理,後續將分別介紹bindService的原理,以及在Android O上對service的新增限制管控。
注:本文基於Android 8.1
2. Service分類web

    從啓動方式上,能夠分別經過startService以及bindService啓動,二者之間最重要的區別在於bindService能夠創建binder鏈接,更加方便通訊。
    從運行方式上,能夠分爲前臺service(foregroundService,下面簡稱fg-service)與後臺service,二者的區別在於有前臺service的進程對應的優先級會更高,不容易被系統清理掉,可是前臺service須要在通知欄裏面顯示一個常駐的通知。緩存

3. startService時序圖
數據結構

startService的啓動大體分爲三種狀況:app

    對應進程不存在(先啓動進程而後啓動service並執行onCreate和onStartCommand)
    進程存在可是service不存在(啓動service並執行onCreate和onStartCommand)
    進程和service都存在(只執行onStartCommand)異步

上面的時序圖主要針對進程存在,可是service不存在的狀況,其餘兩種在主要流程上沒有太大區別,關鍵在於其中有一些特殊判斷,在文章過程當中也會提到。
4. 源碼解析
4.1 ContextImpl.startServiceoop

    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
    
        public ComponentName startForegroundService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, true, mUser);
    }
    // 最終的入口都在這個方法中
    // foreground service只是傳參requireForeground爲true,普通service爲false
    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            // binder call至ams
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());
            if (cn != null) {
                if (cn.getPackageName().equals("!")) {
                    throw new SecurityException(
                            "Not allowed to start service " + service
                            + " without permission " + cn.getClassName());
                } else if (cn.getPackageName().equals("!!")) {
                    throw new SecurityException(
                            "Unable to start service " + service
                            + ": " + cn.getClassName());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }post

   

最終經過startServiceCommon調用至ams,注意這裏返回值有進行特殊處理,而後拋出了一些異常,主要返回值的component的packageName有"!","!!","?"三種,後面在介紹源碼過程當中能夠看到具體是哪裏會返回這些異常。
"!":權限校驗沒經過,不容許啓動
"!!":沒法啓動
"?":不容許啓動
4.2 ActivityManagerService.startServiceui

    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        enforceNotIsolatedCaller("startService");
        // 進行一些簡單的校驗
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
        // callingPackage不能爲空
        if (callingPackage == null) {
            throw new IllegalArgumentException("callingPackage cannot be null");
        }
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                // mService正是ActiveServices對象
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }this


這塊只是簡單校驗以後,就調用到了ActiveServices.startServiceLocked。
參數解析:
caller:發起startService的進程對應的IApplicationThread對象
service:要啓動的service的intent
resolvedType:service類型,啓動的時候能夠設置data已經schema等
requireForeground:是否發起啓動foregroundService
callingPackage:發起startService的進程的packageName
userId:當前用戶id
4.3 ActiveServices.startServiceLocked

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        final boolean callerFg;
        // 獲取發起binder call的caller進程,若是不存在則拋異常
        if (caller != null) {
            final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
            if (callerApp == null) {
                throw new SecurityException(
                        "Unable to find app for caller " + caller
                        + " (pid=" + callingPid
                        + ") when starting service " + service);
            }
            // 根據當前這個進程所處的調度環境判斷是前臺仍是後臺
            callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
        } else {
            callerFg = true;
        }
        // 拿到要啓動的service的信息
        // 主要是從packageManagerService中查詢,而後緩存起來
        // 其中還進行了一些權限的校驗,4.4小節詳細介紹
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);
        // 沒有查到要啓動的service,直接return了
        if (res == null) {
            return null;
        }
        // 這裏就能看到前面提到的返回component的package爲「!」的狀況了
        // 緣由是沒有對應的servicerecord,沒有的緣由會在下面4.4小節中進一步介紹
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }
        // 拿到要啓動的serviceRecord,這個就是咱們在manifest中註冊的service組件對應在系統中封裝起來的對象
        ServiceRecord r = res.record;
        // 判斷user是否存在
        if (!mAm.mUserController.exists(r.userId)) {
            return null;
        }
        // 是否要啓動fg-service
        if (!r.startRequested && !fgRequired) {
            // 這塊是校驗若是要啓動的service是一個後臺service
            // 那麼須要看是否擁有後臺啓動的權限,不容許就沒法後臺啓動
            final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
                    r.appInfo.targetSdkVersion, callingPid, false, false);
            if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                // 新升級到O的應用可能會遇到這問題,由於不容許後臺狀況下的app啓動後臺service
                Slog.w(TAG, "Background start not allowed: service "
                        + service + " to " + r.name.flattenToShortString()
                        + " from pid=" + callingPid + " uid=" + callingUid
                        + " pkg=" + callingPackage);
                if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
                    return null;
                }
                // 不容許啓動,此處封裝component的packageName爲「?」,對應前面提到的,會拋出相關異常
                UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
                return new ComponentName("?", "app is in background uid " + uidRec);
            }
        }
        ...
        // 若是這個service正在調度重啓,那麼取消重啓,由於立刻要啓動了
        if (unscheduleServiceRestartLocked(r, callingUid, false)) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
        }
        r.lastActivity = SystemClock.uptimeMillis();
        r.startRequested = true;
        r.delayedStop = false;
        r.fgRequired = fgRequired;
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants, callingUid));
        final ServiceMap smap = getServiceMapLocked(r.userId);
        boolean addToStarting = false;
        // 若是調用者在後臺,且不是啓動的前臺service,判斷是否須要delay
        if (!callerFg && !fgRequired && r.app == null
                && mAm.mUserController.hasStartedUserState(r.userId)) {
            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
            if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
                if (r.delayed) {
                    return r.name;
                }
                if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                    smap.mDelayedStartList.add(r);
                    r.delayed = true;
                    return r.name;
                }
                addToStarting = true;
            } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
                addToStarting = true;
            }
        }
        ...
        // 準備啓動service了
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }

 
小結:

    校驗caller
    拿到serviceRecord,進一步校驗
    校驗是否有能夠後臺啓動
    是否須要delay
    startServiceInnerLocked

4.4 ActiveServices.retrieveServiceLocked

    private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
        ServiceRecord r = null;
        // 獲取user
        userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
                ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
        // 根據userId獲取ServiceMap
        // 有一個user爲key,ServiceMap爲v的map,保存了全部的service信息
        // 每一個user對應一個
        // ServiceMap是一個handler對象,用的looper是ActivityManager線程
        // 其中主要保存的都是存放service的各map,以不一樣的方式存儲的Servicerecord
        ServiceMap smap = getServiceMapLocked(userId);
        final ComponentName comp = service.getComponent();
        // 經過component從ServiceMap查詢
        if (comp != null) {
            r = smap.mServicesByName.get(comp);
        }
        ...
        if (r == null) {
            try {
                // 若是沒能查到,那須要從PackageManager去查詢了
                ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                        userId, callingUid);
                ServiceInfo sInfo =
                    rInfo != null ? rInfo.serviceInfo : null;
                if (sInfo == null) {
                    Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
                          ": not found");
                    return null;
                }
                // 封裝ComponentName
                ComponentName name = new ComponentName(
                        sInfo.applicationInfo.packageName, sInfo.name);
                // FLAG_EXTERNAL_SERVICE類型的service必須有人去bind
                // 這塊就不貼具體實現了,startService過程當中這個邏輯不會走到
                ...

                if (userId > 0) {
                    if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
                            sInfo.name, sInfo.flags)
                            && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
                        userId = 0;
                        smap = getServiceMapLocked(0);
                    }
                    sInfo = new ServiceInfo(sInfo);
                    sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
                }
                r = smap.mServicesByName.get(name);
                // 拿到ServiceRecord,若是沒有須要新建
                if (r == null && createIfNeeded) {
                    ...
                    // 這塊主要就是ServiceRecord對象建立以及放入ServiceMap中
                }
            }
        }
        if (r != null) {
            ...
            // 這塊主要是作一些權限校驗,包括export(manifest中指定是否容許其餘進程啓動)
            // 以及本身指定的service權限
            if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
                    resolvedType, r.appInfo)) {
                return null;
            }
            // 查找成功
            return new ServiceLookupResult(r, null);
        }
        // 沒有查找成功返回null
        // 上面一節有提到,若是這裏返回null則會再進一步返回到ContextImpl中拋出異常
        return null;
    }

   

這塊作了兩件事:

    查找ServiceRecord,若是不存在則建立
    權限檢查

4.5 ActiveServices.startServiceInnerLocked

    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ...
        r.callStart = false;
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
        // bringUpServiceLocked這個是啓動service的核心
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }
        // 下面主要是進行delay
        if (r.startRequested && addToStarting) {
            boolean first = smap.mStartingBackground.size() == 0;
            smap.mStartingBackground.add(r);
            r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
            if (first) {
                smap.rescheduleDelayedStartsLocked();
            }
        } else if (callerFg || r.fgRequired) {
            smap.ensureNotStartingBackgroundLocked(r);
        }
        return r.name;
    }

   
這裏沒作什麼事,主要實現都在bringUpServiceLocked
4.6 ActiveServices.bringUpServiceLocked

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        // 從上面的時序圖能夠知道sendServiceArgsLocked中主要是要調度執行service的onStartCommand
        // 這裏怎麼直接就執行了呢?
        // 緣由在於判斷條件,對於沒有執行onCreate的service,r.app是null,因此不會執行這個流程
        // 也就是沒有啓動過的service不會走這裏,只有啓動過的service纔會
        // 因此對於已經啓動過的service,重複startService只會走onStartCommand,就是由於這裏,而後return
        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }
        // 若是不是調度重啓,且已經在restart列表中,return
        // 只有調度重啓的地方調用過來whileRestarting爲true
        if (!whileRestarting && mRestartingServices.contains(r)) {
            return null;
        }
        // 從restart中移除,由於立刻要執行啓動了
        if (mRestartingServices.remove(r)) {
            clearRestartingIfNeededLocked(r);
        }
        ...
        // 這中間是一些簡單的狀態判斷,有興趣能夠本身查看源碼

        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        String hostingType = "service";
        ProcessRecord app;
        if (!isolated) {
            // 進程存在那就直接走真正啓動service的邏輯了
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }
            }
        } else {
            // isolated進程處理,O上webview進程屬於這種類型,加以特殊處理,標記hostingType
            // hostingType主要用於啓動進程的時候
            app = r.isolatedProc;
            if (WebViewZygote.isMultiprocessEnabled()
                    && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                hostingType = "webview_service";
            }
        }

        // 進程不存在,那還得先啓動進程
        if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingType, r.name, false, isolated, false)) == null) {
                String msg = "Unable to launch app "
                        + r.appInfo.packageName + "/"
                        + r.appInfo.uid + " for service "
                        + r.intent.getIntent() + ": process is bad";
                Slog.w(TAG, msg);
                bringDownServiceLocked(r);
                return msg;
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }
        ...
        // 由於要啓動進程,因此須要記一下此次啓動進程的緣由是由於須要啓動這個service
        // 等到進程啓動成功以後,在進程attachApplicationLocked的時候會再去啓動這個serivice
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }
        return null;
    }

   

小結:

    若是service已經存在那麼直接調度sendServiceArgsLocked(將會執行service.onStartCommand)
    處理service重啓相關數據結構
    進程存在,則realStartServiceLocked
    進程不存在則先啓動進程並把service保存在mPendingServices

4.7 ActiveServices.realStartServiceLocked

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        // 這裏主要是計算設置service的timeout
        // 由於service的執行是計算在ANR機制中的,這裏就是開始計時
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        // 若是是前臺service須要更新並記錄當前前臺serivice的狀態
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        // 更新進程優先級
        mAm.updateOomAdjLocked();

        boolean created = false;
        try {
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            // 設置process的狀態爲start service
            // 這樣在更新進程優先級的時候會有對應的處理,其實就是會提高優先級
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            // 到APP的進程中了,執行IApplicationThread.scheduleCreateService
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            // 發現執行過程當中進程掛掉了,須要處理後事,主要是進程中一些狀態的清除
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            if (!created) {
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                }
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

        if (r.whitelistManager) {
            app.whitelistManager = true;
        }

        requestServiceBindingsLocked(r, execInFg);
        // 更新綁定的activity,這塊主要針對bindService
        updateServiceClientActivitiesLocked(app, null, true);
        // 若是須要執行service的start則加入到pendingStarts
        // r.startRequested在startServiceLocked就標記了
        // 且startServiceLocked時就已經加入到pendingStarts
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }
        // 這裏將會執行service.onStartCommand
        sendServiceArgsLocked(r, execInFg, true);
        ...
        // delay相關
    }

   

小結:

    開始計算service 「create」的ANR計時
    調用到app進程建立並執行service的onCreate
    sendServiceArgsLocked

4.8 ActiveServices.sendServiceArgsLocked

    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
        // startServiceLocked時已經加入到pendingStarts
        final int N = r.pendingStarts.size();
        if (N == 0) {
            return;
        }
        ArrayList<ServiceStartArgs> args = new ArrayList<>();
        while (r.pendingStarts.size() > 0) {
            ServiceRecord.StartItem si = r.pendingStarts.remove(0);
            if (si.intent == null && N > 1) {
                continue;
            }
            si.deliveredTime = SystemClock.uptimeMillis();
            r.deliveredStarts.add(si);
            si.deliveryCount++;
            if (si.neededGrants != null) {
                mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
                        si.getUriPermissionsLocked());
            }
            mAm.grantEphemeralAccessLocked(r.userId, si.intent,
                    r.appInfo.uid, UserHandle.getAppId(si.callingId));
            // 再次開始ANR的計時,不過此處計時是「start」
            bumpServiceExecutingLocked(r, execInFg, "start");
            if (!oomAdjusted) {
                oomAdjusted = true;
                mAm.updateOomAdjLocked(r.app, true);
            }
            //  O上開始,調用startForegroundService須要5s內調用startForeground
            // 若是調用startForegroundService就處於r.fgRequired
            // 此處是若是發現須要調用startForeground可是沒調,則認爲超時了
            if (r.fgRequired && !r.fgWaiting) {
                if (!r.isForeground) {
                    scheduleServiceForegroundTransitionTimeoutLocked(r);
                } else {
                    r.fgRequired = false;
                }
            }
            int flags = 0;
            if (si.deliveryCount > 1) {
                flags |= Service.START_FLAG_RETRY;
            }
            if (si.doneExecutingCount > 0) {
                flags |= Service.START_FLAG_REDELIVERY;
            }
            // 建立ServiceStartArgs
            args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
        }

        ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
        slice.setInlineCountLimit(4);
        Exception caughtException = null;
        try {
            // 調度到APP進程執行scheduleServiceArgs(將會執行service.onStartCommand)
            r.app.thread.scheduleServiceArgs(r, slice);
        } catch (TransactionTooLargeException e) {
            scheduleServiceArgs
            ...
        }
        // 若是發生了異常須要停掉service
        if (caughtException != null) {
            final boolean inDestroying = mDestroyingServices.contains(r);
            for (int i = 0; i < args.size(); i++) {
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            }
            if (caughtException instanceof TransactionTooLargeException) {
                throw (TransactionTooLargeException)caughtException;
            }
        }
    }

   

小結:

    開始service「start」的ANR計時
    建立ServiceStartArgs
    調度到app進程執行service的onStartCommand

4.9 ActivityThread.handleCreateService

    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);
    }
    
public void handleMessage(Message msg) {
switch (msg.what) {
    ...
    case CREATE_SERVICE:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
    handleCreateService((CreateServiceData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;
    ...
}    

    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) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }

        try {
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            // 建立application
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // 執行service attach
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            // 執行service的onCreate
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }
    


app進程中binder線程調度過來以後,發送消息到主線程執行handleCreateService,在handleCreateService中終於看到了咱們熟悉的onCreate了
處理完了service的生命週期,還要告訴ams,我處理完了,由於那邊還在進行service的ANR計時呢
4.10 ActivityThread.handleServiceArgs

    private void handleServiceArgs(ServiceArgsData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                if (data.args != null) {
                    data.args.setExtrasClassLoader(s.getClassLoader());
                    data.args.prepareToEnterProcess();
                }
                int res;
                if (!data.taskRemoved) {
                    // 執行service的onStartCommand方法
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                } else {
                    s.onTaskRemoved(data.args);
                    res = Service.START_TASK_REMOVED_COMPLETE;
                }
                // 這裏在前面講解SharedPreferences的時候有提到,是在等待sp的任務寫入完成
                QueuedWork.waitToFinish();
                try {
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
                ensureJitEnabled();
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to start service " + s
                            + " with " + data.args + ": " + e.toString(), e);
                }
            }
        }
    }

   

scheduleServiceArgs中一樣是發送消息到app主線程而後執行scheduleServiceArgs
scheduleServiceArgs中執行service.onStartCommand,而後告訴AMS執行完畢
4.11 ActivityManagerService.serviceDoneExecuting

    public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
                throw new IllegalArgumentException("Invalid service token");
            }
            // ActiveSercices.serviceDoneExecutingLocked
            mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
        }
    }

   

4.12 ActiveServices.serviceDoneExecutingLocked

    void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
        boolean inDestroying = mDestroyingServices.contains(r);
        if (r != null) {
            if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
                r.callStart = true;
                // 這裏的res是onStartCommand的返回值
                switch (res) {
                    case Service.START_STICKY_COMPATIBILITY:
                    case Service.START_STICKY: {
                        r.findDeliveredStart(startId, true);
                        r.stopIfKilled = false;
                        break;
                    }
                    case Service.START_NOT_STICKY: {
                        r.findDeliveredStart(startId, true);
                        if (r.getLastStartId() == startId) {
                            r.stopIfKilled = true;
                        }
                        break;
                    }
                    case Service.START_REDELIVER_INTENT: {
                        ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
                        if (si != null) {
                            si.deliveryCount = 0;
                            si.doneExecutingCount++;
                            r.stopIfKilled = true;
                        }
                        break;
                    }
                    case Service.START_TASK_REMOVED_COMPLETE: {
                        r.findDeliveredStart(startId, true);
                        break;
                    }
                    default:
                        throw new IllegalArgumentException(
                                "Unknown service start result: " + res);
                }
                if (res == Service.START_STICKY_COMPATIBILITY) {
                    r.callStart = false;
                }
            } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
                if (!inDestroying) {
                    if (r.app != null) {
                        Slog.w(TAG, "Service done with onDestroy, but not inDestroying: "
                                + r + ", app=" + r.app);
                    }
                } else if (r.executeNesting != 1) {
                    Slog.w(TAG, "Service done with onDestroy, but executeNesting="
                            + r.executeNesting + ": " + r);
                    r.executeNesting = 1;
                }
            }
            final long origId = Binder.clearCallingIdentity();
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            Binder.restoreCallingIdentity(origId);
        } else {
            Slog.w(TAG, "Done executing unknown service from pid "
                    + Binder.getCallingPid());
        }
    }

    

    其中的res處理:
    若是是START_STICKY_COMPATIBILITY或者START_STICKY那麼若是進程掛掉了,service依舊會重啓,不少app會利用這個進行保活。
    在其中的serviceDoneExecutingLocked會把前面的計時消息給remove掉,若是service的生命週期在規定時間內執行完畢,就不會ANR了。

總結

    startService過程當中若是進程不存在會建立進程     service不存在時默認狀況下會先執行service的onCreate,再執行service的onStartCommand     service存在時只會執行service的onStartCommand     service的onCreate和onStartCommand都會被ANR計時監控,規定時間內沒有處理完就會超時     onStartCommand處理以後還要等待sp寫入完畢纔會返回ams,因此不適合在onStartCommand中作大量的sp操做,即便是用的是apply異步進行     onStartCommand的返回值能夠控制service是否在進程被kill以後依舊重啓service

相關文章
相關標籤/搜索