diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index dea3ed55401fe..2e329728a02cb 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -8,6 +8,7 @@ package android {
field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB";
field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
field @Deprecated public static final String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO";
+ field public static final String ACCESS_FPS_COUNTER = "android.permission.ACCESS_FPS_COUNTER";
field public static final String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS";
field public static final String ACCESS_LOCUS_ID_USAGE_STATS = "android.permission.ACCESS_LOCUS_ID_USAGE_STATS";
field public static final String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
@@ -15206,6 +15207,8 @@ package android.view {
public interface WindowManager extends android.view.ViewManager {
method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public android.graphics.Region getCurrentImeTouchRegion();
+ method public default void registerTaskFpsCallback(@IntRange(from=0) int, @NonNull android.window.TaskFpsCallback);
+ method public default void unregisterTaskFpsCallback(@NonNull android.window.TaskFpsCallback);
}
public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
@@ -15793,3 +15796,15 @@ package android.webkit {
}
+package android.window {
+
+ public final class TaskFpsCallback {
+ ctor public TaskFpsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.window.TaskFpsCallback.OnFpsCallbackListener);
+ }
+
+ public static interface TaskFpsCallback.OnFpsCallbackListener {
+ method public void onFpsReported(float);
+ }
+
+}
+
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 2c766bd6fd0df..4d24965a419e6 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -66,6 +66,7 @@ import android.view.WindowManager;
import android.view.SurfaceControl;
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
+import android.window.IOnFpsCallbackListener;
/**
* System private interface to the window manager.
@@ -922,4 +923,28 @@ interface IWindowManager
* reverts to using the default task transition with no spec changes.
*/
void clearTaskTransitionSpec();
+
+ /**
+ * Registers the frame rate per second count callback for one given task ID.
+ * Each callback can only register for receiving FPS callback for one task id until unregister
+ * is called. If there's no task associated with the given task id,
+ * {@link IllegalArgumentException} will be thrown. If a task id destroyed after a callback is
+ * registered, the registered callback will not be unregistered until
+ * {@link unregisterTaskFpsCallback()} is called
+ * @param taskId task id of the task.
+ * @param listener listener to be registered.
+ *
+ * @hide
+ */
+ void registerTaskFpsCallback(in int taskId, in IOnFpsCallbackListener listener);
+
+ /**
+ * Unregisters the frame rate per second count callback which was registered with
+ * {@link #registerTaskFpsCallback(int,TaskFpsCallback)}.
+ *
+ * @param listener listener to be unregistered.
+ *
+ * @hide
+ */
+ void unregisterTaskFpsCallback(in IOnFpsCallbackListener listener);
}
diff --git a/core/java/android/view/SurfaceControlFpsListener.java b/core/java/android/view/SurfaceControlFpsListener.java
deleted file mode 100644
index 20a511a090b53..0000000000000
--- a/core/java/android/view/SurfaceControlFpsListener.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 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.view;
-
-import android.annotation.NonNull;
-
-/**
- * Listener for sampling the frames per second for a SurfaceControl and its children.
- * This should only be used by a system component that needs to listen to a SurfaceControl's
- * tree's FPS when it is not actively submitting transactions for that SurfaceControl.
- * Otherwise, ASurfaceTransaction_OnComplete callbacks should be used.
- *
- * @hide
- */
-public abstract class SurfaceControlFpsListener {
- private long mNativeListener;
-
- public SurfaceControlFpsListener() {
- mNativeListener = nativeCreate(this);
- }
-
- protected void destroy() {
- if (mNativeListener == 0) {
- return;
- }
- unregister();
- nativeDestroy(mNativeListener);
- mNativeListener = 0;
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- destroy();
- } finally {
- super.finalize();
- }
- }
-
- /**
- * Reports the fps from the registered SurfaceControl
- */
- public abstract void onFpsReported(float fps);
-
- /**
- * Registers the sampling listener for a particular task ID
- */
- public void register(int taskId) {
- if (mNativeListener == 0) {
- return;
- }
-
- nativeRegister(mNativeListener, taskId);
- }
-
- /**
- * Unregisters the sampling listener.
- */
- public void unregister() {
- if (mNativeListener == 0) {
- return;
- }
- nativeUnregister(mNativeListener);
- }
-
- /**
- * Dispatch the collected sample.
- *
- * Called from native code on a binder thread.
- */
- private static void dispatchOnFpsReported(
- @NonNull SurfaceControlFpsListener listener, float fps) {
- listener.onFpsReported(fps);
- }
-
- private static native long nativeCreate(SurfaceControlFpsListener thiz);
- private static native void nativeDestroy(long ptr);
- private static native void nativeRegister(long ptr, int taskId);
- private static native void nativeUnregister(long ptr);
-}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 5be3a57e8527b..ca7f90080c6c2 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -118,6 +118,7 @@ import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.window.TaskFpsCallback;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -4858,4 +4859,31 @@ public interface WindowManager extends ViewManager {
default boolean isTaskSnapshotSupported() {
return false;
}
+
+ /**
+ * Registers the frame rate per second count callback for one given task ID.
+ * Each callback can only register for receiving FPS callback for one task id until unregister
+ * is called. If there's no task associated with the given task id,
+ * {@link IllegalArgumentException} will be thrown. If a task id destroyed after a callback is
+ * registered, the registered callback will not be unregistered until
+ * {@link #unregisterTaskFpsCallback(TaskFpsCallback))} is called
+ * @param taskId task id of the task.
+ * @param callback callback to be registered.
+ *
+ * @hide
+ */
+ @SystemApi
+ default void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
+ @NonNull TaskFpsCallback callback) {}
+
+ /**
+ * Unregisters the frame rate per second count callback which was registered with
+ * {@link #registerTaskFpsCallback(int,TaskFpsCallback)}.
+ *
+ * @param callback callback to be unregistered.
+ *
+ * @hide
+ */
+ @SystemApi
+ default void unregisterTaskFpsCallback(@NonNull TaskFpsCallback callback) {}
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index dd8041684c785..c16703ef50ef9 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.window.WindowProviderService.isWindowProviderService;
import android.annotation.CallbackExecutor;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
@@ -37,6 +38,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.window.TaskFpsCallback;
import android.window.WindowContext;
import android.window.WindowProvider;
@@ -419,4 +421,22 @@ public final class WindowManagerImpl implements WindowManager {
}
return false;
}
+
+ @Override
+ public void registerTaskFpsCallback(@IntRange(from = 0) int taskId, TaskFpsCallback callback) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerTaskFpsCallback(
+ taskId, callback.getListener());
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void unregisterTaskFpsCallback(TaskFpsCallback callback) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().unregisterTaskFpsCallback(
+ callback.getListener());
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/core/java/android/window/IOnFpsCallbackListener.aidl
new file mode 100644
index 0000000000000..3091df3b23a32
--- /dev/null
+++ b/core/java/android/window/IOnFpsCallbackListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 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;
+
+/**
+ * @hide
+ */
+oneway interface IOnFpsCallbackListener {
+
+ /**
+ * Reports the fps from the registered task
+ * @param fps The frame rate per second of the task that has the registered task id
+ * and its children.
+ */
+ void onFpsReported(in float fps);
+}
diff --git a/core/java/android/window/TaskFpsCallback.java b/core/java/android/window/TaskFpsCallback.java
new file mode 100644
index 0000000000000..a8e01b6df4b84
--- /dev/null
+++ b/core/java/android/window/TaskFpsCallback.java
@@ -0,0 +1,86 @@
+/*
+ * 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.annotation.BinderThread;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Callback for sampling the frames per second for a task and its children.
+ * This should only be used by a system component that needs to listen to a task's
+ * tree's FPS when it is not actively submitting transactions for that corresponding SurfaceControl.
+ * Otherwise, ASurfaceTransaction_OnComplete callbacks should be used.
+ *
+ * Each callback can only register for receiving FPS report for one task id until
+ * {@link WindowManager#unregister()} is called.
+ *
+ * @hide
+ */
+@SystemApi
+public final class TaskFpsCallback {
+
+ /**
+ * Listener interface to receive frame per second of a task.
+ */
+ public interface OnFpsCallbackListener {
+ /**
+ * Reports the fps from the registered task
+ * @param fps The frame per second of the task that has the registered task id
+ * and its children.
+ */
+ void onFpsReported(float fps);
+ }
+
+ private final IOnFpsCallbackListener mListener;
+
+ public TaskFpsCallback(@NonNull Executor executor, @NonNull OnFpsCallbackListener listener) {
+ mListener = new IOnFpsCallbackListener.Stub() {
+ @Override
+ public void onFpsReported(float fps) {
+ executor.execute(() -> {
+ listener.onFpsReported(fps);
+ });
+ }
+ };
+ }
+
+ /**
+ * @hide
+ */
+ public IOnFpsCallbackListener getListener() {
+ return mListener;
+ }
+
+ /**
+ * Dispatch the collected sample.
+ *
+ * Called from native code on a binder thread.
+ */
+ @BinderThread
+ private static void dispatchOnFpsReported(
+ @NonNull IOnFpsCallbackListener listener, float fps) {
+ try {
+ listener.onFpsReported(fps);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index a3ac472bb9008..2b25b8d992434 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -124,7 +124,6 @@ cc_library_shared {
"android_view_PointerIcon.cpp",
"android_view_Surface.cpp",
"android_view_SurfaceControl.cpp",
- "android_view_SurfaceControlFpsListener.cpp",
"android_view_SurfaceControlHdrLayerInfoListener.cpp",
"android_graphics_BLASTBufferQueue.cpp",
"android_view_SurfaceSession.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 21ec64bba9314..f4296becf4843 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -123,7 +123,6 @@ extern int register_android_view_InputApplicationHandle(JNIEnv* env);
extern int register_android_view_InputWindowHandle(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
extern int register_android_view_SurfaceControl(JNIEnv* env);
-extern int register_android_view_SurfaceControlFpsListener(JNIEnv* env);
extern int register_android_view_SurfaceControlHdrLayerInfoListener(JNIEnv* env);
extern int register_android_view_SurfaceSession(JNIEnv* env);
extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
@@ -1546,7 +1545,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_view_InputWindowHandle),
REG_JNI(register_android_view_Surface),
REG_JNI(register_android_view_SurfaceControl),
- REG_JNI(register_android_view_SurfaceControlFpsListener),
REG_JNI(register_android_view_SurfaceControlHdrLayerInfoListener),
REG_JNI(register_android_view_SurfaceSession),
REG_JNI(register_android_view_CompositionSamplingListener),
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0fd46295c8e80..ea3b4c8ecc1b5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6048,6 +6048,11 @@
+
+
+
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index f2b35c72a5671..a80424e500c44 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -38,6 +38,7 @@
+
@@ -64,6 +65,7 @@
+
diff --git a/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java
deleted file mode 100644
index c15fc3a15112d..0000000000000
--- a/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 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.view;
-
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-@Presubmit
-public class SurfaceControlFpsListenerTest {
-
- @Test
- public void registersAndUnregisters() {
-
- SurfaceControlFpsListener listener = new SurfaceControlFpsListener() {
- @Override
- public void onFpsReported(float fps) {
- // Ignore
- }
- };
-
- listener.register(0);
-
- listener.unregister();
- }
-}
diff --git a/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java b/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
new file mode 100644
index 0000000000000..bf508db56852e
--- /dev/null
+++ b/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class TaskFpsCallbackTest {
+
+ private Context mContext;
+ private WindowManager mWindowManager;
+ private ActivityTaskManager mActivityTaskManager;
+
+ @Before
+ public void setup() {
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
+ mWindowManager = mContext.getSystemService(WindowManager.class);
+ }
+
+ @Test
+ public void testRegisterAndUnregister() {
+
+ final TaskFpsCallback.OnFpsCallbackListener listener = fps -> {
+ // Ignore
+ };
+ final TaskFpsCallback callback = new TaskFpsCallback(Runnable::run, listener);
+
+ final List tasks = mActivityTaskManager.getTasks(1);
+ assertEquals(tasks.size(), 1);
+ mWindowManager.registerTaskFpsCallback(tasks.get(0).taskId, callback);
+ mWindowManager.unregisterTaskFpsCallback(callback);
+ }
+}
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index f2a33de008d68..dbc7fdd30f7c7 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -71,5 +71,6 @@
+
diff --git a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
new file mode 100644
index 0000000000000..d9dc9aa9e5e2b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 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 com.android.server.wm;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.window.IOnFpsCallbackListener;
+
+import java.util.HashMap;
+
+final class TaskFpsCallbackController {
+
+ private final Context mContext;
+ private final HashMap mTaskFpsCallbackListeners;
+ private final HashMap mDeathRecipients;
+
+ TaskFpsCallbackController(Context context) {
+ mContext = context;
+ mTaskFpsCallbackListeners = new HashMap<>();
+ mDeathRecipients = new HashMap<>();
+ }
+
+ void registerCallback(int taskId, IOnFpsCallbackListener listener) {
+ if (mTaskFpsCallbackListeners.containsKey(listener)) {
+ return;
+ }
+
+ final long nativeListener = nativeRegister(listener, taskId);
+ mTaskFpsCallbackListeners.put(listener, nativeListener);
+
+ final IBinder.DeathRecipient deathRecipient = () -> unregisterCallback(listener);
+ try {
+ listener.asBinder().linkToDeath(deathRecipient, 0);
+ mDeathRecipients.put(listener, deathRecipient);
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+
+ void unregisterCallback(IOnFpsCallbackListener listener) {
+ if (!mTaskFpsCallbackListeners.containsKey(listener)) {
+ return;
+ }
+
+ listener.asBinder().unlinkToDeath(mDeathRecipients.get(listener), 0);
+ mDeathRecipients.remove(listener);
+
+ nativeUnregister(mTaskFpsCallbackListeners.get(listener));
+ mTaskFpsCallbackListeners.remove(listener);
+ }
+
+ private static native long nativeRegister(IOnFpsCallbackListener listener, int taskId);
+ private static native void nativeUnregister(long ptr);
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2f0ef4a8ee1b4..cc3f2fcb84266 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -143,6 +143,7 @@ import android.Manifest;
import android.Manifest.permission;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -282,6 +283,7 @@ import android.view.WindowManagerPolicyConstants.PointerEventListener;
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
import android.window.ClientWindowFrames;
+import android.window.IOnFpsCallbackListener;
import android.window.TaskSnapshot;
import com.android.internal.R;
@@ -708,6 +710,7 @@ public class WindowManagerService extends IWindowManager.Stub
final TaskSnapshotController mTaskSnapshotController;
final BlurController mBlurController;
+ final TaskFpsCallbackController mTaskFpsCallbackController;
boolean mIsTouchDevice;
boolean mIsFakeTouchDevice;
@@ -1354,6 +1357,7 @@ public class WindowManagerService extends IWindowManager.Stub
mStartingSurfaceController = new StartingSurfaceController(this);
mBlurController = new BlurController(mContext, mPowerManager);
+ mTaskFpsCallbackController = new TaskFpsCallbackController(mContext);
mAccessibilityController = new AccessibilityController(this);
}
@@ -8772,4 +8776,34 @@ public class WindowManagerService extends IWindowManager.Stub
mTaskTransitionSpec = null;
}
+ @Override
+ @RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
+ public void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
+ IOnFpsCallbackListener listener) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FPS_COUNTER)
+ != PackageManager.PERMISSION_GRANTED) {
+ final int pid = Binder.getCallingPid();
+ throw new SecurityException("Access denied to process: " + pid
+ + ", must have permission " + Manifest.permission.ACCESS_FPS_COUNTER);
+ }
+
+ if (mRoot.anyTaskForId(taskId) == null) {
+ throw new IllegalArgumentException("no task with taskId: " + taskId);
+ }
+
+ mTaskFpsCallbackController.registerCallback(taskId, listener);
+ }
+
+ @Override
+ @RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
+ public void unregisterTaskFpsCallback(IOnFpsCallbackListener listener) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FPS_COUNTER)
+ != PackageManager.PERMISSION_GRANTED) {
+ final int pid = Binder.getCallingPid();
+ throw new SecurityException("Access denied to process: " + pid
+ + ", must have permission " + Manifest.permission.ACCESS_FPS_COUNTER);
+ }
+
+ mTaskFpsCallbackController.unregisterCallback(listener);
+ }
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index b6438832399a3..79a980f0d9ee4 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -68,6 +68,7 @@ cc_library_static {
"com_android_server_am_LowMemDetector.cpp",
"com_android_server_pm_PackageManagerShellCommandDataLoader.cpp",
"com_android_server_sensor_SensorService.cpp",
+ "com_android_server_wm_TaskFpsCallbackController.cpp",
"onload.cpp",
":lib_cachedAppOptimizer_native",
":lib_networkStatsFactory_native",
diff --git a/core/jni/android_view_SurfaceControlFpsListener.cpp b/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
similarity index 54%
rename from core/jni/android_view_SurfaceControlFpsListener.cpp
rename to services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
index 0b15acd776893..0202306fc3951 100644
--- a/core/jni/android_view_SurfaceControlFpsListener.cpp
+++ b/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2022 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceControlFpsListener"
+#define LOG_TAG "TaskFpsCallbackController"
#include
#include
@@ -35,11 +35,10 @@ namespace {
struct {
jclass mClass;
jmethodID mDispatchOnFpsReported;
-} gListenerClassInfo;
+} gCallbackClassInfo;
-struct SurfaceControlFpsListener : public gui::BnFpsListener {
- SurfaceControlFpsListener(JNIEnv* env, jobject listener)
- : mListener(env->NewWeakGlobalRef(listener)) {}
+struct TaskFpsCallback : public gui::BnFpsListener {
+ TaskFpsCallback(JNIEnv* env, jobject listener) : mListener(env->NewWeakGlobalRef(listener)) {}
binder::Status onFpsReported(float fps) override {
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -50,13 +49,13 @@ struct SurfaceControlFpsListener : public gui::BnFpsListener {
// Weak reference went out of scope
return binder::Status::ok();
}
- env->CallStaticVoidMethod(gListenerClassInfo.mClass,
- gListenerClassInfo.mDispatchOnFpsReported, listener,
+ env->CallStaticVoidMethod(gCallbackClassInfo.mClass,
+ gCallbackClassInfo.mDispatchOnFpsReported, listener,
static_cast(fps));
env->DeleteGlobalRef(listener);
if (env->ExceptionCheck()) {
- ALOGE("SurfaceControlFpsListener.onFpsReported() failed.");
+ ALOGE("TaskFpsCallback.onFpsReported() failed.");
LOGE_EX(env);
env->ExceptionClear();
}
@@ -64,7 +63,7 @@ struct SurfaceControlFpsListener : public gui::BnFpsListener {
}
protected:
- virtual ~SurfaceControlFpsListener() {
+ virtual ~TaskFpsCallback() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteWeakGlobalRef(mListener);
}
@@ -73,55 +72,48 @@ private:
jweak mListener;
};
-jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
- SurfaceControlFpsListener* listener = new SurfaceControlFpsListener(env, obj);
- listener->incStrong((void*)nativeCreate);
- return reinterpret_cast(listener);
-}
+jlong nativeRegister(JNIEnv* env, jclass clazz, jobject obj, jint taskId) {
+ TaskFpsCallback* callback = new TaskFpsCallback(env, obj);
-void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
- SurfaceControlFpsListener* listener = reinterpret_cast(ptr);
- listener->decStrong((void*)nativeCreate);
-}
-
-void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jint taskId) {
- sp listener = reinterpret_cast(ptr);
- if (SurfaceComposerClient::addFpsListener(taskId, listener) != OK) {
+ if (SurfaceComposerClient::addFpsListener(taskId, callback) != OK) {
constexpr auto error_msg = "Couldn't addFpsListener";
ALOGE(error_msg);
jniThrowRuntimeException(env, error_msg);
}
+ callback->incStrong((void*)nativeRegister);
+
+ return reinterpret_cast(callback);
}
void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
- sp listener = reinterpret_cast(ptr);
+ sp callback = reinterpret_cast(ptr);
- if (SurfaceComposerClient::removeFpsListener(listener) != OK) {
+ if (SurfaceComposerClient::removeFpsListener(callback) != OK) {
constexpr auto error_msg = "Couldn't removeFpsListener";
ALOGE(error_msg);
jniThrowRuntimeException(env, error_msg);
}
+
+ callback->decStrong((void*)nativeRegister);
}
-const JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- {"nativeCreate", "(Landroid/view/SurfaceControlFpsListener;)J", (void*)nativeCreate},
- {"nativeDestroy", "(J)V", (void*)nativeDestroy},
- {"nativeRegister", "(JI)V", (void*)nativeRegister},
+ {"nativeRegister", "(Landroid/window/IOnFpsCallbackListener;I)J", (void*)nativeRegister},
{"nativeUnregister", "(J)V", (void*)nativeUnregister}};
} // namespace
-int register_android_view_SurfaceControlFpsListener(JNIEnv* env) {
- int res = jniRegisterNativeMethods(env, "android/view/SurfaceControlFpsListener", gMethods,
- NELEM(gMethods));
+int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/wm/TaskFpsCallbackController",
+ gMethods, NELEM(gMethods));
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
- jclass clazz = env->FindClass("android/view/SurfaceControlFpsListener");
- gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
- gListenerClassInfo.mDispatchOnFpsReported =
+ jclass clazz = env->FindClass("android/window/TaskFpsCallback");
+ gCallbackClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
+ gCallbackClassInfo.mDispatchOnFpsReported =
env->GetStaticMethodID(clazz, "dispatchOnFpsReported",
- "(Landroid/view/SurfaceControlFpsListener;F)V");
+ "(Landroid/window/IOnFpsCallbackListener;F)V");
return 0;
}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 80d7055735c3d..ba5b3f54efa1a 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -65,6 +65,7 @@ int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env);
int register_android_server_companion_virtual_InputController(JNIEnv* env);
int register_android_server_app_GameManagerService(JNIEnv* env);
+int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
};
using namespace android;
@@ -123,5 +124,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_sensor_SensorService(vm, env);
register_android_server_companion_virtual_InputController(env);
register_android_server_app_GameManagerService(env);
+ register_com_android_server_wm_TaskFpsCallbackController(env);
return JNI_VERSION_1_4;
}