Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Service的啟動過程

Android Service的啟動過程

編輯:關於Android編程

剛開始學習Service的時候以為它是一個線程的封裝,也可以執行耗時操作。其實不然,Service是運行在主線程的。直接執行耗時操作是會阻塞主線程的。長時間就直接ANR了。

我們知道Service可以執行一些後台任務,是後台任務不是耗時的任務,後台和耗時是有區別的喔。
這樣就很容易想到音樂播放器,天氣預報這些應用是要用到Service的。當然如果要在Service中執行耗時操作的話,開個線程就可以了。

關於Service的運行狀態有兩種,啟動狀態和綁定狀態,兩種狀態可以一起。
啟動一個Service只需調用Context的startService方法,傳進一個Intent即可。看起來好像很簡單的說,那是因為Android為了方便開發者,做了很大程度的封裝。那麼你真的有去學習過Service是怎麼啟動的嗎?Service的onCreate方法回調前都做了哪些准備工作?

先上一張圖大致了解下,灰色背景框起來的是同一個類中的方法,如下圖:
Service啟動過程

那接下來就從源碼的角度來分析Service的啟動過程。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPrWxyLvKx7TTQ29udGV4dLXEc3RhcnRTZXJ2aWNlt723qL+qyryjrENvbnRleHS1xMq1z9bA4MrHQ29udGV4dEltcGyjrMTHw7TO0sPHvs2/tLW9Q29udGV4dEltcGy1xHN0YXJ0U2VydmljZbe9t6i8tL/Jo6zI58/Co7o8L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;"> @Override public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, mUser); }

會轉到startServiceCommon方法,那跟進startServiceCommon方法方法瞧瞧。

private ComponentName startServiceCommon(Intent service, UserHandle user) {
    try {
        validateServiceIntent(service);
        service.prepareToLeaveProcess();
        ComponentName cn = ActivityManagerNative.getDefault().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), getOpPackageName(), user.getIdentifier());

    //代碼省略

        return cn;
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}

可以看到調用了ActivityManagerNative.getDefault()的startService方法來啟動Service,ActivityManagerNative.getDefault()是ActivityManagerService,簡稱AMS。

那麼現在啟動Service的過程就轉移到了ActivityManagerService,我們關注ActivityManagerService的startService方法即可,如下:

@Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, String callingPackage, int userId)
        throws TransactionTooLargeException {

     //代碼省略

    synchronized(this) {
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        ComponentName res = mServices.startServiceLocked(caller, service,
                resolvedType, callingPid, callingUid, callingPackage, userId);
        Binder.restoreCallingIdentity(origId);
        return res;
    }
}

在上述的代碼中,調用了ActiveServices的startServiceLocked方法,那麼現在Service的啟動過程從AMS轉移到了ActiveServices了。

繼續跟進ActiveServices的startServiceLocked方法,如下:

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, String callingPackage, int userId)
        throws TransactionTooLargeException {

    //代碼省略

    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg);

    //代碼省略


    ServiceRecord r = res.record;

    //代碼省略

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

在startServiceLocked方法中又會調用startServiceInnerLocked方法,

我們瞧瞧startServiceInnerLocked方法,

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
    ProcessStats.ServiceState stracker = r.getTracker();
    if (stracker != null) {
        stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
    }
    r.callStart = false;
    synchronized (r.stats.getBatteryStats()) {
        r.stats.startRunningLocked();
    }
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);

    //代碼省略

    return r.name;
}

startServiceInnerLocked方法內部調用了bringUpServiceLocked方法,此時啟動過程已經快要離開ActiveServices了。繼續看到bringUpServiceLocked方法。如下:

private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting) throws TransactionTooLargeException {

        //代碼省略

        if (app != null && app.thread != null) {
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                realStartServiceLocked(r, app, execInFg);
                return null;
            } 

       //代碼省略

       return null;
}

省略了大部分if判斷,相信眼尖的你一定發現了核心的方法,那就是
realStartServiceLocked,沒錯,看名字就像是真正啟動Service。那麼事不宜遲跟進去探探吧。如下:

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {

    //代碼省略

    boolean created = false;
    try {

       //代碼省略
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
        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;
    } 

    //代碼省略

    sendServiceArgsLocked(r, execInFg, true);

    //代碼省略

}

找到了。app.thread調用了scheduleCreateService來啟動Service,而app.thread是一個ApplicationThread,也是ActivityThread的內部類。此時已經到了主線程。
那麼我們探探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);
}

對待啟動的Service組件信息進行包裝,然後發送了一個消息。我們關注這個CREATE_SERVICE消息即可。

