Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9df2acb3 authored by chaviw's avatar chaviw
Browse files

Expose TransactionCommittedCallback to Java

By exposing TransactionCommitCallback, we can allow tests to get a
callback when a buffer has actually been latched instead of adding
timeouts

Bug: 192284443
Test: DisplayHashManagerTest#testGenerateAndVerifyDisplayHash
Change-Id: Ic1c1a4d6c83191f64978a94fbd8076ac839197e6
parent 257203f2
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -48490,6 +48490,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.TransactionCommittedListener);
    method public void apply();
    method public void close();
    method public int describeContents();
@@ -48616,6 +48617,10 @@ package android.view {
    field public static final int TO_RIGHT = 8; // 0x8
  }
  public interface TransactionCommittedListener {
    method public void onTransactionCommitted();
  }
  public final class VelocityTracker {
    method public void addMovement(android.view.MotionEvent);
    method public void clear();
+1 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ per-file SyncRtSurfaceTransactionApplier.java = file:/services/core/java/com/and
per-file ViewRootInsetsControllerHost.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file Window*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
per-file TransactionCommittedCallback.java = file:/services/core/java/com/android/server/wm/OWNERS

# Scroll Capture
per-file *ScrollCapture*.aidl = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
+29 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.view.SurfaceControlProto.HASH_CODE;
import static android.view.SurfaceControlProto.LAYER_ID;
import static android.view.SurfaceControlProto.NAME;

import android.annotation.CallbackExecutor;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -74,6 +75,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

/**
@@ -243,6 +245,8 @@ public final class SurfaceControl implements Parcelable {
    private static native void nativeSetTransformHint(long nativeObject, int transformHint);
    private static native int nativeGetTransformHint(long nativeObject);
    private static native int nativeGetLayerId(long nativeObject);
    private static native void nativeAddTransactionCommittedListener(long nativeObject,
            TransactionCommittedListener listener);

    @Nullable
    @GuardedBy("mLock")
@@ -3508,6 +3512,31 @@ public final class SurfaceControl implements Parcelable {
            return this;
        }

        /**
         * Request to add a {@link TransactionCommittedListener}.
         *
         * The callback is invoked when transaction is applied and the updates are ready to be
         * presented. This callback does not mean buffers have been released! It simply means that
         * any new transactions applied will not overwrite the transaction for which we are
         * receiving a callback and instead will be included in the next frame. If you are trying
         * 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.
         *
         * @param executor The executor that the callback should be invoked on.
         * @param listener The callback that will be invoked when the transaction has been
         *                 committed.
         */
        @NonNull
        public Transaction addTransactionCommittedListener(
                @NonNull @CallbackExecutor Executor executor,
                @NonNull TransactionCommittedListener listener) {
            TransactionCommittedListener listenerInner =
                    () -> executor.execute(listener::onTransactionCommitted);
            nativeAddTransactionCommittedListener(mNativeObject, listenerInner);
            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
+30 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import java.util.concurrent.Executor;

/**
 * Interface to handle request to
 * {@link SurfaceControl.Transaction#addTransactionCommittedListener(Executor, TransactionCommittedListener)}
 */
public interface TransactionCommittedListener {
    /**
     * Invoked when the transaction has been committed in SurfaceFlinger.
     */
    void onTransactionCommitted();
}
+64 −0
Original line number Diff line number Diff line
@@ -238,6 +238,11 @@ static struct {
    jmethodID ctor;
} gJankDataClassInfo;

static struct {
    jclass clazz;
    jmethodID onTransactionCommitted;
} gTransactionCommittedListenerClassInfo;

class JNamedColorSpace {
public:
    // ColorSpace.Named.SRGB.ordinal() = 0;
@@ -329,6 +334,44 @@ private:
    }
};

class TransactionCommittedListenerWrapper {
public:
    explicit TransactionCommittedListenerWrapper(JNIEnv* env, jobject object) {
        env->GetJavaVM(&mVm);
        mTransactionCommittedListenerObject = env->NewGlobalRef(object);
        LOG_ALWAYS_FATAL_IF(!mTransactionCommittedListenerObject, "Failed to make global ref");
    }

    ~TransactionCommittedListenerWrapper() {
        getenv()->DeleteGlobalRef(mTransactionCommittedListenerObject);
    }

    void callback() {
        JNIEnv* env = getenv();
        env->CallVoidMethod(mTransactionCommittedListenerObject,
                            gTransactionCommittedListenerClassInfo.onTransactionCommitted);
    }

    static void transactionCallbackThunk(void* context, nsecs_t /*latchTime*/,
                                         const sp<Fence>& /*presentFence*/,
                                         const std::vector<SurfaceControlStats>& /*stats*/) {
        TransactionCommittedListenerWrapper* listener =
                reinterpret_cast<TransactionCommittedListenerWrapper*>(context);
        listener->callback();
        delete listener;
    }

private:
    jobject mTransactionCommittedListenerObject;
    JavaVM* mVm;

    JNIEnv* getenv() {
        JNIEnv* env;
        mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
        return env;
    }
};

// ----------------------------------------------------------------------------

static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
@@ -1730,6 +1773,17 @@ static void nativeSetFrameTimelineVsync(JNIEnv* env, jclass clazz, jlong transac
            {frameTimelineVsyncId, android::os::IInputConstants::INVALID_INPUT_EVENT_ID});
}

static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlong transactionObj,
                                                  jobject transactionCommittedListenerObject) {
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);

    void* context =
            new TransactionCommittedListenerWrapper(env, transactionCommittedListenerObject);
    transaction->addTransactionCommittedCallback(TransactionCommittedListenerWrapper::
                                                         transactionCallbackThunk,
                                                 context);
}

class JankDataListenerWrapper : public JankDataListener {
public:
    JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) {
@@ -2027,6 +2081,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
            (void*)nativeGetLayerId },
    {"nativeSetDropInputMode", "(JJI)V",
             (void*)nativeSetDropInputMode },
    {"nativeAddTransactionCommittedListener", "(JLandroid/view/TransactionCommittedListener;)V",
            (void*) nativeAddTransactionCommittedListener },
        // clang-format on
};

@@ -2242,6 +2298,14 @@ int register_android_view_SurfaceControl(JNIEnv* env)
    gJankDataListenerClassInfo.onJankDataAvailable =
            GetMethodIDOrDie(env, onJankDataListenerClazz, "onJankDataAvailable",
                             "([Landroid/view/SurfaceControl$JankData;)V");

    jclass transactionCommittedListenerClazz =
            FindClassOrDie(env, "android/view/TransactionCommittedListener");
    gTransactionCommittedListenerClassInfo.clazz =
            MakeGlobalRefOrDie(env, transactionCommittedListenerClazz);
    gTransactionCommittedListenerClassInfo.onTransactionCommitted =
            GetMethodIDOrDie(env, transactionCommittedListenerClazz, "onTransactionCommitted",
                             "()V");
    return err;
}