看了好几篇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 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> 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 mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference(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 clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
if (activity != null) {
if (activity.connections == null) {
activity.connections = new HashSet();
}
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();
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 mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference(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方式的源码分析就结束了。