Loading core/java/android/view/SurfaceControl.java +91 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static android.view.SurfaceControlProto.HASH_CODE; import static android.view.SurfaceControlProto.NAME; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -54,12 +55,15 @@ import android.util.proto.ProtoOutputStream; import android.view.Surface.OutOfResourcesException; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.VirtualRefBasePtr; import dalvik.system.CloseGuard; import libcore.util.NativeAllocationRegistry; import java.io.Closeable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteOrder; Loading Loading @@ -224,6 +228,10 @@ public final class SurfaceControl implements Parcelable { IBinder focusedToken, int displayId); private static native void nativeSetFrameTimelineVsync(long transactionObj, long frameTimelineVsyncId); private static native void nativeAddJankDataListener(long nativeListener, long nativeSurfaceControl); private static native void nativeRemoveJankDataListener(long nativeListener); private static native long nativeCreateJankDataListenerWrapper(OnJankDataListener listener); @Nullable @GuardedBy("mLock") Loading @@ -249,6 +257,73 @@ public final class SurfaceControl implements Parcelable { void onReparent(@NonNull Transaction transaction, @Nullable SurfaceControl parent); } /** * Jank information to be fed back via {@link OnJankDataListener}. * @hide */ public static class JankData { /** @hide */ @IntDef(flag = true, value = {JANK_NONE, JANK_DISPLAY, JANK_SURFACEFLINGER_DEADLINE_MISSED, JANK_SURFACEFLINGER_GPU_DEADLINE_MISSED, JANK_APP_DEADLINE_MISSED, JANK_PREDICTION_EXPIRED, JANK_SURFACEFLINGER_EARLY_LATCH}) @Retention(RetentionPolicy.SOURCE) public @interface JankType {} // Needs to be kept in sync with frameworks/native/libs/gui/include/gui/JankInfo.h // No Jank public static final int JANK_NONE = 0x0; // Jank not related to SurfaceFlinger or the App public static final int JANK_DISPLAY = 0x1; // SF took too long on the CPU public static final int JANK_SURFACEFLINGER_DEADLINE_MISSED = 0x2; // SF took too long on the GPU public static final int JANK_SURFACEFLINGER_GPU_DEADLINE_MISSED = 0x4; // Either App or GPU took too long on the frame public static final int JANK_APP_DEADLINE_MISSED = 0x8; // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a // jank // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame. public static final int JANK_PREDICTION_EXPIRED = 0x10; // Latching a buffer early might cause an early present of the frame public static final int JANK_SURFACEFLINGER_EARLY_LATCH = 0x20; public JankData(long frameVsyncId, @JankType int jankType) { this.frameVsyncId = frameVsyncId; this.jankType = jankType; } public final long frameVsyncId; public final @JankType int jankType; } /** * Listener interface to be informed about SurfaceFlinger's jank classification for a specific * surface. * * @see JankData * @see #addJankDataListener * @hide */ public static abstract class OnJankDataListener { private final VirtualRefBasePtr mNativePtr; public OnJankDataListener() { mNativePtr = new VirtualRefBasePtr(nativeCreateJankDataListenerWrapper(this)); } /** * Called when new jank classifications are available. */ public abstract void onJankDataAvailable(JankData[] jankStats); } private final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; Loading Loading @@ -2519,6 +2594,22 @@ public final class SurfaceControl implements Parcelable { nativeSetGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius); } /** * Adds a callback to be informed about SF's jank classification for a specific surface. * @hide */ public static void addJankDataListener(OnJankDataListener listener, SurfaceControl surface) { nativeAddJankDataListener(listener.mNativePtr.get(), surface.mNativeObject); } /** * Removes a jank callback previously added with {@link #addJankDataListener} * @hide */ public static void removeJankDataListener(OnJankDataListener listener) { nativeRemoveJankDataListener(listener.mNativePtr.get()); } /** * An atomic set of changes to a set of SurfaceControl. */ Loading core/jni/android_view_SurfaceControl.cpp +96 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ #include <ui/Rect.h> #include <ui/Region.h> #include <utils/Log.h> #include <utils/LightRefBase.h> // ---------------------------------------------------------------------------- Loading Loading @@ -206,6 +207,16 @@ static struct { jfieldID appRequestRefreshRateMax; } gDesiredDisplayConfigSpecsClassInfo; static struct { jclass clazz; jmethodID onJankDataAvailable; } gJankDataListenerClassInfo; static struct { jclass clazz; jmethodID ctor; } gJankDataClassInfo; class JNamedColorSpace { public: // ColorSpace.Named.SRGB.ordinal() = 0; Loading Loading @@ -1601,6 +1612,73 @@ static void nativeSetFrameTimelineVsync(JNIEnv* env, jclass clazz, jlong transac transaction->setFrameTimelineVsync(frameTimelineVsyncId); } class JankDataListenerWrapper : public JankDataListener { public: JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) { mOnJankDataListenerWeak = env->NewWeakGlobalRef(onJankDataListenerObject); env->GetJavaVM(&mVm); } ~JankDataListenerWrapper() { JNIEnv* env = getEnv(); env->DeleteWeakGlobalRef(mOnJankDataListenerWeak); } void onJankDataAvailable(const std::vector<JankData>& jankData) { JNIEnv* env = getEnv(); jobject target = env->NewLocalRef(mOnJankDataListenerWeak); if (target == nullptr) return; jobjectArray jJankDataArray = env->NewObjectArray(jankData.size(), gJankDataClassInfo.clazz, nullptr); for (int i = 0; i < jankData.size(); i++) { jobject jJankData = env->NewObject(gJankDataClassInfo.clazz, gJankDataClassInfo.ctor, jankData[i].frameVsyncId, jankData[i].jankType); env->SetObjectArrayElement(jJankDataArray, i, jJankData); } env->CallVoidMethod(target, gJankDataListenerClassInfo.onJankDataAvailable, jJankDataArray); env->DeleteLocalRef(target); } private: JNIEnv* getEnv() { JNIEnv* env; mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); return env; } JavaVM* mVm; jobject mOnJankDataListenerWeak; }; static void nativeAddJankDataListener(JNIEnv* env, jclass clazz, jlong jankDataCallbackListenerPtr, jlong nativeSurfaceControl) { sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl *>(nativeSurfaceControl)); if (surface == nullptr) { return; } JankDataListenerWrapper* wrapper = reinterpret_cast<JankDataListenerWrapper*>(jankDataCallbackListenerPtr); TransactionCompletedListener::getInstance()->addJankListener(wrapper, surface); } static void nativeRemoveJankDataListener(JNIEnv* env, jclass clazz, jlong jankDataCallbackListenerPtr) { JankDataListenerWrapper* wrapper = reinterpret_cast<JankDataListenerWrapper*>(jankDataCallbackListenerPtr); TransactionCompletedListener::getInstance()->removeJankListener(wrapper); } static jlong nativeCreateJankDataListenerWrapper(JNIEnv* env, jclass clazz, jobject jankDataListenerObject) { return reinterpret_cast<jlong>(new JankDataListenerWrapper(env, jankDataListenerObject)); } // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { Loading Loading @@ -1785,6 +1863,12 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetFocusedWindow}, {"nativeSetFrameTimelineVsync", "(JJ)V", (void*)nativeSetFrameTimelineVsync }, {"nativeAddJankDataListener", "(JJ)V", (void*)nativeAddJankDataListener }, {"nativeRemoveJankDataListener", "(J)V", (void*)nativeRemoveJankDataListener }, {"nativeCreateJankDataListenerWrapper", "(Landroid/view/SurfaceControl$OnJankDataListener;)J", (void*)nativeCreateJankDataListenerWrapper }, // clang-format on }; Loading Loading @@ -1966,6 +2050,18 @@ int register_android_view_SurfaceControl(JNIEnv* env) gScreenCaptureListenerClassInfo.onScreenCaptureComplete = GetMethodIDOrDie(env, screenCaptureListenerClazz, "onScreenCaptureComplete", "(Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;)V"); jclass jankDataClazz = FindClassOrDie(env, "android/view/SurfaceControl$JankData"); gJankDataClassInfo.clazz = MakeGlobalRefOrDie(env, jankDataClazz); gJankDataClassInfo.ctor = GetMethodIDOrDie(env, gJankDataClassInfo.clazz, "<init>", "(JI)V"); jclass onJankDataListenerClazz = FindClassOrDie(env, "android/view/SurfaceControl$OnJankDataListener"); gJankDataListenerClassInfo.clazz = MakeGlobalRefOrDie(env, onJankDataListenerClazz); gJankDataListenerClassInfo.onJankDataAvailable = GetMethodIDOrDie(env, onJankDataListenerClazz, "onJankDataAvailable", "([Landroid/view/SurfaceControl$JankData;)V"); return err; } Loading Loading
core/java/android/view/SurfaceControl.java +91 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static android.view.SurfaceControlProto.HASH_CODE; import static android.view.SurfaceControlProto.NAME; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -54,12 +55,15 @@ import android.util.proto.ProtoOutputStream; import android.view.Surface.OutOfResourcesException; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.VirtualRefBasePtr; import dalvik.system.CloseGuard; import libcore.util.NativeAllocationRegistry; import java.io.Closeable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteOrder; Loading Loading @@ -224,6 +228,10 @@ public final class SurfaceControl implements Parcelable { IBinder focusedToken, int displayId); private static native void nativeSetFrameTimelineVsync(long transactionObj, long frameTimelineVsyncId); private static native void nativeAddJankDataListener(long nativeListener, long nativeSurfaceControl); private static native void nativeRemoveJankDataListener(long nativeListener); private static native long nativeCreateJankDataListenerWrapper(OnJankDataListener listener); @Nullable @GuardedBy("mLock") Loading @@ -249,6 +257,73 @@ public final class SurfaceControl implements Parcelable { void onReparent(@NonNull Transaction transaction, @Nullable SurfaceControl parent); } /** * Jank information to be fed back via {@link OnJankDataListener}. * @hide */ public static class JankData { /** @hide */ @IntDef(flag = true, value = {JANK_NONE, JANK_DISPLAY, JANK_SURFACEFLINGER_DEADLINE_MISSED, JANK_SURFACEFLINGER_GPU_DEADLINE_MISSED, JANK_APP_DEADLINE_MISSED, JANK_PREDICTION_EXPIRED, JANK_SURFACEFLINGER_EARLY_LATCH}) @Retention(RetentionPolicy.SOURCE) public @interface JankType {} // Needs to be kept in sync with frameworks/native/libs/gui/include/gui/JankInfo.h // No Jank public static final int JANK_NONE = 0x0; // Jank not related to SurfaceFlinger or the App public static final int JANK_DISPLAY = 0x1; // SF took too long on the CPU public static final int JANK_SURFACEFLINGER_DEADLINE_MISSED = 0x2; // SF took too long on the GPU public static final int JANK_SURFACEFLINGER_GPU_DEADLINE_MISSED = 0x4; // Either App or GPU took too long on the frame public static final int JANK_APP_DEADLINE_MISSED = 0x8; // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a // jank // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame. public static final int JANK_PREDICTION_EXPIRED = 0x10; // Latching a buffer early might cause an early present of the frame public static final int JANK_SURFACEFLINGER_EARLY_LATCH = 0x20; public JankData(long frameVsyncId, @JankType int jankType) { this.frameVsyncId = frameVsyncId; this.jankType = jankType; } public final long frameVsyncId; public final @JankType int jankType; } /** * Listener interface to be informed about SurfaceFlinger's jank classification for a specific * surface. * * @see JankData * @see #addJankDataListener * @hide */ public static abstract class OnJankDataListener { private final VirtualRefBasePtr mNativePtr; public OnJankDataListener() { mNativePtr = new VirtualRefBasePtr(nativeCreateJankDataListenerWrapper(this)); } /** * Called when new jank classifications are available. */ public abstract void onJankDataAvailable(JankData[] jankStats); } private final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; Loading Loading @@ -2519,6 +2594,22 @@ public final class SurfaceControl implements Parcelable { nativeSetGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius); } /** * Adds a callback to be informed about SF's jank classification for a specific surface. * @hide */ public static void addJankDataListener(OnJankDataListener listener, SurfaceControl surface) { nativeAddJankDataListener(listener.mNativePtr.get(), surface.mNativeObject); } /** * Removes a jank callback previously added with {@link #addJankDataListener} * @hide */ public static void removeJankDataListener(OnJankDataListener listener) { nativeRemoveJankDataListener(listener.mNativePtr.get()); } /** * An atomic set of changes to a set of SurfaceControl. */ Loading
core/jni/android_view_SurfaceControl.cpp +96 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ #include <ui/Rect.h> #include <ui/Region.h> #include <utils/Log.h> #include <utils/LightRefBase.h> // ---------------------------------------------------------------------------- Loading Loading @@ -206,6 +207,16 @@ static struct { jfieldID appRequestRefreshRateMax; } gDesiredDisplayConfigSpecsClassInfo; static struct { jclass clazz; jmethodID onJankDataAvailable; } gJankDataListenerClassInfo; static struct { jclass clazz; jmethodID ctor; } gJankDataClassInfo; class JNamedColorSpace { public: // ColorSpace.Named.SRGB.ordinal() = 0; Loading Loading @@ -1601,6 +1612,73 @@ static void nativeSetFrameTimelineVsync(JNIEnv* env, jclass clazz, jlong transac transaction->setFrameTimelineVsync(frameTimelineVsyncId); } class JankDataListenerWrapper : public JankDataListener { public: JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) { mOnJankDataListenerWeak = env->NewWeakGlobalRef(onJankDataListenerObject); env->GetJavaVM(&mVm); } ~JankDataListenerWrapper() { JNIEnv* env = getEnv(); env->DeleteWeakGlobalRef(mOnJankDataListenerWeak); } void onJankDataAvailable(const std::vector<JankData>& jankData) { JNIEnv* env = getEnv(); jobject target = env->NewLocalRef(mOnJankDataListenerWeak); if (target == nullptr) return; jobjectArray jJankDataArray = env->NewObjectArray(jankData.size(), gJankDataClassInfo.clazz, nullptr); for (int i = 0; i < jankData.size(); i++) { jobject jJankData = env->NewObject(gJankDataClassInfo.clazz, gJankDataClassInfo.ctor, jankData[i].frameVsyncId, jankData[i].jankType); env->SetObjectArrayElement(jJankDataArray, i, jJankData); } env->CallVoidMethod(target, gJankDataListenerClassInfo.onJankDataAvailable, jJankDataArray); env->DeleteLocalRef(target); } private: JNIEnv* getEnv() { JNIEnv* env; mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); return env; } JavaVM* mVm; jobject mOnJankDataListenerWeak; }; static void nativeAddJankDataListener(JNIEnv* env, jclass clazz, jlong jankDataCallbackListenerPtr, jlong nativeSurfaceControl) { sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl *>(nativeSurfaceControl)); if (surface == nullptr) { return; } JankDataListenerWrapper* wrapper = reinterpret_cast<JankDataListenerWrapper*>(jankDataCallbackListenerPtr); TransactionCompletedListener::getInstance()->addJankListener(wrapper, surface); } static void nativeRemoveJankDataListener(JNIEnv* env, jclass clazz, jlong jankDataCallbackListenerPtr) { JankDataListenerWrapper* wrapper = reinterpret_cast<JankDataListenerWrapper*>(jankDataCallbackListenerPtr); TransactionCompletedListener::getInstance()->removeJankListener(wrapper); } static jlong nativeCreateJankDataListenerWrapper(JNIEnv* env, jclass clazz, jobject jankDataListenerObject) { return reinterpret_cast<jlong>(new JankDataListenerWrapper(env, jankDataListenerObject)); } // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { Loading Loading @@ -1785,6 +1863,12 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetFocusedWindow}, {"nativeSetFrameTimelineVsync", "(JJ)V", (void*)nativeSetFrameTimelineVsync }, {"nativeAddJankDataListener", "(JJ)V", (void*)nativeAddJankDataListener }, {"nativeRemoveJankDataListener", "(J)V", (void*)nativeRemoveJankDataListener }, {"nativeCreateJankDataListenerWrapper", "(Landroid/view/SurfaceControl$OnJankDataListener;)J", (void*)nativeCreateJankDataListenerWrapper }, // clang-format on }; Loading Loading @@ -1966,6 +2050,18 @@ int register_android_view_SurfaceControl(JNIEnv* env) gScreenCaptureListenerClassInfo.onScreenCaptureComplete = GetMethodIDOrDie(env, screenCaptureListenerClazz, "onScreenCaptureComplete", "(Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;)V"); jclass jankDataClazz = FindClassOrDie(env, "android/view/SurfaceControl$JankData"); gJankDataClassInfo.clazz = MakeGlobalRefOrDie(env, jankDataClazz); gJankDataClassInfo.ctor = GetMethodIDOrDie(env, gJankDataClassInfo.clazz, "<init>", "(JI)V"); jclass onJankDataListenerClazz = FindClassOrDie(env, "android/view/SurfaceControl$OnJankDataListener"); gJankDataListenerClassInfo.clazz = MakeGlobalRefOrDie(env, onJankDataListenerClazz); gJankDataListenerClassInfo.onJankDataAvailable = GetMethodIDOrDie(env, onJankDataListenerClazz, "onJankDataAvailable", "([Landroid/view/SurfaceControl$JankData;)V"); return err; } Loading