欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ActivityManagerService之Service啟動過程解析

 更新時間:2023年03月02日 10:34:14   作者:大胃粥  
這篇文章主要為大家介紹了ActivityManagerService之Service啟動過程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

緣由

我曾經(jīng)任職于一家小公司,負(fù)責(zé)上層一切事務(wù),而公司為了給客戶(尤其是小客戶)提供開發(fā)的便利,會強(qiáng)行去掉一些限制,其中就包括啟動 Service 的限制。

本文來分析 Service 的整體啟動流程,順帶也會提一提 Service 啟動的一些限制。但是,讀者請務(wù)必自行了解 Service 的啟動方式,包括前臺 Service 的啟動,這些基本知識本文不會過多提及。

啟動 Service

Service 的啟動最終會調(diào)用如下方法

// ContextImpl.java
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
    try {
        // 從 Android 5.0 ,必須使用顯式 Intent 啟動 Service
        validateServiceIntent(service);
        service.prepareToLeaveProcess(this);
        // 通過 AMS 啟動 Service
        ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service,
                service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                getOpPackageName(), getAttributionTag(), user.getIdentifier());
        if (cn != null) {
            // ... 處理異常結(jié)果 ...
        }
        // 成功啟動后,返回已啟動的 Service 組件名
        return cn;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

Service 最終是通過 AMS 進(jìn)行啟動的,一旦啟動成功,會返回 Service 的組件名,通過這個返回結(jié)果,可以判斷 Service 是否啟動成功,這一點(diǎn)往往被很多開發(fā)者忽略。

AMS 最終會調(diào)用 ActiveService#startServiceLocked() 來啟動 Service

ActivityManagerService 把 Service 的所有事務(wù)都交給 ActiveServices 處理。

// ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, boolean fgRequired,
        String callingPackage, @Nullable String callingFeatureId, final int userId,
        boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
        throws TransactionTooLargeException {
    // 調(diào)用方是否處于前臺
    final boolean callerFg;
    if (caller != null) {
        final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller);
        if (callerApp == null) {
            throw new SecurityException(
                    "Unable to find app for caller " + caller
                    + " (pid=" + callingPid
                    + ") when starting service " + service);
        }
        callerFg = callerApp.mState.getSetSchedGroup() != ProcessList.SCHED_GROUP_BACKGROUND;
    } else {
        callerFg = true;
    }
    // 1. 查詢 Service
    // 其實這是是從緩存獲取 ServiceRecord,或者建立 ServiceRecord 并緩存
    ServiceLookupResult res =
        retrieveServiceLocked(service, null, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg, false, false);
    if (res == null) {
        return null;
    }
    if (res.record == null) {
        return new ComponentName("!", res.permission != null
                ? res.permission : "private to package");
    }
    // 從查詢的結(jié)果中獲取 Service 記錄
    ServiceRecord r = res.record;
    // 2. 對 Service 啟動施加限制
    // ...
    if (forcedStandby || (!r.startRequested && !fgRequired)) {
        // Service 所在的進(jìn)程處于后臺,是無法啟動 Service
        final int allowed = mAm.getAppStartModeLOSP(r.appInfo.uid, r.packageName,
                r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
        if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
            Slog.w(TAG, "Background start not allowed: service "
                    + service + " to " + r.shortInstanceName
                    + " from pid=" + callingPid + " uid=" + callingUid
                    + " pkg=" + callingPackage + " startFg?=" + fgRequired);
            // ...
            UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(r.appInfo.uid);
            return new ComponentName("?", "app is in background uid " + uidRec);
        }
    }
    // ...
    // 3. 進(jìn)入下一步 Service 啟動過程
    return startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
            allowBackgroundActivityStarts, backgroundActivityStartsToken);
}

首先為 Service 在服務(wù)端建立一個記錄 ServiceRecord 并緩存起來,這個過程比較簡單,讀者自行分析。

然后,在 Service 啟動之前,施加一些限制,代碼中展示了一段后臺 app 無法啟動 Service 的限制,但是也省略了其他限制的代碼,有興趣的讀者可以自行分析。

本文旨在分析 Service 的啟動流程,對于一些小細(xì)節(jié),限于篇幅原因,就不細(xì)致分析,請讀者自行研讀代碼。

最后進(jìn)入下一步的啟動的流程

