從Android6.0源碼的角度剖析Service啓動過程

Service是Android四大組件之一,與Activity的可視化界面相反,Service沒有向用戶提供交互界面,因此常被用於執行後臺任務。Service的啓動方式有兩種:普通啓動綁定啓動,其中,前者通過Context.startService方法啓動,常用於執行普通的後臺任務;後者通過Context.bindService方法啓動,用於執行與啓動組件有數據交互的後臺任務。本文將從Android6.0源碼角度,重點闡述這兩種方式的具體啓動過程。

1. 啓動普通Service

 在Android應用開發中,通常普通啓動一個Service是調用Context的startService()方法實現的,Context描述一個應用程序環境的信息(即上下文),通過它我們可以獲取應用程序的資源和類(包括應用級別操作,如啓動Activity,發廣播,接受Intent等)。Context是一個抽象類,它的具體實現類是ContextImpl,因此當我們調用Context的startService方法普通啓動Service時,實際執行的是ContextImpl的startService方法。在ContextImpl的startService()方法中,該方法會直接調用ContextImpl的startServiceCommon()方法執行接下來的調用邏輯,其源碼如下:

private ComponentName startServiceCommon(Intent service, UserHandle user) {
    try {
        validateServiceIntent(service);
        service.prepareToLeaveProcess();
        // ActivityManagerNative.getDefault()即AMS
        ComponentName cn = ActivityManagerNative.getDefault().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                getContentResolver()), getOpPackageName(), user.getIdentifier());
        // 判斷是否有啓動權限
        if (cn != null) {
            if (cn.getPackageName().equals("!")) {
                throw new SecurityException(
                    "Not allowed to start service " + service
                    + " without permission " + cn.getClassName());
            } else if (cn.getPackageName().equals("!!")) {
                throw new SecurityException(
                    "Unable to start service " + service
                    + ": " + cn.getClassName());
            }
        }
        return cn;
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}

 從startServiceCommon()方法源碼可知,它主要完成兩部分任務:(1) 調用ActivityManagerNative.getDefault()的startService()方法執行具體的啓動過程,並返回一個ComponentName的對象cn;(2) 如果(1)執行完畢後返回的cn不爲空,就判斷啓動service是否具有執行權限等情況。其中,ActivityManagerNative.getDefault()返回一個IActivityManager,它繼承於接口android.os.IInterface,這個接口就厲害了,還記得在我的另一篇文章《Android源碼解析之淺析Binder工作原理》中有提到過,IIterface接口通常出現在Binder通信機制中,它表明在IPC通信過程中遠程Server能夠提供什麼樣的能力或稱Client與Server之間的契約,Server端的Binder本地對象和Client端的Binder代理對象均需要繼承該接口。也就是說,關於service的啓動,很可能是一次跨進程通信。當然,現在下結論還有點早,我們還需要把Binder本地對象和Binder代理對象找出來。果然,ActivityManagerNative就是那個Server端的Binder實體,因爲它同時繼承了IBinder和IIterface。同時,我們也在ActivityManagerNative源碼中找到了一個內部類ActivityManagerProxy,從名字我們就能夠猜測到它就是那個Binder的代理對象,何況它繼承了IInterface。這就驗證了:Service的啓動實質是一次基於Binder機制的遠程跨進程通信,即最終的Service啓動工作是交給系統進程中的服務ActivityManagerService(簡稱"AMS")來完成。
 爲什麼是ActivityManagerService?從gDefault對象的定義來看,它是一個單例對象,當該對象的get()方法被調用時,Singleton的create()方法會被調用,具體工作爲:首先,調用ServiceManager的getService()獲得名爲"activity"的遠程服務Binder實體引用,通過跟蹤與ServiceManager相關源碼,我們可以知道其實這一步也是一次遠程IPC,而ServiceManager只是一個用於管理這些Service的管理器;然後,調用ActivityManagerNative的asInterface()方法返回一個ActivityManagerProxy對象給應用進程,之所以一定返回該代理對象,是因爲我們的應用進程與系統進程不可能是同一個進程。getDefault()相關源碼如下:

