ContentService注册和更新机制

ContentService完成数据内容注册和更新的机制。在N平台上SystemServer通过SystemServiceManager.startService的方式拉起ContentService,并且注册到ServiceManager中。
ConentService核心类图
从图中可以看出ContentService完成注册和更新机制的原理:当客户端注册的时候会将ContentObserver注册到ContentService中,但是ContentObserver本身是没有Binder通讯能力的,因此ContentObserver把这个工作丢给Transport类,这个类实现Binder通讯接口IContentObserver。ContentService保存ContentObserver是采取树的形式来保存的,ContentService保存树的根节点mRootNode,每个节点保存孩子节点mChidren和监听节点mObservers,监听节点的类型是ObserverEntry,里面有成员指向客户端Binder IContentObserver,通过这个可以完成和客户端的交互。
这里写图片描述
核心API接口

public final void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)
 构造方法 public void ContentObserver(Handler handler)  
 void onChange(boolean selfChange)

补充:注册树的维护和查找,利用树的特性,采用递归操作。

/**
 * Hide this class since it is not part of api,
 * but current unittest framework requires it to be public
 * @hide
 */
public static final class 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) {
            this.observersLock = observersLock;
            observer = o;
            uid = _uid;
            pid = _pid;
            userHandle = _userHandle;
            notifyForDescendants = n;
            try {
                observer.asBinder().linkToDeath(this, 0);
            } catch (RemoteException e) {
                binderDied();
            }
        }
        public void binderDied() {
            synchronized (observersLock) {
                removeObserverLocked(observer);
            }
        }
        public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
                               String name, String prefix, SparseIntArray pidCounts) {
            pidCounts.put(pid, pidCounts.get(pid)+1);
            pw.print(prefix); pw.print(name); pw.print(": pid=");
            pw.print(pid); pw.print(" uid=");
            pw.print(uid); pw.print(" user=");
            pw.print(userHandle); pw.print(" target=");
            pw.println(Integer.toHexString(System.identityHashCode(
                    observer != null ? observer.asBinder() : null)));
        }
    }
    public static final int INSERT_TYPE = 0;
    public static final int UPDATE_TYPE = 1;
    public static final int DELETE_TYPE = 2;
    private String mName;
    private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
    private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
    public ObserverNode(String name) {
        mName = name;
    }
    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;
        }
    }
    private int countUriSegments(Uri uri) {
        if (uri == null) {
            return 0;
        }
        return uri.getPathSegments().size() + 1;
    }
    // Invariant:  userHandle is either a hard user number or is USER_ALL
    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) {
        // If this is the leaf node add the observer
        if (index == countUriSegments(uri)) {
            mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
                    uid, pid, userHandle));
            return;
        }
        // Look to see if the proper child already exists
        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)) {
                node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
                        observersLock, uid, pid, userHandle);
                return;
            }
        }
        // No child found, create one
        ObserverNode node = new ObserverNode(segment);
        mChildren.add(node);
        node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
                observersLock, uid, pid, userHandle);
    }

从代码来看,逐级建立ObserverNode,到达根目录则添加叶子节点。

    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);
            if (entry.observer.asBinder() == observerBinder) {
                mObservers.remove(i);
                // We no longer need to listen for death notifications. Remove it.
                observerBinder.unlinkToDeath(entry, 0);
                break;
            }
        }
        if (mChildren.size() == 0 && mObservers.size() == 0) {
            return true;
        }
        return false;
    }
    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);
            // Don't notify the observer if it sent the notification and isn't interested
            // in self notifications
            boolean selfChange = (entry.observer.asBinder() == observerBinder);
            if (selfChange && !observerWantsSelfNotifications) {
                continue;
            }
            // Does this observer match the target user?
            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));
                }
            }
        }
    }
    /**
     * targetUserHandle is either a hard user handle or is USER_ALL
     */
    public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
                                       boolean observerWantsSelfNotifications, int targetUserHandle,
                                       ArrayList<ObserverCall> calls) {
        String segment = null;
        int segmentCount = countUriSegments(uri);
        if (index >= segmentCount) {
            // This is the leaf node, notify all observers
            collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
                    targetUserHandle, calls);
        } else if (index < segmentCount){
            segment = getUriSegment(uri, index);
            // Notify any observers at this level who are interested in descendants
            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)) {
                // We found the child,
                node.collectObserversLocked(uri, index + 1,
                        observer, observerWantsSelfNotifications, targetUserHandle, calls);
                if (segment != null) {
                    break;
                }
            }
        }
    }
}

从查找来说,也是从根目录开始进行查找,查看当前是否是叶子节点,叶子节点直接通知,其他非叶子节点则查看是否父节点是否对子节点感兴趣, if (leaf || (!leaf && entry.notifyForDescendants)) {

扩展:ContentObserver是否传Handler是由区别的

private Handler mainHandler= new Handler();
private SettingObserver airplaneCO = new SettingObserver(mainHandler);
// 通过调用getUriFor 方法获得 system表里的"飞行模式"所在行的Uri
Uri airplaneUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
// 注册内容观察者
getContentResolver().registerContentObserver(airplaneUri, false, airplaneCO);

打印出来的是main线程处理

04-18 15:05:17.485 18028-18028/com.example.broadcast2 D/zhanghao: onChangeid:1 name: main
private SettingObserver airplaneCO = new SettingObserver(null);
// 通过调用getUriFor 方法获得 system表里的"飞行模式"所在行的Uri
Uri airplaneUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
// 注册内容观察者
getContentResolver().registerContentObserver(airplaneUri, false, airplaneCO);
打印结果是
04-18 15:06:43.996 21942-21960/com.example.broadcast2 D/zhanghao: onChangeid:385 name: Binder:21942_3

说明这个是在应用的Binder线程中处理的。– 下一步要查的是Binder线程是如何生成的,是不是在客户端和服务端都会有Binder线程?

还有如果存在多次注册,就会存在多次调用onChange的情况,但是只要调用一次反注册。因为里面是通过ArrayList来存储的,没有去重的功能。
对比广播注册就没有这个问题:广播在AMS中注册存储是以receiver.asBinder为key进行存储的。因而达到一个去重的功能。
另外相对于SubscriptionManager.addOnSubscriptionChangeListener,最终实现在TelephonyRegistry.addOnSubscriptionChangeListener,其中的实现有一个查找在添加的过程。
相比较而言,几个实现方式都是类似的,在创建的时候都会隐式创建一个Binder对象,注册的时候都是将这个Binder本地对象注册到注册中心,这个注册中心可以是AMS,ContentService,也可以是TelephonyRegistry,特点都是使用System进程中的服务来充当。

// register
Record r = null;
find_and_add: {
    IBinder b = callback.asBinder();
    final int N = mRecords.size();
    for (int i = 0; i < N; i++) {
        r = mRecords.get(i);
        if (b == r.binder) {
            break find_and_add;
        }
    }
    r = new Record();
    r.binder = b;
    r.callback = callback;
    r.pkgForDebug = pkgForDebug;
    r.callerUid = callerUid;
    mRecords.add(r);
    if (DBG) Slog.i(TAG, "listen: add new record=" + r);
}

这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/xuning2516/article/details/70537126