1. 程式人生 > >startService啟動流程---Service在App程序但未啟動

startService啟動流程---Service在App程序但未啟動

Service啟動流程(startService)的最後,分析了在呼叫startService時可能存在的三種情況,本文分析第二種情況—Service與App在同一個程序,但未啟動。

Service啟動流程(startService)最後已經說明,在這種情況下,系統會執行realStartServiceLocked函式。

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

    app.services.add(r);
    bumpServiceExecutingLocked(r, "create");
    updateLruProcessLocked(app, true, true);

    boolean created = false;
    try {
        ......
        //跨程序去執行Service例項的建立
        app.thread.scheduleCreateService(r, r.serviceInfo,
                compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo));
        r.postNotification();
        created = true;
    } finally {
        if (!created) {
            app.services.remove(r);
            scheduleServiceRestartLocked(r, false);
        }
    }

    ......
    //Service建立完成後,執行onStartCommand函式
    sendServiceArgsLocked(r, true);
}  

函式的邏輯還是比較清晰的,完成的工作主要有兩個:

  • 建立Service例項
  • 執行onStartCommand方法

接下來就來看下這兩個任務時如何完成的。

建立Service例項是一個Binder跨程序呼叫,Binder細節就不分析,直接進入ActivityThread檢視scheduleCreateService的實現

public final void scheduleCreateService(IBinder token,
            ServiceInfo info, CompatibilityInfo compatInfo) {
        CreateServiceData s = new CreateServiceData();
        s.token = token;
        s.info = info;
        s.compatInfo = compatInfo;

        queueOrSendMessage(H.CREATE_SERVICE, s);
    }  

好吧,queueOrSendMessage這個函式我們在ActivityThread中已經看到過很多次呼叫很多次了,我們直接進入到真正執行建立Service例項的函式queueOrSendMessage

private void handleCreateService(CreateServiceData data) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    ......
    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        //反射建立Service例項
        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 = new ContextImpl();
        context.init(packageInfo, null, this);

        Application app = packageInfo.makeApplication(false, mInstrumentation);
        context.setOuterContext(service);
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManagerNative.getDefault());
         //執行Service onCreate方法
        service.onCreate();
        mServices.put(data.token, service);
        try {
            //通知ActivityManagerService例項建立完成
            ActivityManagerNative.getDefault().serviceDoneExecuting(
                    data.token, 0, 0, 0);
        } catch (RemoteException e) {
            // nothing to do.
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to create service " + data.info.name
                + ": " + e.toString(), e);
        }
    }
}

函式的程式碼不短也不長,還是比較好理解的。首先獲取Service的資訊,然後呼叫反射建立Service例項(想想Activity例項的建立,是不是也是反射?),建立完例項後就會去執行attach方法,執行完attach方法後就會去執行onCreate方法(想想Activity,是不是也是先執行attach在執行onCreate?),執行完onCreate方法後,通知ActivityManagerService。

執行完Service例項的建立,接下來執行onStartCommand的流程就是 startService啟動流程—Service已經啟動中描述的流程,我就不再分析了。