Android啟動之Service啟動流程

前言

Service啟動與上一篇說的入口Activity啟動類似,主要分成ContextImpl到ActivityManagerService調(diào)用和ActivityThread啟動Service這兩個過程

ContextImpl到AMS的調(diào)用過程

這個過程比較簡單,如圖所示

image.png

啟動Service肯定是從startService開始,這個方法是在ContextWrapper中實現(xiàn)的,在這個方法中調(diào)用了ContextImpl的startService方法。

在ContextImpl中經(jīng)過startServiceCommon,最終通過IActivityManager的startService方法來通知AMS啟動一個Service。

ActivityThread啟動Service

這部分過程如圖:

image.png

上一個過程最終是調(diào)用了AMS的startService方法,這個過程就是從這開始的,這里會調(diào)用ActiveService的startServiceLocked,代碼如下:

ComponentName startServiceLocked(...) throws TransactionTooLargeException {
        
    ...

    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg, false);  //1
    if (res == null) {
        return null;
    }
    if (res.record == null) {
        return new ComponentName("!", res.permission != null
                ? res.permission : "private to package");
    }

    ServiceRecord r = res.record;  //1

    ...

    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    return cmp;
}

代碼1處通過retrieveServiceLocked方法會先查找參數(shù)service對應(yīng)的ServiceRecord;如果沒有回調(diào)用PackageManagerService取獲取參數(shù)service對應(yīng)的Service信息并封裝到ServiceRecord。最后將ServiceRecord封裝成ServiceLookupResult返回??梢钥吹竭@里與上一篇講的Activity很類似,ServiceRecord就像ActivityRecord一樣用來描述一個Service。

代碼2就是從ServiceLookupResult取出ServiceRecord,然后調(diào)用startServiceInnerLocked。

startServiceInnerLocked方法會調(diào)用bringUpServiceLocked方法,這個方法代碼如下:

private String bringUpServiceLocked(...) throws TransactionTooLargeException {
        
    ...

    final String procName = r.processName;  //1
    String hostingType = "service";
    ProcessRecord app;

    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); //2

        ...

        if (app != null && app.thread != null) { //3
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                realStartServiceLocked(r, app, execInFg); //4
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting service " + r.shortName, e);
            }

        }
    } else {          
        ...
    }

    if (app == null && !permissionsReviewRequired) { //5
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,  //6
                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;
        }
    }

    ...

    return null;
}

代碼1得到進程名稱。代碼2調(diào)用AMS的getProcessRecordLocked查詢與該Service對應(yīng)的ProcessRecord,ProcessRecord一看名字就應(yīng)該能猜出來了,主要是描述運行的應(yīng)用程序進程信息。所以代碼2的目的就是獲取該Service對應(yīng)的應(yīng)用程序進程。

代碼3處判斷如果應(yīng)用程序進程存在,則執(zhí)行代碼4,通過realStartServiceLocked方法來啟動Service。

如果不存在就會跳到代碼5,再次判斷不存在則在代碼6處調(diào)用AMS的startProcessLocked來創(chuàng)建對應(yīng)的應(yīng)用程序信息。

在realStartServiceLocked方法中調(diào)用了IApplicationThread的scheduleCreateService方法,它的實現(xiàn)是ActivityThread內(nèi)部類ApplicatioinThread,這塊跟Activity啟動幾乎一樣。

scheduleCreateService將service的啟動參數(shù)封裝后通過Handler進行通知。最終會在ActivityThread處理,處理方法是handleCreateService,代碼如下:

private void handleCreateService(CreateServiceData data) {
    unscheduleGcIdler();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);  //1
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();  //2
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);  //3
    } 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,
                ActivityManager.getService());  //5
        service.onCreate();  //6
        mServices.put(data.token, service);  //7
        ...
    } catch (Exception e) {
        ...
    }
}

代碼2會獲取類加載器,然后代碼3從之前封裝的對象中獲取Service信息,創(chuàng)建service;代碼4獲取上下文;代碼5通過service的attach方法來初始化service;代碼6則調(diào)用了service的onCreate方法;代碼7將service加入ActivithThread的成員變量mServices中,以便后續(xù)使用。

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

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

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