Service 的啟動,會調(diào)用好幾個類似的函數(shù),但是每一個函數(shù)最做了一部分功能,這樣就可以把一個龐大的函數(shù)分割為幾個小的函數(shù),代碼閱讀性更高,我們要學(xué)習(xí)這種做法。

private ComponentName startServiceInnerLocked(ServiceRecord r, Intent service,
        int callingUid, int callingPid, boolean fgRequired, boolean callerFg,
        boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
        throws TransactionTooLargeException {
    // ...
    // 1. 更新 ServiceRecord 數(shù)據(jù)
    r.lastActivity = SystemClock.uptimeMillis();
    r.startRequested = true;
    r.delayedStop = false;
    r.fgRequired = fgRequired;
    // 保存即將發(fā)送給 Service 的參數(shù)
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
            service, neededGrants, callingUid));
    // 授予 app 啟動前臺 Service 的 app op 權(quán)限
    if (fgRequired) {
        // ...
    }
    // 下面一段,確定 addToStarting 的值
    final ServiceMap smap = getServiceMapLocked(r.userId);
    boolean addToStarting = false;
    // 注意這里的判斷條件
    // !callerFg 表示調(diào)用方不處于前臺
    // !fgRequired 表示啟動的是 非前臺Service
    // r.app == null 表示 Service 還沒有啟動過
    if (!callerFg && !fgRequired && r.app == null
            && mAm.mUserController.hasStartedUserState(r.userId)) {
        ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid);
        if (proc == null || proc.mState.getCurProcState() > PROCESS_STATE_RECEIVER) {
            // app 沒有創(chuàng)建,或者已經(jīng)創(chuàng)建,但是在后臺沒有運(yùn)行任何四大組件
            // ...
            // 延時Service不在這里啟動,直接返回
            if (r.delayed) {
                return r.name;
            }
            // 如果目前要啟動非前臺Service超時過了最大數(shù)量的,那么當(dāng)前這個Service,要設(shè)置為延時 Service
            // 而延時 Service 不在這里啟動,因此直接返回
            if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                // Something else is starting, delay!
                Slog.i(TAG_SERVICE, "Delaying start of: " + r);
                smap.mDelayedStartList.add(r);
                r.delayed = true;
                return r.name;
            }
            addToStarting = true;
        } else if (proc.mState.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) {
            // app 處于后臺,但是只運(yùn)行了 service 和 receiver
            addToStarting = true;
        }
    }
    // allowBackgroundActivityStarts 目前為 false
    if (allowBackgroundActivityStarts) {
        r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken);
    }
    // 2. 繼續(xù)下一階段的啟動流程
    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    return cmp;
}

現(xiàn)在沒有 Service 的啟動限制了,是時候正式啟動了,首先更新 ServiceRecord 數(shù)據(jù),這里要注意,使用 ServiceRecord#pendingStarts 保存了要發(fā)送給 Service 的參數(shù)。

接下來有一段關(guān)于延時 Service 以及監(jiān)聽 后臺Service 相關(guān)的代碼,這是為了優(yōu)化 Service 啟動過多的情況,而做出的一個優(yōu)化。對于系統(tǒng)優(yōu)化的開發(fā)者,你可能要重點(diǎn)關(guān)注一下,本文先不管這個優(yōu)化功能。

然后繼續(xù)看下一步的啟動流程

