summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/ITransitionMetricsReporter.aidl33
-rw-r--r--core/java/android/window/IWindowOrganizerController.aidl4
-rw-r--r--core/java/android/window/TransitionInfo.java4
-rw-r--r--core/java/android/window/TransitionMetrics.java57
-rw-r--r--core/java/android/window/WindowOrganizer.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java6
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java29
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java6
10 files changed, 155 insertions, 3 deletions
diff --git a/core/java/android/window/ITransitionMetricsReporter.aidl b/core/java/android/window/ITransitionMetricsReporter.aidl
new file mode 100644
index 000000000000..00f71dc7bb90
--- /dev/null
+++ b/core/java/android/window/ITransitionMetricsReporter.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package android.window;
+
+import android.os.IBinder;
+
+/**
+ * Implemented by WM Core to know the metrics of transition that runs on a different process.
+ * @hide
+ */
+oneway interface ITransitionMetricsReporter {
+
+ /**
+ * Called when the transition animation starts.
+ *
+ * @param startTime The time when the animation started.
+ */
+ void reportAnimationStart(IBinder transitionToken, long startTime);
+}
diff --git a/core/java/android/window/IWindowOrganizerController.aidl b/core/java/android/window/IWindowOrganizerController.aidl
index e65fcdd7b13b..3c7cd0254e78 100644
--- a/core/java/android/window/IWindowOrganizerController.aidl
+++ b/core/java/android/window/IWindowOrganizerController.aidl
@@ -23,6 +23,7 @@ import android.view.RemoteAnimationAdapter;
import android.window.IDisplayAreaOrganizerController;
import android.window.ITaskFragmentOrganizerController;
import android.window.ITaskOrganizerController;
+import android.window.ITransitionMetricsReporter;
import android.window.ITransitionPlayer;
import android.window.IWindowContainerTransactionCallback;
import android.window.WindowContainerToken;
@@ -98,4 +99,7 @@ interface IWindowOrganizerController {
* this will replace the existing one if set.
*/
void registerTransitionPlayer(in ITransitionPlayer player);
+
+ /** @return An interface enabling the transition players to report its metrics. */
+ ITransitionMetricsReporter getTransitionMetricsReporter();
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index c2ffc03b6119..7208930c0b20 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -140,7 +140,7 @@ public final class TransitionInfo implements Parcelable {
private TransitionInfo(Parcel in) {
mType = in.readInt();
mFlags = in.readInt();
- in.readList(mChanges, null /* classLoader */);
+ in.readTypedList(mChanges, Change.CREATOR);
mRootLeash = new SurfaceControl();
mRootLeash.readFromParcel(in);
mRootOffset.readFromParcel(in);
@@ -152,7 +152,7 @@ public final class TransitionInfo implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeInt(mFlags);
- dest.writeList(mChanges);
+ dest.writeTypedList(mChanges);
mRootLeash.writeToParcel(dest, flags);
mRootOffset.writeToParcel(dest, flags);
dest.writeTypedObject(mOptions, flags);
diff --git a/core/java/android/window/TransitionMetrics.java b/core/java/android/window/TransitionMetrics.java
new file mode 100644
index 000000000000..9a93c1a1ffd6
--- /dev/null
+++ b/core/java/android/window/TransitionMetrics.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package android.window;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Singleton;
+
+/**
+ * A helper class for who plays transition animation can report its metrics easily.
+ * @hide
+ */
+public class TransitionMetrics {
+
+ private final ITransitionMetricsReporter mTransitionMetricsReporter;
+
+ private TransitionMetrics(ITransitionMetricsReporter reporter) {
+ mTransitionMetricsReporter = reporter;
+ }
+
+ /** Reports the current timestamp as when the transition animation starts. */
+ public void reportAnimationStart(IBinder transitionToken) {
+ try {
+ mTransitionMetricsReporter.reportAnimationStart(transitionToken,
+ SystemClock.elapsedRealtime());
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Gets the singleton instance of TransitionMetrics. */
+ public static TransitionMetrics getInstance() {
+ return sTransitionMetrics.get();
+ }
+
+ private static final Singleton<TransitionMetrics> sTransitionMetrics = new Singleton<>() {
+ @Override
+ protected TransitionMetrics create() {
+ return new TransitionMetrics(WindowOrganizer.getTransitionMetricsReporter());
+ }
+ };
+}
diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java
index e9b8174567a8..4ea5ea5694fa 100644
--- a/core/java/android/window/WindowOrganizer.java
+++ b/core/java/android/window/WindowOrganizer.java
@@ -159,7 +159,19 @@ public class WindowOrganizer {
}
}
- IWindowOrganizerController getWindowOrganizerController() {
+ /**
+ * @see TransitionMetrics
+ * @hide
+ */
+ public static ITransitionMetricsReporter getTransitionMetricsReporter() {
+ try {
+ return getWindowOrganizerController().getTransitionMetricsReporter();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ static IWindowOrganizerController getWindowOrganizerController() {
return IWindowOrganizerControllerSingleton.get();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 663d6477c3fe..7abda994bb5e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -70,6 +70,7 @@ import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.window.TransitionInfo;
+import android.window.TransitionMetrics;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -362,6 +363,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
}
}
startTransaction.apply();
+ TransitionMetrics.getInstance().reportAnimationStart(transition);
// run finish now in-case there are no animations
onAnimFinish.run();
return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 27201572d3e8..c36983189a71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -44,6 +44,7 @@ import android.window.ITransitionPlayer;
import android.window.RemoteTransition;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
+import android.window.TransitionMetrics;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
@@ -192,6 +193,8 @@ public class Transitions implements RemoteCallable<Transitions> {
public void register(ShellTaskOrganizer taskOrganizer) {
if (mPlayerImpl == null) return;
taskOrganizer.registerTransitionPlayer(mPlayerImpl);
+ // Pre-load the instance.
+ TransitionMetrics.getInstance();
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2f88a9800f90..0ecee6641509 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -93,6 +93,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
+import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -3230,6 +3231,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
final Transition t = controller.requestTransitionIfNeeded(TRANSIT_CHANGE, this);
if (t != null) {
+ if (getRotation() != getWindowConfiguration().getRotation()) {
+ mWmService.mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
+ controller.mTransitionMetricsReporter.associate(t,
+ startTime -> mWmService.mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN));
+ }
t.setKnownConfigChanges(this, changes);
}
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index b849170d8f3f..bf4cf5f75e36 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -30,10 +30,12 @@ import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.ArrayMap;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.WindowManager;
import android.window.IRemoteTransition;
+import android.window.ITransitionMetricsReporter;
import android.window.ITransitionPlayer;
import android.window.RemoteTransition;
import android.window.TransitionInfo;
@@ -45,6 +47,7 @@ import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.util.ArrayList;
+import java.util.function.LongConsumer;
/**
* Handles all the aspects of recording and synchronizing transitions.
@@ -58,6 +61,8 @@ class TransitionController {
private static final int LEGACY_STATE_RUNNING = 2;
private ITransitionPlayer mTransitionPlayer;
+ final TransitionMetricsReporter mTransitionMetricsReporter = new TransitionMetricsReporter();
+
final ActivityTaskManagerService mAtm;
final TaskSnapshotController mTaskSnapshotController;
@@ -324,6 +329,8 @@ class TransitionController {
/** @see Transition#finishTransition */
void finishTransition(@NonNull IBinder token) {
+ // It is usually a no-op but make sure that the metric consumer is removed.
+ mTransitionMetricsReporter.reportAnimationStart(token, 0 /* startTime */);
final Transition record = Transition.fromBinder(token);
if (record == null || !mPlayingTransitions.contains(record)) {
Slog.e(TAG, "Trying to finish a non-playing transition " + token);
@@ -420,6 +427,28 @@ class TransitionController {
proto.end(token);
}
+ static class TransitionMetricsReporter extends ITransitionMetricsReporter.Stub {
+ private final ArrayMap<IBinder, LongConsumer> mMetricConsumers = new ArrayMap<>();
+
+ void associate(IBinder transitionToken, LongConsumer consumer) {
+ synchronized (mMetricConsumers) {
+ mMetricConsumers.put(transitionToken, consumer);
+ }
+ }
+
+ @Override
+ public void reportAnimationStart(IBinder transitionToken, long startTime) {
+ final LongConsumer c;
+ synchronized (mMetricConsumers) {
+ if (mMetricConsumers.isEmpty()) return;
+ c = mMetricConsumers.remove(transitionToken);
+ }
+ if (c != null) {
+ c.accept(startTime);
+ }
+ }
+ }
+
class Lock {
private int mTransitionWaiters = 0;
void runWhenIdle(long timeout, Runnable r) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 6288ab5de888..6e706e9df003 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -66,6 +66,7 @@ import android.window.IDisplayAreaOrganizerController;
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
import android.window.ITaskOrganizerController;
+import android.window.ITransitionMetricsReporter;
import android.window.ITransitionPlayer;
import android.window.IWindowContainerTransactionCallback;
import android.window.IWindowOrganizerController;
@@ -1040,6 +1041,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
+ @Override
+ public ITransitionMetricsReporter getTransitionMetricsReporter() {
+ return mTransitionController.mTransitionMetricsReporter;
+ }
+
/** Whether the configuration changes are important to report back to an organizer. */
static boolean configurationsAreEqualForOrganizer(
Configuration newConfig, @Nullable Configuration oldConfig) {