Offer to cache ContentResolver-related Bundles.

There are a handful of core system services that collect data from
third-party ContentProviders by spinning them up and then caching the
results locally in memory.  However, if those apps are killed due to
low-memory pressure, they lose that cached data and have to collect
it again from scratch.  It's impossible for those apps to maintain a
correct cache when not running, since they'll miss out on Uri change
notifications.

To work around this, this change introducing a narrowly-scoped
caching mechanism that maps from Uris to Bundles.  The cache is
isolated per-user and per-calling-package, and internally it's
optimized to keep the Uri notification flow as fast as possible.
Each Bundle is invalidated whenever a notification event for a Uri
key is sent, or when the package hosting the provider is changed.

This change also wires up DocumentsUI to use this new mechanism,
which improves cold-start performance from 3300ms to 1800ms.  The
more DocumentsProviders a system has, the more pronounced this
benefit is.  Use BOOT_COMPLETED to build the cache at boot.

Add more permission docs, send a missing extra in DATA_CLEARED
broadcast.

Bug: 18406595
Change-Id: If3eae14bb3c69a8b83a65f530e081efc3b34d4bc
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 4e1b6e0..441f188 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2440,6 +2440,28 @@
         }
     }
 
+    /** {@hide} */
+    public void putCache(Uri key, Bundle value) {
+        try {
+            getContentService().putCache(mContext.getPackageName(), key, value,
+                    mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** {@hide} */
+    public Bundle getCache(Uri key) {
+        try {
+            final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
+                    mContext.getUserId());
+            if (bundle != null) bundle.setClassLoader(mContext.getClassLoader());
+            return bundle;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Returns sampling percentage for a given duration.
      *
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 8b471a0..d47e780 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -179,6 +179,8 @@
             int userId);
 
     void addStatusChangeListener(int mask, ISyncStatusObserver callback);
-
     void removeStatusChangeListener(ISyncStatusObserver callback);
+
+    void putCache(in String packageName, in Uri key, in Bundle value, int userId);
+    Bundle getCache(in String packageName, in Uri key, int userId);
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fbc96c2..6444c6c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1483,11 +1483,21 @@
 
     <!-- Allows an application to manage access to documents, usually as part
          of a document picker.
+         <p>This permission should <em>only</em> be requested by the platform
+         document management app.  This permission cannot be granted to
+         third-party apps.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
         android:protectionLevel="signature" />
 
+    <!-- @hide Allows an application to cache content.
+         <p>Not for use by third-party applications.
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.CACHE_CONTENT"
+        android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions for screenlock         -->
     <!-- ================================== -->