看了好幾篇bindService源碼分析,感謝這篇寫的最好,轉載過來,以後友善學習.
原文位址:https://www.jianshu.com/p/1074af3eda78
bindService流程圖:
在應用層點選bindService,會跳轉到Context中的bindService,context的具體實作是ContextImpl,是以我們跟進去ContextImpl的bindService方法
#ContextImpl
@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) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
//1.重點 将 ServiceConnection對象轉換成ServiceDispatcher.InnerConnection對象
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);
//2.重點 IPC操作,最終調用到ActivityManagerService的bindService方法
int res = ActivityManager.getService().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();
}
}
上述代碼重點部分已經做了标注,我們首先看下 1處,1處調用到 mPackageInfo.getServiceDispatcher方法,将 ServiceConnection對象轉換成ServiceDispatcher.InnerConnection對象,我們跟進去看下:
#LoadedApk
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);
if (map != null) {
if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
sd = map.get(c);
}
if (sd == null) {
//1. 重點!
sd = new ServiceDispatcher(c, context, handler, flags);
if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
//2. 獲得 ServiceDispatcher.InnerConnection執行個體
return sd.getIServiceConnection();
}
}
上述方法中涉及到了 mServices,我們先來看下它的定義:
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<>();
mServices就是一個ArrayMap,它存儲了一個應用目前活動的 ServiceConnection和 ServiceDispatcher之間的映射關系。
可以看到在 1處建立了ServiceDispatcher對象,我們跟進去構造方法看下:
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
private final ServiceConnection mConnection;
private final Context mContext;
private final Handler mActivityThread;
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;
}
}
在ServiceDispatcher的構造方法中,首先建立了InnerConnection對象,并指派給它的成員變量mIServiceConnection,接着将ServiceConnection 對象conn指派給成員變量mConnection ,将ActivityThread類中的Handler H mH指派給mActivityThread 成員變量。
我們接着跟進去 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, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
}
InnerConnection為ServiceDispatcher中的靜态内部類,繼承自 IServiceConnection.Stub,很顯然,它是一個binder對象。類似于ApplicationThread,InnerConnection中的方法是運作在用戶端程序中的Binder線程池中的,它主要參與Service綁定後ServiceConnection 中onServiceConnected方法的回調過程。可以看到在InnerConnection的構造方法中隻是對外部傳入的ServiceDispatcher對象通過WeakReference做了一次封裝,使得InnerConnection對象持有ServiceDispatcher對象的引用,友善後續操作。
好了,我們回過頭看下getServiceDispatcher方法的 2處,可以看到在 2處調用到ServiceDispatcher對象的getIServiceConnection()方法,我們跟進去看下:
#ServiceDispatcher
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
方法中直接将mIServiceConnection return掉,mIServiceConnection不就是我們之前在ServiceDispatcher構造方法中建立的InnerConnection 對象嘛(Binder執行個體),是的沒錯!
我們回過頭ContextImpl的bindServiceCommon方法,繼續向下分析。2處為IPC操作,最終會調用到ActivityManagerService(AMS)的bindService方法,我們跟進去:
#ActivityManagerService
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
synchronized(this) {
//重點!
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
---
#ActiveServices
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
//通過applicationthread對象獲得對應的ProcessRecord
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when binding service " + service);
}
...
//建立 ServiceRecord對象并關聯到新建立的ServiceLookupResult對象
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
if (res == null) {
return 0;
}
if (res.record == null) {
return -1;
}
//通過res.record擷取到建立的ServiceRecord對象并指派給 ServiceRecord s變量
ServiceRecord s = res.record;
...
//調用ServiceRecord 的retrieveAppBindingLocked方法,
//内部對bindings進行put操作,标志目前為bindService
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
//建立ConnectionRecord對象,将 IServiceConnection connection指派給conn成員變量
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
if (activity != null) {
if (activity.connections == null) {
activity.connections = new HashSet<ConnectionRecord>();
}
activity.connections.add(c);
}
b.client.connections.add(c);
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 (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//1.重點!
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
我們跟進去ActiveServices 中的 bringUpServiceLocked方法去看下:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
...
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
//1.重點
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
...
}
接着來到realStartServiceLocked方法:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
if (DEBUG_MU)
Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
+ ", ProcessRecord.uid = " + app.uid);
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
mAm.updateOomAdjLocked();
//标記目前Service對象是否成功建立
boolean created = false;
try {
if (LOG_SERVICE_START_STOP) {
String nameTerm;
int lastPeriod = r.shortName.lastIndexOf('.');
nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
EventLogTags.writeAmCreateService(
r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
}
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//1.重點 發起SystemServer程序到用戶端程序的單向IPC操作,建立Service對象并調用其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 {
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);
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
//2.若目前Service的啟動方式為bindService,則執行Service的綁定操作
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
//3.若目前Service的啟動方式為startService,則新建立一個ServiceRecord.StartItem對象并添加到ServiceRecord對象 r的pendingStarts集合中
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
//4.若目前Service的啟動方式為startService,則回調目前Service對象的 onStartCommand方法
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
}
1處發起SystemServer程序到用戶端程序的單向IPC操作,建立Service對象并調用其onCreate方法,上節課startService方式的時候我們已經分析過了,這裡就不再贅述了。由于目前Service的啟動方式為bindService,是以3處if條件不滿足,導緻ServiceRecord r的pendingStarts集合為empty,之後4處調用到sendServiceArgsLocked方法,在 sendServiceArgsLocked方法内部擷取到pendingStarts.size()為0直接return掉了,至此目前Service對象的 onStartCommand方法并不會被回調。這也就解釋了我們通過bindService的方式啟動Service,onStartCommand方法并不會被回調的原因。好了,我們現在的重點放在 2處的 requestServiceBindingsLocked方法:
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
這裡我同樣要解釋一下,當我們通過bindService的方式啟動Service時,會對ServiceRecord r.bindings集合進行put操作,put操作的位置我們上述代碼中有提及到,不記得的小夥伴可以回過頭看下。這樣子就導緻r.bindings.size()不為0,會調用到for循環中的 requestServiceBindingLocked方法,而當我們通過startService的方式啟動Service時,r.bindings.size()為0,for循環條件不滿足直接退出。這也就解釋了我們通過StartService的方式啟動Service時,Service的onBind方法不會回調的原因。
好了,我們跟進去requestServiceBindingLocked方法:
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 (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
+ " rebind=" + rebind);
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//重點!該操作為SystemServer程序到用戶端程序的單向IPC操作,
//最終會調用到ApplicationThread的scheduleBindService方法
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
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;
}
在ApplicationThread的scheduleBindService方法中發送了一條BIND_SERVICE的Message,最終會調用ActivityThread類的handleBindService方法,我們跟進去看下:
private void handleBindService(BindServiceData data) {
//1.擷取到目前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) {
//2.回調目前Service對象的onBind方法
IBinder binder = s.onBind(data.intent);
//3.重點 IPC 操作,最終調用到AMS的publishService方法
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().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);
}
}
}
}
可以看到 2處回調了目前Service對象的onBind方法,接着看下3處,我們跟進去AMS的publishService方法:
#ActivityManagerService
public void publishService(IBinder token, Intent intent, IBinder service) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
//重點!
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
---
#ActiveServices
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
try {
//重點!IPC操作,最終會調用到InnerConnection 對象的connected方法,該方法運作在用戶端的binder線程池中
c.conn.connected(r.name, service, false);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
}
我們看到在 ActiveServices的publishServiceLocked方法中發起了IPC操作,最終會調用到InnerConnection 對象的connected方法,該方法運作在用戶端的binder線程池中,我們跟過去看下:
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, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
//重點 這裡傳過來的dead為false
sd.connected(name, service, dead);
}
}
}
可以看到在InnerConnection 對象的connected方法中調用到ServiceDispatcher 的connected方法,我們跟進去:
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
//重點
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
我們剛有講過,在ServiceDispatcher的構造方法中,将ActivityThread類中的Handler H mH指派給mActivityThread 成員變量,是以這裡調用到mH的post方法切換到主線程,我們跟進去RunConnection對象的run方法:
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}
public void run() {
//這裡傳入的mCommand 為0,會調用doConnected方法
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}
我們接着跟進去doConnected方法看下:
#ServiceDispatcher
public void doConnected(ComponentName name, IBinder service, boolean dead) {
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.
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
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 now disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
// If there is a new service, it is now connected.
if (service != null) {
//重點!!!
mConnection.onServiceConnected(name, service);
}
}
可以看到在doConnected方法的最後調用到了ServiceConnection的onServiceConnected方法。
至此,Service的啟動方式之bindService方式的源碼分析就結束了。