Add ContentProvider.dump()

This is similar to the existing dump() facility for services.
ContentProviders can now implement dump() and that info will be shown
when running "dumpsys activity provider" and when taking a bugreport.

Change-Id: I33b3b132e3c4f920153355cc368eda2f725a715f
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0c761fc..9e88bc6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -813,6 +813,19 @@
             }
         }
 
+        public void dumpProvider(FileDescriptor fd, IBinder providertoken,
+                String[] args) {
+            DumpComponentInfo data = new DumpComponentInfo();
+            try {
+                data.fd = ParcelFileDescriptor.dup(fd);
+                data.token = providertoken;
+                data.args = args;
+                queueOrSendMessage(H.DUMP_PROVIDER, data);
+            } catch (IOException e) {
+                Slog.w(TAG, "dumpProvider failed", e);
+            }
+        }
+
         @Override
         public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin,
                 boolean all, String[] args) {
@@ -1044,6 +1057,7 @@
         public void scheduleTrimMemory(int level) {
             queueOrSendMessage(H.TRIM_MEMORY, null, level);
         }
+
     }
 
     private class H extends Handler {
@@ -1088,6 +1102,7 @@
         public static final int SET_CORE_SETTINGS       = 138;
         public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
         public static final int TRIM_MEMORY             = 140;
+        public static final int DUMP_PROVIDER           = 141;
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
                 switch (code) {
@@ -1132,6 +1147,7 @@
                     case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
                     case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
                     case TRIM_MEMORY: return "TRIM_MEMORY";
+                    case DUMP_PROVIDER: return "DUMP_PROVIDER";
                 }
             }
             return "(unknown)";
@@ -1264,6 +1280,9 @@
                 case DUMP_ACTIVITY:
                     handleDumpActivity((DumpComponentInfo)msg.obj);
                     break;
+                case DUMP_PROVIDER:
+                    handleDumpProvider((DumpComponentInfo)msg.obj);
+                    break;
                 case SLEEPING:
                     handleSleeping((IBinder)msg.obj, msg.arg1 != 0);
                     break;
@@ -2347,6 +2366,19 @@
         }
     }
 
+    private void handleDumpProvider(DumpComponentInfo info) {
+        ProviderClientRecord r = mLocalProviders.get(info.token);
+        if (r != null && r.mLocalProvider != null) {
+            PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor()));
+            r.mLocalProvider.dump(info.fd.getFileDescriptor(), pw, info.args);
+            pw.flush();
+            try {
+                info.fd.close();
+            } catch (IOException e) {
+            }
+        }
+    }
+
     private void handleServiceArgs(ServiceArgsData data) {
         Service s = mServices.get(data.token);
         if (s != null) {