从源码层解析ContentService如何实现数据变化监听

简介

ContentService是ContentResolver的服务端,运行在system_server进程,为所有应用提供访问ContentProvider数据接口。同时ContentService也提供监听数据变化的接口,这篇文章将从源码的角度去解析registerContentObserver和unregisterContentObserver的流程。再此之前,我先提供一个简短的接口使用实例。

使用实例

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
public class ContentManager {
private static final Uri URI = Settings.System.getUriFor(Settings.System.EXAMPLE_URI);
private MyObserver observer;
class MyObserver extends ContentObserver {
public MyObserver(Handler handler) {
super(handler);
}
}
@Override
public void onChange(boolean selfChange) {
this.onChange(selfChange,null);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
// 数据变化时会回调到这个接口
}
public void start(Context context, Handler handler) {
observer = new MyObserver(handler);
context.getContentResolver().registerContentObserver(URI, false, observer);
}
public void stop(Context context) {
context.getContentResolver().unregisterContentObserver(observer);
}
}

通过调用start接口并传入Context与Handler即可开始监听数据变化,其中onChange是在Handler所在线程进行执行的。调用stop接口即可终止数据监听。

时序图

注册

registerContentObserver

ContextImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private final ApplicationContentResolver mContentResolver;
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
...
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
@Override
public ContentResolver getContentResolver() {
// mContentResolver在ContextImpl初始化时被实例化,调用get接口时直接被返回。
return mContentResolver;
}
private static final class ApplicationContentResolver extends ContentResolver {
private final ActivityThread mMainThread;
private final UserHandle mUser;
...
}

ContextImpl是Context背后真正的办事者,许多操作诸如registerBroadcastReceiver, startService, startActivity都是通过它来进行操作的。至于ContextImpl是怎么被初始化则牵扯到进程的初始化流程,以后有机会再另写一篇来讲。

ContentResolver.java

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
public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendents,
@NonNull ContentObserver observer) {
// registerContentObserver方法首先会进行uri与observer的判空,如何这两个其中一个为空注册都不会成功。
Preconditions.checkNotNull(uri, "uri");
Preconditions.checkNotNull(observer, "observer");
registerContentObserver(ContentProvider.getUriWithoutUserId(uri),
notifyForDescendents,
observer,
ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
}
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer, int userHandle) {
try {
getContentService().registerContentObserver(uri, notifyForDescendents,
observer.getContentObserver(), userHandle);
} catch (RemoteException e) {
}
}
public static IContentService getContentService() {
if (sContentService != null) {
return sContentService;
}
// ContentService运行在system_server端,所以要准备binder通信了,通过ServiceManager获取IBinder来进行通信。
// ServiceManager如何调用getService来获取ContentService其实也是个很复杂的流程,涉及到binder,其实网上的相关概括性的资料很多,以后有机会讲讲细节方面的东西。
IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
if (false) Log.v("ContentService", "default service binder = " + b);
sContentService = IContentService.Stub.asInterface(b);
if (false) Log.v("ContentService", "default service = " + sContentService);
return sContentService;
}

ContentService.java

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
public void registerContentObserver(Uri uri, boolean notifyForDescendants,
IContentObserver observer) {
registerContentObserver(uri, notifyForDescendants, observer,
UserHandle.getCallingUserId());
}
@Override
public void registerContentObserver(Uri uri, boolean notifyForDescendants,
IContentObserver observer, int userHandle) {
// 判空操作,observer对象与uri都是必需的
if (observer == null || uri == null) {
throw new IllegalArgumentException("You must pass a valid uri and observer");
}
// 获取应用端进程与线程id
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final int callingUserHandle = UserHandle.getCallingUserId();
// 权限验证,有些uri如短信读取,需要在manifest注明权限的,用户允许后才能监听
if (callingUserHandle != userHandle &&
mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
enforceCrossUserPermission(userHandle,
"no permission to observe other users' provider view");
}
if (userHandle < 0) {
if (userHandle == UserHandle.USER_CURRENT) {
userHandle = ActivityManager.getCurrentUser();
// 当UserHandle传入的不为USER_ALL时会抛出异常,默认的UserHandle是客户端的uid
} else if (userHandle != UserHandle.USER_ALL) {
throw new InvalidParameterException("Bad user handle for registerContentObserver: "
+ userHandle);
}
}
synchronized (mRootNode) {
// node确定可以被添加,使用初始化完成的root节点添加node
// 这里用到了设计模式中的组合模式
mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
uid, pid, userHandle);
if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
" with notifyForDescendants " + notifyForDescendants);
}
}

