Attach the Choreographer instance with SurfaceControl
The attached choreographer will register with the event receiver through native api. Test: atest ChoreographerTest SurfaceControlTest BUG: 258235154 Change-Id: I33c0e686a1fd42becc0bfb1ae0185efd673e7b5a
This commit is contained in:
@@ -3132,6 +3132,9 @@ package android.view {
|
||||
|
||||
public final class SurfaceControl implements android.os.Parcelable {
|
||||
ctor public SurfaceControl(@NonNull android.view.SurfaceControl, @NonNull String);
|
||||
method @NonNull public android.view.Choreographer getChoreographer();
|
||||
method @NonNull public android.view.Choreographer getChoreographer(@NonNull android.os.Looper);
|
||||
method public boolean hasChoreographer();
|
||||
method public boolean isSameSurface(@NonNull android.view.SurfaceControl);
|
||||
}
|
||||
|
||||
|
||||
@@ -270,10 +270,14 @@ public final class Choreographer {
|
||||
private static final int CALLBACK_LAST = CALLBACK_COMMIT;
|
||||
|
||||
private Choreographer(Looper looper, int vsyncSource) {
|
||||
this(looper, vsyncSource, /* layerHandle */ 0L);
|
||||
}
|
||||
|
||||
private Choreographer(Looper looper, int vsyncSource, long layerHandle) {
|
||||
mLooper = looper;
|
||||
mHandler = new FrameHandler(looper);
|
||||
mDisplayEventReceiver = USE_VSYNC
|
||||
? new FrameDisplayEventReceiver(looper, vsyncSource)
|
||||
? new FrameDisplayEventReceiver(looper, vsyncSource, layerHandle)
|
||||
: null;
|
||||
mLastFrameTimeNanos = Long.MIN_VALUE;
|
||||
|
||||
@@ -312,6 +316,26 @@ public final class Choreographer {
|
||||
return sSfThreadInstance.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the choreographer associated with the SurfaceControl.
|
||||
*
|
||||
* @param layerHandle to which the choreographer will be attached.
|
||||
* @param looper the choreographer is attached on this looper.
|
||||
*
|
||||
* @return The choreographer for the looper which is attached
|
||||
* to the sourced SurfaceControl::mNativeHandle.
|
||||
* @throws IllegalStateException if the looper sourced is null.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
static Choreographer getInstanceForSurfaceControl(long layerHandle,
|
||||
@NonNull Looper looper) {
|
||||
if (looper == null) {
|
||||
throw new IllegalStateException("The current thread must have a looper!");
|
||||
}
|
||||
return new Choreographer(looper, VSYNC_SOURCE_APP, layerHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
|
||||
* @hide
|
||||
@@ -333,6 +357,15 @@ public final class Choreographer {
|
||||
mDisplayEventReceiver.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose the DisplayEventReceiver on the Choreographer.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
void invalidate() {
|
||||
dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, between each frame of the animation.
|
||||
* <p>
|
||||
@@ -1166,8 +1199,8 @@ public final class Choreographer {
|
||||
private int mFrame;
|
||||
private VsyncEventData mLastVsyncEventData = new VsyncEventData();
|
||||
|
||||
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
|
||||
super(looper, vsyncSource, 0);
|
||||
FrameDisplayEventReceiver(Looper looper, int vsyncSource, long layerHandle) {
|
||||
super(looper, vsyncSource, /* eventRegistration */ 0, layerHandle);
|
||||
}
|
||||
|
||||
// TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
|
||||
|
||||
@@ -80,7 +80,7 @@ public abstract class DisplayEventReceiver {
|
||||
private MessageQueue mMessageQueue;
|
||||
|
||||
private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
|
||||
MessageQueue messageQueue, int vsyncSource, int eventRegistration);
|
||||
MessageQueue messageQueue, int vsyncSource, int eventRegistration, long layerHandle);
|
||||
private static native void nativeDispose(long receiverPtr);
|
||||
@FastNative
|
||||
private static native void nativeScheduleVsync(long receiverPtr);
|
||||
@@ -93,7 +93,11 @@ public abstract class DisplayEventReceiver {
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public DisplayEventReceiver(Looper looper) {
|
||||
this(looper, VSYNC_SOURCE_APP, 0);
|
||||
this(looper, VSYNC_SOURCE_APP, /* eventRegistration */ 0, /* layerHandle */ 0L);
|
||||
}
|
||||
|
||||
public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) {
|
||||
this(looper, vsyncSource, eventRegistration, /* layerHandle */ 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,15 +107,17 @@ public abstract class DisplayEventReceiver {
|
||||
* @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
|
||||
* @param eventRegistration Which events to dispatch. Must be a bitfield consist of the
|
||||
* EVENT_REGISTRATION_*_FLAG values.
|
||||
* @param layerHandle Layer to which the current instance is attached to
|
||||
*/
|
||||
public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) {
|
||||
public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration,
|
||||
long layerHandle) {
|
||||
if (looper == null) {
|
||||
throw new IllegalArgumentException("looper must not be null");
|
||||
}
|
||||
|
||||
mMessageQueue = looper.getQueue();
|
||||
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
|
||||
vsyncSource, eventRegistration);
|
||||
vsyncSource, eventRegistration, layerHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -64,6 +64,7 @@ import android.opengl.EGLDisplay;
|
||||
import android.opengl.EGLSync;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
@@ -463,6 +464,10 @@ public final class SurfaceControl implements Parcelable {
|
||||
public long mNativeObject;
|
||||
private long mNativeHandle;
|
||||
|
||||
private final Object mChoreographerLock = new Object();
|
||||
@GuardedBy("mChoreographerLock")
|
||||
private Choreographer mChoreographer;
|
||||
|
||||
// TODO: Move width/height to native and fix locking through out.
|
||||
private final Object mLock = new Object();
|
||||
@GuardedBy("mLock")
|
||||
@@ -1268,6 +1273,59 @@ public final class SurfaceControl implements Parcelable {
|
||||
return other.mNativeHandle == mNativeHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated {@link Choreographer} instance with the
|
||||
* current instance of the SurfaceControl.
|
||||
* Must be called from a thread that already has a {@link android.os.Looper}
|
||||
* associated with it.
|
||||
* If there is no {@link Choreographer} associated with the SurfaceControl then a new instance
|
||||
* of the {@link Choreographer} is created.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public @NonNull Choreographer getChoreographer() {
|
||||
return getChoreographer(Looper.myLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated {@link Choreographer} instance with the
|
||||
* current instance of the SurfaceControl.
|
||||
* If there is no {@link Choreographer} associated with the SurfaceControl then a new instance
|
||||
* of the {@link Choreographer} is created.
|
||||
*
|
||||
* @param looper the choreographer is attached on this looper
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public @NonNull Choreographer getChoreographer(@NonNull Looper looper) {
|
||||
checkNotReleased();
|
||||
synchronized (mChoreographerLock) {
|
||||
if (mChoreographer != null) {
|
||||
return mChoreographer;
|
||||
}
|
||||
|
||||
mChoreographer = Choreographer.getInstanceForSurfaceControl(mNativeHandle, looper);
|
||||
return mChoreographer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@link Choreographer} is present otherwise false.
|
||||
* To check the validity use {@link #isValid} on the SurfaceControl, a valid SurfaceControl with
|
||||
* choreographer will have the valid Choreographer.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
@UnsupportedAppUsage
|
||||
public boolean hasChoreographer() {
|
||||
synchronized (mChoreographerLock) {
|
||||
return mChoreographer != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to a protocol buffer output stream. Protocol buffer message definition is at {@link
|
||||
* android.view.SurfaceControlProto}.
|
||||
@@ -1325,6 +1383,13 @@ public final class SurfaceControl implements Parcelable {
|
||||
mNativeObject = 0;
|
||||
mNativeHandle = 0;
|
||||
mCloseGuard.close();
|
||||
synchronized (mChoreographerLock) {
|
||||
if (mChoreographer != null) {
|
||||
mChoreographer.invalidate();
|
||||
// TODO(b/266121235): Use NativeAllocationRegistry to clean up Choreographer.
|
||||
mChoreographer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class NativeDisplayEventReceiver : public DisplayEventDispatcher {
|
||||
public:
|
||||
NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
|
||||
const sp<MessageQueue>& messageQueue, jint vsyncSource,
|
||||
jint eventRegistration);
|
||||
jint eventRegistration, jlong layerHandle);
|
||||
|
||||
void dispose();
|
||||
|
||||
@@ -88,11 +88,15 @@ private:
|
||||
|
||||
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
|
||||
const sp<MessageQueue>& messageQueue,
|
||||
jint vsyncSource, jint eventRegistration)
|
||||
jint vsyncSource, jint eventRegistration,
|
||||
jlong layerHandle)
|
||||
: DisplayEventDispatcher(messageQueue->getLooper(),
|
||||
static_cast<gui::ISurfaceComposer::VsyncSource>(vsyncSource),
|
||||
static_cast<gui::ISurfaceComposer::EventRegistration>(
|
||||
eventRegistration)),
|
||||
eventRegistration),
|
||||
layerHandle != 0 ? sp<IBinder>::fromExisting(
|
||||
reinterpret_cast<IBinder*>(layerHandle))
|
||||
: nullptr),
|
||||
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
|
||||
mMessageQueue(messageQueue) {
|
||||
ALOGV("receiver %p ~ Initializing display event receiver.", this);
|
||||
@@ -214,7 +218,7 @@ void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
|
||||
}
|
||||
|
||||
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
|
||||
jint vsyncSource, jint eventRegistration) {
|
||||
jint vsyncSource, jint eventRegistration, jlong layerHandle) {
|
||||
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
|
||||
if (messageQueue == NULL) {
|
||||
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
|
||||
@@ -223,7 +227,7 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject
|
||||
|
||||
sp<NativeDisplayEventReceiver> receiver =
|
||||
new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
|
||||
eventRegistration);
|
||||
eventRegistration, layerHandle);
|
||||
status_t status = receiver->initialize();
|
||||
if (status) {
|
||||
String8 message;
|
||||
@@ -268,7 +272,7 @@ static jobject nativeGetLatestVsyncEventData(JNIEnv* env, jclass clazz, jlong re
|
||||
|
||||
static const JNINativeMethod gMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{"nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;II)J",
|
||||
{"nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;IIJ)J",
|
||||
(void*)nativeInit},
|
||||
{"nativeDispose", "(J)V", (void*)nativeDispose},
|
||||
// @FastNative
|
||||
|
||||
Reference in New Issue
Block a user