Merge "Import translations. DO NOT MERGE"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 30c2c69..6160acb 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -253,6 +253,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/overlay/ExperimentNavigationBarSlim)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/SystemUI)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/DynamicAndroidInstallationService)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/api/current.txt b/api/current.txt
index 636339a..a15daa2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12357,6 +12357,7 @@
     method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[]);
     method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@StyleRes int, @NonNull @StyleableRes int[]) throws android.content.res.Resources.NotFoundException;
     method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@Nullable android.util.AttributeSet, @NonNull @StyleableRes int[], @AttrRes int, @StyleRes int);
+    method public void rebase();
     method public boolean resolveAttribute(int, android.util.TypedValue, boolean);
     method public void setTo(android.content.res.Resources.Theme);
   }
@@ -26395,15 +26396,15 @@
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0
     field @NonNull public static final android.os.Parcelable.Creator<android.media.Session2Command> CREATOR;
-    field public static final int RESULT_ERROR_UNKNOWN_ERROR = -1; // 0xffffffff
-    field public static final int RESULT_INFO_SKIPPED = 1; // 0x1
-    field public static final int RESULT_SUCCESS = 0; // 0x0
   }
 
   public static final class Session2Command.Result {
     ctor public Session2Command.Result(int, @Nullable android.os.Bundle);
     method public int getResultCode();
     method @Nullable public android.os.Bundle getResultData();
+    field public static final int RESULT_ERROR_UNKNOWN_ERROR = -1; // 0xffffffff
+    field public static final int RESULT_INFO_SKIPPED = 1; // 0x1
+    field public static final int RESULT_SUCCESS = 0; // 0x0
   }
 
   public final class Session2CommandGroup implements android.os.Parcelable {
@@ -41727,7 +41728,7 @@
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int);
-    method public void onStatusBarIconsBehaviorChanged(boolean);
+    method public void onSilentStatusBarIconsVisibilityChanged(boolean);
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
     method public static void requestRebind(android.content.ComponentName);
diff --git a/api/system-current.txt b/api/system-current.txt
index 1fad776..876c2b2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9495,6 +9495,10 @@
     method public int getUid();
   }
 
+  public final class StatsLog {
+    method public static void writeRaw(@NonNull byte[], int);
+  }
+
   public class StatsLogAtoms {
     field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED = 170; // 0xaa
     field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED = 8; // 0x8
diff --git a/api/test-current.txt b/api/test-current.txt
index d3036f3..6532cf8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -588,12 +588,14 @@
   }
 
   public final class ContentCaptureOptions implements android.os.Parcelable {
+    ctor public ContentCaptureOptions(int);
     ctor public ContentCaptureOptions(int, int, int, int, int, @Nullable android.util.ArraySet<android.content.ComponentName>);
     method public int describeContents();
     method public static android.content.ContentCaptureOptions forWhitelistingItself();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.ContentCaptureOptions> CREATOR;
     field public final int idleFlushingFrequencyMs;
+    field public final boolean lite;
     field public final int logHistorySize;
     field public final int loggingLevel;
     field public final int maxBufferSize;
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 2a3eee2..16c936c 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -84,4 +84,6 @@
     optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC];
 
     optional bool allow_from_any_uid = 50003 [default = false];
+
+    optional string log_from_module = 50004;
 }
\ No newline at end of file
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index 6be0bea..1727d34 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -72,9 +72,29 @@
     @Nullable
     public final ArraySet<ComponentName> whitelistedComponents;
 
+    /**
+     * Used to enable just a small set of APIs so it can used by activities belonging to the
+     * content capture service APK.
+     */
+    public final boolean lite;
+
+    public ContentCaptureOptions(int loggingLevel) {
+        this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0,
+                /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0,
+                /* logHistorySize= */ 0, /* whitelistedComponents= */ null);
+    }
+
     public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
             int textChangeFlushingFrequencyMs, int logHistorySize,
             @Nullable ArraySet<ComponentName> whitelistedComponents) {
+        this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
+                textChangeFlushingFrequencyMs, logHistorySize, whitelistedComponents);
+    }
+
+    private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize,
+            int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize,
+            @Nullable ArraySet<ComponentName> whitelistedComponents) {
+        this.lite = lite;
         this.loggingLevel = loggingLevel;
         this.maxBufferSize = maxBufferSize;
         this.idleFlushingFrequencyMs = idleFlushingFrequencyMs;
@@ -115,6 +135,9 @@
 
     @Override
     public String toString() {
+        if (lite) {
+            return "ContentCaptureOptions [(lite) loggingLevel=" + loggingLevel + "]";
+        }
         return "ContentCaptureOptions [loggingLevel=" + loggingLevel + ", maxBufferSize="
                 + maxBufferSize + ", idleFlushingFrequencyMs=" + idleFlushingFrequencyMs
                 + ", textChangeFlushingFrequencyMs=" + textChangeFlushingFrequencyMs
@@ -125,6 +148,10 @@
     /** @hide */
     public void dumpShort(@NonNull PrintWriter pw) {
         pw.print("logLvl="); pw.print(loggingLevel);
+        if (lite) {
+            pw.print(", lite");
+            return;
+        }
         pw.print(", bufferSize="); pw.print(maxBufferSize);
         pw.print(", idle="); pw.print(idleFlushingFrequencyMs);
         pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs);
@@ -141,7 +168,10 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeBoolean(lite);
         parcel.writeInt(loggingLevel);
+        if (lite) return;
+
         parcel.writeInt(maxBufferSize);
         parcel.writeInt(idleFlushingFrequencyMs);
         parcel.writeInt(textChangeFlushingFrequencyMs);
@@ -154,7 +184,11 @@
 
                 @Override
                 public ContentCaptureOptions createFromParcel(Parcel parcel) {
+                    final boolean lite = parcel.readBoolean();
                     final int loggingLevel = parcel.readInt();
+                    if (lite) {
+                        return new ContentCaptureOptions(loggingLevel);
+                    }
                     final int maxBufferSize = parcel.readInt();
                     final int idleFlushingFrequencyMs = parcel.readInt();
                     final int textChangeFlushingFrequencyMs = parcel.readInt();
@@ -171,6 +205,5 @@
                 public ContentCaptureOptions[] newArray(int size) {
                     return new ContentCaptureOptions[size];
                 }
-
     };
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a5f627d..032e5ac 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -29,6 +29,7 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.app.AppGlobals;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
@@ -43,6 +44,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.IncidentManager;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -51,6 +53,7 @@
 import android.os.ShellCommand;
 import android.os.StrictMode;
 import android.os.UserHandle;
+import android.os.storage.StorageManager;
 import android.provider.ContactsContract.QuickContact;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
@@ -68,6 +71,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Serializable;
@@ -632,6 +636,8 @@
  * of all possible flags.
  */
 public class Intent implements Parcelable, Cloneable {
+    private static final String TAG = "Intent";
+
     private static final String ATTR_ACTION = "action";
     private static final String TAG_CATEGORIES = "categories";
     private static final String ATTR_CATEGORY = "category";
@@ -9807,7 +9813,7 @@
                 // may fail.  We really should handle this (i.e., the Bundle
                 // impl shouldn't be on top of a plain map), but for now just
                 // ignore it and keep the original contents. :(
-                Log.w("Intent", "Failure filling in extras", e);
+                Log.w(TAG, "Failure filling in extras", e);
             }
         }
         if (mayHaveCopiedUris && mContentUserHint == UserHandle.USER_CURRENT
@@ -10523,7 +10529,7 @@
             } else if (ATTR_FLAGS.equals(attrName)) {
                 intent.setFlags(Integer.parseInt(attrValue, 16));
             } else {
-                Log.e("Intent", "restoreFromXml: unknown attribute=" + attrName);
+                Log.e(TAG, "restoreFromXml: unknown attribute=" + attrName);
             }
         }
 
@@ -10539,7 +10545,7 @@
                         intent.addCategory(in.getAttributeValue(attrNdx));
                     }
                 } else {
-                    Log.w("Intent", "restoreFromXml: unknown name=" + name);
+                    Log.w(TAG, "restoreFromXml: unknown name=" + name);
                     XmlUtils.skipCurrentTag(in);
                 }
             }
@@ -10653,6 +10659,20 @@
                     mData.checkContentUriWithoutPermission("Intent.getData()", getFlags());
             }
         }
+
+        // Translate raw filesystem paths out of storage sandbox
+        if (ACTION_MEDIA_SCANNER_SCAN_FILE.equals(mAction) && mData != null
+                && ContentResolver.SCHEME_FILE.equals(mData.getScheme()) && leavingPackage) {
+            final StorageManager sm = AppGlobals.getInitialApplication()
+                    .getSystemService(StorageManager.class);
+            final File before = new File(mData.getPath());
+            final File after = sm.translateAppToSystem(before,
+                    android.os.Process.myPid(), android.os.Process.myUid());
+            if (!Objects.equals(before, after)) {
+                Log.v(TAG, "Translated " + before + " to " + after);
+                mData = Uri.fromFile(after);
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 6b8416d..d7e4e14 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1721,8 +1721,6 @@
          * Rebases the theme against the parent Resource object's current
          * configuration by re-applying the styles passed to
          * {@link #applyStyle(int, boolean)}.
-         *
-         * @hide
          */
         public void rebase() {
             mThemeImpl.rebase();
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 915baab..3420007 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -649,11 +649,13 @@
                     Boolean.parseBoolean(USAP_POOL_ENABLED_DEFAULT));
         }
 
-        if (origVal != mUsapPoolEnabled) {
+        boolean valueChanged = origVal != mUsapPoolEnabled;
+
+        if (valueChanged) {
             Log.i(LOG_TAG, "usapPoolEnabled = " + mUsapPoolEnabled);
         }
 
-        return origVal != mUsapPoolEnabled;
+        return valueChanged;
     }
 
     private boolean mIsFirstPropCheck = true;
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 368ba3c..20d3c91 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -1381,6 +1381,11 @@
         }
 
         /** @hide */
+        public static @NonNull Uri getContentUri(@NonNull String volumeName, long id) {
+            return ContentUris.withAppendedId(getContentUri(volumeName), id);
+        }
+
+        /** @hide */
         public static @NonNull Uri getContentUriForPath(@NonNull String path) {
             return getContentUri(getVolumeName(new File(path)));
         }
@@ -1752,6 +1757,11 @@
                         .appendPath("media").build();
             }
 
+            /** @hide */
+            public static @NonNull Uri getContentUri(@NonNull String volumeName, long id) {
+                return ContentUris.withAppendedId(getContentUri(volumeName), id);
+            }
+
             /**
              * The content:// style URI for the internal storage.
              */
@@ -2240,6 +2250,11 @@
                         .appendPath("media").build();
             }
 
+            /** @hide */
+            public static @NonNull Uri getContentUri(@NonNull String volumeName, long id) {
+                return ContentUris.withAppendedId(getContentUri(volumeName), id);
+            }
+
             /**
              * Get the content:// style URI for the given audio media file.
              *
@@ -3018,6 +3033,11 @@
                         .appendPath("media").build();
             }
 
+            /** @hide */
+            public static @NonNull Uri getContentUri(@NonNull String volumeName, long id) {
+                return ContentUris.withAppendedId(getContentUri(volumeName), id);
+            }
+
             /**
              * The content:// style URI for the internal storage.
              */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6dd7ecc..53c7eda 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -876,7 +876,8 @@
 
     /**
      * Activity Action: Show screen for controlling app usage properties for an app.
-     * Input: Intent's extra EXTRA_PACKAGE_NAME must specify the application package name.
+     * Input: Intent's extra {@link android.content.Intent#EXTRA_PACKAGE_NAME} must specify the
+     * application package name.
      * Output: Nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 23607eb..333868a 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -476,7 +476,7 @@
      * @param hideSilentStatusIcons whether or not status bar icons should be hidden for silent
      *                              notifications
      */
-    public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+    public void onSilentStatusBarIconsVisibilityChanged(boolean hideSilentStatusIcons) {
         // optional
     }
 
@@ -2255,7 +2255,7 @@
                 } break;
 
                 case MSG_ON_STATUS_BAR_ICON_BEHAVIOR_CHANGED: {
-                    onStatusBarIconsBehaviorChanged((Boolean) msg.obj);
+                    onSilentStatusBarIconsVisibilityChanged((Boolean) msg.obj);
                 } break;
             }
         }
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index bf46e95..30d3d7d 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -22,6 +22,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.app.IActivityManager;
 import android.content.Context;
 import android.os.IStatsManager;
@@ -199,6 +200,16 @@
         }
     }
 
+    /**
+     * Write an event to stats log using the raw format.
+     *
+     * @param buffer    The encoded buffer of data to write..
+     * @param size      The number of bytes from the buffer to write.
+     * @hide
+     */
+    @SystemApi
+    public static native void writeRaw(@NonNull byte[] buffer, int size);
+
     private static void enforceDumpCallingPermission(Context context) {
         context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission.");
     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index afddc38..9e546a8 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -246,6 +246,7 @@
     @UiThread
     public void onActivityCreated(@NonNull IBinder applicationToken,
             @NonNull ComponentName activityComponent, int flags) {
+        if (mOptions.lite) return;
         synchronized (mLock) {
             mFlags |= flags;
             getMainContentCaptureSession().start(applicationToken, activityComponent, mFlags);
@@ -255,18 +256,21 @@
     /** @hide */
     @UiThread
     public void onActivityResumed() {
+        if (mOptions.lite) return;
         getMainContentCaptureSession().notifySessionLifecycle(/* started= */ true);
     }
 
     /** @hide */
     @UiThread
     public void onActivityPaused() {
+        if (mOptions.lite) return;
         getMainContentCaptureSession().notifySessionLifecycle(/* started= */ false);
     }
 
     /** @hide */
     @UiThread
     public void onActivityDestroyed() {
+        if (mOptions.lite) return;
         getMainContentCaptureSession().destroy();
     }
 
@@ -279,6 +283,7 @@
      */
     @UiThread
     public void flush(@FlushReason int reason) {
+        if (mOptions.lite) return;
         getMainContentCaptureSession().flush(reason);
     }
 
@@ -288,7 +293,7 @@
      */
     @Nullable
     public ComponentName getServiceComponentName() {
-        if (!isContentCaptureEnabled()) return null;
+        if (!isContentCaptureEnabled() && !mOptions.lite) return null;
 
         final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         try {
@@ -307,6 +312,7 @@
      *
      * @hide
      */
+    // TODO: use "lite" options as it's done by activities from the content capture service
     @Nullable
     public static ComponentName getServiceSettingsComponentName() {
         final IBinder binder = ServiceManager
@@ -342,6 +348,8 @@
      * </ul>
      */
     public boolean isContentCaptureEnabled() {
+        if (mOptions.lite) return false;
+
         final MainContentCaptureSession mainSession;
         synchronized (mLock) {
             mainSession = mMainSession;
diff --git a/core/java/com/android/internal/os/ZygoteConfig.java b/core/java/com/android/internal/os/ZygoteConfig.java
index c8ff51e..c6af8c2 100644
--- a/core/java/com/android/internal/os/ZygoteConfig.java
+++ b/core/java/com/android/internal/os/ZygoteConfig.java
@@ -24,14 +24,14 @@
 public class ZygoteConfig {
 
     /** If {@code true}, enables the unspecialized app process (USAP) pool feature */
-    public static final String USAP_POOL_ENABLED = "blastula_pool_enabled";
+    public static final String USAP_POOL_ENABLED = "usap_pool_enabled";
 
     /** The threshold used to determine if the pool should be refilled */
-    public static final String USAP_POOL_REFILL_THRESHOLD = "blastula_refill_threshold";
+    public static final String USAP_POOL_REFILL_THRESHOLD = "usap_refill_threshold";
 
     /** The maximum number of processes to keep in the USAP pool */
-    public static final String USAP_POOL_SIZE_MAX = "blastula_pool_size_max";
+    public static final String USAP_POOL_SIZE_MAX = "usap_pool_size_max";
 
     /** The minimum number of processes to keep in the USAP pool */
-    public static final String USAP_POOL_SIZE_MIN = "blastula_pool_size_min";
+    public static final String USAP_POOL_SIZE_MIN = "usap_pool_size_min";
 }
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 3f3aba9..5d1911b 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -353,6 +353,8 @@
             return null;
         }
 
+        Log.i(TAG, "USAP Pool status change: " + (newStatus ? "ENABLED" : "DISABLED"));
+
         mUsapPoolEnabled = newStatus;
 
         if (newStatus) {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index cd34d2e..664f7f4 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -1,10 +1,10 @@
 
 genrule {
-    name: "android_util_StatsLog.cpp",
+    name: "android_util_StatsLogInternal.cpp",
     tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLog.cpp",
+    cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLogInternal.cpp",
     out: [
-        "android_util_StatsLog.cpp",
+        "android_util_StatsLogInternal.cpp",
     ],
 }
 
@@ -111,6 +111,7 @@
         "android_util_Binder.cpp",
         "android_util_EventLog.cpp",
         "android_util_Log.cpp",
+        "android_util_StatsLog.cpp",
         "android_util_MemoryIntArray.cpp",
         "android_util_PathParser.cpp",
         "android_util_Process.cpp",
@@ -306,7 +307,7 @@
         "server_configurable_flags",
     ],
 
-    generated_sources: ["android_util_StatsLog.cpp"],
+    generated_sources: ["android_util_StatsLogInternal.cpp"],
 
     local_include_dirs: ["android/graphics"],
     export_include_dirs: [
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 20bed1b..ccd0b66 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -127,6 +127,7 @@
 extern int register_android_content_AssetManager(JNIEnv* env);
 extern int register_android_util_EventLog(JNIEnv* env);
 extern int register_android_util_StatsLog(JNIEnv* env);
+extern int register_android_util_StatsLogInternal(JNIEnv* env);
 extern int register_android_util_Log(JNIEnv* env);
 extern int register_android_util_MemoryIntArray(JNIEnv* env);
 extern int register_android_util_PathParser(JNIEnv* env);
@@ -1400,6 +1401,7 @@
     REG_JNI(register_android_util_MemoryIntArray),
     REG_JNI(register_android_util_PathParser),
     REG_JNI(register_android_util_StatsLog),
+    REG_JNI(register_android_util_StatsLogInternal),
     REG_JNI(register_android_app_admin_SecurityLog),
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
diff --git a/core/jni/android_util_StatsLog.cpp b/core/jni/android_util_StatsLog.cpp
new file mode 100644
index 0000000..e749d34
--- /dev/null
+++ b/core/jni/android_util_StatsLog.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NAMESPACE "StatsLog.tag."
+#define LOG_TAG "StatsLog_println"
+
+#include <assert.h>
+#include <cutils/properties.h>
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include "utils/misc.h"
+#include "core_jni_helpers.h"
+#include "stats_event_list.h"
+
+namespace android {
+
+static void android_util_StatsLog_writeRaw(JNIEnv* env, jobject clazz, jbyteArray buf, jint size)
+{
+    if (buf == NULL) {
+        return;
+    }
+    jint actualSize = env->GetArrayLength(buf);
+    if (actualSize < size) {
+        return;
+    }
+
+    jbyte* bufferArray = env->GetByteArrayElements(buf, NULL);
+    if (bufferArray == NULL) {
+        return;
+    }
+    const uint32_t statsEventTag = 1937006964;
+    struct iovec vec[2];
+    vec[0].iov_base = (void*) &statsEventTag;
+    vec[0].iov_len = sizeof(statsEventTag);
+    vec[1].iov_base = (void*) bufferArray;
+    vec[1].iov_len = size;
+    write_to_statsd(vec, 2);
+
+    env->ReleaseByteArrayElements(buf, bufferArray, 0);
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "writeRaw", "([BI)V", (void*) android_util_StatsLog_writeRaw },
+};
+
+int register_android_util_StatsLog(JNIEnv* env)
+{
+    return RegisterMethodsOrDie(env, "android/util/StatsLog", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/media/apex/java/android/media/MediaController2.java b/media/apex/java/android/media/MediaController2.java
index 2743a34..1e8438e 100644
--- a/media/apex/java/android/media/MediaController2.java
+++ b/media/apex/java/android/media/MediaController2.java
@@ -22,8 +22,8 @@
 import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
 import static android.media.MediaConstants.KEY_SESSION2LINK;
 import static android.media.MediaConstants.KEY_TOKEN_EXTRAS;
-import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
-import static android.media.Session2Command.RESULT_INFO_SKIPPED;
+import static android.media.Session2Command.Result.RESULT_ERROR_UNKNOWN_ERROR;
+import static android.media.Session2Command.Result.RESULT_INFO_SKIPPED;
 import static android.media.Session2Token.TYPE_SESSION;
 
 import android.annotation.NonNull;
@@ -329,7 +329,7 @@
                     MediaController2.this, command, args);
             if (resultReceiver != null) {
                 if (result == null) {
-                    resultReceiver.send(Session2Command.RESULT_INFO_SKIPPED, null);
+                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
                 } else {
                     resultReceiver.send(result.getResultCode(), result.getResultData());
                 }
diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java
index d63de09..a900d87 100644
--- a/media/apex/java/android/media/MediaSession2.java
+++ b/media/apex/java/android/media/MediaSession2.java
@@ -22,8 +22,8 @@
 import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
 import static android.media.MediaConstants.KEY_SESSION2LINK;
 import static android.media.MediaConstants.KEY_TOKEN_EXTRAS;
-import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
-import static android.media.Session2Command.RESULT_INFO_SKIPPED;
+import static android.media.Session2Command.Result.RESULT_ERROR_UNKNOWN_ERROR;
+import static android.media.Session2Command.Result.RESULT_INFO_SKIPPED;
 import static android.media.Session2Token.TYPE_SESSION;
 
 import android.annotation.NonNull;
@@ -415,7 +415,7 @@
                     MediaSession2.this, controllerInfo, command, args);
             if (resultReceiver != null) {
                 if (result == null) {
-                    resultReceiver.send(Session2Command.RESULT_INFO_SKIPPED, null);
+                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
                 } else {
                     resultReceiver.send(result.getResultCode(), result.getResultData());
                 }
diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java
index 6822ea5..7f73dc1 100644
--- a/media/apex/java/android/media/Session2Command.java
+++ b/media/apex/java/android/media/Session2Command.java
@@ -48,22 +48,6 @@
      */
     public static final int COMMAND_CODE_CUSTOM = 0;
 
-    /**
-     * Result code representing that the command is skipped or canceled. For an example, a seek
-     * command can be skipped if it is followed by another seek command.
-     */
-    public static final int RESULT_INFO_SKIPPED = 1;
-
-    /**
-     * Result code representing that the command is successfully completed.
-     */
-    public static final int RESULT_SUCCESS = 0;
-
-    /**
-     * Result code represents that call is ended with an unknown error.
-     */
-    public static final int RESULT_ERROR_UNKNOWN_ERROR = -1;
-
     public static final @android.annotation.NonNull Parcelable.Creator<Session2Command> CREATOR =
             new Parcelable.Creator<Session2Command>() {
                 @Override
@@ -185,6 +169,22 @@
         private final Bundle mResultData;
 
         /**
+         * Result code representing that the command is skipped or canceled. For an example, a seek
+         * command can be skipped if it is followed by another seek command.
+         */
+        public static final int RESULT_INFO_SKIPPED = 1;
+
+        /**
+         * Result code representing that the command is successfully completed.
+         */
+        public static final int RESULT_SUCCESS = 0;
+
+        /**
+         * Result code represents that call is ended with an unknown error.
+         */
+        public static final int RESULT_ERROR_UNKNOWN_ERROR = -1;
+
+        /**
          * Constructor of {@link Result}.
          *
          * @param resultCode result code
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 30719fd..771628c 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -116,7 +116,14 @@
  * The MediaScanner class is not thread-safe, so it should only be used in a single threaded manner.
  *
  * {@hide}
+ *
+ * @deprecated this media scanner has served faithfully for many years, but it's
+ *             become tedious to test and maintain, mainly due to the way it
+ *             weaves obscurely between managed and native code. It's been
+ *             replaced by {@code ModernMediaScanner} in the
+ *             {@code MediaProvider} package.
  */
+@Deprecated
 public class MediaScanner implements AutoCloseable {
     static {
         System.loadLibrary("media_jni");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index be63bad..aeaceb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -79,7 +79,7 @@
             }
         });
         NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
-        onStatusBarIconsBehaviorChanged(noMan.shouldHideSilentStatusBarIcons());
+        onSilentStatusBarIconsVisibilityChanged(noMan.shouldHideSilentStatusBarIcons());
     }
 
     @Override
@@ -144,7 +144,7 @@
     }
 
     @Override
-    public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+    public void onSilentStatusBarIconsVisibilityChanged(boolean hideSilentStatusIcons) {
         for (NotificationSettingsListener listener : mSettingsListeners) {
             listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 2a01356..1a1acdf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -129,7 +129,7 @@
                 mock(NotificationListener.NotificationSettingsListener.class);
         mListener.addNotificationSettingsListener(settingsListener);
 
-        mListener.onStatusBarIconsBehaviorChanged(true);
+        mListener.onSilentStatusBarIconsVisibilityChanged(true);
 
         verify(settingsListener).onStatusBarIconsBehaviorChanged(true);
     }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index f3814c6..d909736 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -459,6 +459,10 @@
     @Nullable
     ContentCaptureOptions getOptionsForPackageLocked(@NonNull String packageName) {
         if (!mWhitelistHelper.isWhitelisted(packageName)) {
+            if (packageName.equals(getServicePackageName())) {
+                if (mMaster.verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
+                return new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel);
+            }
             if (mMaster.verbose) {
                 Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
             }
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 5725f0c..4ce4406 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -31,6 +31,7 @@
     shared_libs: [
         "libstats_proto_host",
         "libprotobuf-cpp-full",
+        "libbase",
     ],
 
     proto: {
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index a8d970e..e66ead7 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -49,7 +49,9 @@
       exclusiveField(that.exclusiveField),
       uidField(that.uidField),
       whitelisted(that.whitelisted),
-      binaryFields(that.binaryFields) {}
+      binaryFields(that.binaryFields),
+      hasModule(that.hasModule),
+      moduleName(that.moduleName) {}
 
 AtomDecl::AtomDecl(int c, const string& n, const string& m)
     :code(c),
@@ -391,7 +393,12 @@
     AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
 
     if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
-      atomDecl.whitelisted = true;
+        atomDecl.whitelisted = true;
+    }
+
+    if (atomField->options().HasExtension(os::statsd::log_from_module)) {
+        atomDecl.hasModule = true;
+        atomDecl.moduleName = atomField->options().GetExtension(os::statsd::log_from_module);
     }
 
     vector<java_type_t> signature;
@@ -399,25 +406,49 @@
     if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
         errorCount++;
     }
-    atoms->signatures.insert(signature);
+
+    // Add the signature if does not already exist.
+    auto signature_to_modules_it = atoms->signatures_to_modules.find(signature);
+    if (signature_to_modules_it == atoms->signatures_to_modules.end()) {
+        set<string> modules;
+        if (atomDecl.hasModule) {
+            modules.insert(atomDecl.moduleName);
+        }
+        atoms->signatures_to_modules[signature] = modules;
+    } else {
+        if (atomDecl.hasModule) {
+            signature_to_modules_it->second.insert(atomDecl.moduleName);
+        }
+    }
     atoms->decls.insert(atomDecl);
 
     AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
     vector<java_type_t> nonChainedSignature;
     if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
-        atoms->non_chained_signatures.insert(nonChainedSignature);
+        auto it = atoms->non_chained_signatures_to_modules.find(signature);
+        if (it == atoms->non_chained_signatures_to_modules.end()) {
+            set<string> modules_non_chained;
+            if (atomDecl.hasModule) {
+                modules_non_chained.insert(atomDecl.moduleName);
+            }
+            atoms->non_chained_signatures_to_modules[nonChainedSignature] = modules_non_chained;
+        } else {
+            if (atomDecl.hasModule) {
+                it->second.insert(atomDecl.moduleName);
+            }
+        }
         atoms->non_chained_decls.insert(nonChainedAtomDecl);
     }
   }
 
   if (dbg) {
     printf("signatures = [\n");
-    for (set<vector<java_type_t>>::const_iterator it =
-             atoms->signatures.begin();
-         it != atoms->signatures.end(); it++) {
+    for (map<vector<java_type_t>, set<string>>::const_iterator it =
+             atoms->signatures_to_modules.begin();
+         it != atoms->signatures_to_modules.end(); it++) {
       printf("   ");
-      for (vector<java_type_t>::const_iterator jt = it->begin();
-           jt != it->end(); jt++) {
+      for (vector<java_type_t>::const_iterator jt = it->first.begin();
+           jt != it->first.end(); jt++) {
         printf(" %d", (int)*jt);
       }
       printf("\n");
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 6b86b862..44746c9 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -93,6 +93,9 @@
 
     vector<int> binaryFields;
 
+    bool hasModule = false;
+    string moduleName;
+
     AtomDecl();
     AtomDecl(const AtomDecl& that);
     AtomDecl(int code, const string& name, const string& message);
@@ -104,10 +107,10 @@
 };
 
 struct Atoms {
-    set<vector<java_type_t>> signatures;
+    map<vector<java_type_t>, set<string>> signatures_to_modules;
     set<AtomDecl> decls;
     set<AtomDecl> non_chained_decls;
-    set<vector<java_type_t>> non_chained_signatures;
+    map<vector<java_type_t>, set<string>> non_chained_signatures_to_modules;
 };
 
 /**
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 0270c72..daee6d6 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -12,6 +12,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "android-base/strings.h"
+
 using namespace google::protobuf;
 using namespace std;
 
@@ -20,6 +22,10 @@
 
 int maxPushedAtomId = 2;
 
+const string DEFAULT_MODULE_NAME = "DEFAULT";
+const string DEFAULT_CPP_NAMESPACE = "android,util";
+const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
+
 using android::os::statsd::Atom;
 
 /**
@@ -97,40 +103,27 @@
     }
 }
 
-static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
-                               const AtomDecl &attributionDecl) {
-    // Print prelude
-    fprintf(out, "// This file is autogenerated\n");
-    fprintf(out, "\n");
+static bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) {
+    if (moduleName == DEFAULT_MODULE_NAME) {
+        return true;
+    }
+    return atomDecl.hasModule && (moduleName == atomDecl.moduleName);
+}
 
-    fprintf(out, "#include <mutex>\n");
-    fprintf(out, "#include <chrono>\n");
-    fprintf(out, "#include <thread>\n");
-    fprintf(out, "#ifdef __ANDROID__\n");
-    fprintf(out, "#include <cutils/properties.h>\n");
-    fprintf(out, "#endif\n");
-    fprintf(out, "#include <stats_event_list.h>\n");
-    fprintf(out, "#include <log/log.h>\n");
-    fprintf(out, "#include <statslog.h>\n");
-    fprintf(out, "#include <utils/SystemClock.h>\n");
-    fprintf(out, "\n");
+static bool signature_needed_for_module(const set<string>& modules, const string& moduleName) {
+    if (moduleName == DEFAULT_MODULE_NAME) {
+        return true;
+    }
+    return modules.find(moduleName) != modules.end();
+}
 
-    fprintf(out, "namespace android {\n");
-    fprintf(out, "namespace util {\n");
-    fprintf(out, "// the single event tag id for all stats logs\n");
-    fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
-    fprintf(out, "#ifdef __ANDROID__\n");
-    fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
-    fprintf(out, "#else\n");
-    fprintf(out, "const static bool kStatsdEnabled = false;\n");
-    fprintf(out, "#endif\n");
-
+static void write_atoms_info_cpp(FILE *out, const Atoms &atoms) {
     std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
-                                             "audio_state_changed",
-                                             "call_state_changed",
-                                             "phone_signal_strength_changed",
-                                             "mobile_bytes_transfer_by_fg_bg",
-                                             "mobile_bytes_transfer"};
+                                                 "audio_state_changed",
+                                                 "call_state_changed",
+                                                 "phone_signal_strength_changed",
+                                                 "mobile_bytes_transfer_by_fg_bg",
+                                                 "mobile_bytes_transfer"};
     fprintf(out,
             "const std::set<int> "
             "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n");
@@ -256,6 +249,56 @@
             "const std::map<int, std::vector<int>> "
             "AtomsInfo::kBytesFieldAtoms = "
             "getBinaryFieldAtoms();\n");
+}
+
+// Writes namespaces for the cpp and header files, returning the number of namespaces written.
+void write_namespace(FILE* out, const string& cppNamespaces) {
+    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+    for (string cppNamespace : cppNamespaceVec) {
+        fprintf(out, "namespace %s {\n", cppNamespace.c_str());
+    }
+}
+
+// Writes namespace closing brackets for cpp and header files.
+void write_closing_namespace(FILE* out, const string& cppNamespaces) {
+    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+    for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
+        fprintf(out, "} // namespace %s\n", it->c_str());
+    }
+}
+
+static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
+                               const string& moduleName, const string& cppNamespace,
+                               const string& importHeader) {
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "#include <mutex>\n");
+    fprintf(out, "#include <chrono>\n");
+    fprintf(out, "#include <thread>\n");
+    fprintf(out, "#ifdef __ANDROID__\n");
+    fprintf(out, "#include <cutils/properties.h>\n");
+    fprintf(out, "#endif\n");
+    fprintf(out, "#include <stats_event_list.h>\n");
+    fprintf(out, "#include <log/log.h>\n");
+    fprintf(out, "#include <%s>\n", importHeader.c_str());
+    fprintf(out, "#include <utils/SystemClock.h>\n");
+    fprintf(out, "\n");
+
+    write_namespace(out, cppNamespace);
+    fprintf(out, "// the single event tag id for all stats logs\n");
+    fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
+    fprintf(out, "#ifdef __ANDROID__\n");
+    fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
+    fprintf(out, "#else\n");
+    fprintf(out, "const static bool kStatsdEnabled = false;\n");
+    fprintf(out, "#endif\n");
+
+    // AtomsInfo is only used by statsd internally and is not needed for other modules.
+    if (moduleName == DEFAULT_MODULE_NAME) {
+        write_atoms_info_cpp(out, atoms);
+    }
 
     fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
     fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
@@ -263,15 +306,19 @@
 
     // Print write methods
     fprintf(out, "\n");
-    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
-        signature != atoms.signatures.end(); signature++) {
+    for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
+        signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
+        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+            continue;
+        }
+        vector<java_type_t> signature = signature_to_modules_it->first;
         int argIndex;
 
         fprintf(out, "int\n");
         fprintf(out, "try_stats_write(int32_t code");
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -303,8 +350,8 @@
         fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
         fprintf(out, "    event << android::elapsedRealtimeNano();\n\n");
         fprintf(out, "    event << code;\n\n");
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (const auto &chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -387,15 +434,19 @@
         fprintf(out, "\n");
     }
 
-   for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
-       signature != atoms.signatures.end(); signature++) {
+   for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
+       signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
+       if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+           continue;
+       }
+       vector<java_type_t> signature = signature_to_modules_it->first;
        int argIndex;
 
        fprintf(out, "int\n");
        fprintf(out, "stats_write(int32_t code");
        argIndex = 1;
-       for (vector<java_type_t>::const_iterator arg = signature->begin();
-           arg != signature->end(); arg++) {
+       for (vector<java_type_t>::const_iterator arg = signature.begin();
+           arg != signature.end(); arg++) {
            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                for (auto chainField : attributionDecl.fields) {
                    if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -429,8 +480,8 @@
        fprintf(out, "      ret =  try_stats_write(code");
 
        argIndex = 1;
-       for (vector<java_type_t>::const_iterator arg = signature->begin();
-           arg != signature->end(); arg++) {
+       for (vector<java_type_t>::const_iterator arg = signature.begin();
+           arg != signature.end(); arg++) {
            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                for (auto chainField : attributionDecl.fields) {
                    if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -468,15 +519,19 @@
        fprintf(out, "\n");
    }
 
-    for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
-        signature != atoms.non_chained_signatures.end(); signature++) {
+    for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
+            signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
+        if (!signature_needed_for_module(signature_it->second, moduleName)) {
+            continue;
+        }
+        vector<java_type_t> signature = signature_it->first;
         int argIndex;
 
         fprintf(out, "int\n");
         fprintf(out, "try_stats_write_non_chained(int32_t code");
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
             argIndex++;
         }
@@ -488,8 +543,8 @@
         fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
         fprintf(out, "    event << android::elapsedRealtimeNano();\n\n");
         fprintf(out, "    event << code;\n\n");
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             if (argIndex == 1) {
                 fprintf(out, "    event.begin();\n\n");
                 fprintf(out, "    event.begin();\n");
@@ -522,15 +577,19 @@
         fprintf(out, "\n");
     }
 
-   for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
-       signature != atoms.non_chained_signatures.end(); signature++) {
+    for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
+            signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
+       if (!signature_needed_for_module(signature_it->second, moduleName)) {
+           continue;
+       }
+       vector<java_type_t> signature = signature_it->first;
        int argIndex;
 
        fprintf(out, "int\n");
        fprintf(out, "stats_write_non_chained(int32_t code");
        argIndex = 1;
-       for (vector<java_type_t>::const_iterator arg = signature->begin();
-           arg != signature->end(); arg++) {
+       for (vector<java_type_t>::const_iterator arg = signature.begin();
+           arg != signature.end(); arg++) {
            fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
            argIndex++;
        }
@@ -543,8 +602,8 @@
        fprintf(out, "      ret =  try_stats_write_non_chained(code");
 
        argIndex = 1;
-       for (vector<java_type_t>::const_iterator arg = signature->begin();
-           arg != signature->end(); arg++) {
+       for (vector<java_type_t>::const_iterator arg = signature.begin();
+           arg != signature.end(); arg++) {
            fprintf(out, ", arg%d",   argIndex);
            argIndex++;
        }
@@ -572,8 +631,7 @@
 
     // Print footer
     fprintf(out, "\n");
-    fprintf(out, "} // namespace util\n");
-    fprintf(out, "} // namespace android\n");
+    write_closing_namespace(out, cppNamespace);
 
     return 0;
 }
@@ -623,14 +681,23 @@
 }
 
 static void write_cpp_method_header(
-    FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
-    const AtomDecl &attributionDecl) {
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-            signature != signatures.end(); signature++) {
+        FILE* out,
+        const string& method_name,
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const AtomDecl &attributionDecl, const string& moduleName) {
+
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        // Skip if this signature is not needed for the module.
+        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+            continue;
+        }
+
+        vector<java_type_t> signature = signature_to_modules_it->first;
         fprintf(out, "int %s(int32_t code", method_name.c_str());
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -659,7 +726,8 @@
 }
 
 static int
-write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
+write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+        const string& moduleName, const string& cppNamespace)
 {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
@@ -672,8 +740,7 @@
     fprintf(out, "#include <set>\n");
     fprintf(out, "\n");
 
-    fprintf(out, "namespace android {\n");
-    fprintf(out, "namespace util {\n");
+    write_namespace(out, cppNamespace);
     fprintf(out, "\n");
     fprintf(out, "/*\n");
     fprintf(out, " * API For logging statistics events.\n");
@@ -691,6 +758,10 @@
     // Print atom constants
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
         atom != atoms.decls.end(); atom++) {
+        // Skip if the atom is not needed for the module.
+        if (!atom_needed_for_module(*atom, moduleName)) {
+            continue;
+        }
         string constant = make_constant_name(atom->name);
         fprintf(out, "\n");
         fprintf(out, "    /**\n");
@@ -720,6 +791,11 @@
     fprintf(out, "//\n\n");
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
         atom != atoms.decls.end(); atom++) {
+        // Skip if the atom is not needed for the module.
+        if (!atom_needed_for_module(*atom, moduleName)) {
+            continue;
+        }
+
         for (vector<AtomField>::const_iterator field = atom->fields.begin();
             field != atom->fields.end(); field++) {
             if (field->javaType == JAVA_TYPE_ENUM) {
@@ -747,47 +823,51 @@
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
-    fprintf(out, "struct StateAtomFieldOptions {\n");
-    fprintf(out, "  std::vector<int> primaryFields;\n");
-    fprintf(out, "  int exclusiveField;\n");
-    fprintf(out, "};\n");
-    fprintf(out, "\n");
+    // This metadata is only used by statsd, which uses the default libstatslog.
+    if (moduleName == DEFAULT_MODULE_NAME) {
 
-    fprintf(out, "struct AtomsInfo {\n");
-    fprintf(out,
-            "  const static std::set<int> "
-            "kNotTruncatingTimestampAtomWhiteList;\n");
-    fprintf(out, "  const static std::map<int, int> kAtomsWithUidField;\n");
-    fprintf(out,
-            "  const static std::set<int> kAtomsWithAttributionChain;\n");
-    fprintf(out,
-            "  const static std::map<int, StateAtomFieldOptions> "
-            "kStateAtomsFieldOptions;\n");
-    fprintf(out,
-            "  const static std::map<int, std::vector<int>> "
-            "kBytesFieldAtoms;");
-    fprintf(out,
-            "  const static std::set<int> kWhitelistedAtoms;\n");
-    fprintf(out, "};\n");
+        fprintf(out, "struct StateAtomFieldOptions {\n");
+        fprintf(out, "  std::vector<int> primaryFields;\n");
+        fprintf(out, "  int exclusiveField;\n");
+        fprintf(out, "};\n");
+        fprintf(out, "\n");
 
-    fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
-            maxPushedAtomId);
+        fprintf(out, "struct AtomsInfo {\n");
+        fprintf(out,
+                "  const static std::set<int> "
+                "kNotTruncatingTimestampAtomWhiteList;\n");
+        fprintf(out, "  const static std::map<int, int> kAtomsWithUidField;\n");
+        fprintf(out,
+                "  const static std::set<int> kAtomsWithAttributionChain;\n");
+        fprintf(out,
+                "  const static std::map<int, StateAtomFieldOptions> "
+                "kStateAtomsFieldOptions;\n");
+        fprintf(out,
+                "  const static std::map<int, std::vector<int>> "
+                "kBytesFieldAtoms;");
+        fprintf(out,
+                "  const static std::set<int> kWhitelistedAtoms;\n");
+        fprintf(out, "};\n");
+
+        fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
+                maxPushedAtomId);
+    }
 
     // Print write methods
     fprintf(out, "//\n");
     fprintf(out, "// Write methods\n");
     fprintf(out, "//\n");
-    write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl);
+    write_cpp_method_header(out, "stats_write", atoms.signatures_to_modules, attributionDecl,
+            moduleName);
 
     fprintf(out, "//\n");
     fprintf(out, "// Write flattened methods\n");
     fprintf(out, "//\n");
-    write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures,
-        attributionDecl);
+    write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures_to_modules,
+        attributionDecl, moduleName);
 
     fprintf(out, "\n");
-    fprintf(out, "} // namespace util\n");
-    fprintf(out, "} // namespace android\n");
+    write_closing_namespace(out, cppNamespace);
 
     return 0;
 }
@@ -812,15 +892,19 @@
 }
 
 static void write_java_method(
-    FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
-    const AtomDecl &attributionDecl) {
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-        signature != signatures.end(); signature++) {
+        FILE* out,
+        const string& method_name,
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const AtomDecl &attributionDecl) {
+
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        vector<java_type_t> signature = signature_to_modules_it->first;
         fprintf(out, "    /** @hide */\n");
         fprintf(out, "    public static native int %s(int code", method_name.c_str());
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-            arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+            arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     fprintf(out, ", %s[] %s",
@@ -837,15 +921,17 @@
     }
 }
 
-static void write_java_work_source_method(FILE* out, const set<vector<java_type_t>>& signatures) {
+static void write_java_work_source_method(FILE* out,
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules) {
     fprintf(out, "\n    // WorkSource methods.\n");
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-            signature != signatures.end(); signature++) {
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        vector<java_type_t> signature = signature_to_modules_it->first;
         // Determine if there is Attribution in this signature.
         int attributionArg = -1;
         int argIndexMax = 0;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             argIndexMax++;
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 if (attributionArg > -1) {
@@ -865,8 +951,8 @@
         fprintf(out, "    /** @hide */\n");
         fprintf(out, "    public static void write(int code");
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 fprintf(out, ", WorkSource ws");
             } else {
@@ -974,9 +1060,10 @@
 
     // Print write methods
     fprintf(out, "    // Write methods\n");
-    write_java_method(out, "write", atoms.signatures, attributionDecl);
-    write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
-    write_java_work_source_method(out, atoms.signatures);
+    write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
+    write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
+            attributionDecl);
+    write_java_work_source_method(out, atoms.signatures_to_modules);
 
     fprintf(out, "}\n");
 
@@ -1154,19 +1241,20 @@
 
 static int
 write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
-    const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
-{
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const AtomDecl &attributionDecl) {
     // Print write methods
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-        signature != signatures.end(); signature++) {
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        vector<java_type_t> signature = signature_to_modules_it->first;
         int argIndex;
 
         fprintf(out, "static int\n");
         fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
-                jni_function_name(java_method_name, *signature).c_str());
+                jni_function_name(java_method_name, signature).c_str());
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
@@ -1187,8 +1275,8 @@
         argIndex = 1;
         bool hadStringOrChain = false;
         bool isKeyValuePairAtom = false;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_STRING) {
                 hadStringOrChain = true;
                 fprintf(out, "    const char* str%d;\n", argIndex);
@@ -1288,8 +1376,8 @@
         argIndex = 1;
         fprintf(out, "\n    int ret =  android::util::%s(code",
                 cpp_method_name.c_str());
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_INT) {
@@ -1316,8 +1404,8 @@
 
         // Clean up strings
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature->begin();
-                arg != signature->end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_STRING) {
                 fprintf(out, "    if (str%d != NULL) {\n", argIndex);
                 fprintf(out, "        env->ReleaseStringUTFChars(arg%d, str%d);\n",
@@ -1357,13 +1445,15 @@
 }
 
 void write_jni_registration(FILE* out, const string& java_method_name,
-    const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) {
-    for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
-            signature != signatures.end(); signature++) {
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const AtomDecl &attributionDecl) {
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        vector<java_type_t> signature = signature_to_modules_it->first;
         fprintf(out, "    { \"%s\", \"%s\", (void*)%s },\n",
             java_method_name.c_str(),
-            jni_function_signature(*signature, attributionDecl).c_str(),
-            jni_function_name(java_method_name, *signature).c_str());
+            jni_function_signature(signature, attributionDecl).c_str(),
+            jni_function_name(java_method_name, signature).c_str());
     }
 }
 
@@ -1388,25 +1478,26 @@
     fprintf(out, "namespace android {\n");
     fprintf(out, "\n");
 
-    write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl);
+    write_stats_log_jni(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl);
     write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
-        atoms.non_chained_signatures, attributionDecl);
+            atoms.non_chained_signatures_to_modules, attributionDecl);
 
     // Print registration function table
     fprintf(out, "/*\n");
     fprintf(out, " * JNI registration.\n");
     fprintf(out, " */\n");
     fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
-    write_jni_registration(out, "write", atoms.signatures, attributionDecl);
-    write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
+    write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl);
+    write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
+            attributionDecl);
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
     // Print registration function
-    fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
+    fprintf(out, "int register_android_util_StatsLogInternal(JNIEnv* env) {\n");
     fprintf(out, "    return RegisterMethodsOrDie(\n");
     fprintf(out, "            env,\n");
-    fprintf(out, "            \"android/util/StatsLog\",\n");
+    fprintf(out, "            \"android/util/StatsLogInternal\",\n");
     fprintf(out, "            gRegisterMethods, NELEM(gRegisterMethods));\n");
     fprintf(out, "}\n");
 
@@ -1426,6 +1517,10 @@
     fprintf(stderr, "  --help               this message\n");
     fprintf(stderr, "  --java FILENAME      the java file to output\n");
     fprintf(stderr, "  --jni FILENAME       the jni file to output\n");
+    fprintf(stderr, "  --module NAME        optional, module name to generate outputs for\n");
+    fprintf(stderr, "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with module\n");
+    fprintf(stderr, "                                    comma separated namespace of the files\n");
+    fprintf(stderr, "  --importHeader NAME  required for cpp/jni to say which header to import\n");
 }
 
 /**
@@ -1439,6 +1534,10 @@
     string javaFilename;
     string jniFilename;
 
+    string moduleName = DEFAULT_MODULE_NAME;
+    string cppNamespace = DEFAULT_CPP_NAMESPACE;
+    string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
+
     int index = 1;
     while (index < argc) {
         if (0 == strcmp("--help", argv[index])) {
@@ -1472,6 +1571,27 @@
                 return 1;
             }
             jniFilename = argv[index];
+        } else if (0 == strcmp("--module", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            moduleName = argv[index];
+        } else if (0 == strcmp("--namespace", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            cppNamespace = argv[index];
+        } else if (0 == strcmp("--importHeader", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            cppHeaderImport = argv[index];
         }
         index++;
     }
@@ -1503,8 +1623,18 @@
             fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
             return 1;
         }
+        // If this is for a specific module, the namespace must also be provided.
+        if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
+            fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
+            return 1;
+        }
+        // If this is for a specific module, the header file to import must also be provided.
+        if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
+            fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
+            return 1;
+        }
         errorCount = android::stats_log_api_gen::write_stats_log_cpp(
-            out, atoms, attributionDecl);
+            out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport);
         fclose(out);
     }
 
@@ -1515,8 +1645,12 @@
             fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
             return 1;
         }
+        // If this is for a specific module, the namespace must also be provided.
+        if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
+            fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
+        }
         errorCount = android::stats_log_api_gen::write_stats_log_header(
-            out, atoms, attributionDecl);
+            out, atoms, attributionDecl, moduleName, cppNamespace);
         fclose(out);
     }
 
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index 24ebf4d..c3e70382 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -213,4 +213,24 @@
     // by whitelisted sources
     NonWhitelistedAtom non_whitelisted_atom = 2;
   }
+}
+
+message ModuleOneAtom {
+    optional int32 field = 1;
+}
+
+message ModuleTwoAtom {
+    optional int32 field = 1;
+}
+
+message NoModuleAtom {
+    optional string field = 1;
+}
+
+message ModuleAtoms {
+    oneof event {
+        ModuleOneAtom module_one_atom = 1 [(android.os.statsd.log_from_module) = "module1"];
+        ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.log_from_module) = "module2"];
+        NoModuleAtom no_module_atom = 3;
+    }
 }
\ No newline at end of file
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index dc585c1..bcf18ae 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -32,7 +32,7 @@
  * Return whether the set contains a vector of the elements provided.
  */
 static bool
-set_contains_vector(const set<vector<java_type_t>>& s, int count, ...)
+set_contains_vector(const map<vector<java_type_t>, set<string>>& s, int count, ...)
 {
     va_list args;
     vector<java_type_t> v;
@@ -86,17 +86,17 @@
     int errorCount = collate_atoms(Event::descriptor(), &atoms);
 
     EXPECT_EQ(0, errorCount);
-    EXPECT_EQ(3ul, atoms.signatures.size());
+    EXPECT_EQ(3ul, atoms.signatures_to_modules.size());
 
     // IntAtom, AnotherIntAtom
-    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT);
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT);
 
     // OutOfOrderAtom
-    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT, JAVA_TYPE_INT);
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT, JAVA_TYPE_INT);
 
     // AllTypesAtom
     EXPECT_SET_CONTAINS_SIGNATURE(
-        atoms.signatures,
+        atoms.signatures_to_modules,
         JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
         JAVA_TYPE_DOUBLE,            // double
         JAVA_TYPE_FLOAT,             // float
@@ -228,8 +228,7 @@
 
 TEST(CollationTest, PassOnWhitelistedAtom) {
     Atoms atoms;
-    int errorCount =
-            collate_atoms(ListedAtoms::descriptor(), &atoms);
+    int errorCount = collate_atoms(ListedAtoms::descriptor(), &atoms);
     EXPECT_EQ(errorCount, 0);
     EXPECT_EQ(atoms.decls.size(), 2ul);
 }
@@ -246,5 +245,46 @@
     }
 }
 