addObserverLocked

CountService.java

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
// userHandle要么是客户端uid要么是USER_ALL
public void addObserverLocked(Uri uri, IContentObserver observer,
boolean notifyForDescendants, Object observersLock,
int uid, int pid, int userHandle) {
// index初始化为0
addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
uid, pid, userHandle);
}
private void addObserverLocked(Uri uri, int index, IContentObserver observer,
boolean notifyForDescendants, Object observersLock,
int uid, int pid, int userHandle) {
// 如何这个node是子节点,则加入到树中
// 如何不是,则继续向树的下一层搜索
if (index == countUriSegments(uri)) {
mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
uid, pid, userHandle));
return;
}
// 通过查看uri字符串确认是否有合法的子节点存在
// 如果不存在会抛出异常终止注册
String segment = getUriSegment(uri, index);
if (segment == null) {
throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
}
// 如果存在,则遍历当前的每个子节点,查看当前的节点名称是否和已存在的子节点名称能匹配上
int N = mChildren.size();
for (int i = 0; i < N; i++) {
ObserverNode node = mChildren.get(i);
if (node.mName.equals(segment)) {
// 如果匹配上了,则把当前节点添加到这个匹配上的节点当中
// index自增1
node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
observersLock, uid, pid, userHandle);
return;
}
}
// 如果目前已经存在的节点都不能和当前节点匹配上,则新建一个子节点,将observer添加到这个节点下
// index自增1
ObserverNode node = new ObserverNode(segment);
mChildren.add(node);
node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
observersLock, uid, pid, userHandle);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private int countUriSegments(Uri uri) {
if (uri == null) {
return 0;
}
// 返回uri路径的分段个数
// 如:content://sms/inbox,则这个方法会返回3,表示这个节点将会被放到第3层,mRootNode为第1层
return uri.getPathSegments().size() + 1;
}
private String getUriSegment(Uri uri, int index) {
if (uri != null) {
if (index == 0) {
return uri.getAuthority();
} else {
return uri.getPathSegments().get(index - 1);
}
} else {
return null;
}
}

StringUri.java

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
63
64
65
66
67
68
69
70
71
72
73
public List<String> getPathSegments() {
return getPathPart().getPathSegments();
}
private PathPart getPathPart() {
return path == null
? path = PathPart.fromEncoded(parsePath())
: path;
}
private String parsePath() {
String uriString = this.uriString;
int ssi = findSchemeSeparator();
// If the URI is absolute.
if (ssi > -1) {
// Is there anything after the ':'?
boolean schemeOnly = ssi + 1 == uriString.length();
if (schemeOnly) {
// Opaque URI.
return null;
}
// A '/' after the ':' means this is hierarchical.
if (uriString.charAt(ssi + 1) != '/') {
// Opaque URI.
return null;
}
} else {
// All relative URIs are hierarchical.
}
return parsePath(uriString, ssi);
}
static String parsePath(String uriString, int ssi) {
int length = uriString.length();
// Find start of path.
int pathStart;
if (length > ssi + 2
&& uriString.charAt(ssi + 1) == '/'
&& uriString.charAt(ssi + 2) == '/') {
// Skip over authority to path.
pathStart = ssi + 3;
LOOP: while (pathStart < length) {
switch (uriString.charAt(pathStart)) {
case '?': // Start of query
case '#': // Start of fragment
return ""; // Empty path.
case '/': // Start of path!
break LOOP;
}
pathStart++;
}
} else {
// Path starts immediately after scheme separator.
pathStart = ssi + 1;
}
// Find end of path.
int pathEnd = pathStart;
LOOP: while (pathEnd < length) {
switch (uriString.charAt(pathEnd)) {
case '?': // Start of query
case '#': // Start of fragment
break LOOP;
}
pathEnd++;
}
return uriString.substring(pathStart, pathEnd);
}

