前言
⚠️ 本文为修正版 。初版存在关键错误:误认为
registerContentObserver走IContentProviderBinder 到 Provider 进程、误认为通知通过 AMS 广播。经阅读实际 AOSP 12 源码后修正。
在 Android 开发中,监听系统设置变化是一个常见需求:
java
getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
false,
new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange, Uri uri) {
// 收到变化回调
}
}
);
这短短几行代码背后,跨越了应用进程和 SystemServer 进程 ,涉及 ContentService 中央注册、ObserverNode 树形匹配、Binder 回调 等多个机制。本文基于 AOSP 12 (android-12.0.0_r32) 源码,逐层拆解这条完整的回调链路。
一、核心架构:ContentService 是中央枢纽
与许多开发者的直觉不同,ContentObserver 的注册和通知分发不经过 Provider 进程,也不经过 AMS 。Android 有一个独立的 ContentService 运行在 system_server 中,作为全局唯一的注册中心和通知分发器。
plain
┌──────────────────────────────────────────────────────────────────┐
│ SystemServer 进程 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ContentService (IContentService.Stub) │ │
│ │ │ │
│ │ mRootNode: ObserverNode │ │
│ │ ├─ "" (根节点) │ │
│ │ │ └─ "settings" ← authority │ │
│ │ │ └─ "global" ← path segment[0] │ │
│ │ │ └─ "airplane_mode_on" ← path seg[1] │ │
│ │ │ └─ ObserverEntry[ uid, pid, │ │
│ │ │ IContentObserver ] │ │
│ │ │ │ │
│ │ ObserverCollector: 聚合 → dispatch(按进程优先级) │ │
│ │ BackgroundThread: 10s延迟调度(后台进程) │ │
│ │ BinderDeathDispatcher: 自动清理死进程的 observer │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ SettingsProvider (ContentProvider) 也运行在此进程 │ │
│ │ → 通过 MyHandler 异步触发 notifyChange │ │
│ └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘ │
▲ │ │
│ registerContentObserver │ notifyChange │
│ (IContentService Binder) │ (IContentService│
│ │ Binder) │
▼ ▼ │
┌──────────────────────┐ ┌──────────────────────┐ │
│ App Process │ │ App Process 2 │ │
│ (IContentObserver │ │ (IContentObserver │ │
│ Binder 服务端) │ │ Binder 服务端) │ │
└──────────────────────┘ └──────────────────────┘ │
二、注册监听 --- registerContentObserver
2.1 ContentResolver.registerContentObserver()
源码路径 : frameworks/base/core/java/android/content/ContentResolver.java
java
// ContentResolver.java
public final void registerContentObserver(@NonNull Uri uri,
boolean notifyForDescendents, @NonNull ContentObserver observer,
@UserIdInt int userHandle) {
try {
// 关键:获取的是 ContentService 的 Binder 代理(IContentService)
// 而不是 IContentProvider!
getContentService().registerContentObserver(
uri, notifyForDescendents,
observer.getContentObserver(), // IContentObserver Binder
userHandle, mTargetSdkVersion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
关键区别 :getContentService() 返回的是 IContentService(ContentService 的 Binder 接口),而不是 IContentProvider。观察者注册在 system_server 的 ContentService 中,而不是 Provider 进程。
2.2 ContentService.registerContentObserver()
源码路径 : frameworks/base/services/core/java/com/android/server/content/ContentService.java
java
// ContentService.java --- 运行在 system_server
public final class ContentService extends IContentService.Stub {
// 全局观察者树的根节点
private ObserverNode mRootNode;
@Override
public void registerContentObserver(Uri uri, boolean notifyForDescendants,
IContentObserver observer, int userHandle, int targetSdkVersion) {
if (observer == null || uri == null) {
throw new IllegalArgumentException(
"You must pass a valid uri and observer");
}
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
// 1. 校验用户 ID
userHandle = handleIncomingUser(uri, pid, uid,
Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle);
// 2. 检查是否有权限访问该 Provider
final String msg = LocalServices.getService(ActivityManagerInternal.class)
.checkContentProviderAccess(uri.getAuthority(), userHandle);
if (msg != null) {
if (targetSdkVersion >= Build.VERSION_CODES.O) {
throw new SecurityException(msg);
} else {
// 兼容老版本...
return;
}
}
// 3. 🔥 核心:将观察者添加到 ObserverNode 树
synchronized (mRootNode) {
mRootNode.addObserverLocked(uri, observer, notifyForDescendants,
mRootNode, uid, pid, userHandle);
}
}
}
2.3 ObserverNode 树形结构
源码路径 : frameworks/base/services/core/java/com/android/server/content/ContentService.java(ObserverNode 是 ContentService 的内部类)
java
// ObserverNode --- ContentService 的静态内部类
public static final class ObserverNode {
private String mName;
private ArrayList<ObserverNode> mChildren = new ArrayList<>();
private ArrayList<ObserverEntry> mObservers = new ArrayList<>();
// URI 分段规则(重要!):
// index 0 → uri.getAuthority()
// index ≥ 1 → uri.getPathSegments().get(index - 1)
public static 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;
}
}
public static int countUriSegments(Uri uri) {
if (uri == null) return 0;
return uri.getPathSegments().size() + 1;
}
public void addObserverLocked(Uri uri, IContentObserver observer,
boolean notifyForDescendants, Object observersLock,
int uid, int pid, int userHandle) {
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) {
// 到达叶子节点 → 添加 ObserverEntry
if (index == countUriSegments(uri)) {
mObservers.add(new ObserverEntry(observer, notifyForDescendants,
observersLock, uid, pid, userHandle, uri));
return;
}
// 查找或创建子节点(按 segment 名匹配)
String segment = getUriSegment(uri, index);
for (ObserverNode node : mChildren) {
if (node.mName.equals(segment)) {
node.addObserverLocked(uri, index + 1, observer,
notifyForDescendants, observersLock, uid, pid, userHandle);
return;
}
}
ObserverNode node = new ObserverNode(segment);
mChildren.add(node);
node.addObserverLocked(uri, index + 1, observer,
notifyForDescendants, observersLock, uid, pid, userHandle);
}
}
URI 树结构示例 :注册 content://settings/global/airplane_mode_on 后,树结构为:
plain
mRootNode (name="")
└─ "settings" ← index 0: authority
└─ "global" ← index 1: path segment[0]
└─ "airplane_mode_on" ← index 2: path segment[1]
└─ ObserverEntry(uid=10089, pid=1234, user=0,
notifyForDescendants=false)
注意树中不包含 scheme 和 authority 之外的 URI 前缀,只按 authority 和 path segments 组织。
2.4 ObserverEntry --- 节点条目与 Binder 死亡监听
java
// ObserverNode 的内部类
private class ObserverEntry implements IBinder.DeathRecipient {
public final IContentObserver observer;
public final int uid;
public final int pid;
public final boolean notifyForDescendants;
private final int userHandle;
private final Object observersLock;
public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
int _uid, int _pid, int _userHandle, Uri uri) {
this.observersLock = observersLock;
observer = o;
uid = _uid;
pid = _pid;
userHandle = _userHandle;
notifyForDescendants = n;
// 🔥 注册 Binder 死亡回调
final int entries = sObserverDeathDispatcher.linkToDeath(observer, this);
if (entries == -1) {
binderDied(); // 已死,立即清理
} else if (entries == TOO_MANY_OBSERVERS_THRESHOLD) {
// 泄漏检测:同一 observer 注册超过 1000 次
Slog.wtf(TAG, "Observer registered too many times. Leak? ...");
}
}
@Override
public void binderDied() {
synchronized (observersLock) {
removeObserverLocked(observer);
}
}
}
关键机制 :
BinderDeathDispatcher监听 observer 对应的 Binder 对象。如果 App 进程异常死亡,binderDied()会自动从树中移除该 observer,防止内存泄漏和死回调。
2.5 ContentObserver$Transport --- 跨进程回调的 Binder 门面
源码路径 : frameworks/base/core/java/android/database/ContentObserver.java
java
// ContentObserver.java
public abstract class ContentObserver {
private Transport mTransport; // 懒加载,synchronized(mLock)
Handler mHandler;
public ContentObserver(Handler handler) {
mHandler = handler;
}
// 获取 Binder 对象,传递到 ContentService 注册
public IContentObserver getContentObserver() {
synchronized (mLock) {
if (mTransport == null) {
mTransport = new Transport(this);
}
return mTransport;
}
}
// IContentObserver.Stub --- 运行在 App 进程的 Binder 服务端
private static final class Transport extends IContentObserver.Stub {
private ContentObserver mContentObserver;
public Transport(ContentObserver contentObserver) {
mContentObserver = contentObserver;
}
// ContentService 通过 Binder 调用的入口
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
// 内部委托给 onChangeEtc
onChangeEtc(selfChange, new Uri[] { uri }, 0, userId);
}
// 🔥 实际的回调入口(AOSP 12 新增批量 API)
@Override
public void onChangeEtc(boolean selfChange, Uri[] uris,
int flags, int userId) {
ContentObserver contentObserver = mContentObserver;
if (contentObserver != null) {
contentObserver.dispatchChange(selfChange,
Arrays.asList(uris), flags, userId);
}
}
}
// dispatchChange 最终实现
public final void dispatchChange(boolean selfChange,
@NonNull Collection<Uri> uris, @NotifyFlags int flags,
@UserIdInt int userId) {
if (mHandler == null) {
// 无 Handler → 在 Binder 线程池直接回调
onChange(selfChange, uris, flags, userId);
} else {
// 🔥 通过 Handler 切到目标线程(通常是主线程)
mHandler.post(() -> {
onChange(selfChange, uris, flags, userId);
});
}
}
// onChange 默认链式调用
public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
@NotifyFlags int flags, @UserIdInt int userId) {
for (Uri uri : uris) {
onChange(selfChange, uri, flags);
}
}
public void onChange(boolean selfChange, @Nullable Uri uri,
@NotifyFlags int flags) {
onChange(selfChange, uri);
}
public void onChange(boolean selfChange, @Nullable Uri uri) {
onChange(selfChange); // 默认回调无参版本
}
public void onChange(boolean selfChange) {}
}
重点 :AOSP 12 中 Transport 支持批量通知
onChangeEtc(),ContentService 分发时优先调用此方法,将同一 observer 的多个 URI 合并为一次 Binder 调用,减少 IPC 开销。
三、数据写入触发变化
3.1 应用调用 putInt
java
Settings.Global.putInt(getContentResolver(), "airplane_mode_on", 1);
实际的调用链并非通过 ContentResolver.update(),而是走 NameValueCache + IContentProvider.call() 路径:
java
// Settings.java --- Global 类
public static boolean putInt(ContentResolver cr, String name, int value) {
return putIntForUser(cr, name, value, cr.getUserId());
}
public static boolean putIntForUser(ContentResolver cr, String name, int value,
int userHandle) {
return putStringForUser(cr, name, Integer.toString(value), userHandle);
}
private static boolean putStringForUser(ContentResolver resolver, String name,
String value, int userHandle, boolean overrideableByRestore) {
// 委托给 NameValueCache
return sNameValueCache.putStringForUser(resolver, name, value,
null, false, userHandle, overrideableByRestore);
}
3.2 NameValueCache.putStringForUser() → IContentProvider.call()
java
// Settings.java --- NameValueCache 内部类
public boolean putStringForUser(ContentResolver cr, String name, String value,
String tag, boolean makeDefault, final int userHandle,
boolean overrideableByRestore) {
try {
Bundle arg = new Bundle();
arg.putString(Settings.NameValueTable.VALUE, value);
arg.putInt(CALL_METHOD_USER_KEY, userHandle);
// ...
// 🔥 关键:调用 IContentProvider.call(),而非 cr.update()
// 这是 SettingsProvider 自定义的 "CALL" 协议
IContentProvider cp = mProviderHolder.getProvider(cr);
cp.call(cr.getAttributionSource(),
mProviderHolder.mUri.getAuthority(),
mCallSetCommand, // 例如 "PUT_global"
name, arg);
} catch (RemoteException e) {
return false;
}
return true;
}
为什么用
call()而非update()? SettingsProvider 自定义了一套 CALL 命令协议(CALL_METHOD_PUT_GLOBAL/CALL_METHOD_PUT_SYSTEM等),通过provider.call()的method参数区分操作类型,而非通过 ContentValues + SQL 更新。这样可以更灵活地处理各类型设置的写前校验、权限检查等逻辑。
对应的 SettingsProvider.call() 处理(简化):
java
// SettingsProvider.java
public class SettingsProvider extends ContentProvider {
@Override
public Bundle call(String method, String name, Bundle args) {
final int requestingUserId = getRequestingUserId(args);
switch (method) {
...代码省略...
case Settings.CALL_METHOD_PUT_GLOBAL: {
String value = getSettingValue(args);
String tag = getSettingTag(args);
final boolean makeDefault = getSettingMakeDefault(args);
final boolean overrideableByRestore = getSettingOverrideableByRestore(args);
insertGlobalSetting(name, value, tag, makeDefault, requestingUserId, false,
overrideableByRestore);
break;
}
...代码省略...
default: {
Slog.w(LOG_TAG, "call() with invalid method: " + method);
}
break;
}
return null;
}
private boolean insertGlobalSetting(String name, String value, String tag,
boolean makeDefault, int requestingUserId, boolean forceNotify,
boolean overrideableByRestore) {
if (DEBUG) {
Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ", "
+ ", " + tag + ", " + makeDefault + ", " + requestingUserId
+ ", " + forceNotify + ")");
}
return mutateGlobalSetting(name, value, tag, makeDefault, requestingUserId,
MUTATION_OPERATION_INSERT, forceNotify, 0, overrideableByRestore);
}
}
对于非 Settings 的其他 ContentProvider,通常还是走
ContentResolver.update()→provider.update()路径。Settings 的特殊之处在于它使用call()协议来完成写入。
3.3 SettingsProvider.update() --- 实际通知路径
源码路径 : packages/providers/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
SettingsProvider 并不直接调用 getContext().getContentResolver().notifyChange()。实际路径要经过多层:
java
// SettingsProvider.java --- 运行在 system_server 进程
@Override
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
Arguments args = new Arguments(uri, where, whereArgs, false);
// ...
switch (args.table) {
case TABLE_GLOBAL: {
return updateGlobalSetting(args.name, value, ...) ? 1 : 0;
}
// ...
}
}
// → updateGlobalSetting → mutateGlobalSetting
private boolean mutateGlobalSetting(..., String name, ...) {
synchronized (mLock) {
return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_GLOBAL,
UserHandle.USER_SYSTEM, name, value, ...);
}
}
// → SettingsRegistry.updateSettingLocked
public boolean updateSettingLocked(...) {
// 1. 写入 SettingsState
boolean success = settingsState.updateSettingLocked(name, value, ...);
// 2. 通知变化
if (forceNotify || success) {
notifyForSettingsChange(key, name);
}
return success;
}
// → notifyForSettingsChange
private void notifyForSettingsChange(int key, String name) {
// Global 设置需通知所有正在运行的用户
if (isGlobalSettingsKey(key) || isConfigSettingsKey(key)) {
notifySettingChangeForRunningUsers(key, name);
} else {
// Secure/System: 只通知对应用户
Uri uri = getNotificationUriFor(key, name);
mHandler.obtainMessage(MSG_NOTIFY_URI_CHANGED,
userId, 0, uri).sendToTarget();
}
}
// → notifySettingChangeForRunningUsers
private void notifySettingChangeForRunningUsers(int key, String name) {
Uri uri = getNotificationUriFor(key, name);
for (UserInfo user : mUserManager.getAliveUsers()) {
if (mUserManager.isUserRunning(UserHandle.of(user.id))) {
// 异步发送到 MyHandler
mHandler.obtainMessage(MSG_NOTIFY_URI_CHANGED,
user.id, 0, uri).sendToTarget();
}
}
}
// → MyHandler.handleMessage
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_NOTIFY_URI_CHANGED: {
Uri uri = (Uri) msg.obj;
int userId = msg.arg1;
// 最终在这里调用 ContentResolver.notifyChange
getContext().getContentResolver().notifyChange(
uri, null, true, userId);
}
}
}
完整链路 :
SettingsProvider.update()→SettingsRegistry.updateSettingLocked()→notifyForSettingsChange()→notifySettingChangeForUsers()→MyHandler异步消息 →getContentResolver().notifyChange()→ContentService.notifyChange()
关键点:
- 通知是 异步走 Handler 的,不会在 update 线程中同步阻塞
- 对 Global 设置会通知所有正在运行的用户,而非仅调用者用户
forceNotify=true确保即使数据没变化也能通知(某些场景需要)
四、核心:notifyChange 分发机制
4.1 ContentResolver.notifyChange() → ContentService
java
// ContentResolver.java
public void notifyChange(@NonNull Uri[] uris, ContentObserver observer,
@NotifyFlags int flags, @UserIdInt int userHandle) {
try {
// 🔥 通知也走 ContentService 进行中央分发!
// 注意:参数是 Uri[] 数组,而非单个 Uri
getContentService().notifyChange(
uris,
observer == null ? null : observer.getContentObserver(),
observer != null && observer.deliverSelfNotifications(),
flags,
userHandle,
mTargetSdkVersion,
mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
参数详解(与文章旧版不同):
- 第一个参数是
Uri[](数组),支持批量通知 - 第三个参数是
observerWantsSelfNotifications,由observer.deliverSelfNotifications()决定,控制是否向发起者自通知 - 最后一个参数是
callingPackage(调用包名)
4.2 ContentService.notifyChange()
java
// ContentService.java
@Override
public void notifyChange(Uri[] uris, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags, int userId,
int targetSdkVersion, String callingPackage) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
// 用于收集所有需要分发的通知事件
final ObserverCollector collector = new ObserverCollector();
final ArrayMap<Pair<String, Integer>, String> validatedProviders = new ArrayMap<>();
for (Uri uri : uris) {
// 1. 校验用户 ID 和权限
final int resolvedUserId = handleIncomingUser(uri, callingPid, callingUid,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userId);
// ... 权限校验 ...
// 2. 🔥 遍历 ObserverNode 树,收集匹配的 observer
synchronized (mRootNode) {
final int segmentCount = ObserverNode.countUriSegments(uri);
mRootNode.collectObserversLocked(uri, segmentCount, 0,
observer, observerWantsSelfNotifications, flags,
resolvedUserId, collector);
}
}
// 3. 分发所有收集到的通知
final long token = clearCallingIdentity();
try {
collector.dispatch(); // 根据进程优先级决定同步/延迟
// 4. 处理 SYNC_TO_NETWORK 和缓存失效
if ((flags & ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
// 调度网络同步适配器
}
invalidateCache(); // 使相关缓存失效
} finally {
restoreCallingIdentity(token);
}
}
4.3 collectObserversLocked --- 递归遍历 ObserverNode 树
java
// ContentService.ObserverNode
public void collectObserversLocked(Uri uri, int segmentCount, int index,
IContentObserver observer, boolean observerWantsSelfNotifications,
int flags, int targetUserHandle, ObserverCollector collector) {
String segment = null;
if (index >= segmentCount) {
// ✅ 到达叶子节点:通知此节点上的所有 observer
collectMyObserversLocked(uri, true /* leaf */, observer,
observerWantsSelfNotifications, flags,
targetUserHandle, collector);
} else if (index < segmentCount) {
segment = getUriSegment(uri, index);
// 非叶子节点:通知那些声明 notifyForDescendants=true 的 observer
collectMyObserversLocked(uri, false /* non-leaf */, observer,
observerWantsSelfNotifications, flags,
targetUserHandle, collector);
}
// 递归进入匹配的子节点
for (ObserverNode node : mChildren) {
if (segment == null || node.mName.equals(segment)) {
node.collectObserversLocked(uri, segmentCount, index + 1,
observer, observerWantsSelfNotifications, flags,
targetUserHandle, collector);
if (segment != null) break;
}
}
}
// 收集当前节点上的 observer
private void collectMyObserversLocked(Uri uri, boolean leaf,
IContentObserver observer, boolean observerWantsSelfNotifications,
int flags, int targetUserHandle, ObserverCollector collector) {
for (ObserverEntry entry : mObservers) {
// 自通知过滤
boolean selfChange = entry.observer.asBinder() == observer.asBinder();
if (selfChange && !observerWantsSelfNotifications) continue;
// 用户匹配
if (targetUserHandle != UserHandle.USER_ALL
&& entry.userHandle != UserHandle.USER_ALL
&& targetUserHandle != entry.userHandle) continue;
// 叶节点 → 始终通知(除非 NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS 过滤)
// 非叶节点 → 仅通知 notifyForDescendants=true 的 observer
if (leaf) {
if ((flags & NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0
&& entry.notifyForDescendants) continue;
} else {
if (!entry.notifyForDescendants) continue;
}
collector.collect(entry.observer, entry.uid, selfChange,
uri, flags, targetUserHandle);
}
}
4.4 ObserverCollector --- 聚合分发器
AOSP 12 使用 ObserverCollector 替代了旧版逐条分发的方式:
java
// ContentService.ObserverCollector
public static class ObserverCollector {
private final ArrayMap<Key, List<Uri>> collected = new ArrayMap<>();
// Key 聚合条件:相同 observer + uid + flags + userId 的 Uri 合并
private static class Key {
final IContentObserver observer;
final int uid;
final boolean selfChange;
final int flags;
final int userId;
// equals() 和 hashCode() 基于以上字段
}
public void collect(IContentObserver observer, int uid,
boolean selfChange, Uri uri, int flags, int userId) {
Key key = new Key(observer, uid, selfChange, flags, userId);
List<Uri> value = collected.get(key);
if (value == null) {
value = new ArrayList<>();
collected.put(key, value);
}
value.add(uri); // 相同 key 的 Uri 追加到列表
}
public void dispatch() {
for (int i = 0; i < collected.size(); i++) {
final Key key = collected.keyAt(i);
final List<Uri> value = collected.valueAt(i);
Runnable task = () -> {
// 批量调用 onChangeEtc,一次 Binder 传输多个 Uri
key.observer.onChangeEtc(key.selfChange,
value.toArray(new Uri[value.size()]),
key.flags, key.userId);
};
// 🔥 根据进程优先级决定调度策略
boolean noDelay = (key.flags & NOTIFY_NO_DELAY) != 0;
int procState = LocalServices.getService(ActivityManagerInternal.class)
.getUidProcessState(key.uid);
if (procState <= PROCESS_STATE_IMPORTANT_FOREGROUND || noDelay) {
// 前台进程 → 立即同步执行
task.run();
} else {
// 后台进程 → 延迟 10 秒,防 stampede
BackgroundThread.getHandler().postDelayed(task,
BACKGROUND_OBSERVER_DELAY); // 10s
}
}
}
}
核心设计思想:
- 聚合批量调用:同一 observer 的多个 URI 一次 Binder 回传,减少 IPC 次数
- 前台优先:前台进程(PROCESS_STATE_IMPORTANT_FOREGROUND 及更高)立即通知,后台进程延迟 10s
- NOTIFY_NO_DELAY:调用方可要求强制同步(如 SettingsProvider 的关键设置变更)
五、完整回调链路总图
plain
┌───────────────────────────────────────────────────────────────────────────────┐
│ 注册阶段 │
│ │
│ App 进程 SystemServer │
│ ┌──────────────┐ ┌─────────────────────────────────┐ │
│ │ContentResolver│ │ContentService │ │
│ │ .register │ │ │ │
│ │ ContentObser │ IContentService │ mRootNode.addObserverLocked │ │
│ │ ver() │ ──────────────────►│ (按 authority/segments 匹配) │ │
│ │ │ Binder 调用 │ → ObserverEntry(uid, pid, │ │
│ │ │ │ userHandle, binder死亡监听) │ │
│ └──────────────┘ └─────────────────────────────────┘ │
│ │
├───────────────────────────────────────────────────────────────────────────────┤
│ 触发阶段 (以 SettingsProvider 为例) │
│ │
│ App 进程(或任意进程) SystemServer │
│ ┌──────────────┐ ┌─────────────────────────────────┐ │
│ │Settings │ IContentProvider │SettingsProvider │ │
│ │.Global.putInt│ ──── .call() ──► │ .call("PUT_global", ...) │ │
│ │ → │ (Binder) │ → mutateGlobalSetting() │ │
│ │NameValueCache│ │ → SettingsRegistry │ │
│ └──────────────┘ │ .updateSettingLocked() │ │
│ │ │ → notifyForSettingsChange() │ │
│ │ │ → MSG_NOTIFY_URI_CHANGED │ │
│ │ │ (Handler异步) │ │
│ │ └──────────┬──────────────────────┘ │
│ │ ▼ │
│ │ ┌─────────────────────────────────┐ │
│ │ │MyHandler.handleMessage() │ │
│ │ │ → resolver.notifyChange(uri) │ │
│ │ └──────────┬──────────────────────┘ │
│ │ ▼ │
│ │ ┌─────────────────────────────────┐ │
│ │ │ContentService.notifyChange() │ │
│ │ │ │ │
│ │ │ 1. 遍历 ObserverNode 树 │ │
│ │ │ 2. ObserverCollector.collect() │ │
│ │ │ 3. ObserverCollector.dispatch() │ │
│ │ │ ├─ 前台进程 → 同步分发 │ │
│ │ │ └─ 后台进程 → 延迟 10s 分发 │ │
│ │ └──────────┬──────────────────────┘ │
│ │ ▼ │
│ │ ┌────────────────────────────────┐ │
│ │ │App进程 Transport.onChangeEtc() │ │
│ │ │ → ContentObserver │ │
│ │ │ .dispatchChange() │ │
│ │ │ → mHandler.post() │ │
│ │ │ → onChange() 回调用户 │ │
│ │ └────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────────┘
六、关键设计要点总结
| 维度 | 机制 | 说明 |
|---|---|---|
| 注册中心 | ContentService (system_server) | 不经过 Provider 进程,也不经过 AMS |
| 存储结构 | ObserverNode 前缀树 | 按 URI authority + path segments 分层组织 |
| Binder 死亡 | BinderDeathDispatcher | 进程异常死亡时自动清理 observer,防泄漏 |
| 回调传输 | IContentObserver Binder | Transport.onChangeEtc() 批量传递 Uri\[\] |
| 线程切换 | ContentObserver.mHandler | 用户侧自行决定回调线程(通常是主线程) |
| 通知聚合 | ObserverCollector | 相同 observer 的多 URI 一次 Binder 回传 |
| 优先级调度 | 进程 procState | 前台进程同步分发,后台进程延迟 10s |
| SettingsProvider | MyHandler 异步 | 写操作不阻塞通知,Global 设置通知所有用户 |
| 自通知控制 | deliverSelfNotifications() | 控制是否接收自身发起的变更通知 |
| 通知范围 | notifyForDescendants | 控制父节点 observer 是否接收子路径的变更 |