前篇:Service的啟動過程
剛開始的過程和startService類似:
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, 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(this);
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 e.rethrowFromSystemServer();
}
}
複製程式碼
bindServiceCommon
主要完成了兩件事情:
-
通過
mPackageInfo.getServiceDispatcher
將ServiceConnection
轉化成了ServiceDispatcher.InnerConnection
物件,為什麼需要轉換呢?這是因為服務的繫結有可能是跨程式的,所以ServiceConnection必須藉助Binder機制才能讓伺服器來回撥自己的方法,而
InnerConnection
正好實現了IServiceConnection.Stub
,轉化成了Binder物件。 -
完成繫結操作。
ActivityManagerService.bindService -> ActiveServices.bindServiceLocked -> ActiveServices.bringUpServiceLocked -> ActiveServices.realStartServiceLocked 複製程式碼
同樣的和啟動過程類似,都是通過ApplicationThread來建立Service的例項,並執行onCreate方法。
之後會呼叫requestServiceBindingsLocked
方法來繫結Service。
ActiveServices.requestServiceBindingsLocked
-> ActiveServices.requestServiceBindingLocked
-> ApplicaitonThread.scheduleBindService
複製程式碼
同樣的是通過Handler來傳送BIND_SERVICE
訊息
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
private void handleBindService(BindServiceData data) {
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) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
複製程式碼
這個時候通過s.onBind(data.intent)
就將Service繫結起來了。
那麼客戶端是如何知道已經成功連線到Service了呢?
這個時候就要呼叫onServiceConnected
方法,這個過程就由publishService
來完成。
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
-> ActivityManagerService.publishService
-> ActiveServices.publishServiceLocked
複製程式碼
在publishServiceLocked
中核心就一句c.conn.connected(r.name, service)
其中c.conn
就是一開始將ServiceConnection
轉化成的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) {
sd.connected(name, service);
}
}
}
// LoadedApk.java
public void connected(ComponentName name, IBinder service) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0));
} else {
doConnected(name, service);
}
}
複製程式碼
由程式碼可以知道mActivityThread
是一個Handler,其實就是ActivityThread中的H,是不可能為空的,所以必定會呼叫post
方法。
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command) {
mName = name;
mService = service;
mCommand = command;
}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
}
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
// 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) {
mConnection.onServiceConnected(name, service);
}
}
複製程式碼
由於mCommand
傳的值為0,所以呼叫的是doConnected
方法,這個時候很方便的呼叫到了onServiceConnected
。
至此,Service的繫結過程就完全分析結束了。