本文基于 Android 7.1.1 源码分析,转载请说明出处!
0 综述
我们通过 bindService 绑定的服务,需要通过 unbindService 来解除绑定:
1 | context.unbindService(conn); |
以前我们只是会调用,但是其底层的调用到底是什么样的呢?知其然知其所以然,今天我们就来学习下 unbindService 的过程!
1 发起端进程
1.1 ContextWrapper.unbindService
1 |
|
ContextWrapper 提供了两个方法来启动 Service,其中一个是隐藏方法:startServiceAsUser!
mBase 是 ContextImpl 对象,继续看!
1.2 ContextImpl.unbindService
1 | class ContextImpl extends Context { |
ContextImpl 和 ContextWrapper 的具体关系,请来看另一博文:Android 系统的 Context 分析,这里我们不再详细说明!
mUser:表示的是当前的设备 user!
1.2.1 LoadedApk.forgetServiceDispatcher
参数传入:
ServiceConnection c:应用程序的链接对象!
1 | public final IServiceConnection forgetServiceDispatcher(Context context, |
这里逻辑很简单,其中,调用了 ServiceDispatcher.doForget 方法!
1 | void doForget() { |
我们继续看!!
接着,调用 ActivityManagerNative.getDefault() 方法,获得 AMS 的代理对象 ActivityManagerProxy!
ActivityManagerProxy 是 ActivityManagerN 的内部类,通过 getDefault 方法创建了对应的单例模式,保存在 ActivityManagerNative 的类变量 getDefault 中!
1.3 ActivityManagerP.unbindService
1 | public boolean unbindService(IServiceConnection connection) throws RemoteException { |
通过 binder 进程间通信,进入系统进程,参数分析:
IServiceConnection connection:InnerConnection对象!
2 系统进程
首先,进入 ActivityManagerN 中去看看:1
2
3
4
5
6
7
8
9
10
11
12
13
14case UNBIND_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
//【1】这里是转换为 IServiceConnection.proxy 对象!
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
boolean res = unbindService(conn);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
return true;
}
2.1 ActivityManagerP.unbindService
继续来看:1
2
3
4
5
6
7
8public boolean unbindService(IServiceConnection connection) {
synchronized (this) {
//【1】进入 ActiveServices 方法!
return mServices.unbindServiceLocked(connection);
}
}
2.2 ActiveServices.unbindServiceLocked
解除服务 bind,参数传入如下:
IServiceConnection connection:是IServiceConnection.Proxy类型的对象,是InnerConnection在系统进程中的Binder实体对象!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63boolean unbindServiceLocked(IServiceConnection connection) {
IBinder binder = connection.asBinder();
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
//【1】从 mServiceConnections 中获得对应的 ConnectionRecord 集合!
// 表示 IServiceConnection 对象对应的所有连接对象!
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
Slog.w(TAG, "Unbind failed: could not find connection for "
+ connection.asBinder());
return false;
}
final long origId = Binder.clearCallingIdentity();
try {
while (clist.size() > 0) {
// 遍历 ConnectionRecord 列表!
ConnectionRecord r = clist.get(0);
//【2】移除连接,并拉起被绑定服务的 unbind 方法,这个我们后面看!
removeConnectionLocked(r, null, null);
if (clist.size() > 0 && clist.get(0) == r) {
// removeConnectionLocked 中会移除这个 ConnectionRecord 对象,这里是异常判断;
// 如果 removeConnectionLocked 移除失败,这里会再次移除!
Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
clist.remove(0);
}
// 如果绑定的服务的进程已经启动,进入该分支!
if (r.binding.service.app != null) {
if (r.binding.service.app.whitelistManager) {
updateWhitelistManagerLocked(r.binding.service.app);
}
// This could have made the service less important.
if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
r.binding.service.app.treatLikeActivity = true;
mAm.updateLruProcessLocked(r.binding.service.app,
r.binding.service.app.hasClientActivities
|| r.binding.service.app.treatLikeActivity, null);
}
// 更新服务的 adj 的值!
mAm.updateOomAdjLocked(r.binding.service.app);
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
return true;
}ActiveServices的mServiceConnections用来封装所有服务的连接对象IServiceConnection.proxy和ConnectionRecord的映射关系,二者是一对多的关系!
继续来看!
2.3 ActiveServices.removeConnectionLocked
这个方法是 unbindService 整个流程中的关键!
ConnectionRecord c:连接信息对象;ProcessRecord skipApp:传入为null;ActivityRecord skipAct:传入为null;
1 | void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) { |
这段代码最开始是解除 bindService 时创建的数据结构和引用关系!然后拉起了被绑定服务的 unbind 方法,最后尝试停止服务!
注意:
如果之前对应的 bindService 使用了 Context.BIND_AUTO_CREATE 的 flags,这里就会尝试把服务停止,但是如果之前对应的 bindService 没有设置 Context.BIND_AUTO_CREATE 标志位,从前面的 bindService 流程中,可以看出,只会把之前 bind 时的绑定信息删除即可!
下面我们来一个一个分析!
2.3.1 ApplicationThreadP.scheduleUnbindService
首先,来看看拉起 onUnbind 方法的逻辑!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public final void scheduleUnbindService(IBinder token, Intent intent)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
intent.writeToParcel(data, 0);
//【1】binder 通信,采用的是 IBinder.FLAG_ONEWAY 的方式,非阻塞式!
mRemote.transact(SCHEDULE_UNBIND_SERVICE_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
这里通过 binder 通信,进入服务所在的应用进程中!我们在第三部分详细讨论!!
2.3.2 ActiveServices.bringDownServiceIfNeededLocked
拉起了服务的 onUnbind 方法后,对于 bindService 时,如果设置了 Context.BIND_AUTO_CREATE 的 flags,还要尝试停止服务!
我们来看一下具体的逻辑!
1 | private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, |
如果这个服务仍然被需要,或者服务所在的进程正在启动,这两种情况下,不能停止服务!
2.3.2.1 ActiveServices.isServiceNeeded
1 | private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) { |
hasAutoCreateConnections 方法遍历 ServiceRecord.connections 集合:1
2
3
4
5
6
7
8
9
10
11
12
13// in ServiceRecord
public boolean hasAutoCreateConnections() {
for (int conni=connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
for (int i=0; i<cr.size(); i++) {
if ((cr.get(i).flags&Context.BIND_AUTO_CREATE) != 0) {
return true;
}
}
}
return false;
}
判断一个服务是否仍被需要,有两种情况:
- 服务已经通过
startService被请求启动了; - 服务仍然被一些应用通过自动创建的方式绑定,即
bindService时,flags为Context.BIND_AUTO_CREATE;
如果满足上面的任何一个条件,isServiceNeeded 返回的是 true,那么,就不会停止这个任务了!
通过我们上面的分析,当我们调用 unbindService后,会将之前 bind 时的创建的连接对象从集合中移除,所以hasConn为false,但是如果服务之前被startService启动了,并没有stopService,那么unbindService不会继续执行!
下面,我们继续来看:
2.3.2.2 ActiveServices.bringDownServiceLocked
如果没有其他的应用通过 BIND_AUTO_CREATE 的方式来绑定这个服务,那么就要调用 bringDownServiceLocked 方法,来停止服务,这里我们假设没有其他的绑定信息!
1 | private final void bringDownServiceLocked(ServiceRecord r) { |
这段代码很简单,主要逻辑如下:
- 首先进入绑定服务的应用进程,回调
ServiceConnection的onServiceDisconnected方法,取消所有进程对该服务的绑定; - 接着,进入服务所在的进程,拉起服务的
onUnbind方法; - 最后,拉起服务的
onDestroy方法,销毁服务;
整个过程,还会清空和重置一些关键变量!!
下面我们重点分析一下上面的三个过程!
3 服务所在进程
首先要进入 ApplicationThreadN.onTransact 方法:1
2
3
4
5
6
7
8
9
10case SCHEDULE_UNBIND_SERVICE_TRANSACTION: {
data.enforceInterface(IApplicationThread.descriptor);
IBinder token = data.readStrongBinder();
Intent intent = Intent.CREATOR.createFromParcel(data);
//【1】执行 unbind 方法!
scheduleUnbindService(token, intent);
return true;
}
继续来看:
进入 ApplicationThread 中!
3.1 ApplicationThread.scheduleUnbindService
1 | public final void scheduleUnbindService(IBinder token, Intent intent) { |
进入 H!
3.1.1 ActivityThread.H
1 | private class H extends Handler { |
继续来看!!
3.1.2 ActivityThread.handleUnbindService
接着,这里是关键地方!:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36private void handleUnbindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
//【3】拉起服务的 onUnbind 方法,并获得返回值!
boolean doRebind = s.onUnbind(data.intent);
try {
if (doRebind) {
// 如果 doRebind 值为 true,进入该分支!
ActivityManagerNative.getDefault().unbindFinished(
data.token, data.intent, doRebind);
} else {
// 如果返回 false(默认),就会执行 serviceDoneExecuting 方法!
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to unbind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
如果 doRebind 为 true,调用 AMS 的 unbindFinished 方法;
如果 doRebind 为 false,调用 AMS 的 serviceDoneExecuting 方法;
拉起了 onUnbind 方法后,需要根据返回值做相应的处理,接下来进入系统进程,具体逻辑见第四部分!!
3.2 InnerConnection.connected
系统进程会调用 IServiceConnection.Proxy 代理对象的 connected 方法,通过 binder 调用,进入绑定服务的应用进程,这个是异步调用:
1 | cr.conn.connected(r.name, null); |
我们去看看!
1 | private static class InnerConnection extends IServiceConnection.Stub { |
继续来看:
3.2.1 ServiceDispatcher.connected
1 | public void connected(ComponentName name, IBinder service) { |
最后都会调用 doConnected 方法:
3.2.2 ServiceDispatcher.doConnected
参数 service 这里为 null!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
// mForgotten 在最开始就被设置成了 true,所以这里就会直接返回的!
// ServiceConnection.onServiceDisconnected 方法不会被调用!
if (mForgotten) {
// We unbound before receiving the connection; ignore
// any connection received.
return;
}
// 获得已有的活跃的 connection 对象!
old = mActiveConnections.get(name);
if (old != null && old.binder == service) { // 因为 service 为 null,所以这里不会进入该分支!
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 {
// service 为 null,说明是解除绑定,所以要从 mActiveConnections 中移除绑定对象!
mActiveConnections.remove(name);
}
// 取消死亡通知监控器
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
// 之前是有连接的,所以会进入这分支!!
if (old != null) {
// 拉起服务的 onServiceDisconnected 方法!
mConnection.onServiceDisconnected(name);
}
// 不进入这个分支!
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
这里,最后会进入应用的 ServiceConnection 对象!1
2
3
4
5
6private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
}
}
注意:onServiceDisconnected 方法是非阻塞的,即,系统进程不会等 onServiceDisconnected 执行完才继续执行!!
4 系统进程
首先会进入 ActivityManagerNative 的 onTransact 方法中:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28case UNBIND_FINISHED_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
Intent intent = Intent.CREATOR.createFromParcel(data);
boolean doRebind = data.readInt() != 0;
// 继续来看!
unbindFinished(token, intent, doRebind);
reply.writeNoException();
return true;
}
case SERVICE_DONE_EXECUTING_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
int type = data.readInt();
int startId = data.readInt();
int res = data.readInt();
// 继续来看!
serviceDoneExecuting(token, type, startId, res);
reply.writeNoException();
return true;
}
接下来,进入 AMS!
4.1 ActivityManagerS.unbindFinished
如果 onUnbind 方法返回的是 true,进入该方法:1
2
3
4
5
6
7
8
9
10
11
12
13public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
// 不能通过 intent 传递文件描述符!
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
// 进入 ActiveServices!
mServices.unbindFinishedLocked((ServiceRecord)token, intent, doRebind);
}
}
4.1.1 ActiveServices.unbindFinishedLocked
继续来看,doRebind 是服务的 onUnbind 方法的返回值!!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57void unbindFinishedLocked(ServiceRecord r, Intent intent, boolean doRebind) {
final long origId = Binder.clearCallingIdentity();
try {
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
// 获得绑定 Serivce 的 intent 对应的 IntentBindRecord 对象!
IntentBindRecord b = r.bindings.get(filter);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindFinished in " + r
+ " at " + b + ": apps="
+ (b != null ? b.apps.size() : 0));
// 这里的 inDestroying 的值为 false,因为还没有添加!
boolean inDestroying = mDestroyingServices.contains(r);
// 显然,这里不会为 null!
if (b != null) {
if (b.apps.size() > 0 && !inDestroying) {
// Applications have already bound since the last
// unbind, so just rebind right here.
boolean inFg = false;
for (int i=b.apps.size()-1; i>=0; i--) {
ProcessRecord client = b.apps.valueAt(i).client;
if (client != null && client.setSchedGroup
!= ProcessList.SCHED_GROUP_BACKGROUND) {
inFg = true;
break;
}
}
try {
requestServiceBindingLocked(r, b, inFg, true);
} catch (TransactionTooLargeException e) {
// Don't pass this back to ActivityThread, it's unrelated.
}
} else {
// 将 doRebind 置为 true!
b.doRebind = true;
}
}
// 最后进入 serviceDoneExecutingLocked 方法!
serviceDoneExecutingLocked(r, inDestroying, false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
接着来看!
4.1.2 ActiveServices.serviceDoneExecutingLocked
参数传递:
boolean inDestroying:传入false;boolean finishing:传入false;
1 | private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, |
这里就不再详细说了!!
4.2 ActivityManagerS.serviceDoneExecuting
对于拉起 onDestroy 方法,最后会调用:1
2
3
4
5
6
7
8
9
10
11
12public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
throw new IllegalArgumentException("Invalid service token");
}
// 最后,进入 AS!
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
接着,进入 ActiveServices!
4.2.1 ActiveServices.serviceDoneExecutingLocked
根据参数传递:
int type:传入ActivityThread.SERVICE_DONE_EXECUTING_STOP;int startId:传入0;int res:传入0;
1 | void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) { |
4.2.2 ActiveServices.serviceDoneExecutingLocked
参数传递:
boolean inDestroying:传入true;boolean finishing:传入true;
1 | private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, |
5 总结
这里我们来总结一下,接触绑定的流程!