diff options
| author | 2020-12-10 17:25:47 +0000 | |
|---|---|---|
| committer | 2020-12-10 17:25:47 +0000 | |
| commit | 3f7ed056ede92096e05f66cc4b6ee6bf4a249e61 (patch) | |
| tree | b0208b676308462b731db48d131c5463df884ecc | |
| parent | 7349aa999b46ad1353fc231d219ad47b6e439436 (diff) | |
| parent | e418a013e36be280d82d6ebfcbbacf3bde1f9b18 (diff) | |
Merge "Add Shared timeline jank classification listener (2/2)"
| -rw-r--r-- | core/java/android/view/SurfaceControl.java | 91 | ||||
| -rw-r--r-- | core/jni/android_view_SurfaceControl.cpp | 96 |
2 files changed, 187 insertions, 0 deletions
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index d7ee6ad15166..81e0852fdfa2 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -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; @@ -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; @@ -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") @@ -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; @@ -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. */ diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 6ec656c16790..a21545c21011 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -52,6 +52,7 @@ #include <ui/Rect.h> #include <ui/Region.h> #include <utils/Log.h> +#include <utils/LightRefBase.h> // ---------------------------------------------------------------------------- @@ -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; @@ -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[] = { @@ -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 }; @@ -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; } |