Merge "Push mapping from file extension to GID."
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index d6688e3..a41f45b 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -189,6 +189,13 @@
     /** {@hide} */
     public static final int LAST_APPLICATION_CACHE_GID = 29999;
 
+    /** {@hide} */
+    public static final int MEDIA_AUDIO_GID = 1055;
+    /** {@hide} */
+    public static final int MEDIA_VIDEO_GID = 1056;
+    /** {@hide} */
+    public static final int MEDIA_IMAGE_GID = 1057;
+
     /**
      * Standard priority of application threads.
      * Use with {@link #setThreadPriority(int)} and
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c07add0..629da86 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -108,6 +108,8 @@
 import com.android.server.NativeDaemonConnector.SensitiveArg;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.storage.AppFuseBridge;
+import com.android.server.storage.FileCollector;
+
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
@@ -817,6 +819,9 @@
     }
 
     private void handleSystemReady() {
+        // Register kernel mapping from extensions to statistics GIDs
+        FileCollector.updateKernelExtensions();
+
         initIfReadyAndConnected();
         resetIfReadyAndConnected();
 
diff --git a/services/core/java/com/android/server/storage/FileCollector.java b/services/core/java/com/android/server/storage/FileCollector.java
index 90f9f139..59cfaf7 100644
--- a/services/core/java/com/android/server/storage/FileCollector.java
+++ b/services/core/java/com/android/server/storage/FileCollector.java
@@ -26,7 +26,6 @@
 import java.io.File;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Map;
 
 /**
  * FileCollector walks over a directory and categorizes storage usage by their type.
@@ -44,8 +43,9 @@
             AUDIO })
     private @interface FileTypes {}
 
-
-    private static final Map<String, Integer> EXTENSION_MAP = new ArrayMap<String, Integer>();
+    // NOTE: If you update these extensions, you'll also want to update
+    // matchgen.py over in installd which is used for non-quota stats.
+    private static final ArrayMap<String, Integer> EXTENSION_MAP = new ArrayMap<>();
     static {
         // Audio
         EXTENSION_MAP.put("aac", AUDIO);
@@ -144,6 +144,36 @@
         EXTENSION_MAP.put("xwd", IMAGES);
     }
 
+    private static File mkdir(File parent, String name) {
+        final File file = new File(parent, name);
+        file.mkdir();
+        return file;
+    }
+
+    /**
+     * Update the mapping used by sdcardfs to map from file extensions to GIDs
+     * used for statistics purposes.
+     */
+    public static void updateKernelExtensions() {
+        final File root = new File("/config/sdcardfs/extensions/");
+        if (!root.exists()) return;
+
+        final File audio = mkdir(root, Integer.toString(android.os.Process.MEDIA_AUDIO_GID));
+        final File video = mkdir(root, Integer.toString(android.os.Process.MEDIA_VIDEO_GID));
+        final File image = mkdir(root, Integer.toString(android.os.Process.MEDIA_IMAGE_GID));
+
+        for (int i = 0; i < EXTENSION_MAP.size(); i++) {
+            final String ext = EXTENSION_MAP.keyAt(i);
+            final int type = EXTENSION_MAP.valueAt(i);
+
+            switch (type) {
+                case AUDIO: mkdir(audio, ext); break;
+                case VIDEO: mkdir(video, ext); break;
+                case IMAGES: mkdir(image, ext); break;
+            }
+        }
+    }
+
     /**
      * Returns the file categorization measurement result.
      * @param path Directory to collect and categorize storage in.