Merge "Handle launch time while device is sleeping" into sc-dev
This commit is contained in:
@@ -127,6 +127,12 @@ class ActivityMetricsLogger {
|
||||
private static final int WINDOW_STATE_MULTI_WINDOW = 4;
|
||||
private static final int WINDOW_STATE_INVALID = -1;
|
||||
|
||||
/**
|
||||
* If a launching activity isn't visible within this duration when the device is sleeping, e.g.
|
||||
* keyguard is locked, its transition info will be dropped.
|
||||
*/
|
||||
private static final long UNKNOWN_VISIBILITY_CHECK_DELAY_MS = 3000;
|
||||
|
||||
/**
|
||||
* The flag for {@link #notifyActivityLaunching} to skip associating a new launch with an active
|
||||
* transition, in the case the launch is standalone (e.g. from recents).
|
||||
@@ -300,8 +306,7 @@ class ActivityMetricsLogger {
|
||||
}
|
||||
|
||||
/** @return {@code true} if the activity matches a launched activity in this transition. */
|
||||
boolean contains(WindowContainer wc) {
|
||||
final ActivityRecord r = AppTransitionController.getAppFromContainer(wc);
|
||||
boolean contains(ActivityRecord r) {
|
||||
return r != null && (r == mLastLaunchedActivity || mPendingDrawActivities.contains(r));
|
||||
}
|
||||
|
||||
@@ -473,10 +478,10 @@ class ActivityMetricsLogger {
|
||||
|
||||
/** @return Non-null {@link TransitionInfo} if the activity is found in an active transition. */
|
||||
@Nullable
|
||||
private TransitionInfo getActiveTransitionInfo(WindowContainer wc) {
|
||||
private TransitionInfo getActiveTransitionInfo(ActivityRecord r) {
|
||||
for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
|
||||
final TransitionInfo info = mTransitionInfoList.get(i);
|
||||
if (info.contains(wc)) {
|
||||
if (info.contains(r)) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -587,8 +592,8 @@ class ActivityMetricsLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
if (info != null
|
||||
&& info.mLastLaunchedActivity.mDisplayContent == launchedActivity.mDisplayContent) {
|
||||
final DisplayContent targetDisplay = launchedActivity.mDisplayContent;
|
||||
if (info != null && info.mLastLaunchedActivity.mDisplayContent == targetDisplay) {
|
||||
// If we are already in an existing transition on the same display, only update the
|
||||
// activity name, but not the other attributes.
|
||||
|
||||
@@ -616,6 +621,13 @@ class ActivityMetricsLogger {
|
||||
// As abort for no process switch.
|
||||
launchObserverNotifyIntentFailed();
|
||||
}
|
||||
if (targetDisplay.isSleeping()) {
|
||||
// It is unknown whether the activity can be drawn or not, e.g. ut depends on the
|
||||
// keyguard states and the attributes or flags set by the activity. If the activity
|
||||
// keeps invisible in the grace period, the tracker will be cancelled so it won't get
|
||||
// a very long launch time that takes unlocking as the end of launch.
|
||||
scheduleCheckActivityToBeDrawn(launchedActivity, UNKNOWN_VISIBILITY_CHECK_DELAY_MS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -667,12 +679,15 @@ class ActivityMetricsLogger {
|
||||
* ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
|
||||
*/
|
||||
void notifyTransitionStarting(ArrayMap<WindowContainer, Integer> activityToReason) {
|
||||
if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
|
||||
if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting " + activityToReason);
|
||||
|
||||
final long timestampNs = SystemClock.elapsedRealtimeNanos();
|
||||
for (int index = activityToReason.size() - 1; index >= 0; index--) {
|
||||
final WindowContainer wc = activityToReason.keyAt(index);
|
||||
final TransitionInfo info = getActiveTransitionInfo(wc);
|
||||
final WindowContainer<?> wc = activityToReason.keyAt(index);
|
||||
final ActivityRecord activity = wc.asActivityRecord();
|
||||
final ActivityRecord r = activity != null ? activity
|
||||
: wc.getTopActivity(false /* includeFinishing */, true /* includeOverlays */);
|
||||
final TransitionInfo info = getActiveTransitionInfo(r);
|
||||
if (info == null || info.mLoggedTransitionStarting) {
|
||||
// Ignore any subsequent notifyTransitionStarting.
|
||||
continue;
|
||||
@@ -717,26 +732,32 @@ class ActivityMetricsLogger {
|
||||
Slog.i(TAG, "notifyVisibilityChanged " + r + " visible=" + r.mVisibleRequested
|
||||
+ " state=" + r.getState() + " finishing=" + r.finishing);
|
||||
}
|
||||
if (!r.mVisibleRequested || r.finishing) {
|
||||
info.removePendingDrawActivity(r);
|
||||
}
|
||||
if (info.mLastLaunchedActivity != r) {
|
||||
if (r.isState(Task.ActivityState.RESUMED) && r.mDisplayContent.isSleeping()) {
|
||||
// The activity may be launching while keyguard is locked. The keyguard may be dismissed
|
||||
// after the activity finished relayout, so skip the visibility check to avoid aborting
|
||||
// the tracking of launch event.
|
||||
return;
|
||||
}
|
||||
// The activity and its task are passed separately because the activity may be removed from
|
||||
// the task later.
|
||||
r.mAtmService.mH.sendMessage(PooledLambda.obtainMessage(
|
||||
ActivityMetricsLogger::checkVisibility, this, r.getTask(), r));
|
||||
if (!r.mVisibleRequested || r.finishing) {
|
||||
info.removePendingDrawActivity(r);
|
||||
if (info.mLastLaunchedActivity == r) {
|
||||
// Check if the tracker can be cancelled because the last launched activity may be
|
||||
// no longer visible.
|
||||
scheduleCheckActivityToBeDrawn(r, 0 /* delay */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return {@code true} if the given task has an activity will be drawn. */
|
||||
private static boolean hasActivityToBeDrawn(Task t) {
|
||||
return t.forAllActivities(r -> r.mVisibleRequested && !r.isReportedDrawn() && !r.finishing);
|
||||
private void scheduleCheckActivityToBeDrawn(@NonNull ActivityRecord r, long delay) {
|
||||
// The activity and its task are passed separately because it is possible that the activity
|
||||
// is removed from the task later.
|
||||
r.mAtmService.mH.sendMessageDelayed(PooledLambda.obtainMessage(
|
||||
ActivityMetricsLogger::checkActivityToBeDrawn, this, r.getTask(), r), delay);
|
||||
}
|
||||
|
||||
private void checkVisibility(Task t, ActivityRecord r) {
|
||||
/** Cancels the tracking of launch if there won't be an activity to be drawn. */
|
||||
private void checkActivityToBeDrawn(Task t, ActivityRecord r) {
|
||||
synchronized (mSupervisor.mService.mGlobalLock) {
|
||||
|
||||
final TransitionInfo info = getActiveTransitionInfo(r);
|
||||
|
||||
// If we have an active transition that's waiting on a certain activity that will be
|
||||
@@ -757,13 +778,14 @@ class ActivityMetricsLogger {
|
||||
// window drawn event should report later to complete the transition. Otherwise all
|
||||
// activities in this task may be finished, invisible or drawn, so the transition event
|
||||
// should be cancelled.
|
||||
if (hasActivityToBeDrawn(t)) {
|
||||
if (t.forAllActivities(
|
||||
a -> a.mVisibleRequested && !a.isReportedDrawn() && !a.finishing)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible activity=" + r);
|
||||
if (DEBUG_METRICS) Slog.i(TAG, "checkActivityToBeDrawn cancels activity=" + r);
|
||||
logAppTransitionCancel(info);
|
||||
abort(info, "notifyVisibilityChanged to invisible");
|
||||
abort(info, "checkActivityToBeDrawn (invisible or drawn already)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
|
||||
import android.app.ActivityOptions;
|
||||
@@ -250,6 +251,19 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
|
||||
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnActivityLaunchWhileSleeping() {
|
||||
notifyActivityLaunching(mTopActivity.intent);
|
||||
notifyActivityLaunched(START_SUCCESS, mTopActivity);
|
||||
doReturn(true).when(mTopActivity.mDisplayContent).isSleeping();
|
||||
mTopActivity.setState(Task.ActivityState.RESUMED, "test");
|
||||
mTopActivity.setVisibility(false);
|
||||
waitHandlerIdle(mAtm.mH);
|
||||
// Not cancel immediately because in one of real cases, the keyguard may be going away or
|
||||
// occluded later, then the activity can be drawn.
|
||||
verify(mLaunchObserver, never()).onActivityLaunchCancelled(eqProto(mTopActivity));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnReportFullyDrawn() {
|
||||
mActivityOptions = ActivityOptions.makeBasic();
|
||||
|
||||
Reference in New Issue
Block a user