总结

  • ContentService中使用了以mRootNode为root节点的树来维护已注册的ContentObserver, 属于设计模式中的组合模式
  • StringUri中的路径层级和组合模式中的树可以相互对应
  • ObserverNode维护了mChilderen和mObservers两个链表,mChildren代表了这个节点的子节点,mObservers代表了这个节点下的ContentObserver

notifyChange

这一节是这篇文章的核心章节,当客户端调用register接口后,相应的ContentObserver已经被存取到了ContentService维护的树中。当ContentProvider数据变化后,这时ContentService该怎么找到对应的Observer进行回调呢?

notifyChange

随便在源码里找来一个继承ContentProvider并实现了onUpdate接口的类:

LocalProvider.java

1
2
3
4
5
6
7
8
9
10
public class LocalProvider extends ContentProvider {
@Override
public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
// 进行数据更新操作,省略掉
...
getContext().getContentResolver().notifyChange(url, null);
return count;
}
}

可以看见,当数据更新完毕后,会调用ContentResolver.notifyChange通知ContentObserver数据已经变化。

代码最终会调用到ContentService.notifyChange方法,中间获取ContentResovler实例的逻辑和registerContentObserver一样。

ContentService.java

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
63
64
65
public void notifyChange(Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, boolean syncToNetwork) {
notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
UserHandle.getCallingUserId());
}
@Override
public void notifyChange(Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, boolean syncToNetwork,
int userHandle) {
// 省略一些检查权限的代码
...
long identityToken = clearCallingIdentity();
try {
ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
synchronized (mRootNode) {
// 传入新建的链表,用来存储符合规则的ContentObserver
mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
userHandle, calls);
}
final int numCalls = calls.size();
for (int i=0; i<numCalls; i++) {
ObserverCall oc = calls.get(i);
try {
// 这里调用了binder IPC, 通知各个客户端数据已经变化
oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
}
} catch (RemoteException ex) {
// 如果进程间通信失败了,很有可能是客户端的进程已经死亡
// 也有可能客户端binder空间被占满无法通信
synchronized (mRootNode) {
Log.w(TAG, "Found dead observer, removing");
IBinder binder = oc.mObserver.asBinder();
final ArrayList<ObserverNode.ObserverEntry> list
= oc.mNode.mObservers;
int numList = list.size();
// 进行删除操作
for (int j=0; j<numList; j++) {
ObserverNode.ObserverEntry oe = list.get(j);
if (oe.observer.asBinder() == binder) {
list.remove(j);
j--;
numList--;
}
}
}
}
}
// 通知SyncManager启动对应账号的同步
// 这里涉及到安卓自带的账号同步框架,了解的不多,有机会接触再深入了解吧
if (syncToNetwork) {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
uri.getAuthority());
}
}
} finally {
restoreCallingIdentity(identityToken);
}
}

collectObserversLocked

ObserverNode.java

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
public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
boolean observerWantsSelfNotifications, int targetUserHandle,
ArrayList<ObserverCall> calls) {
String segment = null;
// uri 层级
int segmentCount = countUriSegments(uri);
// 如果当前递归的层级已经到了底部,很有可能已经到叶节点
if (index >= segmentCount) {
collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
targetUserHandle, calls);
} else if (index < segmentCount){
// 获取当前的segment名称
segment = getUriSegment(uri, index);
// notifyForDescendants如果为true,也是要进行通知的
collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
targetUserHandle, calls);
}
int N = mChildren.size();
for (int i = 0; i < N; i++) {
ObserverNode node = mChildren.get(i);
if (segment == null || node.mName.equals(segment)) {
// 进行下一级递归去搜寻
node.collectObserversLocked(uri, index + 1,
observer, observerWantsSelfNotifications, targetUserHandle, calls);
if (segment != null) {
break;
}
}
}
}
private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
boolean observerWantsSelfNotifications, int targetUserHandle,
ArrayList<ObserverCall> calls) {
int N = mObservers.size();
IBinder observerBinder = observer == null ? null : observer.asBinder();
for (int i = 0; i < N; i++) {
ObserverEntry entry = mObservers.get(i);
// 如果selfChange为true, 不在同一进程的change将不会被通知
boolean selfChange = (entry.observer.asBinder() == observerBinder);
if (selfChange && !observerWantsSelfNotifications) {
continue;
}
// 进行匹配,如果匹配上了将会被加入到calls链表,之后会进行依次notify
if (targetUserHandle == UserHandle.USER_ALL
|| entry.userHandle == UserHandle.USER_ALL
|| targetUserHandle == entry.userHandle) {
// Make sure the observer is interested in the notification
if (leaf || (!leaf && entry.notifyForDescendants)) {
calls.add(new ObserverCall(this, entry.observer, selfChange));
}
}
}
}

