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