Merge "Add JNI and public methods for TrustedPresentationCallback"

This commit is contained in:
Chavi Weingarten
2023-01-30 17:49:24 +00:00
committed by Android (Google) Code Review
3 changed files with 314 additions and 1 deletions

View File

@@ -51245,6 +51245,7 @@ package android.view {
method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener);
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);
method public void close();
method public int describeContents();
method @NonNull public android.view.SurfaceControl.Transaction merge(@NonNull android.view.SurfaceControl.Transaction);
@@ -51265,6 +51266,7 @@ package android.view {
method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean);
method @NonNull public android.view.SurfaceControl.Transaction setPosition(@NonNull android.view.SurfaceControl, float, float);
method @NonNull public android.view.SurfaceControl.Transaction setScale(@NonNull android.view.SurfaceControl, float, float);
method @NonNull public android.view.SurfaceControl.Transaction setTrustedPresentationCallback(@NonNull android.view.SurfaceControl, @NonNull android.view.SurfaceControl.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @NonNull public android.view.SurfaceControl.Transaction setVisibility(@NonNull android.view.SurfaceControl, boolean);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.SurfaceControl.Transaction> CREATOR;
@@ -51274,6 +51276,10 @@ package android.view {
method public void onTransactionCommitted();
}
public static 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);
}
public class SurfaceControlViewHost {
ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder);
method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage();

View File