// ActiveServices.java
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
    synchronized (mAm.mProcessStats.mLock) {
        final ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
        }
    }
    // 是否調(diào)用 onStart()
    r.callStart = false;
    final int uid = r.appInfo.uid;
    final String packageName = r.name.getPackageName();
    final String serviceName = r.name.getClassName();
    FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, uid, packageName,
            serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__START);
    mAm.mBatteryStatsService.noteServiceStartRunning(uid, packageName, serviceName);
    // 1. 拉起 Service
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg,
            false /* whileRestarting */,
            false /* permissionsReviewRequired */,
            false /* packageFrozen */,
            true /* enqueueOomAdj */);
    /* Will be a no-op if nothing pending */
    mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
    if (error != null) {
        return new ComponentName("!!", error);
    }
    // 優(yōu)化后臺Service啟動過多的情況
    if (r.startRequested && addToStarting) {
        boolean first = smap.mStartingBackground.size() == 0;
        smap.mStartingBackground.add(r);
        // 設(shè)置一個超時時間
        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() 拉起 Service

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
        boolean enqueueOomAdj)
        throws TransactionTooLargeException {
    // 1. 如果 Service 已經(jīng)啟動過一次,直接發(fā)送發(fā)送參數(shù)給 Service 即可
    // 因為只有 Service 啟動過,r.app 才不為 null
    if (r.app != null && r.app.getThread() != null) {
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }
    // ...
    final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
    final String procName = r.processName;
    HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
    ProcessRecord app;
    if (!isolated) {
        // 1. Service 進(jìn)程存在,但是 Service 還沒有啟動過,那么通知宿主進(jìn)程啟動 Service
        // 由于前面已經(jīng)判斷過 r.app 不為 null 的情況,所以這里處理的就是 Service 沒有啟動過的情況
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);
        if (app != null) { // 進(jìn)程粗在
            final IApplicationThread thread = app.getThread();
            final int pid = app.getPid();
            final UidRecord uidRecord = app.getUidRecord();
            if (thread != null) { // attach application 已經(jīng)完成
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode,
                            mAm.mProcessStats);
                    realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,
                            enqueueOomAdj);
                    return null;
                } 
                // ...
            }
        }
    } else {
        // ...
    }
    // 3. Service 所在的進(jìn)程沒有運(yùn)行,那么要 fork 一個進(jìn)程
    if (app == null && !permissionsReviewRequired && !packageFrozen) {
        // TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service
        //  was initiated from a notification tap or not.
        if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated)) == 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, enqueueOomAdj);
            return msg;
        }
        if (isolated) {
            r.isolatedProc = app;
        }
    }
    // 對于前臺 Service 的 app, 暫時添加到省電模式白名單中
    if (r.fgRequired) {
        mAm.tempAllowlistUidLocked(r.appInfo.uid,
                SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH,
                "fg-service-launch",
                TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
                r.mRecentCallingUid);
    }
    // 3.1 mPendingServices 保存正在等待進(jìn)程起來的 Service
    // 進(jìn)程起來后,執(zhí)行 attach application 過程時,會自動啟動這個 Service
    if (!mPendingServices.contains(r)) {
        mPendingServices.add(r);
    }
    if (r.delayedStop) {
        // ...
    }
    return null;
}

拉起一個 Service 要分好幾種情況

  • 如果 Service 已經(jīng)啟動過,那么直接發(fā)送參數(shù)給 Service 去執(zhí)行任務(wù)即可。這是最簡單的一種情況。
  • 如果 Service 沒有啟動過,但是 Service 的宿主進(jìn)程是存在的,那么通知宿主進(jìn)程創(chuàng)建 Service,然后發(fā)送參數(shù)給它。
  • 如果 Service 的宿主進(jìn)程不存在,那么得先 fork 一個進(jìn)程,然后用 mPendingServices 保存這個等待進(jìn)程啟動的 Service。當(dāng)進(jìn)程起來后,在執(zhí)行 attach application 的過程中,AMS 會自動完成 Service 的啟動流程。

第3種情況,明顯是包含前面兩種情況,因此下面直接分析這個過程。

宿主進(jìn)程的啟動

Service 的宿主進(jìn)程起來后,在執(zhí)行 attach application 的過程中,AMS 會自動啟動那些等待進(jìn)程起來的 Service,如下

    private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
        // ...
        try {
            // ...
            // 進(jìn)程初始化
            if (app.getIsolatedEntryPoint() != null) {
                // This is an isolated process which should just call an entry point instead of
                // being bound to an application.
                thread.runIsolatedEntryPoint(
                        app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
            } else if (instr2 != null) {
                thread.bindApplication(processName, appInfo, providerList,
                        instr2.mClass,
                        profilerInfo, instr2.mArguments,
                        instr2.mWatcher,
                        instr2.mUiAutomationConnection, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                        new Configuration(app.getWindowProcessController().getConfiguration()),
                        app.getCompat(), getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, autofillOptions, contentCaptureOptions,
                        app.getDisabledCompatChanges(), serializedSystemFontMap);
            } else {
                thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                        new Configuration(app.getWindowProcessController().getConfiguration()),
                        app.getCompat(), getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, autofillOptions, contentCaptureOptions,
                        app.getDisabledCompatChanges(), serializedSystemFontMap);
            }
            // ...
        } catch (Exception e) {
            // ...
            return false;
        }
        // ...
        if (!badApp) {
            try {
                // 啟動等待進(jìn)程的 Service
                didSomething |= mServices.attachApplicationLocked(app, processName);
                checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
            }
        }
        // ...
        return true;
    }

