話不多說,上代碼(本文基于Android 29 源碼分析):
bindService(Intent(this, MyService::class.java), MyConnection(), Context.BIND_AUTO_CREATE)
其中MyConection代碼為:
inner class MyConnection : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
}
}
日常操作,就不用解釋了,下面從 bindService 開始,跟蹤源碼,理解整個過程。activity繼承至contextWrapper,contextWrapper其實是contextImpl的代理類,所以bindService直接跟進到contextImpl中,最終到bindServiceCommon:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// 后面會分析,這地方記住這個句柄 sd 是 IServiceConnection 對象
IServiceConnection sd;
...
if (mPackageInfo != null) {
if (executor != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
} else {
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);
// 關鍵點 1:跳轉(zhuǎn)到AMS處理,開始了跨進程之旅
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, 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();
}
}
關鍵點1處注意幾個參數(shù):
getApplicationThread: 都知道進程啟動、activity啟動都會有一個ApplicationThread,同理這地方也是,在啟動service的時候依然是走到 ActivityThread,走生命周期。
getActivityToken:每一個Activity都有一個token,該token會在ActivityRecord中保存,由WMS有關,這地方就是找到指定的Activity
sd:IServiceConnection對象,后面會用到
接著走到AMS,看一下AMS怎么做的處理:
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
...
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, instanceName, callingPackage, userId);
}
}
參數(shù)對應上,又調(diào)用 了bindServiceLocked方法,go on:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, String callingPackage, final int userId)
throws TransactionTooLargeException {
...
//獲取調(diào)用者線程
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
...
//本質(zhì)上就是創(chuàng)建一個ServiceRecord對象,該對象實現(xiàn)了binder接口
ServiceLookupResult res =
retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
callerFg, isBindExternal, allowInstant);
if (res == null) {
return 0;
}
if (res.record == null) {
return -1;
}
ServiceRecord s = res.record;
...
try {
...
//關鍵點1
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent,
callerApp.uid, callerApp.processName, callingPackage);
IBinder binder = connection.asBinder();
s.addConnection(binder, c);
b.connections.add(c);
if (activity != null) {
activity.addConnection(c);
}
b.client.connections.add(c);
c.startAssociationIfNeeded();
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.hasAboveClient = true;
}
if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
s.whitelistManager = true;
}
if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
s.setHasBindingWhitelistingBgActivityStarts(true);
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
// 關鍵點2
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
...
return 1;
}
該方法較長,分析關鍵 的流程,在關鍵點1處,創(chuàng)建了ConnectionRecord對象,從名稱可看出就是我們bind service方法調(diào)用傳的 Connection對象,不過這地方是包裝的IServiceConnection ,這個就是上面說的sd對象,先知道是包裝了Connection的對象,后面會分析,接著一些flag相關。關鍵點2 這個是真正重要的地方,先看flag判斷,(flags&Context.BIND_AUTO_CREATE) != 0,如果參數(shù)是Context.BIND_AUTO_CREATE,就會走到bringUpServiceLocked,Context.BIND_AUTO_CREATE就是bindeservice方法最后一個參數(shù),
bindService(Intent(this, MyService::class.java), MyConnection(), Context.BIND_AUTO_CREATE)
這個參數(shù)的意義就是,自動startService,在執(zhí)行綁定操作,繼續(xù)跟進bringUpServiceLocked,
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
...
realStartServiceLocked(r, app, execInFg);
....
}
該方法關鍵的就是執(zhí)行realStartServiceLocked(r, app, execInFg);其他沒什么好分析的 ,繼續(xù)跟進:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
r.setProcess(app);
...
boolean created = false;
try {
//關鍵點1 : 開始回調(diào)調(diào)用者進程,熟悉的調(diào)用方式
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
...
}
...
//關鍵點 2
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
...
}
看到關鍵點1 有沒有熟悉的感覺,沒錯就是跟activity啟動流程類似的調(diào)用,該方法的執(zhí)行會到ActivityThread執(zhí)行service的啟動,同理,注意相關參數(shù)
r:ServiceRecord,service的記錄,后續(xù)會通過該對象作為key保存啟動的Service
跨進程到了調(diào)用者進程,找到ActivityThread,跟進如下:
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);
}
包裝一個CreateServiceData,發(fā)送一個message ,進入主線程調(diào)用,最終到:
private void handleCreateService(CreateServiceData data) {
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//反射方式創(chuàng)建一個service對象
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
try {
// 創(chuàng)建了一個context 對象,本質(zhì)上一個service對應一個context
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,
ActivityManager.getService());
// 關鍵點1 執(zhí)行service的oncreate 生命周期
service.onCreate();
mServices.put(data.token, service);
try {
// 關鍵點2 繼續(xù)跨進程到AMS 繼續(xù)執(zhí)行后續(xù)操作
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
從關鍵點1看出我們的service的生命周期開始執(zhí)行了,關鍵點2,又開始了跨進程之旅,到這我門的bind操作還沒真正執(zhí)行,目前只是start service了,好繼續(xù)serviceDoneExecuting的跟蹤,其實serviceDoneExecuting的執(zhí)行很簡單,就是沒有做任何有用的操作,這地方有興趣的自己可以跟蹤過去,注意對照SERVICE_DONE_EXECUTING_ANON參數(shù)看。
我們回到上面的realStartServiceLocked方法,繼續(xù)看下面的關鍵點2的執(zhí)行,發(fā)現(xiàn)執(zhí)行完啟動過程,會緊跟著執(zhí)行requestServiceBindingsLocked方法,這個又是做什么的,源碼如下:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
// 關鍵點1 ,熟悉的調(diào)用方式
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.getReportedProcState());
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
// Keep the executeNesting count accurate.
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
throw e;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
return false;
}
}
return true;
}
看到在關鍵點1處,又跨進程執(zhí)行了ActivityThread的scheduleBindService方法,從名字也可猜出執(zhí)行到了我們的bind操作,nice,繼續(xù)看ActivityThread的執(zhí)行過程,最終經(jīng)過 handler 回調(diào)到 handleBindService:
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
...
if (!data.rebind) {
//關鍵點1 終于到了我們的onbind
IBinder binder = s.onBind(data.intent);
//關鍵點2 再一次跨進程到AMS
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
...
}
}
關鍵點1 終于到了我們的onbind方法,還記得我們service中onbind會返回bind對象,然后關鍵點2處又開始將我們返回的binder對象傳遞到AMS ,那么繼續(xù)跟進去看看 :
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
...
ConnectionRecord c = clist.get(i);
// conn :IServiceConnectio service: 對應上面的返回的binder
c.conn.connected(r.name, service, false);
...
}
該方法做了精簡主要的地方就是調(diào)用了connected方法,conn還記得開始分析的IServiceConnection嗎,沒錯,就是我們執(zhí)行bindServiceCommon方法中的sd對象(忘了的翻到上面的bindServiceCommon方法看看就知道了),我們看看這個對象怎么生成的,
很簡單跟蹤源碼可以看到就是new ServiceDispatcher(c, context, executor, flags)的操作,對應的構(gòu)造函數(shù)
ServiceDispatcher(ServiceConnection conn,
Context context, Executor activityExecutor, int flags) {
mIServiceConnection = new InnerConnection(this);
mConnection = conn;
mContext = context;
mActivityThread = null;
mActivityExecutor = activityExecutor;
mLocation = new ServiceConnectionLeaked(null);
mLocation.fillInStackTrace();
mFlags = flags;
}
回到上面的c.conn.connected(r.name, service, false); 就是ServiceDispatcher的connected(r.name, service, false),這個方法如下:
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityExecutor != null) {
mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
} else if (mActivityThread != null) {
//執(zhí)行到這,畢竟 ActivityThread 是存在的,service:對應上面的返回的binder
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
這地方post了一個runnable對象,就是執(zhí)行到了相關的run方法,在run方法中會調(diào)用到我們的onServiceConnected(name, service);
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
...
// 關鍵點1 終于執(zhí)行了onServiceConnected
if (service != null) {
mConnection.onServiceConnected(name, service);
} else {
// The binding machinery worked, but the remote returned null from onBind().
mConnection.onNullBinding(name);
}
}
}
就是我們自己寫的MyConnection中的onServiceConnected,這地方的service參數(shù)就是service的onbind方法返回的binder對象,到此跟蹤了整個service的bind過程,bindService方式的源碼分析也就結(jié)束了。