前沿
上一篇文章给大家分析了一下Binder的交互流程,这篇文章分析一下上篇遗留的bindService执行流程,当我们调用了bindService系统为我们做了些什么。
首先,当我们想要去绑定一个远程service时,我们需要写以下代码:
Intent intent = new Intent(this,MyService.class);
bindService(intent,connection,BIND_AUTO_CREATE);
这时候我们就要进入bindService
中
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
public abstract boolean bindService(Intent service, ServiceConnection conn,
int flags);
这时候我们发现这个调用了mBase.bindService
.进入这个方法才发现是个抽象方法。我去,那怎么办,我们需要找到他真正的子类实现,这里就不给大家卖关子了,我们真正的子类实现是ContextImpl
这个类,那我们去看一下这个类中的bindService
吧。
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
if (mPackageInfo != null) {
//这里先记录以下,一会还会回来
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
//省略一些代码。
service.prepareToLeaveProcess();
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
return false;
}
}
这时候就会调用ActivityManagerNative.getDefault().bindService
这个ActivityManagerNative.getDefault()
代码如下:
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
通过ServiceManager
去获取了一个binder,并把这个binder返回了,是一个IActivityManager
如果大家看过很多底层代码就会很熟悉这样的接口类,我们通过这个接口可以猜出其子类是ActivityManagerService
。我们去这个类中的bindService
一探究竟。
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType,
connection, flags, userId);
}
}
调用了bindServiceLocked
方法
// 省略掉一些有关Activity的启动流程,我们再后面再说
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
requestServiceBindingsLocked(r, execInFg);
}
最后会调用requestServiceBindingsLocked
方法
private final boolean requestServiceBindingLocked(ServiceRecord r,
IntentBindRecord i, boolean execInFg, boolean rebind) {
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);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
return false;
}
}
return true;
}
这里我们看r.app.thread.scheduleBindService
这个方法,但是你又会问,点不进去啊,这个scheduleBindService
在哪里呢。我们进到ProcessRecord
里面看一下
final class ProcessRecord {
private final BatteryStatsImpl mBatteryStats; // where to collect runtime statistics
final ApplicationInfo info; // all about the first app in the process
final boolean isolated; // true if this is a special isolated process
final int uid; // uid of process; may be different from 'info' if isolated
final int userId; // user of process.
final String processName; // name of the process
// List of packages running in the process
final ArrayMap<String, ProcessStats.ProcessState> pkgList
= new ArrayMap<String, ProcessStats.ProcessState>();
IApplicationThread thread;
发现又是一个IApplicationThread
那我们的实现类是是就可以猜出是ApplicationThread
这个类呢,其实这样想我们是对的,但是在这里你是找不到这个类的,我在开始找的时候也很头疼,找了半天发现不是我所想的那样。这里的ApplicationThread
是一个内部类,它在ActivityThread
中。让我们继续走刚刚的方吧。
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;
Binder.getCallingPid());
sendMessage(H.BIND_SERVICE, s);
}
这里通过H 发送了一个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;
调用了handleBindService
方法
private void handleBindService(BindServiceData data) {
//从记录中获取一个service对象,每次启动Service,系统都会记录到mServices中
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
try {
//判断service是否未绑定过了
if (!data.rebind) {
//没有绑定需要走onBind
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
//绑定过需要走onRebind
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, 0, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
这里会判断是否已经绑定过了,如果未绑定就回调onBind方法,绑定过了就会回调onRebingd方法。最后会调用publishService
方法,我们在前面见过这个类,而且知道他的子类是ActivityManagerService
,那我们去里面看看吧。
public void publishService(IBinder token, Intent intent, IBinder service) {
synchronized(this) {
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
调用了publishServiceLocked
这里我们只贴关键代码
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v(
TAG, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v(
TAG, "Bound intent: " + c.binding.intent.intent);
if (DEBUG_SERVICE) Slog.v(
TAG, "Published intent: " + intent);
continue;
}
if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
}
}
这时候就会去ConnectionRecord list中去查找,找到就开始调用c.conn.connected(r.name, service)
,那这个conn又是什么呢,我们点进去看一下。
final class ConnectionRecord {
final IServiceConnection conn;
是不是感觉很熟悉,那我们按照以前的套路去查一下ServiceConnection
这个类吧,但是你会失望的发现他还是个接口,那咋办,还记得我在上面有个地方说一会还会回来看这里的地方么。我们去看看。
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
}
发现进入到了LoadedApk
中的getServiceDispatcher
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) {
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
这里把LoadedApk.ServiceDispatcher
放进了一个map中,这里就是我们上面要找的那个conn
,让我们看一下这个类的实现吧。
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);
}
}
}
public void connected(ComponentName name, IBinder service) {
doConnected(name, service);
}
public void doConnected(ComponentName name, IBinder service) {
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
经过一连串的方法调用,终于看到了我们认识的方法mConnection.onServiceConnected(name, service);
最后会吧IBinder回调到我们的客户端。到这里bindService的流程就完了。
UML图如下:
bindService.jpg喜欢的请大家点赞哦!不对的地方请留言指出,谢谢。
网友评论