Merge "Fix leak where system held onto slice providers" into pi-dev
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index 4e7fb96..e139ab8 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -154,8 +154,8 @@
     }
 
     ContentProviderClient getClient() {
-        ContentProviderClient client =
-                mService.getContext().getContentResolver().acquireContentProviderClient(mUri);
+        ContentProviderClient client = mService.getContext().getContentResolver()
+                .acquireUnstableContentProviderClient(mUri);
         if (client == null) return null;
         client.setDetectNotResponding(SLICE_TIMEOUT);
         return client;
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index 3c4e333..82e0fbe 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -1,16 +1,16 @@
 package com.android.server.slice;
 
+import static android.testing.TestableContentResolver.UNSTABLE;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -71,11 +71,12 @@
         mSliceService = mock(SliceManagerService.class);
         when(mSliceService.getContext()).thenReturn(mContext);
         when(mSliceService.getLock()).thenReturn(new Object());
-        when(mSliceService.getHandler()).thenReturn(new Handler(TestableLooper.get(this).getLooper()));
+        when(mSliceService.getHandler()).thenReturn(
+                new Handler(TestableLooper.get(this).getLooper()));
         mContentProvider = mock(ContentProvider.class);
         mIContentProvider = mock(IContentProvider.class);
         when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider);
-        mContext.getContentResolver().addProvider(AUTH, mContentProvider);
+        mContext.getContentResolver().addProvider(AUTH, mContentProvider, UNSTABLE);
         mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI, "pkg");
     }
 
diff --git a/tests/testables/src/android/testing/TestableContentResolver.java b/tests/testables/src/android/testing/TestableContentResolver.java
index 0850916..a0afef8 100644
--- a/tests/testables/src/android/testing/TestableContentResolver.java
+++ b/tests/testables/src/android/testing/TestableContentResolver.java
@@ -20,6 +20,7 @@
 import android.content.IContentProvider;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import com.google.android.collect.Maps;
@@ -35,7 +36,11 @@
  */
 public class TestableContentResolver extends ContentResolver {
 
-    private final Map<String, ContentProvider> mProviders = Maps.newHashMap();
+    public static final int STABLE = 1;
+    public static final int UNSTABLE = 2;
+
+    private final Map<String, ContentProvider> mProviders = new ArrayMap<>();
+    private final Map<String, ContentProvider> mUnstableProviders = new ArrayMap<>();
     private final ContentResolver mParent;
     private final ArraySet<ContentProvider> mInUse = new ArraySet<>();
     private boolean mFallbackToExisting;
@@ -62,7 +67,23 @@
      * subclasses, or null.
      */
     public void addProvider(String name, ContentProvider provider) {
-        mProviders.put(name, provider);
+        addProvider(name, provider, STABLE | UNSTABLE);
+    }
+
+    /**
+     * Adds access to a provider based on its authority
+     *
+     * @param name The authority name associated with the provider.
+     * @param provider An instance of {@link android.content.ContentProvider} or one of its
+     * subclasses, or null.
+     */
+    public void addProvider(String name, ContentProvider provider, int flags) {
+        if ((flags & STABLE) != 0) {
+            mProviders.put(name, provider);
+        }
+        if ((flags & UNSTABLE) != 0) {
+            mUnstableProviders.put(name, provider);
+        }
     }
 
     @Override
@@ -98,7 +119,7 @@
 
     @Override
     protected IContentProvider acquireUnstableProvider(Context c, String name) {
-        final ContentProvider provider = mProviders.get(name);
+        final ContentProvider provider = mUnstableProviders.get(name);
         if (provider != null) {
             return provider.getIContentProvider();
         } else {
@@ -128,7 +149,8 @@
     @Override
     public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
         if (!mFallbackToExisting) return;
-        if (!mProviders.containsKey(uri.getAuthority())) {
+        if (!mProviders.containsKey(uri.getAuthority())
+                && !mUnstableProviders.containsKey(uri.getAuthority())) {
             super.notifyChange(uri, observer, syncToNetwork);
         }
     }
diff --git a/tests/testables/tests/src/android/testing/TestableContentResolverTest.java b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java
new file mode 100644
index 0000000..71afda0
--- /dev/null
+++ b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java
@@ -0,0 +1,61 @@
+package android.testing;
+
+import android.content.ContentProvider;
+import android.content.IContentProvider;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class TestableContentResolverTest {
+
+    @Rule
+    public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext());
+    private TestableContentResolver mContentResolver;
+
+    @Before
+    public void setup() {
+        mContentResolver = new TestableContentResolver(mContext);
+        mContentResolver.setFallbackToExisting(false);
+    }
+
+    @Test
+    public void testDefaultContentProvider() {
+        ContentProvider provider = Mockito.mock(ContentProvider.class);
+        IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+        Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+        mContentResolver.addProvider("test", provider);
+
+        Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test"));
+        Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test"));
+    }
+
+    @Test
+    public void testStableContentProvider() {
+        ContentProvider provider = Mockito.mock(ContentProvider.class);
+        IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+        Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+        mContentResolver.addProvider("test", provider, TestableContentResolver.STABLE);
+
+        Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test"));
+        Assert.assertNull(mContentResolver.acquireUnstableProvider(mContext, "test"));
+    }
+
+    @Test
+    public void testUnstableContentProvider() {
+        ContentProvider provider = Mockito.mock(ContentProvider.class);
+        IContentProvider iprovider = Mockito.mock(IContentProvider.class);
+        Mockito.when(provider.getIContentProvider()).thenReturn(iprovider);
+        mContentResolver.addProvider("test", provider, TestableContentResolver.UNSTABLE);
+
+        Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test"));
+        Assert.assertNull(mContentResolver.acquireProvider(mContext, "test"));
+    }
+}