Merge "Reduce overhead of activity launch observer" into tm-dev am: e0d2119461
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17937859 Change-Id: I0aeb51ec024ebd95e4142525e2a5165a2608fbdd Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -1024,30 +1024,9 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
private final ActivityMetricsLaunchObserver mActivityLaunchObserver =
|
private final ActivityMetricsLaunchObserver mActivityLaunchObserver =
|
||||||
new ActivityMetricsLaunchObserver() {
|
new ActivityMetricsLaunchObserver() {
|
||||||
@Override
|
@Override
|
||||||
public void onActivityLaunched(byte[] activity, int temperature) {
|
public void onActivityLaunched(long id, ComponentName name, int temperature) {
|
||||||
mAppProfiler.onActivityLaunched();
|
mAppProfiler.onActivityLaunched();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The other observer methods are unused
|
|
||||||
@Override
|
|
||||||
public void onIntentStarted(Intent intent, long timestampNs) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onIntentFailed() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityLaunchCancelled(byte[] abortingActivity) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityLaunchFinished(byte[] finalActivity, long timestampNs) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReportFullyDrawn(byte[] finalActivity, long timestampNs) {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private volatile boolean mBinderTransactionTrackingEnabled = false;
|
private volatile boolean mBinderTransactionTrackingEnabled = false;
|
||||||
|
|||||||
@@ -18,17 +18,19 @@ package com.android.server.wm;
|
|||||||
|
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observe activity manager launch sequences.
|
* Observe activity launch sequences.
|
||||||
*
|
*
|
||||||
* The activity manager can have at most 1 concurrent launch sequences. Calls to this interface
|
* Multiple calls to the callback methods can occur without first terminating the current launch
|
||||||
* are ordered by a happens-before relation for each defined state transition (see below).
|
* sequence because activity can be launched concurrently. So the implementation should associate
|
||||||
|
* the corresponding event according to the timestamp from {@link #onIntentStarted} which is also
|
||||||
|
* used as the identifier to indicate which launch sequence it belongs to.
|
||||||
*
|
*
|
||||||
* When a new launch sequence is made, that sequence is in the {@code INTENT_STARTED} state which
|
* When a new launch sequence is made, that sequence is in the {@code INTENT_STARTED} state which
|
||||||
* is communicated by the {@link #onIntentStarted} callback. This is a transient state.
|
* is communicated by the {@link #onIntentStarted} callback. This is a transient state.
|
||||||
@@ -47,7 +49,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
* Note this transition may not happen if the reportFullyDrawn event is not receivied,
|
* Note this transition may not happen if the reportFullyDrawn event is not receivied,
|
||||||
* in which case {@code FINISHED} is terminal.
|
* in which case {@code FINISHED} is terminal.
|
||||||
*
|
*
|
||||||
* Note that the {@code ActivityRecordProto} provided as a parameter to some state transitions isn't
|
* Note that the {@code ComponentName} provided as a parameter to some state transitions isn't
|
||||||
* necessarily the same within a single launch sequence: it is only the top-most activity at the
|
* necessarily the same within a single launch sequence: it is only the top-most activity at the
|
||||||
* time (if any). Trampoline activities coalesce several activity starts into a single launch
|
* time (if any). Trampoline activities coalesce several activity starts into a single launch
|
||||||
* sequence.
|
* sequence.
|
||||||
@@ -67,7 +69,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
* ╚════════════════╝ ╚═══════════════════════════╝ ╚═══════════════════════════╝
|
* ╚════════════════╝ ╚═══════════════════════════╝ ╚═══════════════════════════╝
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public interface ActivityMetricsLaunchObserver {
|
public class ActivityMetricsLaunchObserver {
|
||||||
/**
|
/**
|
||||||
* The 'temperature' at which a launch sequence had started.
|
* The 'temperature' at which a launch sequence had started.
|
||||||
*
|
*
|
||||||
@@ -98,14 +100,6 @@ public interface ActivityMetricsLaunchObserver {
|
|||||||
/** Hot launch sequence: process reused, activity brought-to-top. */
|
/** Hot launch sequence: process reused, activity brought-to-top. */
|
||||||
public static final int TEMPERATURE_HOT = 3;
|
public static final int TEMPERATURE_HOT = 3;
|
||||||
|
|
||||||
/**
|
|
||||||
* Typedef marker that a {@code byte[]} actually contains an
|
|
||||||
* <a href="proto/android/server/activitymanagerservice.proto">ActivityRecordProto</a>
|
|
||||||
* in the protobuf format.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
@interface ActivityRecordProto {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the observer that a new launch sequence has begun as a result of a new intent.
|
* Notifies the observer that a new launch sequence has begun as a result of a new intent.
|
||||||
*
|
*
|
||||||
@@ -113,26 +107,25 @@ public interface ActivityMetricsLaunchObserver {
|
|||||||
* {@link #onActivityLaunched} or abort early (for example due to a resolution error or due to
|
* {@link #onActivityLaunched} or abort early (for example due to a resolution error or due to
|
||||||
* a security error) with {@link #onIntentFailed}.
|
* a security error) with {@link #onIntentFailed}.
|
||||||
*
|
*
|
||||||
* Multiple calls to this method cannot occur without first terminating the current
|
* @param timestampNanos The timestamp when receiving the intent. It is also use as an
|
||||||
* launch sequence.
|
* identifier for other callback methods to known which launch sequence
|
||||||
|
* it is associated with.
|
||||||
*/
|
*/
|
||||||
public void onIntentStarted(@NonNull Intent intent, long timestampNanos);
|
public void onIntentStarted(@NonNull Intent intent, long timestampNanos) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the observer that the current launch sequence has failed to launch an activity.
|
* Notifies the observer that the current launch sequence has failed to launch an activity.
|
||||||
*
|
*
|
||||||
* This function call terminates the current launch sequence. The next method call, if any,
|
* This function call terminates the current launch sequence.
|
||||||
* must be {@link #onIntentStarted}.
|
|
||||||
*
|
*
|
||||||
* Examples of this happening:
|
* Examples of this happening:
|
||||||
* - Failure to resolve to an activity
|
* - Failure to resolve to an activity
|
||||||
* - Calling package did not have the security permissions to call the requested activity
|
* - Calling package did not have the security permissions to call the requested activity
|
||||||
* - Resolved activity was already running and only needed to be brought to the top
|
* - Resolved activity was already running and only needed to be brought to the top
|
||||||
*
|
|
||||||
* Multiple calls to this method cannot occur without first terminating the current
|
|
||||||
* launch sequence.
|
|
||||||
*/
|
*/
|
||||||
public void onIntentFailed();
|
public void onIntentFailed(long id) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the observer that the current launch sequence had begun starting an activity.
|
* Notifies the observer that the current launch sequence had begun starting an activity.
|
||||||
@@ -145,62 +138,58 @@ public interface ActivityMetricsLaunchObserver {
|
|||||||
* necessarily the activity which will be considered as displayed when the activity
|
* necessarily the activity which will be considered as displayed when the activity
|
||||||
* finishes launching (e.g. {@code activity} in {@link #onActivityLaunchFinished}).
|
* finishes launching (e.g. {@code activity} in {@link #onActivityLaunchFinished}).
|
||||||
*
|
*
|
||||||
* Multiple calls to this method cannot occur without first terminating the current
|
* @param id The timestamp as an identifier from {@link #onIntentStarted}. It may be a new id
|
||||||
* launch sequence.
|
* if the launching activity is started from an existing launch sequence (trampoline)
|
||||||
|
* but cannot coalesce to the existing one, e.g. to a different display.
|
||||||
|
* @param name The launching activity name.
|
||||||
*/
|
*/
|
||||||
public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
|
public void onActivityLaunched(long id, ComponentName name, @Temperature int temperature) {
|
||||||
@Temperature int temperature);
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the observer that the current launch sequence has been aborted.
|
* Notifies the observer that the current launch sequence has been aborted.
|
||||||
*
|
*
|
||||||
* This function call terminates the current launch sequence. The next method call, if any,
|
* This function call terminates the current launch sequence.
|
||||||
* must be {@link #onIntentStarted}.
|
|
||||||
*
|
*
|
||||||
* This can happen for many reasons, for example the user switches away to another app
|
* This can happen for many reasons, for example the user switches away to another app
|
||||||
* prior to the launch sequence completing, or the application being killed.
|
* prior to the launch sequence completing, or the application being killed.
|
||||||
*
|
*
|
||||||
* Multiple calls to this method cannot occur without first terminating the current
|
* @param id The timestamp as an identifier from {@link #onIntentStarted}.
|
||||||
* launch sequence.
|
|
||||||
*
|
|
||||||
* @param abortingActivity the last activity that had the top-most window during abort
|
|
||||||
* (this can be {@code null} in rare situations its unknown).
|
|
||||||
*
|
*
|
||||||
* @apiNote The aborting activity isn't necessarily the same as the starting activity;
|
* @apiNote The aborting activity isn't necessarily the same as the starting activity;
|
||||||
* in the case of a trampoline, multiple activities could've been started
|
* in the case of a trampoline, multiple activities could've been started
|
||||||
* and only the latest activity is reported here.
|
* and only the latest activity is reported here.
|
||||||
*/
|
*/
|
||||||
public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] abortingActivity);
|
public void onActivityLaunchCancelled(long id) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the observer that the current launch sequence has been successfully finished.
|
* Notifies the observer that the current launch sequence has been successfully finished.
|
||||||
*
|
*
|
||||||
* This function call terminates the current launch sequence. The next method call, if any,
|
* This function call terminates the current launch sequence.
|
||||||
* must be {@link #onIntentStarted}.
|
|
||||||
*
|
*
|
||||||
* A launch sequence is considered to be successfully finished when a frame is fully
|
* A launch sequence is considered to be successfully finished when a frame is fully
|
||||||
* drawn for the first time: the top-most activity at the time is what's reported here.
|
* drawn for the first time: the top-most activity at the time is what's reported here.
|
||||||
*
|
*
|
||||||
* @param finalActivity the top-most activity whose windows were first to fully draw
|
* @param id The timestamp as an identifier from {@link #onIntentStarted}.
|
||||||
|
* @param name The name of drawn activity. It can be different from {@link #onActivityLaunched}
|
||||||
|
* if the transition contains multiple launching activities (e.g. trampoline).
|
||||||
* @param timestampNanos the timestamp of ActivityLaunchFinished event in nanoseconds.
|
* @param timestampNanos the timestamp of ActivityLaunchFinished event in nanoseconds.
|
||||||
* To compute the TotalTime duration, deduct the timestamp {@link #onIntentStarted}
|
* To compute the TotalTime duration, deduct the timestamp {@link #onIntentStarted}
|
||||||
* from {@code timestampNanos}.
|
* from {@code timestampNanos}.
|
||||||
*
|
*
|
||||||
* Multiple calls to this method cannot occur without first terminating the current
|
|
||||||
* launch sequence.
|
|
||||||
*
|
|
||||||
* @apiNote The finishing activity isn't necessarily the same as the starting activity;
|
* @apiNote The finishing activity isn't necessarily the same as the starting activity;
|
||||||
* in the case of a trampoline, multiple activities could've been started
|
* in the case of a trampoline, multiple activities could've been started
|
||||||
* and only the latest activity that was top-most during first-frame drawn
|
* and only the latest activity that was top-most during first-frame drawn
|
||||||
* is reported here.
|
* is reported here.
|
||||||
*/
|
*/
|
||||||
public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] finalActivity,
|
public void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos) {
|
||||||
long timestampNanos);
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the observer that the application self-reported itself as being fully drawn.
|
* Notifies the observer that the application self-reported itself as being fully drawn.
|
||||||
*
|
*
|
||||||
* @param activity the activity that triggers the ReportFullyDrawn event.
|
* @param id The timestamp as an identifier from {@link #onIntentStarted}.
|
||||||
* @param timestampNanos the timestamp of ReportFullyDrawn event in nanoseconds.
|
* @param timestampNanos the timestamp of ReportFullyDrawn event in nanoseconds.
|
||||||
* To compute the duration, deduct the deduct the timestamp {@link #onIntentStarted}
|
* To compute the duration, deduct the deduct the timestamp {@link #onIntentStarted}
|
||||||
* from {@code timestampNanos}.
|
* from {@code timestampNanos}.
|
||||||
@@ -209,7 +198,7 @@ public interface ActivityMetricsLaunchObserver {
|
|||||||
* It is used as an accurate estimate of meanfully app startup time.
|
* It is used as an accurate estimate of meanfully app startup time.
|
||||||
* This event may be missing for many apps.
|
* This event may be missing for many apps.
|
||||||
*/
|
*/
|
||||||
public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
|
public void onReportFullyDrawn(long id, long timestampNanos) {
|
||||||
long timestampNanos);
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ import android.util.Log;
|
|||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.TimeUtils;
|
import android.util.TimeUtils;
|
||||||
import android.util.proto.ProtoOutputStream;
|
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
@@ -176,7 +175,6 @@ class ActivityMetricsLogger {
|
|||||||
* in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
|
* in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
|
||||||
*/
|
*/
|
||||||
private final LaunchObserverRegistryImpl mLaunchObserver;
|
private final LaunchObserverRegistryImpl mLaunchObserver;
|
||||||
@VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512;
|
|
||||||
private final ArrayMap<String, Boolean> mLastHibernationStates = new ArrayMap<>();
|
private final ArrayMap<String, Boolean> mLastHibernationStates = new ArrayMap<>();
|
||||||
private AppHibernationManagerInternal mAppHibernationManagerInternal;
|
private AppHibernationManagerInternal mAppHibernationManagerInternal;
|
||||||
|
|
||||||
@@ -675,7 +673,7 @@ class ActivityMetricsLogger {
|
|||||||
launchObserverNotifyActivityLaunched(newInfo);
|
launchObserverNotifyActivityLaunched(newInfo);
|
||||||
} else {
|
} else {
|
||||||
// As abort for no process switch.
|
// As abort for no process switch.
|
||||||
launchObserverNotifyIntentFailed();
|
launchObserverNotifyIntentFailed(newInfo.mTransitionStartTimeNs);
|
||||||
}
|
}
|
||||||
scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);
|
scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);
|
||||||
|
|
||||||
@@ -910,7 +908,7 @@ class ActivityMetricsLogger {
|
|||||||
}
|
}
|
||||||
if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
|
if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
|
||||||
state.stopTrace(true /* abort */);
|
state.stopTrace(true /* abort */);
|
||||||
launchObserverNotifyIntentFailed();
|
launchObserverNotifyIntentFailed(state.mCurrentTransitionStartTimeNs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Aborts tracking of current launch metrics. */
|
/** Aborts tracking of current launch metrics. */
|
||||||
@@ -1187,7 +1185,7 @@ class ActivityMetricsLogger {
|
|||||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
||||||
|
|
||||||
// Notify reportFullyDrawn event.
|
// Notify reportFullyDrawn event.
|
||||||
launchObserverNotifyReportFullyDrawn(r, currentTimestampNs);
|
launchObserverNotifyReportFullyDrawn(info, currentTimestampNs);
|
||||||
|
|
||||||
return infoSnapshot;
|
return infoSnapshot;
|
||||||
}
|
}
|
||||||
@@ -1531,11 +1529,11 @@ class ActivityMetricsLogger {
|
|||||||
* aborted due to intent failure (e.g. intent resolve failed or security error, etc) or
|
* aborted due to intent failure (e.g. intent resolve failed or security error, etc) or
|
||||||
* intent being delivered to the top running activity.
|
* intent being delivered to the top running activity.
|
||||||
*/
|
*/
|
||||||
private void launchObserverNotifyIntentFailed() {
|
private void launchObserverNotifyIntentFailed(long id) {
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
||||||
"MetricsLogger:launchObserverNotifyIntentFailed");
|
"MetricsLogger:launchObserverNotifyIntentFailed");
|
||||||
|
|
||||||
mLaunchObserver.onIntentFailed();
|
mLaunchObserver.onIntentFailed(id);
|
||||||
|
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
||||||
}
|
}
|
||||||
@@ -1552,8 +1550,8 @@ class ActivityMetricsLogger {
|
|||||||
convertTransitionTypeToLaunchObserverTemperature(info.mTransitionType);
|
convertTransitionTypeToLaunchObserverTemperature(info.mTransitionType);
|
||||||
|
|
||||||
// Beginning a launch is timing sensitive and so should be observed as soon as possible.
|
// Beginning a launch is timing sensitive and so should be observed as soon as possible.
|
||||||
mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.mLastLaunchedActivity),
|
mLaunchObserver.onActivityLaunched(info.mTransitionStartTimeNs,
|
||||||
temperature);
|
info.mLastLaunchedActivity.mActivityComponent, temperature);
|
||||||
|
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
||||||
}
|
}
|
||||||
@@ -1561,10 +1559,10 @@ class ActivityMetricsLogger {
|
|||||||
/**
|
/**
|
||||||
* Notifies the {@link ActivityMetricsLaunchObserver} the reportFullDrawn event.
|
* Notifies the {@link ActivityMetricsLaunchObserver} the reportFullDrawn event.
|
||||||
*/
|
*/
|
||||||
private void launchObserverNotifyReportFullyDrawn(ActivityRecord r, long timestampNs) {
|
private void launchObserverNotifyReportFullyDrawn(TransitionInfo info, long timestampNs) {
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
||||||
"MetricsLogger:launchObserverNotifyReportFullyDrawn");
|
"MetricsLogger:launchObserverNotifyReportFullyDrawn");
|
||||||
mLaunchObserver.onReportFullyDrawn(convertActivityRecordToProto(r), timestampNs);
|
mLaunchObserver.onReportFullyDrawn(info.mTransitionStartTimeNs, timestampNs);
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1576,10 +1574,7 @@ class ActivityMetricsLogger {
|
|||||||
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
||||||
"MetricsLogger:launchObserverNotifyActivityLaunchCancelled");
|
"MetricsLogger:launchObserverNotifyActivityLaunchCancelled");
|
||||||
|
|
||||||
final @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] activityRecordProto =
|
mLaunchObserver.onActivityLaunchCancelled(info.mTransitionStartTimeNs);
|
||||||
info != null ? convertActivityRecordToProto(info.mLastLaunchedActivity) : null;
|
|
||||||
|
|
||||||
mLaunchObserver.onActivityLaunchCancelled(activityRecordProto);
|
|
||||||
|
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
||||||
}
|
}
|
||||||
@@ -1592,33 +1587,12 @@ class ActivityMetricsLogger {
|
|||||||
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
||||||
"MetricsLogger:launchObserverNotifyActivityLaunchFinished");
|
"MetricsLogger:launchObserverNotifyActivityLaunchFinished");
|
||||||
|
|
||||||
mLaunchObserver.onActivityLaunchFinished(
|
mLaunchObserver.onActivityLaunchFinished(info.mTransitionStartTimeNs,
|
||||||
convertActivityRecordToProto(info.mLastLaunchedActivity), timestampNs);
|
info.mLastLaunchedActivity.mActivityComponent, timestampNs);
|
||||||
|
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
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.dumpDebug(protoOutputStream, WindowTraceLogLevel.ALL);
|
|
||||||
final byte[] bytes = protoOutputStream.getBytes();
|
|
||||||
|
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static @ActivityMetricsLaunchObserver.Temperature int
|
private static @ActivityMetricsLaunchObserver.Temperature int
|
||||||
convertTransitionTypeToLaunchObserverTemperature(int transitionType) {
|
convertTransitionTypeToLaunchObserverTemperature(int transitionType) {
|
||||||
switch (transitionType) {
|
switch (transitionType) {
|
||||||
|
|||||||
@@ -16,12 +16,11 @@
|
|||||||
|
|
||||||
package com.android.server.wm;
|
package com.android.server.wm;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
|
||||||
|
|
||||||
import com.android.internal.os.BackgroundThread;
|
|
||||||
import com.android.internal.util.function.pooled.PooledLambda;
|
import com.android.internal.util.function.pooled.PooledLambda;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -39,8 +38,8 @@ import java.util.ArrayList;
|
|||||||
*
|
*
|
||||||
* @see ActivityTaskManagerInternal#getLaunchObserverRegistry()
|
* @see ActivityTaskManagerInternal#getLaunchObserverRegistry()
|
||||||
*/
|
*/
|
||||||
class LaunchObserverRegistryImpl implements
|
class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implements
|
||||||
ActivityMetricsLaunchObserverRegistry, ActivityMetricsLaunchObserver {
|
ActivityMetricsLaunchObserverRegistry {
|
||||||
private final ArrayList<ActivityMetricsLaunchObserver> mList = new ArrayList<>();
|
private final ArrayList<ActivityMetricsLaunchObserver> mList = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,45 +78,36 @@ class LaunchObserverRegistryImpl implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIntentFailed() {
|
public void onIntentFailed(long id) {
|
||||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||||
LaunchObserverRegistryImpl::handleOnIntentFailed, this));
|
LaunchObserverRegistryImpl::handleOnIntentFailed, this, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityLaunched(
|
public void onActivityLaunched(long id, ComponentName name, int temperature) {
|
||||||
@ActivityRecordProto byte[] activity,
|
|
||||||
int temperature) {
|
|
||||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||||
LaunchObserverRegistryImpl::handleOnActivityLaunched,
|
LaunchObserverRegistryImpl::handleOnActivityLaunched,
|
||||||
this, activity, temperature));
|
this, id, name, temperature));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityLaunchCancelled(
|
public void onActivityLaunchCancelled(long id) {
|
||||||
@ActivityRecordProto byte[] activity) {
|
|
||||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||||
LaunchObserverRegistryImpl::handleOnActivityLaunchCancelled, this, activity));
|
LaunchObserverRegistryImpl::handleOnActivityLaunchCancelled, this, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityLaunchFinished(
|
public void onActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
|
||||||
@ActivityRecordProto byte[] activity,
|
|
||||||
long timestampNs) {
|
|
||||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||||
LaunchObserverRegistryImpl::handleOnActivityLaunchFinished,
|
LaunchObserverRegistryImpl::handleOnActivityLaunchFinished,
|
||||||
this,
|
this, id, name, timestampNs));
|
||||||
activity,
|
|
||||||
timestampNs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReportFullyDrawn(@ActivityRecordProto byte[] activity, long timestampNs) {
|
public void onReportFullyDrawn(long id, long timestampNs) {
|
||||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||||
LaunchObserverRegistryImpl::handleOnReportFullyDrawn,
|
LaunchObserverRegistryImpl::handleOnReportFullyDrawn,
|
||||||
this,
|
this, id, timestampNs));
|
||||||
activity,
|
|
||||||
timestampNs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use PooledLambda.obtainMessage to invoke below methods. Every method reference must be
|
// Use PooledLambda.obtainMessage to invoke below methods. Every method reference must be
|
||||||
@@ -135,53 +125,43 @@ class LaunchObserverRegistryImpl implements
|
|||||||
private void handleOnIntentStarted(Intent intent, long timestampNs) {
|
private void handleOnIntentStarted(Intent intent, long timestampNs) {
|
||||||
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
||||||
for (int i = 0; i < mList.size(); i++) {
|
for (int i = 0; i < mList.size(); i++) {
|
||||||
ActivityMetricsLaunchObserver o = mList.get(i);
|
mList.get(i).onIntentStarted(intent, timestampNs);
|
||||||
o.onIntentStarted(intent, timestampNs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleOnIntentFailed() {
|
private void handleOnIntentFailed(long id) {
|
||||||
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
||||||
for (int i = 0; i < mList.size(); i++) {
|
for (int i = 0; i < mList.size(); i++) {
|
||||||
ActivityMetricsLaunchObserver o = mList.get(i);
|
mList.get(i).onIntentFailed(id);
|
||||||
o.onIntentFailed();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleOnActivityLaunched(
|
private void handleOnActivityLaunched(long id, ComponentName name,
|
||||||
@ActivityRecordProto byte[] activity,
|
|
||||||
@Temperature int temperature) {
|
@Temperature int temperature) {
|
||||||
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
||||||
for (int i = 0; i < mList.size(); i++) {
|
for (int i = 0; i < mList.size(); i++) {
|
||||||
ActivityMetricsLaunchObserver o = mList.get(i);
|
mList.get(i).onActivityLaunched(id, name, temperature);
|
||||||
o.onActivityLaunched(activity, temperature);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleOnActivityLaunchCancelled(
|
private void handleOnActivityLaunchCancelled(long id) {
|
||||||
@ActivityRecordProto byte[] activity) {
|
|
||||||
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
||||||
for (int i = 0; i < mList.size(); i++) {
|
for (int i = 0; i < mList.size(); i++) {
|
||||||
ActivityMetricsLaunchObserver o = mList.get(i);
|
mList.get(i).onActivityLaunchCancelled(id);
|
||||||
o.onActivityLaunchCancelled(activity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleOnActivityLaunchFinished(
|
private void handleOnActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
|
||||||
@ActivityRecordProto byte[] activity, long timestampNs) {
|
|
||||||
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
||||||
for (int i = 0; i < mList.size(); i++) {
|
for (int i = 0; i < mList.size(); i++) {
|
||||||
ActivityMetricsLaunchObserver o = mList.get(i);
|
mList.get(i).onActivityLaunchFinished(id, name, timestampNs);
|
||||||
o.onActivityLaunchFinished(activity, timestampNs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleOnReportFullyDrawn(
|
private void handleOnReportFullyDrawn(long id, long timestampNs) {
|
||||||
@ActivityRecordProto byte[] activity, long timestampNs) {
|
|
||||||
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
|
||||||
for (int i = 0; i < mList.size(); i++) {
|
for (int i = 0; i < mList.size(); i++) {
|
||||||
ActivityMetricsLaunchObserver o = mList.get(i);
|
mList.get(i).onReportFullyDrawn(id, timestampNs);
|
||||||
o.onReportFullyDrawn(activity, timestampNs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,36 +274,11 @@ public final class ProfcollectForwardingService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
|
private class AppLaunchObserver extends ActivityMetricsLaunchObserver {
|
||||||
@Override
|
@Override
|
||||||
public void onIntentStarted(Intent intent, long timestampNanos) {
|
public void onIntentStarted(Intent intent, long timestampNanos) {
|
||||||
traceOnAppStart(intent.getPackage());
|
traceOnAppStart(intent.getPackage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onIntentFailed() {
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityLaunched(byte[] activity, int temperature) {
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityLaunchCancelled(byte[] abortingActivity) {
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityLaunchFinished(byte[] finalActivity, long timestampNanos) {
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReportFullyDrawn(byte[] activity, long timestampNanos) {
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerOTAObserver() {
|
private void registerOTAObserver() {
|
||||||
|
|||||||
@@ -27,10 +27,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMor
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.clearInvocations;
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@@ -40,24 +38,22 @@ import android.app.ActivityOptions;
|
|||||||
import android.app.ActivityOptions.SourceInfo;
|
import android.app.ActivityOptions.SourceInfo;
|
||||||
import android.app.WaitResult;
|
import android.app.WaitResult;
|
||||||
import android.app.WindowConfiguration;
|
import android.app.WindowConfiguration;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
|
import android.util.Log;
|
||||||
import android.window.WindowContainerToken;
|
import android.window.WindowContainerToken;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentMatcher;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.ToIntFunction;
|
import java.util.function.ToIntFunction;
|
||||||
|
|
||||||
@@ -75,13 +71,14 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
private ActivityMetricsLogger mActivityMetricsLogger;
|
private ActivityMetricsLogger mActivityMetricsLogger;
|
||||||
private ActivityMetricsLogger.LaunchingState mLaunchingState;
|
private ActivityMetricsLogger.LaunchingState mLaunchingState;
|
||||||
private ActivityMetricsLaunchObserver mLaunchObserver;
|
private ActivityMetricsLaunchObserver mLaunchObserver;
|
||||||
private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry;
|
|
||||||
|
|
||||||
private ActivityRecord mTrampolineActivity;
|
private ActivityRecord mTrampolineActivity;
|
||||||
private ActivityRecord mTopActivity;
|
private ActivityRecord mTopActivity;
|
||||||
private ActivityOptions mActivityOptions;
|
private ActivityOptions mActivityOptions;
|
||||||
private boolean mLaunchTopByTrampoline;
|
private boolean mLaunchTopByTrampoline;
|
||||||
private boolean mNewActivityCreated = true;
|
private boolean mNewActivityCreated = true;
|
||||||
|
private long mExpectedStartedId;
|
||||||
|
private final ArrayMap<ComponentName, Long> mLastLaunchedIds = new ArrayMap<>();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUpAMLO() {
|
public void setUpAMLO() {
|
||||||
@@ -89,9 +86,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
|
|
||||||
// ActivityTaskSupervisor always creates its own instance of ActivityMetricsLogger.
|
// ActivityTaskSupervisor always creates its own instance of ActivityMetricsLogger.
|
||||||
mActivityMetricsLogger = mSupervisor.getActivityMetricsLogger();
|
mActivityMetricsLogger = mSupervisor.getActivityMetricsLogger();
|
||||||
|
mActivityMetricsLogger.getLaunchObserverRegistry().registerLaunchObserver(mLaunchObserver);
|
||||||
mLaunchObserverRegistry = mActivityMetricsLogger.getLaunchObserverRegistry();
|
|
||||||
mLaunchObserverRegistry.registerLaunchObserver(mLaunchObserver);
|
|
||||||
|
|
||||||
// Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
|
// Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
|
||||||
// This seems to be the easiest way to create an ActivityRecord.
|
// This seems to be the easiest way to create an ActivityRecord.
|
||||||
@@ -107,33 +102,6 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
mTrampolineActivity.mVisibleRequested = false;
|
mTrampolineActivity.mVisibleRequested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDownAMLO() {
|
|
||||||
if (mLaunchObserverRegistry != null) { // Don't NPE if setUp failed.
|
|
||||||
mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ActivityRecordMatcher implements ArgumentMatcher</*@ActivityRecordProto*/ byte[]> {
|
|
||||||
private final @ActivityRecordProto byte[] mExpected;
|
|
||||||
|
|
||||||
public ActivityRecordMatcher(ActivityRecord activityRecord) {
|
|
||||||
mExpected = activityRecordToProto(activityRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matches(@ActivityRecordProto byte[] actual) {
|
|
||||||
return Arrays.equals(mExpected, actual);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static @ActivityRecordProto byte[] activityRecordToProto(ActivityRecord record) {
|
|
||||||
return ActivityMetricsLogger.convertActivityRecordToProto(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
static @ActivityRecordProto byte[] eqProto(ActivityRecord record) {
|
|
||||||
return argThat(new ActivityRecordMatcher(record));
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T verifyAsync(T mock) {
|
private <T> T verifyAsync(T mock) {
|
||||||
// With WindowTestRunner, all test methods are inside WM lock, so we have to unblock any
|
// With WindowTestRunner, all test methods are inside WM lock, so we have to unblock any
|
||||||
// messages that are waiting for the lock.
|
// messages that are waiting for the lock.
|
||||||
@@ -142,30 +110,62 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
return verify(mock, timeout(TIMEOUT_MS));
|
return verify(mock, timeout(TIMEOUT_MS));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyOnActivityLaunchFinished(ActivityRecord activity) {
|
private void verifyOnActivityLaunched(ActivityRecord activity) {
|
||||||
verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(activity), anyLong());
|
final ArgumentCaptor<Long> idCaptor = ArgumentCaptor.forClass(Long.class);
|
||||||
|
verifyAsync(mLaunchObserver).onActivityLaunched(idCaptor.capture(),
|
||||||
|
eq(activity.mActivityComponent), anyInt());
|
||||||
|
final long id = idCaptor.getValue();
|
||||||
|
setExpectedStartedId(id, activity);
|
||||||
|
mLastLaunchedIds.put(activity.mActivityComponent, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onIntentStarted(Intent intent) {
|
private void verifyOnActivityLaunchFinished(ActivityRecord activity) {
|
||||||
|
verifyAsync(mLaunchObserver).onActivityLaunchFinished(eq(mExpectedStartedId),
|
||||||
|
eq(activity.mActivityComponent), anyLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setExpectedStartedId(long id, Object reason) {
|
||||||
|
mExpectedStartedId = id;
|
||||||
|
Log.i("AMLTest", "setExpectedStartedId=" + id + " from " + reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLastExpectedStartedId(ActivityRecord r) {
|
||||||
|
setExpectedStartedId(getLastStartedId(r), r);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getLastStartedId(ActivityRecord r) {
|
||||||
|
final Long id = mLastLaunchedIds.get(r.mActivityComponent);
|
||||||
|
return id != null ? id : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long eqLastStartedId(ActivityRecord r) {
|
||||||
|
return eq(getLastStartedId(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
private long onIntentStarted(Intent intent) {
|
||||||
notifyActivityLaunching(intent);
|
notifyActivityLaunching(intent);
|
||||||
|
|
||||||
|
long timestamp = -1;
|
||||||
// If it is launching top activity from trampoline activity, the observer shouldn't receive
|
// If it is launching top activity from trampoline activity, the observer shouldn't receive
|
||||||
// onActivityLaunched because the activities should belong to the same transition.
|
// onActivityLaunched because the activities should belong to the same transition.
|
||||||
if (!mLaunchTopByTrampoline) {
|
if (!mLaunchTopByTrampoline) {
|
||||||
verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), anyLong());
|
final ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class);
|
||||||
|
verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), captor.capture());
|
||||||
|
timestamp = captor.getValue();
|
||||||
}
|
}
|
||||||
verifyNoMoreInteractions(mLaunchObserver);
|
verifyNoMoreInteractions(mLaunchObserver);
|
||||||
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnIntentFailed() {
|
public void testOnIntentFailed() {
|
||||||
onIntentStarted(new Intent("testOnIntentFailed"));
|
final long id = onIntentStarted(new Intent("testOnIntentFailed"));
|
||||||
|
|
||||||
// Bringing an intent that's already running 'to front' is not considered
|
// Bringing an intent that's already running 'to front' is not considered
|
||||||
// as an ACTIVITY_LAUNCHED state transition.
|
// as an ACTIVITY_LAUNCHED state transition.
|
||||||
notifyActivityLaunched(START_TASK_TO_FRONT, null /* launchedActivity */);
|
notifyActivityLaunched(START_TASK_TO_FRONT, null /* launchedActivity */);
|
||||||
|
|
||||||
verifyAsync(mLaunchObserver).onIntentFailed();
|
verifyAsync(mLaunchObserver).onIntentFailed(eq(id));
|
||||||
verifyNoMoreInteractions(mLaunchObserver);
|
verifyNoMoreInteractions(mLaunchObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,9 +208,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
|
|
||||||
private void onActivityLaunched(ActivityRecord activity) {
|
private void onActivityLaunched(ActivityRecord activity) {
|
||||||
onIntentStarted(activity.intent);
|
onIntentStarted(activity.intent);
|
||||||
notifyActivityLaunched(START_SUCCESS, activity);
|
notifyAndVerifyActivityLaunched(activity);
|
||||||
|
|
||||||
verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(activity), anyInt());
|
|
||||||
verifyNoMoreInteractions(mLaunchObserver);
|
verifyNoMoreInteractions(mLaunchObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +234,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
// Cannot time already-visible activities.
|
// Cannot time already-visible activities.
|
||||||
notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
|
notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
|
||||||
|
|
||||||
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
|
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqLastStartedId(mTopActivity));
|
||||||
verifyNoMoreInteractions(mLaunchObserver);
|
verifyNoMoreInteractions(mLaunchObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,33 +249,33 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
notifyActivityLaunching(noDrawnActivity.intent);
|
notifyActivityLaunching(noDrawnActivity.intent);
|
||||||
notifyActivityLaunched(START_SUCCESS, noDrawnActivity);
|
notifyAndVerifyActivityLaunched(noDrawnActivity);
|
||||||
|
|
||||||
noDrawnActivity.mVisibleRequested = false;
|
noDrawnActivity.mVisibleRequested = false;
|
||||||
mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
|
mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
|
||||||
|
|
||||||
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity));
|
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqLastStartedId(noDrawnActivity));
|
||||||
|
|
||||||
// If an activity is removed immediately before visibility update, it should cancel too.
|
// If an activity is removed immediately before visibility update, it should cancel too.
|
||||||
final ActivityRecord removedImm = new ActivityBuilder(mAtm).setCreateTask(true).build();
|
final ActivityRecord removedImm = new ActivityBuilder(mAtm).setCreateTask(true).build();
|
||||||
clearInvocations(mLaunchObserver);
|
clearInvocations(mLaunchObserver);
|
||||||
onActivityLaunched(removedImm);
|
onActivityLaunched(removedImm);
|
||||||
removedImm.removeImmediately();
|
removedImm.removeImmediately();
|
||||||
// Verify any() instead of proto because the field of record may be changed.
|
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqLastStartedId(removedImm));
|
||||||
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(any());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnActivityLaunchWhileSleeping() {
|
public void testOnActivityLaunchWhileSleeping() {
|
||||||
notifyActivityLaunching(mTrampolineActivity.intent);
|
notifyActivityLaunching(mTrampolineActivity.intent);
|
||||||
notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
|
notifyAndVerifyActivityLaunched(mTrampolineActivity);
|
||||||
doReturn(true).when(mTrampolineActivity.mDisplayContent).isSleeping();
|
doReturn(true).when(mTrampolineActivity.mDisplayContent).isSleeping();
|
||||||
mTrampolineActivity.setState(ActivityRecord.State.RESUMED, "test");
|
mTrampolineActivity.setState(ActivityRecord.State.RESUMED, "test");
|
||||||
mTrampolineActivity.setVisibility(false);
|
mTrampolineActivity.setVisibility(false);
|
||||||
waitHandlerIdle(mAtm.mH);
|
waitHandlerIdle(mAtm.mH);
|
||||||
// Not cancel immediately because in one of real cases, the keyguard may be going away or
|
// Not cancel immediately because in one of real cases, the keyguard may be going away or
|
||||||
// occluded later, then the activity can be drawn.
|
// occluded later, then the activity can be drawn.
|
||||||
verify(mLaunchObserver, never()).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
|
verify(mLaunchObserver, never()).onActivityLaunchCancelled(
|
||||||
|
eqLastStartedId(mTrampolineActivity));
|
||||||
|
|
||||||
clearInvocations(mLaunchObserver);
|
clearInvocations(mLaunchObserver);
|
||||||
mLaunchTopByTrampoline = true;
|
mLaunchTopByTrampoline = true;
|
||||||
@@ -289,9 +288,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
// The posted message will acquire wm lock, so the test needs to release the lock to verify.
|
// The posted message will acquire wm lock, so the test needs to release the lock to verify.
|
||||||
final Throwable error = awaitInWmLock(() -> {
|
final Throwable error = awaitInWmLock(() -> {
|
||||||
try {
|
try {
|
||||||
// Though the aborting target should be eqProto(mTopActivity), use any() to avoid
|
verify(mLaunchObserver, timeout(TIMEOUT_MS)).onActivityLaunchCancelled(
|
||||||
// any changes in proto that may cause failure by different arguments.
|
mExpectedStartedId);
|
||||||
verify(mLaunchObserver, timeout(TIMEOUT_MS)).onActivityLaunchCancelled(any());
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Catch any errors including assertion because this runs in another thread.
|
// Catch any errors including assertion because this runs in another thread.
|
||||||
return e;
|
return e;
|
||||||
@@ -314,9 +312,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
mActivityOptions = ActivityOptions.makeBasic();
|
mActivityOptions = ActivityOptions.makeBasic();
|
||||||
mActivityOptions.setSourceInfo(SourceInfo.TYPE_LAUNCHER, SystemClock.uptimeMillis() - 10);
|
mActivityOptions.setSourceInfo(SourceInfo.TYPE_LAUNCHER, SystemClock.uptimeMillis() - 10);
|
||||||
onIntentStarted(mTopActivity.intent);
|
onIntentStarted(mTopActivity.intent);
|
||||||
notifyActivityLaunched(START_SUCCESS, mTopActivity);
|
notifyAndVerifyActivityLaunched(mTopActivity);
|
||||||
verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
|
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eq(getLastStartedId(prev)));
|
||||||
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(prev));
|
|
||||||
|
|
||||||
// The activity reports fully drawn before windows drawn, then the fully drawn event will
|
// The activity reports fully drawn before windows drawn, then the fully drawn event will
|
||||||
// be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
|
// be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
|
||||||
@@ -328,7 +325,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
.isEqualTo(SourceInfo.TYPE_LAUNCHER);
|
.isEqualTo(SourceInfo.TYPE_LAUNCHER);
|
||||||
assertWithMessage("Record event time").that(info.sourceEventDelayMs).isAtLeast(10);
|
assertWithMessage("Record event time").that(info.sourceEventDelayMs).isAtLeast(10);
|
||||||
|
|
||||||
verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong());
|
verifyAsync(mLaunchObserver).onReportFullyDrawn(eq(mExpectedStartedId), anyLong());
|
||||||
verifyOnActivityLaunchFinished(mTopActivity);
|
verifyOnActivityLaunchFinished(mTopActivity);
|
||||||
verifyNoMoreInteractions(mLaunchObserver);
|
verifyNoMoreInteractions(mLaunchObserver);
|
||||||
|
|
||||||
@@ -339,9 +336,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
|
|
||||||
private void onActivityLaunchedTrampoline() {
|
private void onActivityLaunchedTrampoline() {
|
||||||
onIntentStarted(mTrampolineActivity.intent);
|
onIntentStarted(mTrampolineActivity.intent);
|
||||||
notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
|
notifyAndVerifyActivityLaunched(mTrampolineActivity);
|
||||||
|
|
||||||
verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTrampolineActivity), anyInt());
|
|
||||||
|
|
||||||
// A second, distinct, activity launch is coalesced into the current app launch sequence.
|
// A second, distinct, activity launch is coalesced into the current app launch sequence.
|
||||||
mLaunchTopByTrampoline = true;
|
mLaunchTopByTrampoline = true;
|
||||||
@@ -370,6 +365,11 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
mNewActivityCreated, activity, mActivityOptions);
|
mNewActivityCreated, activity, mActivityOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void notifyAndVerifyActivityLaunched(ActivityRecord activity) {
|
||||||
|
notifyActivityLaunched(START_SUCCESS, activity);
|
||||||
|
verifyOnActivityLaunched(activity);
|
||||||
|
}
|
||||||
|
|
||||||
private void notifyTransitionStarting(ActivityRecord activity) {
|
private void notifyTransitionStarting(ActivityRecord activity) {
|
||||||
final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>();
|
final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>();
|
||||||
reasons.put(activity, ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN);
|
reasons.put(activity, ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN);
|
||||||
@@ -430,7 +430,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
// Cannot time already-visible activities.
|
// Cannot time already-visible activities.
|
||||||
notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
|
notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
|
||||||
|
|
||||||
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
|
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(mExpectedStartedId);
|
||||||
verifyNoMoreInteractions(mLaunchObserver);
|
verifyNoMoreInteractions(mLaunchObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,25 +447,14 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
// be reported successfully.
|
// be reported successfully.
|
||||||
notifyTransitionStarting(mTopActivity);
|
notifyTransitionStarting(mTopActivity);
|
||||||
|
|
||||||
|
verifyOnActivityLaunched(mTopActivity);
|
||||||
verifyOnActivityLaunchFinished(mTopActivity);
|
verifyOnActivityLaunchFinished(mTopActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testActivityRecordProtoIsNotTooBig() {
|
|
||||||
// The ActivityRecordProto must not be too big, otherwise converting it at runtime
|
|
||||||
// will become prohibitively expensive.
|
|
||||||
assertWithMessage("mTopActivity: %s", mTopActivity)
|
|
||||||
.that(activityRecordToProto(mTopActivity).length)
|
|
||||||
.isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
|
|
||||||
|
|
||||||
assertWithMessage("mTrampolineActivity: %s", mTrampolineActivity)
|
|
||||||
.that(activityRecordToProto(mTrampolineActivity).length)
|
|
||||||
.isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConcurrentLaunches() {
|
public void testConcurrentLaunches() {
|
||||||
onActivityLaunched(mTopActivity);
|
onActivityLaunched(mTopActivity);
|
||||||
|
clearInvocations(mLaunchObserver);
|
||||||
final ActivityMetricsLogger.LaunchingState previousState = mLaunchingState;
|
final ActivityMetricsLogger.LaunchingState previousState = mLaunchingState;
|
||||||
|
|
||||||
final ActivityRecord otherActivity = new ActivityBuilder(mAtm)
|
final ActivityRecord otherActivity = new ActivityBuilder(mAtm)
|
||||||
@@ -476,11 +465,13 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
// state should be created here.
|
// state should be created here.
|
||||||
onActivityLaunched(otherActivity);
|
onActivityLaunched(otherActivity);
|
||||||
|
|
||||||
assertWithMessage("Different callers should get 2 indepedent launching states")
|
assertWithMessage("Different callers should get 2 independent launching states")
|
||||||
.that(previousState).isNotEqualTo(mLaunchingState);
|
.that(previousState).isNotEqualTo(mLaunchingState);
|
||||||
|
setLastExpectedStartedId(otherActivity);
|
||||||
transitToDrawnAndVerifyOnLaunchFinished(otherActivity);
|
transitToDrawnAndVerifyOnLaunchFinished(otherActivity);
|
||||||
|
|
||||||
// The first transition should still be valid.
|
// The first transition should still be valid.
|
||||||
|
setLastExpectedStartedId(mTopActivity);
|
||||||
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
|
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,10 +525,12 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
// Before TopActivity is drawn, it launches another activity on a different display.
|
// Before TopActivity is drawn, it launches another activity on a different display.
|
||||||
mActivityMetricsLogger.notifyActivityLaunching(activityOnNewDisplay.intent,
|
mActivityMetricsLogger.notifyActivityLaunching(activityOnNewDisplay.intent,
|
||||||
mTopActivity /* caller */, mTopActivity.getUid());
|
mTopActivity /* caller */, mTopActivity.getUid());
|
||||||
notifyActivityLaunched(START_SUCCESS, activityOnNewDisplay);
|
notifyAndVerifyActivityLaunched(activityOnNewDisplay);
|
||||||
|
|
||||||
// There should be 2 events instead of coalescing as one event.
|
// There should be 2 events instead of coalescing as one event.
|
||||||
|
setLastExpectedStartedId(mTopActivity);
|
||||||
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
|
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
|
||||||
|
setLastExpectedStartedId(activityOnNewDisplay);
|
||||||
transitToDrawnAndVerifyOnLaunchFinished(activityOnNewDisplay);
|
transitToDrawnAndVerifyOnLaunchFinished(activityOnNewDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,9 +541,11 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
|||||||
onActivityLaunched(mTrampolineActivity);
|
onActivityLaunched(mTrampolineActivity);
|
||||||
mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent,
|
mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent,
|
||||||
mTrampolineActivity /* caller */, mTrampolineActivity.getUid());
|
mTrampolineActivity /* caller */, mTrampolineActivity.getUid());
|
||||||
notifyActivityLaunched(START_SUCCESS, mTopActivity);
|
notifyAndVerifyActivityLaunched(mTopActivity);
|
||||||
// Different windowing modes should be independent launch events.
|
// Different windowing modes should be independent launch events.
|
||||||
|
setLastExpectedStartedId(mTrampolineActivity);
|
||||||
transitToDrawnAndVerifyOnLaunchFinished(mTrampolineActivity);
|
transitToDrawnAndVerifyOnLaunchFinished(mTrampolineActivity);
|
||||||
|
setLastExpectedStartedId(mTopActivity);
|
||||||
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
|
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user