最終調(diào)用 ActiveServices#attachApplicationLocked() 完成 Service 的啟動

// ActiveServices.java
boolean attachApplicationLocked(ProcessRecord proc, String processName)
        throws RemoteException {
    boolean didSomething = false;
    // mPendingServices 保存的就是那些等待進(jìn)程起來的 Service
    if (mPendingServices.size() > 0) {
        ServiceRecord sr = null;
        try {
            // 遍歷 mPendingServices ,啟動屬于該進(jìn)程的所有 Service
            for (int i=0; i<mPendingServices.size(); i++) {
                sr = mPendingServices.get(i);
                // 過濾掉不屬于這個進(jìn)程的 Service
                if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                        || !processName.equals(sr.processName))) {
                    continue;
                }
                final IApplicationThread thread = proc.getThread();
                final int pid = proc.getPid();
                final UidRecord uidRecord = proc.getUidRecord();
                mPendingServices.remove(i);
                i--;
                proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
                        mAm.mProcessStats);
                // 啟動 Service
                realStartServiceLocked(sr, proc, thread, pid, uidRecord, sr.createdFromFg,
                        true);
                didSomething = true;
                if (!isServiceNeededLocked(sr, false, false)) {
                    bringDownServiceLocked(sr, true);
                }
                mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
            }
        } catch (RemoteException e) {
            // ...
        }
    }
    // 處理進(jìn)程重啟而需要重啟的 Service
    if (mRestartingServices.size() > 0) {
        // ...
    }
    return didSomething;
}

終于,我們看到了我們想看到的東西,先從 mPendingServices 中過濾掉不屬于進(jìn)程的 Service,然后啟動它

// ActiveServices.java
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
        IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
        boolean enqueueOomAdj) throws RemoteException {
    // ...
    // 注意,r.app 的值才不為 null,也就是 ServiceRecord#app 不為 null
    // 因此可以通過 r.app 判斷 Service 是否已經(jīng)啟動過
    r.setProcess(app, thread, pid, uidRecord);
    r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
    final ProcessServiceRecord psr = app.mServices;
    final boolean newService = psr.startService(r);
    // 注意,這里實現(xiàn)了 Service 超時的功能
    bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */);
    mAm.updateLruProcessLocked(app, false, null);
    updateServiceForegroundLocked(psr, /* oomAdj= */ false);
    // Force an immediate oomAdjUpdate, so the client app could be in the correct process state
    // before doing any service related transactions
    mAm.enqueueOomAdjTargetLocked(app);
    mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
    boolean created = false;
    try {
        // ...
        // 1. 通知宿主進(jìn)程創(chuàng)建Service
        thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                app.mState.getReportedProcState());
        r.postNotification();
        created = true;
        // ...
    } catch (DeadObjectException e) {
        // ...
    } finally {
        if (!created) {
            // ...
        }
    }
    // ...
    // 2. 發(fā)送參數(shù)給 Service
    sendServiceArgsLocked(r, execInFg, true);
    if (r.delayed) {
        // ...
    }
    if (r.delayedStop) {
        // ...
    }
}

現(xiàn)在,正式與宿主進(jìn)程交互來啟動 Service

  • 首先通過 IApplicationThread#scheduleCreateService() 來通知宿主進(jìn)程創(chuàng)建 Service。
  • 然后通過 IApplicationThread#scheduleServiceArgs() 把參數(shù)發(fā)送給宿主進(jìn)程,宿主進(jìn)程會把參數(shù)發(fā)送給 Service 執(zhí)行任務(wù)。

宿主進(jìn)程創(chuàng)建 Service

宿主進(jìn)程接收到創(chuàng)建 Service 的指令后,會通過 Handler 發(fā)送一個消息,最終調(diào)用如下方法

// ActivityThread.java
private void handleCreateService(CreateServiceData data) {
    unscheduleGcIdler();
    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        // 創(chuàng)建 Application,并調(diào)用 Application#onCreate()
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        final java.lang.ClassLoader cl;
        if (data.info.splitName != null) {
            cl = packageInfo.getSplitClassLoader(data.info.splitName);
        } else {
            cl = packageInfo.getClassLoader();
        }
        // 創(chuàng)建 Service
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);
        ContextImpl context = ContextImpl.getImpl(service
                .createServiceBaseContext(this, packageInfo));
        if (data.info.splitName != null) {
            context = (ContextImpl) context.createContextForSplit(data.info.splitName);
        }
        if (data.info.attributionTags != null &amp;&amp; data.info.attributionTags.length &gt; 0) {
            final String attributionTag = data.info.attributionTags[0];
            context = (ContextImpl) context.createAttributionContext(attributionTag);
        }
        context.getResources().addLoaders(
                app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
        context.setOuterContext(service);
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        // 執(zhí)行 Service#onCreate()
        service.onCreate();
        mServicesData.put(data.token, data);
        mServices.put(data.token, service);
        // 通知服務(wù)端Service創(chuàng)建成功
        try {
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } catch (Exception e) {
        // ...
    }
}

