前言:
Service的启动流程将会分为一个系列来讲述。
本系列开始将分析Service的启动过程。
看这个系列文章之前你所需要知道的知识点:
1. 熟悉service的基本用法。
2. 了解bind机制,知道android的客户端和AMS间通信流程。
3. 最好学习过activity的启动流程。
本系列将涉及到以下一些分支:
startService源码分析
bindService源码分析、startService和bindService区别
第二次startService为什么没有调用onCreate
为什么bindService和startService同时调用后需要同时调用unBind和stop才能使服务停止。
前台Service原理
今天这一篇将讲述bindService源码分析:
分析bindService,不打算像startService一样,分析整个AMS流程。
因为两者的AMS流程很相似,所以打算结合startService流程,分析两者的不同之处。
首先我们要思考一下startService和bindService用法上有什么不同:
1. 服务端:
区别 | startService | bindService |
---|---|---|
生命周期 | 会调用onStartCommend | 会调用onBind |
返回值 | onStartCommend没有返回值 | onBind需要返回一个Bind类型的值 |
2. 客户端
区别 | startService | bindService |
---|---|---|
启动 | 用startService来启动startService | 用bindService来启动bindService |
参数 | startService参数只需要一个Intent | bindService参数多需要ServiceConnection |
回调 | 没有回调 | 需要重写ServiceConnection的onServiceConnected方法 |
3、其他区别
区别 | startService | bindService |
---|---|---|
直接UI更新(非广播或eventbus等其他机制) | 不可以 | 可以 |
跨进程 | 不可以 | 可以 |
区别大概就是以上几点。可以看出bindService和startService相比,多了一个bind机制,可以让Service和Activity之间相互通信。当然,主要目的是为了可以进行跨进程通信。
我们先从客户端的bindService方法开始看,
当然,客户端经过一系列调用最终会执行到ContextImpl的bindServiceCommon方法:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;//sd具体实现类是ServiceDispatch
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
//新建一个ServiceDispatch.InnerConnection,第一个参数是:ServiceConnection
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;
}
//Prepare this {@link Intent} to leave an app process. 跨进程通信准备
service.prepareToLeaveProcess(this);
//开始AMS通信,注意参数多了一个sd,该参数包含了ServiceConnection信息
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();
}
}
bindServiceCommon相比startServiceCommend多了一步sd参数的生成。sd参数是什么?怎么生成的呢?
先来看下获取sd的方法mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
:
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) {
//用ServiceConnection生成一个LoadedApk.ServiceDispatcher
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();//获取InnerConnection
}
}
ServiceDispatcher的getIServiceConnection方法
private final ServiceDispatcher.InnerConnection mIServiceConnection;
..
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
从上面两段代码我们看到sd原来是一个IServiceConnection。看上去是一个跨进程通信的玩意儿。
这里涉及到三个类(LoadedApk,ServiceDispatch,InnerConnection)、一个接口IServiceConnection:
LoadedApk,ServiceDispatch,InnerConnection关系如下:
LoadedApk: Local state maintained about a currently loaded .apk.:保持当前加载的.apk的本地状态。
ServiceDispatch:它是LoadedApk内部类,其构造函数:
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
mIServiceConnection = new InnerConnection(this);//用自己新建一个InnerConnection
mConnection = conn;//保存了ServiceConnection
mContext = context;
mActivityThread = activityThread;
mLocation = new ServiceConnectionLeaked(null);
mLocation.fillInStackTrace();
mFlags = flags;
}
InnerConnection:它是ServiceDispatch内部类,继承了IServiceConnection.Stub,可以跨进程通信,其源码:
private static class InnerConnection extends IServiceConnection.Stub {//继承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,且该connected方法执行的是ServiceDispatcher的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);
}
}
可以看到connected方法会会执行RunConnection的run()方法或者doConnected方法,再看RunConnection类:
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() {
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方法,doConnected方法源码:
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
...省略一些代码
// 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) {
//执行ServiceConnection的onServiceConnected
mConnection.onServiceConnected(name, service);
}
}
最终会执行ServiceConnection的onServiceConnected方法。
至于为什么这么麻烦的使用这么多类来生成一个sd,主要是因为涉及到跨进程通信,而ServiceConnection并不能进行跨进程通信,只能用ServiceDispatcher.InnerConnection来保存其信息,进行跨进程通信。
以上分析了ServiceConnection是如何被封装成ServiceDispatcher.InnerConnection的。
我们只要知道2点:
1. 由于ServiceConnection不能跨进程,所以使用了ServiceDispatcher.InnerConnection来保存ServiceConnection的信息,
2. ServiceDispatcher.InnerConnection执行connected方法会执行ServiceConnection的onServiceConnected方法。
记住以上两点,在后面的onServiceConnected我们流程中会用到,继续回头看,下面会进行跨进程通信。
调用AMS的bindService,经过一系列调用最终同样会走到realStartServiceLocked。具体调用了哪些方法可以看时序图。总结如下:
bindService(ActivityManagerService)—bindServiceLocked(ActiveServices)—-bringUpServiceLocked(ActiveServices)—-realStartServiceLocked(ActiveServices)。
最终执行的realStartServiceLocked方法,其实在startService中最终也是realStartServiceLocked方法。很神奇,怎么都走了这个方法?为什么后面客户端的流程会不一样呢(startService执行了onStartCommend,bindService执行了onBind)?那么我们再来回顾一下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);
mAm.updateOomAdjLocked();
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);
//会调用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;
}
//后续onBind方法会调用
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}
//后续onStartCommend方法会调用
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(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);
}
}
}
注意requestServiceBindingsLocked方法,它后续会调用bindService。
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;
}
}
}
该方法用到了r.bindings。它是一个ArrayMap,保存了客户端的bind消息:
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
= new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
哈哈,前文中的卖得关子现在看到了,原来是用r.bindings来判断是否执行onBind方法的啊~。
具体保存方法在AMS一开始的方法bindServiceLocked中:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
...
//该方法给bindings赋值
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
....
return 1;
}
public AppBindRecord retrieveAppBindingLocked(Intent intent,
ProcessRecord app) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord i = bindings.get(filter);
if (i == null) {
i = new IntentBindRecord(this, filter);
bindings.put(filter, i);
}
AppBindRecord a = i.apps.get(app);
if (a != null) {
return a;
}
a = new AppBindRecord(this, i, app);
i.apps.put(app, a);
return a;
}
这里可以看到bindings里面保存了IntentBindRecord记录。IntentBindRecord保存的是intent。
requestServiceBindingsLocked通过循环取出该记录,执行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 ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//调用客户端的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;
}
这里值得注意的是:
1. startService流程也会执行到requestServiceBindingsLocked方法,可是由于没有给bindings赋值,所以不会执行循环里的requestServiceBindingLocked方法。即不会执行onBind方法
2. bindService流程执行requestServiceBindingsLocked后,会继续执行sendServiceArgsLocked方法,通过startService流程解析,我们知道该方法后续会执行onStartCommend。执行onStartCommend的标识是pendingStarts这个记录。在前文中有提到记录如何赋值的。bindService流程并没有给其赋值。所以bindService并不会执行onStartCommend方法。
我们再看requestServiceBindingLocked方法又开始执行客户端ActivityThread中的方法: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);
}
后面的流程和startService在客户端流程一致,会调用到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) {
//执行客户端-server的onBind方法,并返回IBinder
IBinder binder = s.onBind(data.intent);
//注意:又一个AMS流程,用返回的IBinder调用客户端-client的onServiceConnected
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().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);
}
}
}
}
这里相比startService不同的是:ActivityManagerNative.getDefault().publishService(data.token, data.intent, binder);方法。该方法其实又是AMS流程,最终调用客户端-client的onServiceConnected方法。
那么我们看下具体是怎么实现的吧。经过一系列调用,最终会执行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 = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Published intent: " + intent);
continue;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "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);
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
关键代码是c.conn.connected(r.name, service);这里的c是一个ConnectionRecord。是从ServiceRecord中的connections获取的。connections是在哪里赋值的呢?其实还是在一开始的bindServiceLocked方法里:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
...
//生成ConnectionRecord作为value
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();//获取 InnerConnection,作为key
ArrayList clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList();
s.connections.put(binder, clist);//给connections赋值
}
clist.add(c);
....
return 1;
}
注意这里的connection参数,其实它就是文章一开始说的InnerConnection。
ConnectionRecord类保存了该connection。最终在publishServiceLocked里面循环取出并调用connection的connected方法。文章开头已经知道该方法最终会执行ServiceConnection的onServiceConnected方法。
至此bindService整个流程结束。