public void handleMessage(Message msg) {

        //代碼省略

        case CREATE_SERVICE:
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
            handleCreateService((CreateServiceData)msg.obj);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            break;

        //代碼省略

}

在handleMessage方法中接收到這個消息,然後調用了handleCreateService方法,跟進handleCreateService探探究竟:

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.
    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 {
        if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service);

        Application app = packageInfo.makeApplication(false, mInstrumentation);
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManagerNative.getDefault());
        service.onCreate();
        mServices.put(data.token, service);
        try {
            ActivityManagerNative.getDefault().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 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);
        }
    }
}

終於擊破,這個方法很核心的。一點點分析

首先獲取到一個LoadedApk對象,在通過這個LoadedApk對象獲取到一個類加載器,通過這個類加載器來創建Service。如下:

java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();

接著調用ContextImpl的createAppContext方法創建了一個ContextImpl對象。

之後再調用LoadedApk的makeApplication方法來創建Application,這個創建過程如下:

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }

    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            initializeJavaContextClassLoader();
        }
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + ": " + e.toString(), e);
        }
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    if (instrumentation != null) {
        try {
            instrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!instrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to create application " + app.getClass().getName()
                    + ": " + e.toString(), e);
            }
        }
    }

    // Rewrite the R 'constants' for all library apks.
    SparseArray packageIdentifiers = getAssets(mActivityThread)
            .getAssignedPackageIdentifiers();
    final int N = packageIdentifiers.size();
    for (int i = 0; i < N; i++) {
        final int id = packageIdentifiers.keyAt(i);
        if (id == 0x01 || id == 0x7f) {
            continue;
        }

        rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
    }

    return app;
}

當然Application是只有一個的,從上述代碼中也可以看出。

在回來繼續看handleCreateService方法,之後service調用了attach方法關聯了ContextImpl和Application等

最後service回調了onCreate方法,

service.onCreate();
mServices.put(data.token, service);

並將這個service添加進了一個了列表進行管理。

至此service啟動了起來,以上就是service的啟動過程。

你可能還想要知道onStartCommand方法是怎麼被回調的?可能細心的你發現了在ActiveServices的realStartServiceLocked方法中,那裡還有一個sendServiceArgsLocked方法。是的,那個就是入口。

那麼我們跟進sendServiceArgsLocked方法看看onStartCommand方法是怎麼回調的。

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
        boolean oomAdjusted) throws TransactionTooLargeException {
    final int N = r.pendingStarts.size();

        //代碼省略

        try {

        //代碼省略

            r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
        } catch (TransactionTooLargeException e) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large: intent="
                    + si.intent);
            caughtException = e;
        } catch (RemoteException e) {
            // Remote process gone...  we'll let the normal cleanup take care of this.
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);
            caughtException = e;
        } 

        //代碼省略
}

可以看到onStartCommand方法回調過程和onCreate方法的是很相似的,都會轉到app.thread。那麼現在就跟進ApplicationThread的scheduleServiceArgs。
你也可能猜到了應該又是封裝一些Service的信息,然後發送一個消息, handleMessage接收。是的,源碼如下:

public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
    int flags ,Intent args) {
    ServiceArgsData s = new ServiceArgsData();
    s.token = token;
    s.taskRemoved = taskRemoved;
    s.startId = startId;
    s.flags = flags;
    s.args = args;

    sendMessage(H.SERVICE_ARGS, s);
}
public void handleMessage(Message msg) {

        //代碼省略

        case SERVICE_ARGS:
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
            handleServiceArgs((ServiceArgsData)msg.obj);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            break;

        //代碼省略
}

咦,真的是這樣。謎底應該就在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) {
                res = s.onStartCommand(data.args, data.flags, data.startId);
            } else {
                s.onTaskRemoved(data.args);
                res = Service.START_TASK_REMOVED_COMPLETE;
            }

            QueuedWork.waitToFinish();

            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
            } catch (RemoteException e) {
                // nothing to do.
            }
            ensureJitEnabled();
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to start service " + s
                        + " with " + data.args + ": " + e.toString(), e);
            }
        }
    }
}

可以看到回調了onStartCommand方法。

以上就是Service的啟動過程的源碼分析。

從中,我理解了Service的啟動過程的同時,閱讀源碼的能力也提高了,分析源碼的時候我沒能力把每一個變量,每一個方法都搞懂,我關注的都是一些關鍵的字眼,比如這篇文章就是start呀,service呀。會有那種感覺,就是這裡沒錯了。當然如果陷入胡同了也要兜出來。

這樣的分析也能夠摸清整體的過程,對於細節,等我有扎實的功底了在去研究吧。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved