diff --git a/core/api/system-current.txt b/core/api/system-current.txt index cf20b4c4a12ac..6f7bacf54ceae 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"; @@ -15258,6 +15259,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 { @@ -15845,3 +15848,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 9ed11375c7fe0..50e9f237c5895 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 d0bb4dc4d185c..be18940521d6b 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -72,5 +72,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; }