Raise SurfaceControlFpsListener to System API.

Previously the SurfaceControlFpsListener is a hidden API which only
allows platform code access. This patch renames it to follow the
callback convention and raises it to be a system API in order to allow
system applications to access the FPS count of a task and its children.
The FPS count access is guarded by a permission ACCESS_FPS_COUNTER.

To follow the API convention and properly check the permission, the
register/unregister callback APIs are moved to WindowManager and
permission check is done in the System Server.

Minor: Rename to SurfaceControlFpsCallback to TaskFpsCallback in order
to follow the API naming convention.

Bug: b/199920468
CTS-Coverage-Bug: b/199920468
Test: atest TaskFpsCallbackTest
Change-Id: I6b0a0ad6500278b3da09059e9c2ede28d9a743aa
This commit is contained in:
Peiyong Lin
2021-12-01 23:05:59 +00:00
parent 53aa02dd89
commit 399e06d648
19 changed files with 412 additions and 179 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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) {}
}

View File

@@ -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) {
}
}
}

View 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);
}

View 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 */
}
}
}

View File

@@ -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",

View File

@@ -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),

View File

@@ -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 -->

View File

@@ -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"/>

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -71,5 +71,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>

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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",

View File

@@ -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;
}

View File

@@ -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;
}