// 位於ActivityManagerNative.java
static public IActivityManager getDefault() {
    // 返回ActivityManagerSevice實例
    return gDefault.get();
}

// 位於ActivityManagerNative.java
// 單例模式
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        // Binder本地實體的引用
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        // 返回Binder代理對象ActivityManagerProxy
        // 因爲我們的應用不可能與系統進程歸屬於同一個進程
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};
// 位於ActivityManagerNative.java
// 將Binder對象轉換爲IActivityManager
static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    // 返回Binder本地對象,但這裏in應該恆爲null
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }
	// 返回Binder代理對象
    return new ActivityManagerProxy(obj);
}

 也就是說,gDefault.get()=ActivityManagerProxy?此言差矣!我們知道,ActivityManagerProxy中的方法,比如startService,它只是對調用參數進行了封裝,真正的實現是交給遠程服務的Binder實體(本地對象)完成,這個Binder實體就是ActivityManagerNative,但是ActivityManagerNative又是個抽象類,像startService這些方法均是抽象方法,ActivityManagerService纔是它的實現類。因此,我們可以得出:gDefault.get()=ActivityManagerService

// 位於ActivityManagerProxy
public ComponentName startService(IApplicationThread caller, Intent service,
     String resolvedType, String callingPackage, int userId) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        // 封裝函數參數到Parcel類型的data對象,
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        service.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeString(callingPackage);
        data.writeInt(userId);
        // 通過遠程Binder實體的引用,調用Binder請求處理方法並將處理結果返回寫入reply
        // 這步由內核中的Binder驅動控制,最終調用遠程Binder實體中的onTransact,
        // 該方法會通過分析傳入的函數code(編號)決定調用哪個方法
        mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
        reply.readException();
        ComponentName res = ComponentName.readFromParcel(reply);
        data.recycle();
        reply.recycle();
        return res;
    }
    
// 位於ActivityManagerNative    
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
    throws RemoteException {
    switch (code) {
      	...
        // 響應遠程請求start Service
        case START_SERVICE_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder b = data.readStrongBinder();
            IApplicationThread app = ApplicationThreadNative.asInterface(b);
            Intent service = Intent.CREATOR.createFromParcel(data);
            String resolvedType = data.readString();
            String callingPackage = data.readString();
            int userId = data.readInt();
            // 調用ActivityManagerService完成Service的啓動工作
            ComponentName cn = startService(app, service, resolvedType, 
                                            callingPackage, userId);
            reply.writeNoException();
            ComponentName.writeToParcel(cn, reply);
            return true;
        }
        ...
    }

小結1:

  • ActivityManagerNative.getDefault()即ActivityManagerService,Service啓動過程實質是一次基於Binder機制的遠程跨進程通信,最終的啓動工作由系統進程中的ActivityManagerService服務完成。

接下來,我們就着重分析下ActivityManagerService的startService是如何啓動Service,它的源碼如下:

// 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();
        // 調用ActiveServices的startServiceLocked方法
        ComponentName res = mServices.startServiceLocked(caller, service,
                      resolvedType, callingPid, callingUid, callingPackage, userId);
        Binder.restoreCallingIdentity(origId);
        return res;
    }
}

 從上述源碼來看,ActivityManagerService的startService()並沒有執行具體的功能,而是直接調用了ActiveServices的startServiceLocked()方法,該方法首先會獲得一個ServiceRecord對象,ServiceRecord用於描述一個Service記錄,它緩存了與Service有關的變量,並且會一直貫穿整個Service的啓動過程;然後將該ServiceRecord對象和Intent類型的service對象作爲參數調用ActiveServices的startServiceInnerLocked()方法,該方法繼續調用ActiveServices的bringUpServiceLocked()方法,在這個方法中,我們最終會看到它會調用一個名爲realStartServiceLocked的方法,從名字可以猜測得到從這個方法開始就是真正進入啓動過程了,我們來看看這個方法的源碼:

