Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db204c23 authored by Fred Quintana's avatar Fred Quintana Committed by Android (Google) Code Review
Browse files

Merge "change ObserverNode.binderDied() to lock the root node before...

Merge "change ObserverNode.binderDied() to lock the root node before manipulating the observers tree by calling removeObserverLocked()"
parents 6c26fe4e 002ffad5
Loading
Loading
Loading
Loading
+27 −26
Original line number Original line Diff line number Diff line
@@ -32,7 +32,6 @@ import android.Manifest;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.List;


/**
/**
@@ -104,7 +103,7 @@ public final class ContentService extends IContentService.Stub {
            throw new IllegalArgumentException("You must pass a valid uri and observer");
            throw new IllegalArgumentException("You must pass a valid uri and observer");
        }
        }
        synchronized (mRootNode) {
        synchronized (mRootNode) {
            mRootNode.addObserver(uri, observer, notifyForDescendents);
            mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode);
            if (Config.LOGV) Log.v(TAG, "Registered observer " + observer + " at " + uri +
            if (Config.LOGV) Log.v(TAG, "Registered observer " + observer + " at " + uri +
                    " with notifyForDescendents " + notifyForDescendents);
                    " with notifyForDescendents " + notifyForDescendents);
        }
        }
@@ -115,7 +114,7 @@ public final class ContentService extends IContentService.Stub {
            throw new IllegalArgumentException("You must pass a valid observer");
            throw new IllegalArgumentException("You must pass a valid observer");
        }
        }
        synchronized (mRootNode) {
        synchronized (mRootNode) {
            mRootNode.removeObserver(observer);
            mRootNode.removeObserverLocked(observer);
            if (Config.LOGV) Log.v(TAG, "Unregistered observer " + observer);
            if (Config.LOGV) Log.v(TAG, "Unregistered observer " + observer);
        }
        }
    }
    }
@@ -132,7 +131,7 @@ public final class ContentService extends IContentService.Stub {
        try {
        try {
            ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
            ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
            synchronized (mRootNode) {
            synchronized (mRootNode) {
                mRootNode.collectObservers(uri, 0, observer, observerWantsSelfNotifications,
                mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
                        calls);
                        calls);
            }
            }
            final int numCalls = calls.size();
            final int numCalls = calls.size();
@@ -470,10 +469,12 @@ public final class ContentService extends IContentService.Stub {
     */
     */
    public static final class ObserverNode {
    public static final class ObserverNode {
        private class ObserverEntry implements IBinder.DeathRecipient {
        private class ObserverEntry implements IBinder.DeathRecipient {
            public IContentObserver observer;
            public final IContentObserver observer;
            public boolean notifyForDescendents;
            public final boolean notifyForDescendents;
            private final Object observersLock;


            public ObserverEntry(IContentObserver o, boolean n) {
            public ObserverEntry(IContentObserver o, boolean n, Object observersLock) {
                this.observersLock = observersLock;
                observer = o;
                observer = o;
                notifyForDescendents = n;
                notifyForDescendents = n;
                try {
                try {
@@ -484,7 +485,9 @@ public final class ContentService extends IContentService.Stub {
            }
            }


            public void binderDied() {
            public void binderDied() {
                removeObserver(observer);
                synchronized (observersLock) {
                    removeObserverLocked(observer);
                }
            }
            }
        }
        }


@@ -519,16 +522,16 @@ public final class ContentService extends IContentService.Stub {
            return uri.getPathSegments().size() + 1;
            return uri.getPathSegments().size() + 1;
        }
        }


        public void addObserver(Uri uri, IContentObserver observer, boolean notifyForDescendents) {
        public void addObserverLocked(Uri uri, IContentObserver observer,
            addObserver(uri, 0, observer, notifyForDescendents);
                boolean notifyForDescendents, Object observersLock) {
            addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock);
        }
        }


        private void addObserver(Uri uri, int index, IContentObserver observer,
        private void addObserverLocked(Uri uri, int index, IContentObserver observer,
                boolean notifyForDescendents) {
                boolean notifyForDescendents, Object observersLock) {

            // If this is the leaf node add the observer
            // If this is the leaf node add the observer
            if (index == countUriSegments(uri)) {
            if (index == countUriSegments(uri)) {
                mObservers.add(new ObserverEntry(observer, notifyForDescendents));
                mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock));
                return;
                return;
            }
            }


@@ -538,7 +541,7 @@ public final class ContentService extends IContentService.Stub {
            for (int i = 0; i < N; i++) {
            for (int i = 0; i < N; i++) {
                ObserverNode node = mChildren.get(i);
                ObserverNode node = mChildren.get(i);
                if (node.mName.equals(segment)) {
                if (node.mName.equals(segment)) {
                    node.addObserver(uri, index + 1, observer, notifyForDescendents);
                    node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
                    return;
                    return;
                }
                }
            }
            }
@@ -546,13 +549,13 @@ public final class ContentService extends IContentService.Stub {
            // No child found, create one
            // No child found, create one
            ObserverNode node = new ObserverNode(segment);
            ObserverNode node = new ObserverNode(segment);
            mChildren.add(node);
            mChildren.add(node);
            node.addObserver(uri, index + 1, observer, notifyForDescendents);
            node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
        }
        }


        public boolean removeObserver(IContentObserver observer) {
        public boolean removeObserverLocked(IContentObserver observer) {
            int size = mChildren.size();
            int size = mChildren.size();
            for (int i = 0; i < size; i++) {
            for (int i = 0; i < size; i++) {
                boolean empty = mChildren.get(i).removeObserver(observer);
                boolean empty = mChildren.get(i).removeObserverLocked(observer);
                if (empty) {
                if (empty) {
                    mChildren.remove(i);
                    mChildren.remove(i);
                    i--;
                    i--;
@@ -578,10 +581,8 @@ public final class ContentService extends IContentService.Stub {
            return false;
            return false;
        }
        }


        private void collectMyObservers(Uri uri,
        private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
                boolean leaf, IContentObserver observer, boolean selfNotify,
                boolean selfNotify, ArrayList<ObserverCall> calls) {
                ArrayList<ObserverCall> calls)
        {
            int N = mObservers.size();
            int N = mObservers.size();
            IBinder observerBinder = observer == null ? null : observer.asBinder();
            IBinder observerBinder = observer == null ? null : observer.asBinder();
            for (int i = 0; i < N; i++) {
            for (int i = 0; i < N; i++) {
@@ -600,17 +601,17 @@ public final class ContentService extends IContentService.Stub {
            }
            }
        }
        }


        public void collectObservers(Uri uri, int index, IContentObserver observer,
        public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
                boolean selfNotify, ArrayList<ObserverCall> calls) {
                boolean selfNotify, ArrayList<ObserverCall> calls) {
            String segment = null;
            String segment = null;
            int segmentCount = countUriSegments(uri);
            int segmentCount = countUriSegments(uri);
            if (index >= segmentCount) {
            if (index >= segmentCount) {
                // This is the leaf node, notify all observers
                // This is the leaf node, notify all observers
                collectMyObservers(uri, true, observer, selfNotify, calls);
                collectMyObserversLocked(true, observer, selfNotify, calls);
            } else if (index < segmentCount){
            } else if (index < segmentCount){
                segment = getUriSegment(uri, index);
                segment = getUriSegment(uri, index);
                // Notify any observers at this level who are interested in descendents
                // Notify any observers at this level who are interested in descendents
                collectMyObservers(uri, false, observer, selfNotify, calls);
                collectMyObserversLocked(false, observer, selfNotify, calls);
            }
            }


            int N = mChildren.size();
            int N = mChildren.size();
@@ -618,7 +619,7 @@ public final class ContentService extends IContentService.Stub {
                ObserverNode node = mChildren.get(i);
                ObserverNode node = mChildren.get(i);
                if (segment == null || node.mName.equals(segment)) {
                if (segment == null || node.mName.equals(segment)) {
                    // We found the child,
                    // We found the child,
                    node.collectObservers(uri, index + 1, observer, selfNotify, calls);
                    node.collectObserversLocked(uri, index + 1, observer, selfNotify, calls);
                    if (segment != null) {
                    if (segment != null) {
                        break;
                        break;
                    }
                    }
+17 −18
Original line number Original line Diff line number Diff line
@@ -24,7 +24,6 @@ import android.database.ContentObserver;
import android.net.Uri;
import android.net.Uri;
import android.os.Handler;
import android.os.Handler;
import android.test.AndroidTestCase;
import android.test.AndroidTestCase;
import android.util.Log;


public class ObserverNodeTest extends AndroidTestCase {
public class ObserverNodeTest extends AndroidTestCase {
    static class TestObserver  extends ContentObserver {
    static class TestObserver  extends ContentObserver {
@@ -49,15 +48,15 @@ public class ObserverNodeTest extends AndroidTestCase {
        int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3};
        int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3};


        // special case
        // special case
        root.addObserver(uris[0], new TestObserver().getContentObserver(), false);
        root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root);
        for(int i = 1; i < uris.length; i++) {
        for(int i = 1; i < uris.length; i++) {
            root.addObserver(uris[i], new TestObserver().getContentObserver(), true);
            root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root);
        }
        }


        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();


        for (int i = nums.length - 1; i >=0; --i) {
        for (int i = nums.length - 1; i >=0; --i) {
            root.collectObservers(uris[i], 0, null, false, calls);
            root.collectObserversLocked(uris[i], 0, null, false, calls);
            assertEquals(nums[i], calls.size());
            assertEquals(nums[i], calls.size());
            calls.clear();
            calls.clear();
        }
        }
@@ -78,13 +77,13 @@ public class ObserverNodeTest extends AndroidTestCase {
        int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1};
        int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1};


        for(int i = 0; i < uris.length; i++) {
        for(int i = 0; i < uris.length; i++) {
            root.addObserver(uris[i], new TestObserver().getContentObserver(), false);
            root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root);
        }
        }


        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();


        for (int i = uris.length - 1; i >=0; --i) {
        for (int i = uris.length - 1; i >=0; --i) {
            root.collectObservers(uris[i], 0, null, false, calls);        
            root.collectObserversLocked(uris[i], 0, null, false, calls);
            assertEquals(nums[i], calls.size());
            assertEquals(nums[i], calls.size());
            calls.clear();
            calls.clear();
        }
        }