Merge "Raise SurfaceControlFpsListener to System API."
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
30
core/java/android/window/IOnFpsCallbackListener.aidl
Normal file
30
core/java/android/window/IOnFpsCallbackListener.aidl
Normal file
@@ -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);
|
||||
}
|
||||
86
core/java/android/window/TaskFpsCallback.java
Normal file
86
core/java/android/window/TaskFpsCallback.java
Normal file
@@ -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 */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -6048,6 +6048,11 @@
|
||||
<permission android:name="android.permission.MANAGE_GAME_MODE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @SystemApi Allows accessing the frame rate per second of a given application
|
||||
@hide -->
|
||||
<permission android:name="android.permission.ACCESS_FPS_COUNTER"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- @SystemApi Allows the holder to register callbacks to inform the RebootReadinessManager
|
||||
when they are performing reboot-blocking work.
|
||||
@hide -->
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
|
||||
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
|
||||
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FPS_COUNTER" />
|
||||
<uses-permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
@@ -64,6 +65,7 @@
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
|
||||
<uses-permission android:name="android.permission.READ_DREAM_STATE" />
|
||||
<uses-permission android:name="android.permission.REAL_GET_TASKS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />
|
||||
<uses-permission android:name="android.permission.READ_LOGS"/>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(1);
|
||||
assertEquals(tasks.size(), 1);
|
||||
mWindowManager.registerTaskFpsCallback(tasks.get(0).taskId, callback);
|
||||
mWindowManager.unregisterTaskFpsCallback(callback);
|
||||
}
|
||||
}
|
||||
@@ -72,5 +72,6 @@
|
||||
<permission name="android.permission.USE_BACKGROUND_BLUR" />
|
||||
<permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
|
||||
<permission name="android.permission.FORCE_STOP_PACKAGES" />
|
||||
<permission name="android.permission.ACCESS_FPS_COUNTER" />
|
||||
</privapp-permissions>
|
||||
</permissions>
|
||||
|
||||
@@ -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<IOnFpsCallbackListener, Long> mTaskFpsCallbackListeners;
|
||||
private final HashMap<IOnFpsCallbackListener, IBinder.DeathRecipient> 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 <android/gui/BnFpsListener.h>
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
@@ -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<jfloat>(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<jlong>(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<SurfaceControlFpsListener*>(ptr);
|
||||
listener->decStrong((void*)nativeCreate);
|
||||
}
|
||||
|
||||
void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jint taskId) {
|
||||
sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(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<jlong>(callback);
|
||||
}
|
||||
|
||||
void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
|
||||
sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
|
||||
sp<TaskFpsCallback> callback = reinterpret_cast<TaskFpsCallback*>(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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user