补充一点,既然ContentObserver的onChange方法能够被binder调用,为什么ContentObserver没有继承Binder Stub接口呢?

ContentObserver.java

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
public IContentObserver getContentObserver() {
synchronized (mLock) {
if (mTransport == null) {
mTransport = new Transport(this);
}
return mTransport;
}
}
private static final class Transport extends IContentObserver.Stub {
private ContentObserver mContentObserver;
public Transport(ContentObserver contentObserver) {
mContentObserver = contentObserver;
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
ContentObserver contentObserver = mContentObserver;
if (contentObserver != null) {
contentObserver.dispatchChange(selfChange, uri, userId);
}
}
public void releaseContentObserver() {
mContentObserver = null;
}
}

可以看见,ContentObserver中有getContentObserver接口在ContentResolver.registerContentObserver中会被调用,真正传输到服务端的对象是Transport,它的onChange方法会被binder call调用,最终调用dispatchChange接口。

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
private void dispatchChange(boolean selfChange, Uri uri, int userId) {
if (mHandler == null) {
// mHanlder为空将在主线程中直接执行onChange方法
onChange(selfChange, uri, userId);
} else {
// 不为空则在Hanlder所在进程异步执行中执行
mHandler.post(new NotificationRunnable(selfChange, uri, userId));
}
}
private final class NotificationRunnable implements Runnable {
private final boolean mSelfChange;
private final Uri mUri;
private final int mUserId;
public NotificationRunnable(boolean selfChange, Uri uri, int userId) {
mSelfChange = selfChange;
mUri = uri;
mUserId = userId;
}
@Override
public void run() {
ContentObserver.this.onChange(mSelfChange, mUri, mUserId);
}
}

mHandler是在ContentObserver被实例化时传进来的,Handler的传入涉及到业务逻辑真正在那个线程执行,做应用的人应该格外关注。

总结

  • ContentProvider调用onUpdate更新数据完毕后将会调用notifyChange通知数据已经更新
  • ContentService先调用ObserverNode的收集接口,获取所有需要通知的observer
  • 最后ContentService会使用binder call调用onChange接口

unregisterContentObserver

register和notifyChange这两块的逻辑很重要,unregister其实在实战中也很重要,因为如果不在合适的时候unregister,服务端就还会维护额外的ObserverNode,给系统带来不必要的开销。同时也会在客户端这边造成内存泄露,更严重的是,如果onChange在主线程更新了控件也会有几率抛出空指针异常导致应用FC

ContentService.java

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
public void unregisterContentObserver(IContentObserver observer) {
if (observer == null) {
throw new IllegalArgumentException("You must pass a valid observer");
}
synchronized (mRootNode) {
// 从root节点开始remove
mRootNode.removeObserverLocked(observer);
if (false) Log.v(TAG, "Unregistered observer " + observer);
}
}
public boolean removeObserverLocked(IContentObserver observer) {
int size = mChildren.size();
for (int i = 0; i < size; i++) {
boolean empty = mChildren.get(i).removeObserverLocked(observer);
// 当前节点的孩子如果全部被移出,则将当前节点在他的父节点链表中也移除掉
if (empty) {
mChildren.remove(i);
i--;
size--;
}
}
IBinder observerBinder = observer.asBinder();
size = mObservers.size();
for (int i = 0; i < size; i++) {
ObserverEntry entry = mObservers.get(i);
// 进行匹配,值得注意的是,同节点下相同的observer一次只能移除一个
if (entry.observer.asBinder() == observerBinder) {
mObservers.remove(i);
// observer binder不再需要监听死亡回掉了
observerBinder.unlinkToDeath(entry, 0);
break;
}
}
// 当前节点的孩子已经全部被移除了
if (mChildren.size() == 0 && mObservers.size() == 0) {
return true;
}
return false;
}

类图

扫码支持0.99元,您的支持将鼓励我继续创作!