summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt9
-rw-r--r--core/java/android/hardware/SyncFence.java17
-rw-r--r--core/java/android/view/SurfaceControl.java137
-rw-r--r--core/java/android/window/flags/window_surfaces.aconfig10
-rw-r--r--core/jni/android_hardware_SyncFence.cpp5
-rw-r--r--core/jni/android_view_SurfaceControl.cpp89
6 files changed, 261 insertions, 6 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 95af71cfa074..b8464914e8d3 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -18613,6 +18613,7 @@ package android.hardware {
}
public final class SyncFence implements java.lang.AutoCloseable android.os.Parcelable {
+ ctor @FlaggedApi("com.android.window.flags.sdk_desired_present_time") public SyncFence(@NonNull android.hardware.SyncFence);
method public boolean await(@NonNull java.time.Duration);
method public boolean awaitForever();
method public void close();
@@ -51784,6 +51785,7 @@ package android.view {
public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable {
ctor public SurfaceControl.Transaction();
method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener);
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction addTransactionCompletedListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.SurfaceControl.TransactionStats>);
method public void apply();
method @NonNull public android.view.SurfaceControl.Transaction clearFrameRate(@NonNull android.view.SurfaceControl);
method @NonNull public android.view.SurfaceControl.Transaction clearTrustedPresentationCallback(@NonNull android.view.SurfaceControl);
@@ -51800,9 +51802,11 @@ package android.view {
method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
method @NonNull public android.view.SurfaceControl.Transaction setDamageRegion(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Region);
method @NonNull public android.view.SurfaceControl.Transaction setDataSpace(@NonNull android.view.SurfaceControl, int);
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setDesiredPresentTime(long);
method @NonNull public android.view.SurfaceControl.Transaction setExtendedRangeBrightness(@NonNull android.view.SurfaceControl, float, float);
method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int);
method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int, int);
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setFrameTimeline(long);
method @Deprecated @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean);
@@ -51818,6 +51822,11 @@ package android.view {
method public void onTransactionCommitted();
}
+ @FlaggedApi("com.android.window.flags.sdk_desired_present_time") public static final class SurfaceControl.TransactionStats {
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") public long getLatchTime();
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.hardware.SyncFence getPresentFence();
+ }
+
public static final class SurfaceControl.TrustedPresentationThresholds {
ctor public SurfaceControl.TrustedPresentationThresholds(@FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @IntRange(from=1) int);
}
diff --git a/core/java/android/hardware/SyncFence.java b/core/java/android/hardware/SyncFence.java
index d6052cd4c67f..c2440fbaab1b 100644
--- a/core/java/android/hardware/SyncFence.java
+++ b/core/java/android/hardware/SyncFence.java
@@ -16,6 +16,7 @@
package android.hardware;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.media.Image;
import android.media.ImageWriter;
@@ -26,6 +27,8 @@ import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.SystemClock;
+import com.android.window.flags.Flags;
+
import libcore.util.NativeAllocationRegistry;
import java.io.FileDescriptor;
@@ -121,6 +124,19 @@ public final class SyncFence implements AutoCloseable, Parcelable {
}
}
+ /**
+ * Creates a copy of the SyncFence from an existing one.
+ * Both fences must be closed() independently.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ public SyncFence(@NonNull SyncFence other) {
+ this(other.mNativePtr);
+
+ if (mNativePtr != 0) {
+ nIncRef(mNativePtr);
+ }
+ }
+
private SyncFence() {
mCloser = () -> {};
}
@@ -312,4 +328,5 @@ public final class SyncFence implements AutoCloseable, Parcelable {
private static native int nGetFd(long nPtr);
private static native boolean nWait(long nPtr, long timeout);
private static native long nGetSignalTime(long nPtr);
+ private static native void nIncRef(long nPtr);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b957b31a5bb7..674f22c4166e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -28,6 +28,7 @@ import static android.view.SurfaceControlProto.NAME;
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -71,6 +72,7 @@ import android.view.Surface.OutOfResourcesException;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.internal.util.VirtualRefBasePtr;
+import com.android.window.flags.Flags;
import dalvik.system.CloseGuard;
@@ -277,6 +279,8 @@ public final class SurfaceControl implements Parcelable {
private static native int nativeGetLayerId(long nativeObject);
private static native void nativeAddTransactionCommittedListener(long nativeObject,
TransactionCommittedListener listener);
+ private static native void nativeAddTransactionCompletedListener(long nativeObject,
+ Consumer<TransactionStats> listener);
private static native void nativeSanitize(long transactionObject, int pid, int uid);
private static native void nativeSetDestinationFrame(long transactionObj, long nativeObject,
int l, int t, int r, int b);
@@ -290,6 +294,10 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeClearTrustedPresentationCallback(long transactionObj,
long nativeObject);
private static native StalledTransactionInfo nativeGetStalledTransactionInfo(int pid);
+ private static native void nativeSetDesiredPresentTime(long transactionObj,
+ long desiredPresentTime);
+ private static native void nativeSetFrameTimeline(long transactionObj,
+ long vsyncId);
/**
* Transforms that can be applied to buffers as they are displayed to a window.
@@ -2550,6 +2558,50 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Transaction stats given to the listener registered in
+ * {@link SurfaceControl.Transaction#addTransactionCompletedListener}
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ public static final class TransactionStats {
+ private long mLatchTime;
+ private SyncFence mSyncFence;
+
+ // called from native
+ private TransactionStats(long latchTime, long presentFencePtr) {
+ mLatchTime = latchTime;
+ mSyncFence = new SyncFence(presentFencePtr);
+ }
+
+ /**
+ * Close the TransactionStats. Called by the framework when the listener returns.
+ * @hide
+ */
+ public void close() {
+ mSyncFence.close();
+ }
+
+ /**
+ * Returns the timestamp of when the frame was latched by the framework and queued for
+ * presentation.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ public long getLatchTime() {
+ return mLatchTime;
+ }
+
+ /**
+ * Returns a new SyncFence that signals when the transaction has been presented.
+ * The caller takes ownership of the fence and is responsible for closing
+ * it by calling {@link SyncFence#close}.
+ * If a device does not support present fences, an empty fence will be returned.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ public @NonNull SyncFence getPresentFence() {
+ return new SyncFence(mSyncFence);
+ }
+ };
+
+ /**
* Threshold values that are sent with
* {@link Transaction#setTrustedPresentationCallback(SurfaceControl,
* TrustedPresentationThresholds, Executor, Consumer)}
@@ -4185,12 +4237,35 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * Sets the frame timeline vsync id received from choreographer
- * {@link Choreographer#getVsyncId()} that corresponds to the transaction submitted on that
- * surface control.
+ * Sets the frame timeline to use in SurfaceFlinger.
+ *
+ * A frame timeline should be chosen based on the frame deadline the application
+ * can meet when rendering the frame and the application's desired presentation time.
+ * By setting a frame timeline, SurfaceFlinger tries to present the frame at the
+ * corresponding expected presentation time.
+ *
+ * To receive frame timelines, a callback must be posted to Choreographer using
+ * {@link Choreographer#postVsyncCallback} The vsyncId can then be extracted from the
+ * {@link Choreographer.FrameTimeline#getVsyncId}.
+ *
+ * @param vsyncId The vsync ID received from Choreographer, setting the frame's
+ * presentation target to the corresponding expected presentation time
+ * and deadline from the frame to be rendered. A stale or invalid value
+ * will be ignored.
*
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ @NonNull
+ public Transaction setFrameTimeline(long vsyncId) {
+ if (!Flags.sdkDesiredPresentTime()) {
+ Log.w(TAG, "addTransactionCompletedListener was called but flag is disabled");
+ return this;
+ }
+ nativeSetFrameTimelineVsync(mNativeObject, vsyncId);
+ return this;
+ }
+
+ /** @hide */
@NonNull
public Transaction setFrameTimelineVsync(long frameTimelineVsyncId) {
nativeSetFrameTimelineVsync(mNativeObject, frameTimelineVsyncId);
@@ -4207,6 +4282,9 @@ public final class SurfaceControl implements Parcelable {
* to avoid dropping frames (overwriting transactions), and unable to use timestamps (Which
* provide a more efficient solution), then this method provides a method to pace your
* transaction application.
+ * The listener is invoked once the transaction is applied, and never again. Multiple
+ * listeners can be added to the same transaction, however the order the listeners will
+ * be called is not guaranteed.
*
* @param executor The executor that the callback should be invoked on.
* @param listener The callback that will be invoked when the transaction has been
@@ -4223,6 +4301,33 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Request to add a TransactionCompletedListener.
+ *
+ * The listener is invoked when transaction is presented, and never again. Multiple
+ * listeners can be added to the same transaction, however the order the listeners will
+ * be called is not guaranteed.
+ *
+ * @param executor The executor that the callback should be invoked on.
+ * @param listener The callback that will be invoked when the transaction has been
+ * completed.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ @NonNull
+ public Transaction addTransactionCompletedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<TransactionStats> listener) {
+
+ if (!Flags.sdkDesiredPresentTime()) {
+ Log.w(TAG, "addTransactionCompletedListener was called but flag is disabled");
+ return this;
+ }
+ Consumer<TransactionStats> listenerInner = stats -> executor.execute(
+ () -> listener.andThen(TransactionStats::close).accept(stats));
+ nativeAddTransactionCompletedListener(mNativeObject, listenerInner);
+ return this;
+ }
+
+ /**
* Sets a callback to receive feedback about the presentation of a {@link SurfaceControl}.
* When the {@link SurfaceControl} is presented according to the passed in
* {@link TrustedPresentationThresholds}, it is said to "enter the state", and receives the
@@ -4321,6 +4426,30 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Specifies a desiredPresentTime for the transaction. The framework will try to present
+ * the transaction at or after the time specified.
+ *
+ * Transactions will not be presented until all of their acquire fences have signaled even
+ * if the app requests an earlier present time.
+ *
+ * If an earlier transaction has a desired present time of x, and a later transaction has
+ * a desired present time that is before x, the later transaction will not preempt the
+ * earlier transaction.
+ *
+ * @param desiredPresentTime The desired time (in CLOCK_MONOTONIC) for the transaction.
+ * @return This transaction
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ @NonNull
+ public Transaction setDesiredPresentTime(long desiredPresentTime) {
+ if (!Flags.sdkDesiredPresentTime()) {
+ Log.w(TAG, "addTransactionCompletedListener was called but flag is disabled");
+ return this;
+ }
+ nativeSetDesiredPresentTime(mNativeObject, desiredPresentTime);
+ return this;
+ }
+ /**
* Writes the transaction to parcel, clearing the transaction as if it had been applied so
* it can be used to store future transactions. It's the responsibility of the parcel
* reader to apply the original transaction.
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 56df49370379..3794c5d647a4 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -63,4 +63,12 @@ flag {
description: "Enable trustedPresentationListener on windows public API"
is_fixed_read_only: true
bug: "278027319"
-} \ No newline at end of file
+}
+
+flag {
+ namespace: "window_surfaces"
+ name: "sdk_desired_present_time"
+ description: "Feature flag for the new SDK API to set desired present time"
+ is_fixed_read_only: true
+ bug: "295038072"
+}
diff --git a/core/jni/android_hardware_SyncFence.cpp b/core/jni/android_hardware_SyncFence.cpp
index b99665346f25..6e94616db825 100644
--- a/core/jni/android_hardware_SyncFence.cpp
+++ b/core/jni/android_hardware_SyncFence.cpp
@@ -66,6 +66,10 @@ static jlong SyncFence_getSignalTime(JNIEnv* env, jobject, jlong jPtr) {
return fromJlong<Fence>(jPtr)->getSignalTime();
}
+static void SyncFence_incRef(JNIEnv*, jobject, jlong jPtr) {
+ fromJlong<Fence>(jPtr)->incStrong((void*)SyncFence_incRef);
+}
+
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
@@ -80,6 +84,7 @@ static const JNINativeMethod gMethods[] = {
{ "nGetFd", "(J)I", (void*) SyncFence_getFd },
{ "nWait", "(JJ)Z", (void*) SyncFence_wait },
{ "nGetSignalTime", "(J)J", (void*) SyncFence_getSignalTime },
+ { "nIncRef", "(J)V", (void*) SyncFence_incRef },
};
// clang-format on
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index db42246ca76c..55326da2c7df 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -231,6 +231,16 @@ static struct {
static struct {
jclass clazz;
+ jmethodID accept;
+} gConsumerClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+} gTransactionStatsClassInfo;
+
+static struct {
+ jclass clazz;
jmethodID ctor;
jfieldID format;
jfieldID alphaInterpretation;
@@ -317,6 +327,52 @@ private:
}
};
+class TransactionCompletedListenerWrapper {
+public:
+ explicit TransactionCompletedListenerWrapper(JNIEnv* env, jobject object) {
+ env->GetJavaVM(&mVm);
+ mTransactionCompletedListenerObject = env->NewGlobalRef(object);
+ LOG_ALWAYS_FATAL_IF(!mTransactionCompletedListenerObject, "Failed to make global ref");
+ }
+
+ ~TransactionCompletedListenerWrapper() {
+ getenv()->DeleteGlobalRef(mTransactionCompletedListenerObject);
+ }
+
+ void callback(nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& /*stats*/) {
+ JNIEnv* env = getenv();
+ // Adding a strong reference for java SyncFence
+ presentFence->incStrong(0);
+
+ jobject stats =
+ env->NewObject(gTransactionStatsClassInfo.clazz, gTransactionStatsClassInfo.ctor,
+ latchTime, presentFence.get());
+ env->CallVoidMethod(mTransactionCompletedListenerObject, gConsumerClassInfo.accept, stats);
+ env->DeleteLocalRef(stats);
+ DieIfException(env, "Uncaught exception in TransactionCompletedListener.");
+ }
+
+ static void transactionCallbackThunk(void* context, nsecs_t latchTime,
+ const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
+ TransactionCompletedListenerWrapper* listener =
+ reinterpret_cast<TransactionCompletedListenerWrapper*>(context);
+ listener->callback(latchTime, presentFence, stats);
+ delete listener;
+ }
+
+private:
+ jobject mTransactionCompletedListenerObject;
+ JavaVM* mVm;
+
+ JNIEnv* getenv() {
+ JNIEnv* env;
+ mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ return env;
+ }
+};
+
class WindowInfosReportedListenerWrapper : public gui::BnWindowInfosReportedListener {
public:
explicit WindowInfosReportedListenerWrapper(JNIEnv* env, jobject listener) {
@@ -1879,10 +1935,16 @@ static void nativeSetFrameTimelineVsync(JNIEnv* env, jclass clazz, jlong transac
FrameTimelineInfo ftInfo;
ftInfo.vsyncId = frameTimelineVsyncId;
- ftInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID;
transaction->setFrameTimelineInfo(ftInfo);
}
+static void nativeSetDesiredPresentTime(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong desiredPresentTime) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ transaction->setDesiredPresentTime(desiredPresentTime);
+}
+
static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlong transactionObj,
jobject transactionCommittedListenerObject) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -1894,6 +1956,17 @@ static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlo
context);
}
+static void nativeAddTransactionCompletedListener(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jobject transactionCompletedListenerObject) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ void* context =
+ new TransactionCompletedListenerWrapper(env, transactionCompletedListenerObject);
+ transaction->addTransactionCompletedCallback(TransactionCompletedListenerWrapper::
+ transactionCallbackThunk,
+ context);
+}
+
static void nativeSetTrustedPresentationCallback(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jlong trustedPresentationCallbackObject,
@@ -2318,6 +2391,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSurfaceFlushJankData },
{"nativeAddTransactionCommittedListener", "(JLandroid/view/SurfaceControl$TransactionCommittedListener;)V",
(void*) nativeAddTransactionCommittedListener },
+ {"nativeAddTransactionCompletedListener", "(JLjava/util/function/Consumer;)V",
+ (void*) nativeAddTransactionCompletedListener },
{"nativeSetTrustedPresentationCallback", "(JJJLandroid/view/SurfaceControl$TrustedPresentationThresholds;)V",
(void*) nativeSetTrustedPresentationCallback },
{"nativeClearTrustedPresentationCallback", "(JJ)V",
@@ -2337,6 +2412,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
{"getNativeTrustedPresentationCallbackFinalizer", "()J", (void*)getNativeTrustedPresentationCallbackFinalizer },
{"nativeGetStalledTransactionInfo", "(I)Landroid/gui/StalledTransactionInfo;",
(void*) nativeGetStalledTransactionInfo },
+ {"nativeSetDesiredPresentTime", "(JJ)V",
+ (void*) nativeSetDesiredPresentTime },
// clang-format on
};
@@ -2539,6 +2616,16 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gTransactionCommittedListenerClassInfo.onTransactionCommitted =
GetMethodIDOrDie(env, transactionCommittedListenerClazz, "onTransactionCommitted",
"()V");
+ jclass consumerClazz = FindClassOrDie(env, "java/util/function/Consumer");
+ gConsumerClassInfo.clazz = MakeGlobalRefOrDie(env, consumerClazz);
+ gConsumerClassInfo.accept =
+ GetMethodIDOrDie(env, consumerClazz, "accept", "(Ljava/lang/Object;)V");
+
+ jclass transactionStatsClazz =
+ FindClassOrDie(env, "android/view/SurfaceControl$TransactionStats");
+ gTransactionStatsClassInfo.clazz = MakeGlobalRefOrDie(env, transactionStatsClazz);
+ gTransactionStatsClassInfo.ctor =
+ GetMethodIDOrDie(env, gTransactionStatsClassInfo.clazz, "<init>", "(JJ)V");
jclass displayDecorationSupportClazz =
FindClassOrDie(env, "android/hardware/graphics/common/DisplayDecorationSupport");