// ActiveServices.realStartServiceLocked()
private final void realStartServiceLocked(ServiceRecord r,
             ProcessRecord app, boolean execInFg) throws RemoteException {
    // (1) 判斷應用進程是否存在,如果爲null,拋出異常
    if (app.thread == null) {
        throw new RemoteException();
    }
	...
    boolean created = false;
    try {
        ...
        // 執行ApplicationThread.scheduleCreateService
        // 將執行邏輯從系統進程切換到應用進程,即由“內核態”切換到“用戶態”
        app.thread.scheduleCreateService(r, r.serviceInfo,
            	mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
            	app.repProcState);
        r.postNotification();
        // 設置啓動標誌created爲true
        created = true;
    } catch (DeadObjectException e) {
        Slog.w(TAG, "Application dead when creating service " + r);
        mAm.appDiedLocked(app);
        throw e;
    } finally {
        if (!created) {
            // Keep the executeNesting count accurate.
            final boolean inDestroying = mDestroyingServices.contains(r);
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);

            // Cleanup.
            if (newService) {
                app.services.remove(r);
                r.app = null;
            }

            // Retry.
            if (!inDestroying) {
                scheduleServiceRestartLocked(r, false);
            }
        }
    }

    requestServiceBindingsLocked(r, execInFg);

    updateServiceClientActivitiesLocked(app, null, true);

    // If the service is in the started state, and there are no
    // pending arguments, then fake up one so its onStartCommand() will
    // be called.
    if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                                                        null, null));
    }
	// (2)當Service的onCreate方法被調用後
    // 該方法最終會調用Service的onStartCommand()方法
    sendServiceArgsLocked(r, execInFg, true);
	...
}

該方法主要做兩件事情:
 (1) 通過app.thread返回的對象判斷當前應用進程是否存在,如果存在(app.thread!=null),則調用返回對象的scheduleCreateService()方法執行接下來的啓動工作,否則,拋出"RemoteException"異常。那麼,app.thread返回的對象是什麼呢?通過跟蹤源碼發現,app.thread返回一個IApplicationThread對象,但是IApplicationThread是一個接口且繼承系統接口android.os.IInterface,並且ApplicationThreadNative、ApplicationThreadProxy均繼承於該接口。由之前對AMS IPC的分析,我們很容易可以猜測得到app.thread.scheduleCreateService()又是一次遠程跨進程調用,並且ApplicationThread、ApplicationThreadProxy分別是“服務端”的Binder本地對象和"客戶端"的Binder代理對象。但是,與AMS IPC相反的是,這次的"客戶端"的角色由系統進程AMS“扮演”,而"服務端"角色換成了應用進程,ApplicationThreadProxy對象就是ApplicationThread在AMS中的代理,AMS將通過該代理對象與ApplicationThread進行通信。也就是說,service的最終具體啓動工作還是在應用進程中完成的,且app.thread=ApplicationThread。ApplicationThreadNative、ApplicationThreadProxy等類關係如下:

// “契約”接口
public interface IApplicationThread extends IInterface{}

// 服務端Binder本地對象
public abstract class ApplicationThreadNative extends Binder
		implements IApplicationThread {
	...
	// 客戶端Binder代理對象
	class ApplicationThreadProxy implements IApplicationThread {}
}

// 主線程管理器
public final class ActivityThread {
    final H mH = new H();
    ...
    // ApplicationThreadNative實現類,提供真正的服務實現(Binder本地對象)
    private class ApplicationThread extends ApplicationThreadNative {
        
    }
}

 接下來,我們重點分析下應用進程是如何完成Service的啓動工作。首先,對於ApplicationThread的scheduleCreateService()方法來說,它是運行在"服務端"的Binder線程池的線程中(原因參考本文),但是該方法並沒有執行具體的啓動工作,而是調用sendMessage()方法向mH發送一個H.CREATE_SERVICE消息,通過查看源碼可知,sendMessage()方法和mH對象均屬於ActivitiyThread,並且mH是一個Handler!由源碼註釋我們可以瞭解到,ActivitiyThread是一個在應用進程中用於管理主線程(main thread)的運行,比如管理和運行activities、broadcasts或者在activity執行的一些操作,從某些程度來說,ActivitiyThread就是我們熟悉的主線程或稱UI線程,它是APP的真正入口。當開啓APP後,系統會調用APP的main()開始運行,此時ActivityThread就會被創建,並且在主線程中開啓一個消息循環隊列,而mH對象(Handler)就是這個消息循環隊列的“操作手”,用來接收和處理那些傳遞到主線程的所有消息,其中,處理消息工作由mH.handleMessage()完成,它將根據消息編號(H.CREATE_SERVICE)執行最終的處理業務。對於CREATE_SERVICE消息,即啓動service的任務,handleMessage最終交給ActivityThread的handleCreateService()方法來完成。

