本文基于 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
14public 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 总结
这里我们来总结一下,接触绑定的流程!