wm: Add ActivityMetricsLaunchObserverRegistry

Public(@hide)-visibility app sequence launch events.

Anything in system_server can use this new API to subscribe to
the ActivityMetricsLaunchObserver from the ActivityTaskManagerInternal
LocalService.

Also change AMLO to expose ActivityRecordProto as a byte[]; the previous
parameter was ActivityRecord, which is package-private.

Also add systrace for measuring performance of the AMLO callbacks
(seems to be about ~250us on a marlin-userdebug; mostly because of the
protobuf serialization).

Test: atest WmTests:ActivityMetricsLaunchObserverTests
Bug: 72170747
Bug: 112680320
Change-Id: Icc07b727b50438bdd65bb01978e15d839809948b
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 1c08d03..a7bf96b 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -99,10 +99,12 @@
 import android.util.SparseIntArray;
 import android.util.StatsLog;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 
 /**
@@ -168,7 +170,8 @@
      * Due to the global single concurrent launch sequence, all calls to this observer must be made
      * in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
      */
-    private final ActivityMetricsLaunchObserver mLaunchObserver = null;
+    private final LaunchObserverRegistryImpl mLaunchObserver;
+    @VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512;
 
     private final class H extends Handler {
 
@@ -263,6 +266,7 @@
         mSupervisor = supervisor;
         mContext = context;
         mHandler = new H(looper);
+        mLaunchObserver = new LaunchObserverRegistryImpl(looper);
     }
 
     void logWindowState() {
@@ -993,12 +997,19 @@
         }
     }
 
+    public ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry() {
+        return mLaunchObserver;
+    }
+
     /** Notify the {@link ActivityMetricsLaunchObserver} that a new launch sequence has begun. */
     private void launchObserverNotifyIntentStarted(Intent intent) {
-        if (mLaunchObserver != null) {
-            // Beginning a launch is timing sensitive and so should be observed as soon as possible.
-            mLaunchObserver.onIntentStarted(intent);
-        }
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                "MetricsLogger:launchObserverNotifyIntentStarted");
+
+        // Beginning a launch is timing sensitive and so should be observed as soon as possible.
+        mLaunchObserver.onIntentStarted(intent);
+
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     /**
@@ -1007,9 +1018,12 @@
      * intent being delivered to the top running activity.
      */
     private void launchObserverNotifyIntentFailed() {
-        if (mLaunchObserver != null) {
-            mLaunchObserver.onIntentFailed();
-        }
+       Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                "MetricsLogger:launchObserverNotifyIntentFailed");
+
+        mLaunchObserver.onIntentFailed();
+
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     /**
@@ -1017,14 +1031,17 @@
      * has started.
      */
     private void launchObserverNotifyActivityLaunched(WindowingModeTransitionInfo info) {
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                "MetricsLogger:launchObserverNotifyActivityLaunched");
+
         @ActivityMetricsLaunchObserver.Temperature int temperature =
                 convertTransitionTypeToLaunchObserverTemperature(getTransitionType(info));
 
-        if (mLaunchObserver != null) {
-            // Beginning a launch is timing sensitive and so should be observed as soon as possible.
-            mLaunchObserver.onActivityLaunched(info.launchedActivity,
-                                               temperature);
-        }
+        // Beginning a launch is timing sensitive and so should be observed as soon as possible.
+        mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.launchedActivity),
+                                           temperature);
+
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     /**
@@ -1032,11 +1049,15 @@
      * cancelled.
      */
     private void launchObserverNotifyActivityLaunchCancelled(WindowingModeTransitionInfo info) {
-        final ActivityRecord launchedActivity = info != null ? info.launchedActivity : null;
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                "MetricsLogger:launchObserverNotifyActivityLaunchCancelled");
 
-        if (mLaunchObserver != null) {
-            mLaunchObserver.onActivityLaunchCancelled(launchedActivity);
-        }
+        final @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] activityRecordProto =
+                info != null ? convertActivityRecordToProto(info.launchedActivity) : null;
+
+        mLaunchObserver.onActivityLaunchCancelled(activityRecordProto);
+
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     /**
@@ -1044,11 +1065,34 @@
      * has fully finished (successfully).
      */
     private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info) {
-        final ActivityRecord launchedActivity = info.launchedActivity;
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                "MetricsLogger:launchObserverNotifyActivityLaunchFinished");
 
-        if (mLaunchObserver != null) {
-            mLaunchObserver.onActivityLaunchFinished(launchedActivity);
-        }
+        mLaunchObserver.onActivityLaunchFinished(
+                convertActivityRecordToProto(info.launchedActivity));
+
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+    }
+
+    @VisibleForTesting
+    static @ActivityMetricsLaunchObserver.ActivityRecordProto byte[]
+            convertActivityRecordToProto(ActivityRecord record) {
+        // May take non-negligible amount of time to convert ActivityRecord into a proto,
+        // so track the time.
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                "MetricsLogger:convertActivityRecordToProto");
+
+        // There does not appear to be a way to 'reset' a ProtoOutputBuffer stream,
+        // so create a new one every time.
+        final ProtoOutputStream protoOutputStream =
+                new ProtoOutputStream(LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
+        // Write this data out as the top-most ActivityRecordProto (i.e. it is not a sub-object).
+        record.writeToProto(protoOutputStream);
+        final byte[] bytes = protoOutputStream.getBytes();
+
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
+        return bytes;
     }
 
     private static @ActivityMetricsLaunchObserver.Temperature int