// ApplicationThread.scheduleCreateService()
// 運行在Binder線程池
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);
}

// ActivityThread.sendMessage()
// 主線程
public final class ActivityThread {
    // 主線程的Handler
    final H mH = new H();
    ...
    // 實現子線程向主線程發送消息
    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        // 向mH發送一個msg消息
        mH.sendMessage(msg);
	}
    
    private class H extends Handler {
        public static final int CREATE_SERVICE = 114;
        ...
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            	switch (msg.what) {
                    ...
                	case CREATE_SERVICE:
                    	Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, 
                                         "serviceCreate");
                        // 處理Service創建工作
                    	handleCreateService((CreateServiceData)msg.obj);
                    	Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
            }
        }
}

 最後,我們看下ActivityThread.handleCreateService()方法爲了完成Service的啓動,做了哪些工作:
 (a) 創建類加載器,通過該加載器創建要啓動的Service對象;
 (b) 創建Application對象並調用其onCreate方法,並且在應用被啓動後Application始終只會被創建一次;

// LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
	// 如果mApplication被創建,則直接返回
	if (mApplication != null) {
		return mApplication;
	}

	Application app = null;
    try {
    	java.lang.ClassLoader cl = getClassLoader();
		...
   		 ContextImpl appContext = 
   		 	ContextImpl.createAppContext(mActivityThread, this);
   		 // 創建Application
   		 app = mActivityThread.mInstrumentation.newApplication(
    						cl, appClass, appContext);
    	appContext.setOuterContext(app);
   	 } catch (Exception e) {
    	
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;
    if(instrumentation != null) {
    	// 調用Application的onCreate方法
        instrumentation.callApplicationOnCreate(app);
    }

 © 創建ContextImpl對象,並通過Service的attach方法建立兩者之間的關係,這個過程與Activity的啓動相似;
 (d) 調用Service的onCreate()方法,同時將Service對象插入到mService列表中。至此,隨着onCreate()方法被調用,Service成功被啓動,並且onCreate()運行在應用進程的主線程,所以儘量不要在該方法中執行耗時任務,否則,會出現ANR異常。

final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();

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 {
        // (1) 創建類加載器
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        // 加載名爲name的Service類,即實例化Service
        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);
		// (3)創建APP的ContextImpl
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        
        context.setOuterContext(service);
		// (2) 創建Application
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        // 將Context與Service綁定
        service.attach(context, this, data.info.name, data.token, app,
                       ActivityManagerNative.getDefault());
        // (4) 調用Service的onCreate(),即Service啓動成功
        service.onCreate();
        // 將Service對象插入到列表中緩存
        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);
        }
    }
}

(2) 在(1)執行完畢後,Service的onCreate()方法被調用,就說明Service已經被啓動了。但我們知道,當Serivce啓動後除了它的onCreate()方法被調用,還有另外一個方法也會被調用,即onStartCommand,接下來,我們就分析下onStartCommand方法是如何被調用的。首先,我們回到ActiveServices.realStartServiceLocked()中找到sendServiceArgsLocked(r, execInFg, true),該方法會從SerivceRecord中取出ApplicationThread對象,然後調用該對象中的scheduleServiceArgs()方法向主線程ActivityThread發送一個H.SERVICE_ARGS消息。當主線程接收到該消息後,就會執行ActivityThread.handleServiceArgs(),,然後再該方法中Service的onStartCommand方法就會被調用。具體的調用流程:

// ActiveServices.sendServiceArgsLocked()
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
  		boolean oomAdjusted) throws TransactionTooLargeException {
	...
    // 調用ApplicationThread的scheduleServiceArgs
    r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
    ...
}