+TEST(CollationTest, PassOnLogFromModuleAtom) {
+    Atoms atoms;
+    int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
+    EXPECT_EQ(errorCount, 0);
+    EXPECT_EQ(atoms.decls.size(), 3ul);
+}
+
+TEST(CollationTest, RecognizeModuleAtom) {
+    Atoms atoms;
+    int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
+    EXPECT_EQ(errorCount, 0);
+    EXPECT_EQ(atoms.decls.size(), 3ul);
+    for (const auto& atomDecl: atoms.decls) {
+        if (atomDecl.code == 1) {
+            EXPECT_TRUE(atomDecl.hasModule);
+            EXPECT_EQ(atomDecl.moduleName, "module1");
+        } else if (atomDecl.code == 2) {
+            EXPECT_TRUE(atomDecl.hasModule);
+            EXPECT_EQ(atomDecl.moduleName, "module2");
+        } else {
+            EXPECT_FALSE(atomDecl.hasModule);
+        }
+    }
+
+    EXPECT_EQ(atoms.signatures_to_modules.size(), 2u);
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT);
+    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_STRING);
+    for (auto signature_to_modules_it : atoms.signatures_to_modules) {
+        vector<java_type_t> signature = signature_to_modules_it.first;
+        if (signature[0] == JAVA_TYPE_STRING) {
+            EXPECT_EQ(signature_to_modules_it.second.size(), 0u);
+        } else if (signature[0] == JAVA_TYPE_INT) {
+            set<string> modules = signature_to_modules_it.second;
+            EXPECT_EQ(modules.size(), 2u);
+            // Assert that the set contains "module1" and "module2".
+            EXPECT_NE(modules.find("module1"), modules.end());
+            EXPECT_NE(modules.find("module2"), modules.end());
+        }
+    }
+}
+
 }  // namespace stats_log_api_gen
 }  // namespace android
\ No newline at end of file