宿主繼承會先創(chuàng)建 Application,并執(zhí)行 Application#onCreate(),然后創(chuàng)建 Service,并執(zhí)行 Service#onCreate(),最后通知服務(wù)端 Service 創(chuàng)建成功。這一套流程,簡直行云流水。

Service 接收參數(shù)

宿主進(jìn)程接收到服務(wù)端發(fā)送過來的 Service 啟動參數(shù)后,最終調(diào)用如下方法

// ActivityThread.java
private void handleServiceArgs(ServiceArgsData data) {
    CreateServiceData createData = mServicesData.get(data.token);
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            if (data.args != null) {
                data.args.setExtrasClassLoader(s.getClassLoader());
                data.args.prepareToEnterProcess(isProtectedComponent(createData.info),
                        s.getAttributionSource());
            }
            int res;
            if (!data.taskRemoved) {
                // 調(diào)用 Service#onStartCommand() 接收參數(shù),并執(zhí)行任務(wù)
                // 注意,這里是在主線程
                res = s.onStartCommand(data.args, data.flags, data.startId);
            } else {
                s.onTaskRemoved(data.args);
                res = Service.START_TASK_REMOVED_COMPLETE;
            }
            QueuedWork.waitToFinish();
            try {
                // 把 Service#onStartCommand() 的執(zhí)行結(jié)果反饋給服務(wù)端
                // 因為這個結(jié)果影響到 Service 重啟的方式
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            // ...
        }
    }
}

當(dāng)宿主進(jìn)程收到 Service 的啟動參數(shù)后,調(diào)用 Service#onStartCommand() 接收參數(shù),并執(zhí)行任務(wù)。

注意,Service#onStartCommand() 是在主線程中執(zhí)行,其實四大組件的生命周期都是在主線程中執(zhí)行的,這一點(diǎn)大家要牢記。

然后把 Service#onStartCommand() 的返回結(jié)果返回給服務(wù)端。這個方法的返回結(jié)果很重要,它影響了 Service 重啟的方式。這里簡單展示下結(jié)果的處理流程

// ActiveServices.java
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res,
        boolean enqueueOomAdj) {
    boolean inDestroying = mDestroyingServices.contains(r);
    if (r != null) {
        if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
            // 注意了,ServiceRecord#callStart , 是在 Service 執(zhí)行完 onStartCommand() 并反饋結(jié)果后,才設(shè)置為 true
            r.callStart = true;
            switch (res) {
                case Service.START_STICKY_COMPATIBILITY:
                // Service 會重啟,但是不會收到原來的啟動參數(shù)
                case Service.START_STICKY: {
                    // 注意最后一個參數(shù)為 true
                    // 它表示從已發(fā)送的參數(shù) Service#deliveredStarts 中移除此次執(zhí)行的參數(shù)
                    // 因為Service重啟時,不需要這個參數(shù)
                    r.findDeliveredStart(startId, false, true);
                    // Don't stop if killed.
                    r.stopIfKilled = false;
                    break;
                }
                case Service.START_NOT_STICKY: {
                    // ...
                    break;
                }
                // Service 會重啟,并且也會收到原來的啟動參數(shù)
                case Service.START_REDELIVER_INTENT: {
                    // 注意最后一個參數(shù) true
                    // 它表示不需要從已發(fā)送的參數(shù) Service#deliveredStarts 中移除此次執(zhí)行的參數(shù)
                    // 因此Service重啟時,需要這個參數(shù)
                    ServiceRecord.StartItem si = r.findDeliveredStart(startId, false, false);
                    if (si != null) {
                        si.deliveryCount = 0;
                        si.doneExecutingCount++;
                        // Don't stop if killed.
                        r.stopIfKilled = true;
                    }
                    break;
                }
                // ...
            }
            if (res == Service.START_STICKY_COMPATIBILITY) {
                r.callStart = false;
            }
        } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
            // ...
        }
        final long origId = Binder.clearCallingIdentity();
        // 主要更新 oom ajd
        serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj);
        Binder.restoreCallingIdentity(origId);
    }
}