// ActivityThread.ApplicationThread.scheduleServiceArgs()
// 運行在Binder線程池的線程中
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;
	// 向主線程發送一個H.SERVICE_ARGS消息
    sendMessage(H.SERVICE_ARGS, s);
}

// ActivityThread.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) {
                // 調用Service的onStartCommand()方法
                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);
            }
        }
    }
}

小結2:

  • app.thread=ApplicationThread。ActivityManagerService是運行在系統進程的服務,負責系統中所有Activity、Service等組件的生命週期;ActivityThread是App的真正入口,即傳說中的主線程或稱UI線程,它將與ActivityManagerService配合,實現對Activity、Service等組件的管理;ApplicationThread是ActivityManagerService(系統服務)與ActivityThread(主線程)交互的橋樑,當ActivityManagerService需要管理Application(應用進程)中的Activity或Service等組件的生命週期時,會通過ApplicationThread的代理對象ApplicationThreadProxy與ActivityThread進行通信,然後告知ActivityThread需要執行什麼操作。
  • 每調用一次Context.startService()啓動同一個Service,它的onCreate()方法只會被調用一次,而其onStartCommand()方法每次都會被調用。需要注意的是,Service運行在主線程,因此在Service的onCreate等方法中儘量不要執行耗時任務,否則會出現ANR異常。

startService調用流程如下:
在這裏插入圖片描述

2. 綁定Service

 綁定啓動Service的實現過程與普通啓動Service的流程是大致相同的,都是藉助基於Binder機制的IPC方式與AMS交互實現的,只是綁定啓動調用的是Context.bindService()方法,由前面的分析可知,這步的操作實際上是執行了ContextImpl的bindService()方法。bindService方法並沒有執行具體的業務邏輯,而是將工作交給了ContextImpl.bindServiceCommon()方法,它的源碼下:

// ContextImpl
@Override
public boolean bindService(Intent service, ServiceConnection conn,
                           int flags) {
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}

// ContextImpl
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
                                  UserHandle user) {
    IServiceConnection sd;
    if (conn == null) {
        throw new IllegalArgumentException("connection is null");
    }
    if (mPackageInfo != null) {
        // (1) 將客戶端的ServiceConnection轉化爲ServiceDispatcher.InnerConnction對象
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                                               mMainThread.getHandler(), flags);
    } else {
        throw new RuntimeException("Not supported in system context");
    }
    validateServiceIntent(service);
    try {
        IBinder token = getActivityToken();
        if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
            && mPackageInfo.getApplicationInfo().targetSdkVersion
            < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            flags |= BIND_WAIVE_PRIORITY;
        }
        service.prepareToLeaveProcess();
        // (2) 調用AMS的binderService方法
        int res = ActivityManagerNative.getDefault().bindService(
            mMainThread.getApplicationThread(), getActivityToken(), service,
            service.resolveTypeIfNeeded(getContentResolver()),
            sd, flags, getOpPackageName(), user.getIdentifier());
        if (res < 0) {
            throw new SecurityException(
                "Not allowed to bind to service " + service);
        }
        return res != 0;
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}

bindServiceCommon源碼分析:
 (1) 首先,bindServiceCommon調用LoadedApk.getServiceDispatcher()方法獲得IServiceConnection對象sd,該方法接受一個ServiceConnection對象conn作爲參數,並創建一個key、value分別爲ServiceConnection和LoadedApk.ServiceDispatcher的map集合,也就是說,ServiceConnction與LoadedApk.ServiceDispatcher是一個映射關係。然後,判斷集合map是否爲null,如果不爲null,則從集合中取出與ServiceConnection對象相關聯的LoadedApk.ServiceDispatcher對象。當然,如果map集合中不存在對象sd,則new一個ServiceDispatcher對象,並將其與ServiceConnection對象c作爲一條key-value記錄插入到map集合中緩存。源碼如下:

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
                       Context context, Handler handler, int flags) {
    synchronized (mServices) {
        LoadedApk.ServiceDispatcher sd = null;
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = 
            						mServices.get(context);
        // 從map集合中取出 LoadedApk.ServiceDispatcher緩存
        if (map != null) {
            sd = map.get(c);
        }
        // 如果sd不存在map集合中,創建它
        if (sd == null) {
            sd = new ServiceDispatcher(c, context, handler, flags);
            if (map == null) {
                map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                // 存儲一個應用當前活動的ServiceConnection
                // 與LoadedApk.ServiceDispatcher的映射關係
                mServices.put(context, map);
            }
            map.put(c, sd);
        } else {
            sd.validate(context, handler);
        }
        return sd.getIServiceConnection();
    }
}

 but,搞了半天又是IServiceConnection、又是ServiceDispatcher的到底要幹嘛?實際上,考慮到bindService可能是跨進程的,而ServiceConnect對象運行在客戶端,爲了讓自己的方法(即onServiceDisconnectedonServiceConnected)能夠正常被遠程服務端回調,ServiceConnect對象就必須藉助Binder機制來實現。它的實現原理是將客戶端的ServiceConnection對象轉換化爲ServiceDispatcher.InnerConnection對象,並且ServiceDispatcher是銜接ServiceConnection和InnerConnection的橋樑,而InnerConnection恰好可以充當Binder本地對象的角色。LoadedApk.ServiceDispatcher相關源碼如下:

