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對象運行在客戶端,爲了讓自己的方法(即onServiceDisconnected
和onServiceConnected
)能夠正常被遠程服務端回調,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在主線程中被調用。