這里就涉及到 Service 的基本功,上面展示了兩個返回值的處理過程,這兩個返回值都表示,由于內(nèi)存不足而殺掉的 Service,當(dāng)內(nèi)存充足時,會重啟 Service,但是一個返回值需要再次發(fā)送之前的啟動參數(shù),而另外一個返回值不需要。

對于需要發(fā)送參數(shù)的返回值,不需要從 Service#deliveredStart 列表中刪除已經(jīng)發(fā)送的參數(shù),因為 Service 重啟時,需要發(fā)送它。相反,就需要從列表中刪除已經(jīng)發(fā)送的參數(shù),因為 Service 重啟不再需要它了。

結(jié)束

本文完整了分析了 Service 的啟動流程,這個是最基本的,并且需要掌握的。

本文還順帶提了一下 Service 啟動的限制,對于一個專業(yè)的開發(fā)者來說,遵守這些限制即可,但是對于系統(tǒng)開發(fā)者來說,你可能想 去掉/修改/增加 一些限制,那么你得自己研究下。

其實本文還遺留了一個很值得探討的話題,那就是優(yōu)化大量Service啟動,對于系統(tǒng)優(yōu)化的開發(fā)者來說,應(yīng)該是必須要掌握的,后面如果有興趣了,也有時間了,我會補(bǔ)一篇文章,更多關(guān)于ActivityManagerService Service啟動的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Flutter?異步編程之單線程下異步模型圖文示例詳解

    Flutter?異步編程之單線程下異步模型圖文示例詳解

    這篇文章主要為大家介紹了Flutter?異步編程之單線程下異步模型圖文示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • android控制密碼顯示與隱藏的方法

    android控制密碼顯示與隱藏的方法

    這篇文章主要為大家詳細(xì)介紹了android控制密碼顯示與隱藏的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Android調(diào)用攝像頭拍照開發(fā)教程

    Android調(diào)用攝像頭拍照開發(fā)教程

    這篇文章主要為大家詳細(xì)介紹了Android調(diào)用攝像頭拍照的開發(fā)教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • Android性能優(yōu)化全局異常處理詳情

    Android性能優(yōu)化全局異常處理詳情

    這篇文章主要介紹了Android性能優(yōu)化全局異常處理詳情,文章圍繞主題展開詳細(xì)的內(nèi)容協(xié)商,具有一定的參考價值,感興趣的小伙伴可以參考一下
    2022-08-08
  • Android 使用Vibrator服務(wù)實現(xiàn)點(diǎn)擊按鈕帶有震動效果

    Android 使用Vibrator服務(wù)實現(xiàn)點(diǎn)擊按鈕帶有震動效果

    這篇文章主要介紹了Android 使用Vibrator服務(wù)實現(xiàn)點(diǎn)擊按鈕帶有震動效果,,本文通過實例圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)火鍋工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • Android實現(xiàn)底部導(dǎo)航欄功能

    Android實現(xiàn)底部導(dǎo)航欄功能

    這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)底部導(dǎo)航欄功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Android使用xUtils3.0實現(xiàn)文件上傳

    Android使用xUtils3.0實現(xiàn)文件上傳

    這篇文章主要為大家詳細(xì)介紹了Android使用xUtils3.0實現(xiàn)文件上傳的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • android實現(xiàn)接通和掛斷電話

    android實現(xiàn)接通和掛斷電話

    這篇文章主要為大家詳細(xì)介紹了android實現(xiàn)接通和掛斷電話功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • android studio實現(xiàn)簡單的計算器(無bug)

    android studio實現(xiàn)簡單的計算器(無bug)

    這篇文章主要為大家詳細(xì)介紹了android studio實現(xiàn)簡單計算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • Android App開發(fā)中使用RecyclerView替代ListView的實踐

    Android App開發(fā)中使用RecyclerView替代ListView的實踐

    RecyclerView是Android L即5.0版本以來新加入的一個組件,主要用來實現(xiàn)item的瀑布式排列,因而被人們廣泛認(rèn)為用來替代ListView,這里我們就來看一下Android App開發(fā)中使用RecyclerView替代ListView的實踐:
    2016-06-06

最新評論