static final class ServiceDispatcher {
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
    private final ServiceConnection mConnection;
    ...
    // 構造方法
    ServiceDispatcher(ServiceConnection conn,
                          Context context, Handler activityThread, int flags) {
        mIServiceConnection = new InnerConnection(this);
        mConnection = conn;
        mContext = context;
        mActivityThread = activityThread;
        mLocation = new ServiceConnectionLeaked(null);
        mLocation.fillInStackTrace();
        mFlags = flags;
    }
    
    // 運行在遠程服務端的Binder實體或稱Binder本地對象
    private static class InnerConnection extends IServiceConnection.Stub {
        final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
        // 緩存當前的LoadedApk.ServiceDispatcher對象
		InnerConnection(LoadedApk.ServiceDispatcher sd) {
           mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
        }
        
        // 遠程方法,執行調用客戶端ServiceConnect對象的回調方法
        public void connected(ComponentName name, IBinder service) throws 
            RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
            	// 調用LoadedApk.ServiceDispatcher的connected方法
            	// 該方法最終會調用ServiceConnect的回調方法
                if (sd != null) {
                    sd.connected(name, service);
                }
            }
        }
}

 (2) 在(1)獲得與ServiceConnect對應的LoadedApk.ServiceDispatcher對象後,bindServiceCommon接着將該對象作爲參數繼續調用ActivityManagerService(即app.thread,簡稱AMS)的bindService()方法,將業務邏輯切換由應用進程到系統進程的AMS服務中。在AMS的bindService方法中,直接調用ActiveServices的bindServiceLocked()方法,bindServiceLocked方法再調用bringUpServiceLocked,bringUpServiceLocked又會調用realStartServiceLocked。realStartServiceLocked的執行邏輯與普通啓動Service一致,最終都是通過ApplicationThread來完成Service對象的創建並執行其onCreate方法,這裏不再重複分析。realStartServiceLocked源碼如下:

private final void realStartServiceLocked(ServiceRecord r,
                     ProcessRecord app, boolean execInFg) throws RemoteException {
    if (app.thread == null) {
        throw new RemoteException();
    }
    ...
    boolean created = false;
    try {
        ...
        // startService:調用onCreate
        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;
    } finally {
        ...
    }
    // 調用app.thread.scheduleBindService
    requestServiceBindingsLocked(r, execInFg);

    updateServiceClientActivitiesLocked(app, null, true);

    // If the service is in the started state, and there are no
    // pending arguments, then fake up one so its onStartCommand() will
    // be called.
    if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                                                        null, null));
    }
    // 啓動onStartCommand方法
    sendServiceArgsLocked(r, execInFg, true);
	...
}

 與普通啓動Service不同的是,綁定啓動Service不僅會執行app.thread.scheduleCreateService,還會執行app.thread.scheduleBindService,這個從跟蹤requestServiceBindingsLocked代碼可以確定。接着,我們就來看ApplicationThread(即app.thread)的scheduleBindService的方法,scheduleBindService會向主線程ActivityThread發送一個H.BIND_SERVICE消息,ActivitiyThread的H(Handler對象)接收到該消息後,就會調用ActivityThread的handleBindService方法,源碼如下:

