前言
在做Android开发过程中,我们经常使用bindService()
绑定服务,并且通过返回的Binder
对象进行多进程间通信。
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// service是怎么来的?
media = IMedia.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
media = null;
}
};
Intent intent = new Intent(this, MediaService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
但是我很好奇这个Binder
对象service
是怎么被返回的?带着这个疑问去系统源码里寻找答案,然后就有了这篇bindService()过程分析。
第一步 android.app.ContextImpl.java
首先bindService(intent, conn, Context.BIND_AUTO_CREATE)
实际上是调用了ContextImpl
里的bindService(...)
方法
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
接着又调用bindServiceCommon(...)
方法
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) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
}
...
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
...
return res != 0;
}
通过调用ActivityManager.getService().bindService(...)
将跨进程进入到ActivityManagerService
的bindService(...)
方法,第三步将接着这里分析。
另外,bindService(...)
传入了一个重要的参数sd
,那么sd
是怎么获取的?它的具体类型是什么呢?请看第二步。
第二步 android.app.LoadedApk.java
首先mPackageInfo
是一个LoadedApk
类型对象,sd
是通过调用mPackageInfo
的getServiceDispatcher(...)
方法获取的
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) {
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);
}
return sd.getIServiceConnection();
}
}
直接进入到LoadedApk.ServiceDispatcher
的getIServiceConnection()
方法
static final class ServiceDispatcher {
private final Handler mActivityThread;
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
// mIServiceConnection的类型是InnerConnection
mIServiceConnection = new InnerConnection(this);
mConnection = conn;
mContext = context;
mActivityThread = activityThread;
mLocation = new ServiceConnectionLeaked(null);
mLocation.fillInStackTrace();
mFlags = flags;
}
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
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);
}
}
}
}
通过上面的代码可知,sd
是ServiceDispatcher.InnerConnection
类型的对象,这个sd
后面的讲解还会用到。
第三步 com.android.server.am.ActivityManagerService.java
第一步中ContextImpl
通过跨进程通信进入到了ActivityManagerService
的bindService(...)
方法
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);
}
}
然后mServices
是一个ActiveServices
对象、bindService (...)
就直接转交给了ActiveServices
的bindServiceLocked(...)
第四步 com.android.server.am.ActiveServices.java
bindServiceLocked(...)
的代码很长,只列出了关键部分
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
...
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
...
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
c.conn.connected(s.name, b.intent.binder, false);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
...
}
从最开始的调用bindService(intent, conn, Context.BIND_AUTO_CREATE)
可知传进来的参数flags的位Context.BIND_AUTO_CREATE为1,所以会执行bringUpServiceLocked (...)
去启动服务,然后就直接返回了。
如果不为1会继续往下,创建一个ConnectionRecord
对象c
,c
的conn
为传入的参数connection
,这个conn
实际上就是第二步中的sd
对象,即ServiceDispatcher.InnerConnection
类型对象。
接下来判断如果服务已经在运行、则会直接调用c.conn.connected(...)
发布连接,发布连接的过程将在第六步中分析。
第五步 com.android.server.am.ActiveServices.java
接着第四步的bringUpServiceLocked (...)
分析
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
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.
}
} else {
...
}
}
如果进程已启动,会调用realStartServiceLocked(...)
继续去启动服务
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
try {
...
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 {
...
}
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
}
app.thread
是应用程序端ApplicationThread
的一个远程Binder
对象,是在第一步中调用ActivityManager.getService().bindService(...)
传入的mMainThread.getApplicationThread()
,
通过它服务端ActivityManagerService
可以调用应用程序端ApplicationThread
中的方法。
app.thread.scheduleCreateService
这个方法通过多进程通信让应用程序去创建Service
对象,并调用它的onCreate()
方法。
requestServiceBindingsLocked(...)
会辗转调用到r.app.thread.scheduleBindService(...)
,接下来就调用到了ApplicationThread
的scheduleBindService(...)
方法
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
if (DEBUG_SERVICE)
Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
sendMessage(H.BIND_SERVICE, s);
}
发送一个Handler
消息给ActivityThread.H
类对象
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
接下来就调用到了ActivityThread
的handleBindService()
方法
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);
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);
}
}
}
}
然后通过ActivityManager.getService().publishService(...)
又回到了ActivityManagerService
的publishService()
方法
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
的publishServiceLocked()
方法
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList clist = r.connections.valueAt(conni);
for (int i=0; i
首先获取到ConnectionRecord
类型对象c
,然后调用c.conn.connected(...)
发布连接。前面第四步中已提到过如果服务已经在运行,也会直接调用c.conn.connected(...)
来发布连接,接下来就在第六步中具体分析c.conn.connected(...)
。
第六步 android.app.LoadedApk.ServiceDispatcher.InnerConnection.java
c.conn
其实就是sd
,是在第一步中通过ActivityManager.getService().bindService(...)
方法传入的,由于ActivityManager.getService().bindService(...)
是一个跨进程通信方法,从sd
到c.conn
其实在native层传输时有一次转换,这样c.conn
可以从服务端调用到应用端的方法。然后sd
是一个ServiceDispatcher.InnerConnection
类型对象。
InnerConnection
继承于IServiceConnection.Stub
,可知c.conn
确实是一个Binder
对象,调用c.conn.connected(...)
,此时这个connected(...)
方法已经被执行在应用端了
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);
}
}
}
接着又会调用到LoadedApk.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);
}
}
判断mActivityThread
是否存在,注意mActivityThread
是一个Handler
对象,并不是ActivityThread
对象,是第一步中的bindServiceCommon (...)
方法传入的mMainThread.getHandler()
,并创建了ServiceDispatcher
以及ServiceDispatcher.InnerConnection
对象。
如果mActivityThread
存在,则让RunConnection
的run()
方法运行于UI线程,否则直接调用doConnected(...)
方法
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
接着还是调用了doConnected(...)
方法
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);
}
}
最后调用mConnection.onServiceConnected(name, service)
,service
就是这样被传递回应用端的。