死磕Android_Service啓動流程分析

我這裏將啓動Service流程分爲兩章來寫,startService和bindService分別分析.java

這篇文章是分析startService過程的源碼分析過程.其實startService和Activity的啓動很相似,好多地方都差很少.若是以前尚未看過或者不太理解Activity的啓動的同窗能夠看下個人這篇文章: 死磕Android_App 啓動過程(含 Activity 啓動過程).由於本篇文章和Activity 啓動過程有不少類似之處,建議能夠先看一看Activity啓動流程,食用更佳.app

Service主要是有2種方式進行啓動,這裏先將startService方式,使用方式以下:ide

Intent intent = new Intent(this,MyService.class);
startService(intent);
複製代碼

上面的這段代碼寫在Activity裏面的,讓咱們從startService方法進入吧源碼分析

進入startService,發現來到了ContextWrapper的內部.ui

@Override
public ComponentName startService(Intent service) {
    return mBase.startService(service);
}
複製代碼

主要是由於Activity繼承自ContextThemeWrapper,而ContextThemeWrapper又繼承自ContextWrapper.這裏的ContextWrapper實際上是一個Context.能夠看到方法中只有一句代碼....mBase是ContextWrapper裏面的一個Context類型的屬性.因此就來到了Context的startService方法.this

public abstract ComponentName startService(Intent service);
複製代碼

而Context的startService是一個抽象方法.我擦,,那麼這個mBase的實體究竟是什麼呢?startService的具體實現可全得看這個實體是什麼才行.爲了搞清楚這個實體究竟是什麼,因此咱們須要來到mBase賦值的地方.spa

public class ContextWrapper extends Context {
    Context mBase;

    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
}
複製代碼

嘿嘿,這是一個protected方法,咱們只須要找到其調用的地方便可. 這裏實際上是在Activity的attach方法裏面進行的調用.net

final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) {
        
    attachBaseContext(context);       
    ......
}
複製代碼

而後就把mBase賦值了.可是咱們看這個方法的入參context也是用Context代替的,咱們仍是不知道這個context具體是什麼....線程

因此咱們須要知道這個attach方法是在哪裏調用的,上次分析Activity啓動流程的時候分析過這裏.實際上是在ActivityThread裏面的performLaunchActivity方法裏面調用的.performLaunchActivity方法是啓動Activity的核心邏輯.rest

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    
    //構建ContextImpl
    ContextImpl appContext = createBaseContextForActivity(r);

    //實例化Activity
    Activity activity = null;
    java.lang.ClassLoader cl = appContext.getClassLoader();
    activity = mInstrumentation.newActivity(
            cl, component.getClassName(), r.intent);
    
    //調用Activity的attach方法,實例化一些東西
    activity.attach(appContext, this, getInstrumentation(), r.token,
            r.ident, app, r.intent, r.activityInfo, title, r.parent,
            r.embeddedID, r.lastNonConfigurationInstances, config,
            r.referrer, r.voiceInteractor, window, r.configCallback);
    return activity;
}
複製代碼

能夠看到attach方法傳入的context爲ContextImpl,可算找到你了.

那麼咱們繼續startService方法的探索,mBase就是ContextImpl,其內部的startService實現以下:

@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, false, mUser);
}

private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) {
        
    //ActivityManager.getService()是AMS
    ComponentName cn = ActivityManager.getService().startService(
        mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                    getContentResolver()), requireForeground,
                    getOpPackageName(), user.getIdentifier());
    return cn;
}

複製代碼

ActivityManager.getService()其實就是AMS,這裏在Activity啓動流程分析中已分析過這裏,這裏再也不贅述.那咱們來看看AMS的startService方法.

@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;
}
複製代碼

這裏的mServices是一個ActiveServices對象,是AMS裏面的一個屬性.ActiveServices類是輔助AMS管理Service的,包括Service的啓動、綁定和中止等.在ActiveServices類裏面的startServiceLocked方法會調用startServiceInnerLocked方法

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId) throws TransactionTooLargeException {
    .....
    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    return cmp;
}

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;
}
複製代碼

在startServiceInnerLocked方法裏面又會去調用bringUpServiceLocked方法

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired) throws TransactionTooLargeException {
    ......
    realStartServiceLocked(r, app, execInFg);
    return null;
}
複製代碼

終於,咱們在bringUpServiceLocked方法裏面看到了一個realStartServiceLocked方法.從這個方法名就能夠看出,真的要開始真實的調用開啓Service了,前面的都只是鋪墊.

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);
    boolean created = false;
    ......
    app.thread.scheduleCreateService(r, r.serviceInfo,
            mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
            app.repProcState);
    created = true;
    ......
}
複製代碼

app.thread是IApplicationThread,其實就是ApplicationThread(ActivityThread的內部類)的遠程調用,aidl. 下面是ApplicationThread的scheduleCreateService方法.

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);
}
複製代碼

又到了咱們熟悉的環節,這裏和Activity啓動時如出一轍,也是給H這個Handler類發送消息. 而後執行Service的啓動,看來源碼的道理都是一通百通呢..

在該Handler的handleMessage方法中CREATE_SERVICE消息就去調用handleCreateService()方法.這個方法是ActivityThread裏面的.

private void handleCreateService(CreateServiceData data) {
    //構建Service 利用反射取構建實例
    Service service = null;
    java.lang.ClassLoader cl = packageInfo.getClassLoader();
    service = packageInfo.getAppFactory()
            .instantiateService(cl, data.info.name, data.intent);
    
    //初始化ContextImpl
    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);

    Application app = packageInfo.makeApplication(false, mInstrumentation);
    //原來Service也須要這個ContextImpl
    service.attach(context, this, data.info.name, data.token, app,
            ActivityManager.getService());
    //接下來立刻就會調用Service的onCreate方法
    service.onCreate();
    
    //mServices是用來存儲已經啓動的Service的
    mServices.put(data.token, service);
    ....
}
複製代碼

handleCreateService方法就是Service啓動的核心代碼了,這個是在ActivityThread裏面發生的哦.這個方法首先是把Service實例給構建出來,而後調用Service的attach方法,初始化一些東西,而後就開始了Service的onCreate方法的調用.這裏須要注意的是Service的onCreate方法,還有其餘生命週期的方法都是運行在主線程的.

到此,Service的啓動流程就分析完了.

相關文章
相關標籤/搜索