Android 12系统源码_系统设置(三)Setting注册回调链路源码分析

前言

⚠️ 本文为修正版 。初版存在关键错误:误认为 registerContentObserverIContentProvider Binder 到 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
            }
        }
    }
}

核心设计思想

  1. 聚合批量调用:同一 observer 的多个 URI 一次 Binder 回传,减少 IPC 次数
  2. 前台优先:前台进程(PROCESS_STATE_IMPORTANT_FOREGROUND 及更高)立即通知,后台进程延迟 10s
  3. 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 是否接收子路径的变更