private void handleBindService(BindServiceData data) {
    // 獲取對應的Service對象
    Service s = mServices.get(data.token);
    if (DEBUG_SERVICE)
        Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            try {
                if (!data.rebind) {
                    // 調用Service的onBind方法
                   	// 返回遠程Service中Binder本地對象的引用
                    IBinder binder = s.onBind(data.intent);
                    // 調用AMS的publicService方法
                    ActivityManagerNative.getDefault().publishService(
                        data.token, data.intent, binder);
                } else {
                    // 調用Service的onBind方法
                    s.onRebind(data.intent);
 					// 調用AMS的serviceDoneExecuting方法
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
                ensureJitEnabled();
            } catch (RemoteException ex) {
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                    "Unable to bind to service " + s
                    + " with " + data.intent + ": " + e.toString(), e);
            }
        }
    }
}

 在ActivityThread的handleBindService方法中,它首先會判斷Service是否已經被綁定啓動,如果data.rebind不爲空,說明Service已經被綁定啓動,這是會調用Service的onRebind方法,就不會再調用Service的onBind方法,否則,調用Service的onBind方法,然後調用AMS的publishService方法進入綁定啓動Service邏輯。publishService方法會調用ActiveServices的publishServiceLocked方法,在該方法最終會調用LoadedApk.ServiceDispatcher.InnerConnection內部類的connected方法,在connected實現回調客戶端的ServiceConnection的方法,相關源碼如下:

// ActiveServices.publishServiceLocked()方法
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    ...
    ConnectionRecord c = clist.get(i);
    try {
        // 調用ServiceDispatcher.InnerConnection的connected方法
        // 實現回調客戶端ServiceConnection的方法
        c.conn.connected(r.name, service);
    } catch (Exception e) {
         Slog.w(TAG, "Failure sending service " + r.name +
                   " to connection " + c.conn.asBinder() +
                   " (in " + c.binding.client.processName + ")", e);
   }    
}

// LoadedApk.ServiceDispatcher.InnerConnection內部類
private static class InnerConnection extends IServiceConnection.Stub {
    final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

    InnerConnection(LoadedApk.ServiceDispatcher sd) {
        mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
    }

    public void connected(ComponentName name, IBinder service) throws RemoteException {
        LoadedApk.ServiceDispatcher sd = mDispatcher.get();
        if (sd != null) {
            // 調用LoadedApk.ServiceDispatcher的connected方法
            sd.connected(name, service);
        }
    }
}

 從LoadedApk.ServiceDispatcher.InnerConnection內部類的connected方法可知,它會調用LoadedApk.ServiceDispatcher方法的connected方法,該方法首先會判斷mActivityThread對象的爲空情況,實際上該對象是一個Handler且屬於主線程,從前面ServiceDispatcher的創建來看,mActivityThread不會爲null,因此,它會繼續執行mActivityThread.post,從而實現將邏輯由服務端切換到主線程中。也就是說,ServiceConnection的回調方法,是在主線程中被回調的!相關源碼如下:

// LoadedApk.ServiceDispatcher.connected()
public void connected(ComponentName name, IBinder service) {
    if (mActivityThread != null) {
        // 主線程中執行
        mActivityThread.post(new RunConnection(name, service, 0));
    } else {
        doConnected(name, service);
    }
}
// LoadedApk.ServiceDispatcher.RunConnection內部類
private final class RunConnection implements Runnable {
    RunConnection(ComponentName name, IBinder service, int command) {
        mName = name;
        mService = service;
        mCommand = command;
    }

    public void run() {
        // command=0,
        if (mCommand == 0) {
            doConnected(mName, mService);
        } else if (mCommand == 1) {
            doDeath(mName, mService);
        }
    }

    final ComponentName mName;
    final IBinder mService;
    final int mCommand;
}

 在RunnConnection中,由於command=0,因此,會調用LoadedApk.ServiceDispatcher.doConnected()方法,該方法最終實現對ServiceConnection的onServiceConnected的回調。源碼如下:

// LoadedApk.ServiceDispatcher.doConnected()方法
public void doConnected(ComponentName name, IBinder service) {
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;

    synchronized (this) {
        if (mForgotten) {
            // We unbound before receiving the connection; ignore
            // any connection received.
            return;
        }

        old = mActiveConnections.get(name);
        if (old != null && old.binder == service) {
            // Huh, already have this one.  Oh well!
            return;
        }

        if (service != null) {
            // A new service is being connected... set it all up.
            mDied = false;
            info = new ConnectionInfo();
            info.binder = service;
            info.deathMonitor = new DeathMonitor(name, service);
            try {
                // 調用Service的linkToDeath
                service.linkToDeath(info.deathMonitor, 0);
                mActiveConnections.put(name, info);
            } catch (RemoteException e) {
                // This service was dead before we got it...  just
                // don't do anything with it.
                mActiveConnections.remove(name);
                return;
            }

        } else {
            // The named service is being disconnected... clean up.
            mActiveConnections.remove(name);
        }

        if (old != null) {
            old.binder.unlinkToDeath(old.deathMonitor, 0);
        }
    }

    // If there was an old service, it is not disconnected.
    if (old != null) {
        mConnection.onServiceDisconnected(name);
    }
    // If there is a new service, it is now connected.
    if (service != null) {
        // 調用ServiceConnection的onServiceConnected
        mConnection.onServiceConnected(name, service);
    }
}

public void doDeath(ComponentName name, IBinder service) {
    mConnection.onServiceDisconnected(name);
}

小結3:

  • 當多次綁定同一個Service時,Service的onBind方法只會執行一次,除非Service被終止了。另外,客戶端中ServiceConnection的回調方法是在主線程被回調的,用於通知客戶端本地綁定連接的狀態,因此,儘量不要在回調方法中執行耗時任務,否則,會出現ANR異常。當多次綁定同一個Service時,ServiceConnection的回調方法會被回調多次。
  • startService與bindService可以同時執行

3. 停止/解綁Service

3.1 停止Service

在這裏插入圖片描述
handleStopService()源碼如下:

//ActivityThread.handleStopService()
private void handleStopService(IBinder token) {
    // (1)從緩存列表中移除Service對象,並返回
    Service s = mServices.remove(token);
    if (s != null) {
        try {
            if (localLOGV) Slog.v(TAG, "Destroying service " + s);
            // (2)調用Service的onDestory()方法
            s.onDestroy();
            Context context = s.getBaseContext();
       
            if (context instanceof ContextImpl) {
                final String who = s.getClassName();
                // (3)清理註冊信息
                // 調用mPackageInfo.removeContextRegistration()
                ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
            }

            QueuedWork.waitToFinish();

            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                    token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
            } catch (RemoteException e) {
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                    "Unable to stop service " + s
                    + ": " + e.toString(), e);
            }
            Slog.i(TAG, "handleStopService: exception for " + token, e);
        }
    } else {
        Slog.i(TAG, "handleStopService: token=" + token + " not found.");
    }
    //Slog.i(TAG, "Running services: " + mServices);
}

 從源碼可知,該方法主要完成三件事情:
 (1) 從緩存列表mServices中移除指定的Service對象;
 (2) 調用Service的onDestory()方法;
 (3) 調用ActivityThread的performFinalCleanup()清除Context註冊信息。

final void performFinalCleanup(String who, String what) {
	//Log.i(TAG, "Cleanup up context: " + this);
	mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
}
3.2 解綁Service

在這裏插入圖片描述
handleUnbindService源碼如下:

private void handleUnbindService(BindServiceData data) {
    // 從緩存列表獲取Service對象
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            // 調用Service的onUnbind方法
            boolean doRebind = s.onUnbind(data.intent);
            try {
                if (doRebind) {
                    ActivityManagerNative.getDefault().unbindFinished(
                        data.token, data.intent, doRebind);
                } else {
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
            } catch (RemoteException ex) {
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                    "Unable to unbind to service " + s
                    + " with " + data.intent + ": " + e.toString(), e);
            }
        }
    }
}

 解綁過程與綁定過程一致,最終ServiceConnection的onServiceDisconnected在主線程中被調用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章