@@ -280,7 +280,12 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeSetDefaultApplyToken(IBinder token);
private static native IBinder nativeGetDefaultApplyToken();
private static native boolean nativeBootFinished();
private static native long nativeCreateTpc(TrustedPresentationCallback callback);
private static native long getNativeTrustedPresentationCallbackFinalizer();
private static native void nativeSetTrustedPresentationCallback(long transactionObj,
long nativeObject, long nativeTpc, TrustedPresentationThresholds thresholds);
private static native void nativeClearTrustedPresentationCallback(long transactionObj,
long nativeObject);
/**
* Transforms that can be applied to buffers as they are displayed to a window.
@@ -465,6 +470,8 @@ public final class SurfaceControl implements Parcelable {
@GuardedBy("mLock")
private int mHeight;
private TrustedPresentationCallback mTrustedPresentationCallback;
private WeakReference<View> mLocalOwnerView;
static GlobalTransactionWrapper sGlobalTransaction;
@@ -2399,6 +2406,79 @@ public final class SurfaceControl implements Parcelable {
void onTransactionCommitted();
}
/**
* Threshold values that are sent with
* {@link Transaction#setTrustedPresentationCallback(SurfaceControl,
* TrustedPresentationThresholds, Executor, Consumer)}
*/
public static class TrustedPresentationThresholds {
private float mMinAlpha;
private float mMinFractionRendered;
private int mStabilityRequirementMs;
/**
* Creates a TrustedPresentationThresholds that's used when calling
* {@link Transaction#setTrustedPresentationCallback(SurfaceControl,
* TrustedPresentationThresholds, Executor, Consumer)}
*
* @param minAlpha The min alpha the {@link SurfaceControl} is required to
* have to be considered inside the threshold.
* @param minFractionRendered The min fraction of the SurfaceControl that was resented
* to the user to be considered inside the threshold.
* @param stabilityRequirementMs The time in milliseconds required for the
* {@link SurfaceControl} to be in the threshold.
* @throws IllegalArgumentException If threshold values are invalid.
*/
public TrustedPresentationThresholds(
@FloatRange(from = 0f, fromInclusive = false, to = 1f) float minAlpha,
@FloatRange(from = 0f, fromInclusive = false, to = 1f) float minFractionRendered,
@IntRange(from = 1) int stabilityRequirementMs) {
mMinAlpha = minAlpha;
mMinFractionRendered = minFractionRendered;
mStabilityRequirementMs = stabilityRequirementMs;
checkValid();
}
private void checkValid() {
if (mMinAlpha <= 0 || mMinFractionRendered <= 0 || mStabilityRequirementMs < 1) {
throw new IllegalArgumentException(
"TrustedPresentationThresholds values are invalid");
}
}
}
/**
* Register a TrustedPresentationCallback for a particular SurfaceControl so it can be notified
* when the specified Threshold has been crossed.
*
* @hide
*/
public abstract static class TrustedPresentationCallback {
private final long mNativeObject;
private static final NativeAllocationRegistry sRegistry =
NativeAllocationRegistry.createMalloced(
TrustedPresentationCallback.class.getClassLoader(),
getNativeTrustedPresentationCallbackFinalizer());
private final Runnable mFreeNativeResources;
private TrustedPresentationCallback() {
mNativeObject = nativeCreateTpc(this);
mFreeNativeResources = sRegistry.registerNativeAllocation(this, mNativeObject);
}
/**
* Invoked when the SurfaceControl that this TrustedPresentationCallback was registered for
* enters or exits the threshold bounds.
*
* @param inTrustedPresentationState true when the SurfaceControl entered the
* presentation state, false when it has left.
*/
public abstract void onTrustedPresentationChanged(boolean inTrustedPresentationState);
}
/**
* An atomic set of changes to a set of SurfaceControl.
*/
@@ -3776,6 +3856,106 @@ public final class SurfaceControl implements Parcelable {
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
* callback with {@code true}. When the conditions fall out of thresholds, it is then
* said to leave the state.
* <p>
* There are a few simple thresholds:
* <ul>
* <li>minAlpha: Lower bound on computed alpha</li>
* <li>minFractionRendered: Lower bounds on fraction of pixels that were rendered</li>
* <li>stabilityThresholdMs: A time that alpha and fraction rendered must remain within
* bounds before we can "enter the state" </li>
* </ul>
* <p>
* The fraction of pixels rendered is a computation based on scale, crop
* and occlusion. The calculation may be somewhat counterintuitive, so we
* can work through an example. Imagine we have a SurfaceControl with a 100x100 buffer
* which is occluded by (10x100) pixels on the left, and cropped by (100x10) pixels
* on the top. Furthermore imagine this SurfaceControl is scaled by 0.9 in both dimensions.
* (c=crop,o=occluded,b=both,x=none)
*
* <blockquote>
* <table>
* <caption></caption>
* <tr><td>b</td><td>c</td><td>c</td><td>c</td></tr>
* <tr><td>o</td><td>x</td><td>x</td><td>x</td></tr>
* <tr><td>o</td><td>x</td><td>x</td><td>x</td></tr>
* <tr><td>o</td><td>x</td><td>x</td><td>x</td></tr>
* </table>
* </blockquote>
*
*<p>
* We first start by computing fr=xscale*yscale=0.9*0.9=0.81, indicating
* that "81%" of the pixels were rendered. This corresponds to what was 100
* pixels being displayed in 81 pixels. This is somewhat of an abuse of
* language, as the information of merged pixels isn't totally lost, but
* we err on the conservative side.
* <p>
* We then repeat a similar process for the crop and covered regions and
* accumulate the results: fr = fr * (fractionNotCropped) * (fractionNotCovered)
* So for this example we would get 0.9*0.9*0.9*0.9=0.65...
* <p>
* Notice that this is not completely accurate, as we have double counted
* the region marked as b. However we only wanted a "lower bound" and so it
* is ok to err in this direction. Selection of the threshold will ultimately
* be somewhat arbitrary, and so there are some somewhat arbitrary decisions in
* this API as well.
* <p>
* @param sc The {@link SurfaceControl} to set the
* {@link TrustedPresentationCallback} on
* @param thresholds The {@link TrustedPresentationThresholds} that will specify when the to
* invoke the callback.
* @param executor The {@link Executor} where the callback will be invoked on.
* @param listener The {@link Consumer} that will receive the callbacks when entered or
* exited the threshold.
* @return This transaction
* @see TrustedPresentationThresholds
*/
@NonNull
public Transaction setTrustedPresentationCallback(@NonNull SurfaceControl sc,
@NonNull TrustedPresentationThresholds thresholds, @NonNull Executor executor,
@NonNull Consumer<Boolean> listener) {
checkPreconditions(sc);
TrustedPresentationCallback tpc = new TrustedPresentationCallback() {
@Override
public void onTrustedPresentationChanged(boolean inTrustedPresentationState) {
executor.execute(
() -> listener.accept(inTrustedPresentationState));
}
};
if (sc.mTrustedPresentationCallback != null) {
sc.mTrustedPresentationCallback.mFreeNativeResources.run();
}
nativeSetTrustedPresentationCallback(mNativeObject, sc.mNativeObject,
tpc.mNativeObject, thresholds);
sc.mTrustedPresentationCallback = tpc;
return this;
}
/**
* Clears the {@link TrustedPresentationCallback} for a specific {@link SurfaceControl}
*
* @param sc The SurfaceControl that the {@link TrustedPresentationCallback} should be
* cleared from
* @return This transaction
*/
@NonNull
public Transaction clearTrustedPresentationCallback(@NonNull SurfaceControl sc) {
checkPreconditions(sc);
nativeClearTrustedPresentationCallback(mNativeObject, sc.mNativeObject);
if (sc.mTrustedPresentationCallback != null) {
sc.mTrustedPresentationCallback.mFreeNativeResources.run();
sc.mTrustedPresentationCallback = null;
}
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

View File

@@ -246,6 +246,17 @@ static struct {
jmethodID invokeReleaseCallback;
} gSurfaceControlClassInfo;
static struct {
jclass clazz;
jfieldID mMinAlpha;
jfieldID mMinFractionRendered;
jfieldID mStabilityRequirementMs;
} gTrustedPresentationThresholdsClassInfo;
static struct {
jmethodID onTrustedPresentationChanged;
} gTrustedPresentationCallbackClassInfo;
constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode) {
switch (colorMode) {
case ui::ColorMode::DISPLAY_P3:
@@ -328,6 +339,47 @@ private:
}
};
class TrustedPresentationCallbackWrapper {
public:
explicit TrustedPresentationCallbackWrapper(JNIEnv* env, jobject trustedPresentationListener) {
env->GetJavaVM(&mVm);
mTrustedPresentationCallback = env->NewGlobalRef(trustedPresentationListener);
LOG_ALWAYS_FATAL_IF(!mTrustedPresentationCallback, "Failed to make global ref");
}
~TrustedPresentationCallbackWrapper() {
getenv()->DeleteGlobalRef(mTrustedPresentationCallback);
}
void onTrustedPresentationChanged(bool inTrustedPresentationState) {
JNIEnv* env = getenv();
env->CallVoidMethod(mTrustedPresentationCallback,
gTrustedPresentationCallbackClassInfo.onTrustedPresentationChanged,
inTrustedPresentationState);
}
void addCallbackRef(const sp<SurfaceComposerClient::PresentationCallbackRAII>& callbackRef) {
mCallbackRef = callbackRef;
}
static void onTrustedPresentationChangedThunk(void* context, bool inTrustedPresentationState) {
TrustedPresentationCallbackWrapper* listener =
reinterpret_cast<TrustedPresentationCallbackWrapper*>(context);
listener->onTrustedPresentationChanged(inTrustedPresentationState);
}
private:
jobject mTrustedPresentationCallback;
JavaVM* mVm;
sp<SurfaceComposerClient::PresentationCallbackRAII> mCallbackRef;
JNIEnv* getenv() {
JNIEnv* env;
mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
return env;
}
};
// ----------------------------------------------------------------------------
static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
@@ -1806,6 +1858,42 @@ static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlo
context);
}
static void nativeSetTrustedPresentationCallback(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jlong trustedPresentationCallbackObject,
jobject trustedPresentationThresholds) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
TrustedPresentationThresholds thresholds;
thresholds.minAlpha = env->GetFloatField(trustedPresentationThresholds,
gTrustedPresentationThresholdsClassInfo.mMinAlpha);
thresholds.minFractionRendered =
env->GetFloatField(trustedPresentationThresholds,
gTrustedPresentationThresholdsClassInfo.mMinFractionRendered);
thresholds.stabilityRequirementMs =
env->GetIntField(trustedPresentationThresholds,
gTrustedPresentationThresholdsClassInfo.mStabilityRequirementMs);
sp<SurfaceComposerClient::PresentationCallbackRAII> callbackRef;
TrustedPresentationCallbackWrapper* wrapper =
reinterpret_cast<TrustedPresentationCallbackWrapper*>(
trustedPresentationCallbackObject);
transaction->setTrustedPresentationCallback(ctrl,
TrustedPresentationCallbackWrapper::
onTrustedPresentationChangedThunk,
thresholds, wrapper, callbackRef);
wrapper->addCallbackRef(callbackRef);
}
static void nativeClearTrustedPresentationCallback(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
transaction->clearTrustedPresentationCallback(ctrl);
}
class JankDataListenerWrapper : public JankDataListener {
public:
JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) {
@@ -1919,6 +2007,21 @@ static jboolean nativeBootFinished(JNIEnv* env, jclass clazz) {
return error == OK ? JNI_TRUE : JNI_FALSE;
}
jlong nativeCreateTpc(JNIEnv* env, jclass clazz, jobject trustedPresentationCallback) {
return reinterpret_cast<jlong>(
new TrustedPresentationCallbackWrapper(env, trustedPresentationCallback));
}
void destroyNativeTpc(void* ptr) {
TrustedPresentationCallbackWrapper* callback =
reinterpret_cast<TrustedPresentationCallbackWrapper*>(ptr);
delete callback;
}
static jlong getNativeTrustedPresentationCallbackFinalizer(JNIEnv* env, jclass clazz) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeTpc));
}
// ----------------------------------------------------------------------------
SurfaceControl* android_view_SurfaceControl_getNativeSurfaceControl(JNIEnv* env,
@@ -2145,6 +2248,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetDropInputMode },
{"nativeAddTransactionCommittedListener", "(JLandroid/view/SurfaceControl$TransactionCommittedListener;)V",
(void*) nativeAddTransactionCommittedListener },
{"nativeSetTrustedPresentationCallback", "(JJJLandroid/view/SurfaceControl$TrustedPresentationThresholds;)V",
(void*) nativeSetTrustedPresentationCallback },
{"nativeClearTrustedPresentationCallback", "(JJ)V",
(void*) nativeClearTrustedPresentationCallback },
{"nativeSanitize", "(J)V",
(void*) nativeSanitize },
{"nativeSetDestinationFrame", "(JJIIII)V",
@@ -2155,6 +2262,9 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeGetDefaultApplyToken },
{"nativeBootFinished", "()Z",
(void*)nativeBootFinished },
{"nativeCreateTpc", "(Landroid/view/SurfaceControl$TrustedPresentationCallback;)J",
(void*)nativeCreateTpc},
{"getNativeTrustedPresentationCallbackFinalizer", "()J", (void*)getNativeTrustedPresentationCallbackFinalizer },
// clang-format on
};
@@ -2381,6 +2491,23 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gTransactionClassInfo.mNativeObject =
GetFieldIDOrDie(env, gTransactionClassInfo.clazz, "mNativeObject", "J");
jclass trustedPresentationThresholdsClazz =
FindClassOrDie(env, "android/view/SurfaceControl$TrustedPresentationThresholds");
gTrustedPresentationThresholdsClassInfo.clazz =
MakeGlobalRefOrDie(env, trustedPresentationThresholdsClazz);
gTrustedPresentationThresholdsClassInfo.mMinAlpha =
GetFieldIDOrDie(env, trustedPresentationThresholdsClazz, "mMinAlpha", "F");
gTrustedPresentationThresholdsClassInfo.mMinFractionRendered =
GetFieldIDOrDie(env, trustedPresentationThresholdsClazz, "mMinFractionRendered", "F");
gTrustedPresentationThresholdsClassInfo.mStabilityRequirementMs =
GetFieldIDOrDie(env, trustedPresentationThresholdsClazz, "mStabilityRequirementMs",
"I");
jclass trustedPresentationCallbackClazz =
FindClassOrDie(env, "android/view/SurfaceControl$TrustedPresentationCallback");
gTrustedPresentationCallbackClassInfo.onTrustedPresentationChanged =
GetMethodIDOrDie(env, trustedPresentationCallbackClazz, "onTrustedPresentationChanged",
"(Z)V");
return err;
}