Merge changes I223071a2,I7dfe648c into main

* changes:
  Print Motion/KeyEvent's eventId as a hex string
  Increase the test timeout used when waiting for events to be traced
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index d97ba89..37f41be 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -16,44 +16,83 @@
 
 #pragma once
 
+#include <condition_variable>
 #include <chrono>
-#include <future>
+#include <functional>
+#include <mutex>
+#include <thread>
 
 #include <hidl/Status.h>
-#include <utils/Errors.h>
 
 namespace android {
 namespace lshal {
 
-// Call function on interfaceObject and wait for result until the given timeout has reached.
-// Callback functions pass to timeoutIPC() may be executed after the this function
-// has returned, especially if deadline has been reached. Hence, care must be taken when passing
-// data between the background thread and the main thread. See b/311143089.
+class BackgroundTaskState {
+public:
+    explicit BackgroundTaskState(std::function<void(void)> &&func)
+            : mFunc(std::forward<decltype(func)>(func)) {}
+    void notify() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mFinished = true;
+        lock.unlock();
+        mCondVar.notify_all();
+    }
+    template<class C, class D>
+    bool wait(std::chrono::time_point<C, D> end) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
+        return mFinished;
+    }
+    void operator()() {
+        mFunc();
+    }
+private:
+    std::mutex mMutex;
+    std::condition_variable mCondVar;
+    bool mFinished = false;
+    std::function<void(void)> mFunc;
+};
+
+void *callAndNotify(void *data) {
+    BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
+    state();
+    state.notify();
+    return nullptr;
+}
+
+template<class R, class P>
+bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
+    auto now = std::chrono::system_clock::now();
+    BackgroundTaskState state{std::forward<decltype(func)>(func)};
+    pthread_t thread;
+    if (pthread_create(&thread, nullptr, callAndNotify, &state)) {
+        std::cerr << "FATAL: could not create background thread." << std::endl;
+        return false;
+    }
+    bool success = state.wait(now + delay);
+    if (!success) {
+        pthread_kill(thread, SIGINT);
+    }
+    pthread_join(thread, nullptr);
+    return success;
+}
+
 template<class R, class P, class Function, class I, class... Args>
 typename std::invoke_result<Function, I *, Args...>::type
 timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Function &&func,
            Args &&... args) {
     using ::android::hardware::Status;
-
-    // Execute on a background thread but do not defer execution.
-    auto future =
-            std::async(std::launch::async, func, interfaceObject, std::forward<Args>(args)...);
-    auto status = future.wait_for(wait);
-    if (status == std::future_status::ready) {
-        return future.get();
-    }
-
-    // This future belongs to a background thread that we no longer care about.
-    // Putting this in the global list avoids std::future::~future() that may wait for the
-    // result to come back.
-    // This leaks memory, but lshal is a debugging tool, so this is fine.
-    static std::vector<decltype(future)> gDeadPool{};
-    gDeadPool.emplace_back(std::move(future));
-
-    if (status == std::future_status::timeout) {
+    typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
+    auto boundFunc = std::bind(std::forward<Function>(func),
+            interfaceObject.get(), std::forward<Args>(args)...);
+    bool success = timeout(wait, [&ret, &boundFunc] {
+        ret = std::move(boundFunc());
+    });
+    if (!success) {
         return Status::fromStatusT(TIMED_OUT);
     }
-    return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE, "Illegal future_status");
+    return ret;
 }
-} // namespace lshal
-} // namespace android
+
+}  // namespace lshal
+}  // namespace android
diff --git a/cmds/lshal/main.cpp b/cmds/lshal/main.cpp
index bd5fa32..366c938 100644
--- a/cmds/lshal/main.cpp
+++ b/cmds/lshal/main.cpp
@@ -18,6 +18,5 @@
 
 int main(int argc, char **argv) {
     using namespace ::android::lshal;
-    // Use _exit() to force terminate background threads in Timeout.h
-    _exit(Lshal{}.main(Arg{argc, argv}));
+    return Lshal{}.main(Arg{argc, argv});
 }
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index c24f827..cba7c4b 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-#include <chrono>
-#include <future>
-#include <mutex>
-#include "android/hidl/base/1.0/IBase.h"
 #define LOG_TAG "Lshal"
 #include <android-base/logging.h>
 
@@ -40,8 +36,6 @@
 
 using namespace testing;
 
-using std::chrono_literals::operator""ms;
-
 using ::android::hidl::base::V1_0::DebugInfo;
 using ::android::hidl::base::V1_0::IBase;
 using ::android::hidl::manager::V1_0::IServiceManager;
@@ -940,9 +934,12 @@
         return hardware::Void();
     }));
     EXPECT_CALL(*serviceManager, get(_, _))
-            .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> {
-                return sp<IBase>(service);
-            }));
+            .WillRepeatedly(
+                    Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
+                        int id = getIdFromInstanceName(instance);
+                        if (id > inheritanceLevel) return nullptr;
+                        return sp<IBase>(service);
+                    }));
 
     const std::string expected = "[fake description 0]\n"
                                  "Interface\n"
@@ -960,110 +957,6 @@
     EXPECT_EQ("", err.str());
 }
 
-// In SlowService, everything goes slooooooow. Each IPC call will wait for
-// the specified time before calling the callback function or returning.
-class SlowService : public IBase {
-public:
-    explicit SlowService(std::chrono::milliseconds wait) : mWait(wait) {}
-    android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
-        std::this_thread::sleep_for(mWait);
-        cb(getInterfaceName(1));
-        storeHistory("interfaceDescriptor");
-        return hardware::Void();
-    }
-    android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
-        std::this_thread::sleep_for(mWait);
-        std::vector<hidl_string> ret;
-        ret.push_back(getInterfaceName(1));
-        ret.push_back(IBase::descriptor);
-        cb(ret);
-        storeHistory("interfaceChain");
-        return hardware::Void();
-    }
-    android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
-        std::this_thread::sleep_for(mWait);
-        std::vector<hidl_hash> ret;
-        ret.push_back(getHashFromId(0));
-        ret.push_back(getHashFromId(0xff));
-        cb(ret);
-        storeHistory("getHashChain");
-        return hardware::Void();
-    }
-    android::hardware::Return<void> debug(const hidl_handle&,
-                                          const hidl_vec<hidl_string>&) override {
-        std::this_thread::sleep_for(mWait);
-        storeHistory("debug");
-        return Void();
-    }
-
-    template <class R, class P, class Pred>
-    bool waitForHistory(std::chrono::duration<R, P> wait, Pred predicate) {
-        std::unique_lock<std::mutex> lock(mLock);
-        return mCv.wait_for(lock, wait, [&]() { return predicate(mCallHistory); });
-    }
-
-private:
-    void storeHistory(std::string hist) {
-        {
-            std::lock_guard<std::mutex> lock(mLock);
-            mCallHistory.emplace_back(std::move(hist));
-        }
-        mCv.notify_all();
-    }
-
-    const std::chrono::milliseconds mWait;
-    std::mutex mLock;
-    std::condition_variable mCv;
-    // List of functions that have finished being called on this interface.
-    std::vector<std::string> mCallHistory;
-};
-
-class TimeoutTest : public ListTest {
-public:
-    void setMockServiceManager(sp<IBase> service) {
-        EXPECT_CALL(*serviceManager, list(_))
-                .WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
-                    std::vector<hidl_string> ret;
-                    ret.push_back(getInterfaceName(1) + "/default");
-                    cb(ret);
-                    return hardware::Void();
-                }));
-        EXPECT_CALL(*serviceManager, get(_, _))
-                .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> {
-                    return service;
-                }));
-    }
-};
-
-TEST_F(TimeoutTest, BackgroundThreadIsKept) {
-    auto lshalIpcTimeout = 100ms;
-    auto serviceIpcTimeout = 200ms;
-    lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout);
-    sp<SlowService> service = new SlowService(serviceIpcTimeout);
-    setMockServiceManager(service);
-
-    optind = 1; // mimic Lshal::parseArg()
-    EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"})));
-    EXPECT_THAT(err.str(), HasSubstr("Skipping \"a.h.foo1@1.0::IFoo/default\""));
-    EXPECT_TRUE(service->waitForHistory(serviceIpcTimeout * 5, [](const auto& hist) {
-        return hist.size() == 1 && hist[0] == "interfaceChain";
-    })) << "The background thread should continue after the main thread moves on, but it is killed";
-}
-
-TEST_F(TimeoutTest, BackgroundThreadDoesNotBlockMainThread) {
-    auto lshalIpcTimeout = 100ms;
-    auto serviceIpcTimeout = 2000ms;
-    auto start = std::chrono::system_clock::now();
-    lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout);
-    sp<SlowService> service = new SlowService(serviceIpcTimeout);
-    setMockServiceManager(service);
-
-    optind = 1; // mimic Lshal::parseArg()
-    EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"})));
-    EXPECT_LE(std::chrono::system_clock::now(), start + 5 * lshalIpcTimeout)
-            << "The main thread should not be blocked by the background task";
-}
-
 class ListVintfTest : public ListTest {
 public:
     virtual void SetUp() override {
@@ -1186,6 +1079,5 @@
 
 int main(int argc, char **argv) {
     ::testing::InitGoogleMock(&argc, argv);
-    // Use _exit() to force terminate background threads in Timeout.h
-    _exit(RUN_ALL_TESTS());
+    return RUN_ALL_TESTS();
 }
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 38fab9c..7564c26 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -199,7 +199,7 @@
     SAFE_PARCEL(output.writeParcelable, trustedPresentationListener);
     SAFE_PARCEL(output.writeFloat, currentHdrSdrRatio);
     SAFE_PARCEL(output.writeFloat, desiredHdrSdrRatio);
-    SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(cachingHint))
+    SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(cachingHint));
     return NO_ERROR;
 }
 
@@ -484,6 +484,12 @@
             flags &= ~eLayerIsDisplayDecoration;
             ALOGE("Stripped attempt to set LayerIsDisplayDecoration in sanitize");
         }
+        if ((mask & eCanOccludePresentation) &&
+            !(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            flags &= ~eCanOccludePresentation;
+            mask &= ~eCanOccludePresentation;
+            ALOGE("Stripped attempt to set eCanOccludePresentation in sanitize");
+        }
     }
 
     if (what & layer_state_t::eInputInfoChanged) {
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 95b2641..9429d2c 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -109,7 +109,8 @@
             info.inputConfig == inputConfig && info.displayId == displayId &&
             info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
             info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
-            info.layoutParamsFlags == layoutParamsFlags;
+            info.layoutParamsFlags == layoutParamsFlags &&
+            info.canOccludePresentation == canOccludePresentation;
 }
 
 status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -158,8 +159,9 @@
         parcel->write(touchableRegion) ?:
         parcel->writeBool(replaceTouchableRegionWithCrop) ?:
         parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
-        parcel->writeStrongBinder(windowToken);
-        parcel->writeStrongBinder(focusTransferTarget);
+        parcel->writeStrongBinder(windowToken) ?:
+        parcel->writeStrongBinder(focusTransferTarget) ?:
+        parcel->writeBool(canOccludePresentation);
     // clang-format on
     return status;
 }
@@ -210,7 +212,8 @@
         parcel->readBool(&replaceTouchableRegionWithCrop) ?:
         parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?:
         parcel->readNullableStrongBinder(&windowToken) ?:
-        parcel->readNullableStrongBinder(&focusTransferTarget);
+        parcel->readNullableStrongBinder(&focusTransferTarget) ?:
+        parcel->readBool(&canOccludePresentation);
 
     // clang-format on
 
@@ -273,6 +276,7 @@
         << "ms, token=" << info.token.get()
         << ", touchOcclusionMode=" << ftl::enum_string(info.touchOcclusionMode) << "\n"
         << transform;
+    if (info.canOccludePresentation) out << " canOccludePresentation";
     return out;
 }
 
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 6b8e824..920310e 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -161,6 +161,9 @@
         // See SurfaceView scaling behavior for more details.
         eIgnoreDestinationFrame = 0x400,
         eLayerIsRefreshRateIndicator = 0x800, // REFRESH_RATE_INDICATOR
+        // Sets a property on this layer indicating that its visible region should be considered
+        // when computing TrustedPresentation Thresholds.
+        eCanOccludePresentation = 0x1000,
     };
 
     enum {
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index e72fd59..32d60be 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -246,6 +246,10 @@
     // any other window.
     sp<IBinder> focusTransferTarget;
 
+    // Sets a property on this window indicating that its visible region should be considered when
+    // computing TrustedPresentation Thresholds.
+    bool canOccludePresentation = false;
+
     void setInputConfig(ftl::Flags<InputConfig> config, bool value);
 
     void addTouchableRegion(const Rect& region);
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 7fd9c3a..f73fa5d 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -22,8 +22,10 @@
 
 mkdir -p out/javax/microedition/khronos/opengles
 mkdir -p out/com/google/android/gles_jni
+mkdir -p out/android/annotation
 mkdir -p out/android/app
 mkdir -p out/android/graphics
+mkdir -p out/android/hardware
 mkdir -p out/android/view
 mkdir -p out/android/opengl
 mkdir -p out/android/content
@@ -34,18 +36,20 @@
 echo "package android.graphics;" > out/android/graphics/Canvas.java
 echo "public interface Canvas {}" >> out/android/graphics/Canvas.java
 
+echo "package android.annotation; public @interface NonNull {}" > out/android/annotation/NonNull.java
 echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java
 # echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java
 echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java
 echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags, java.lang.String userId) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java
-echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 3;};	}" > out/android/os/Build.java
+echo "package android.hardware; import android.os.ParcelFileDescriptor; public class SyncFence { public static SyncFence create(ParcelFileDescriptor w) { return null; } public static SyncFence createEmpty() { return null; } }" > out/android/hardware/SyncFence.java
+echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 0; public static final int R = 0; }; }" > out/android/os/Build.java
+echo "package android.os; public class ParcelFileDescriptor { public static ParcelFileDescriptor adoptFd(int fd) { return null; } }" > out/android/os/ParcelFileDescriptor.java
 echo "package android.os; public class UserHandle {public static String myUserId() { return \"\"; } }" > out/android/os/UserHandle.java
 echo "package android.os; public class RemoteException extends Exception {}" > out/android/os/RemoteException.java
-echo "package android.util; public class Log {public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java
+echo "package android.util; public class Log {public static void d(String a, String b) {} public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java
 
 echo "package android.opengl; public abstract class EGLObjectHandle { public int getHandle() { return 0; } }" > out/android/opengl/EGLObjectHandle.java
 
-
 echo "package android.graphics;" > out/android/graphics/SurfaceTexture.java
 echo "public interface SurfaceTexture {}" >> out/android/graphics/SurfaceTexture.java
 echo "package android.view;" > out/android/view/SurfaceView.java
diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
index 951ecff..695b571 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
@@ -20,6 +20,7 @@
 
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.SurfaceTexture;
+import android.os.Build;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index b2ea041..ea55179 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -17,6 +17,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
index 6dffac5..8e452fb 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
@@ -17,6 +17,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if
index 523bc57..75e1704 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if
@@ -18,6 +18,11 @@
 
 package android.opengl;
 
+import android.annotation.NonNull;
+import android.hardware.SyncFence;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
 /**
  * EGL Extensions
  */
@@ -30,8 +35,44 @@
     public static final int EGL_OPENGL_ES3_BIT_KHR          = 0x0040;
     public static final int EGL_RECORDABLE_ANDROID          = 0x3142;
 
+    // EGL_ANDROID_native_fence_sync
+    public static final int EGL_SYNC_NATIVE_FENCE_ANDROID     = 0x3144;
+    public static final int EGL_SYNC_NATIVE_FENCE_FD_ANDROID  = 0x3145;
+    public static final int EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID = 0x3146;
+    public static final int EGL_NO_NATIVE_FENCE_FD_ANDROID    = -1;
+
     native private static void _nativeClassInit();
     static {
         _nativeClassInit();
     }
 
+    /**
+     * Retrieves the SyncFence for an EGLSync created with EGL_SYNC_NATIVE_FENCE_ANDROID
+     *
+     * See <a href="https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_native_fence_sync.txt">
+     *     EGL_ANDROID_native_fence_sync</a> extension for more details
+     * @param display The EGLDisplay connection
+     * @param sync The EGLSync to fetch the SyncFence from
+     * @return A SyncFence representing the native fence.
+     *       * If <sync> is not a valid sync object for <display>,
+     *         an {@link SyncFence#isValid() invalid} SyncFence is returned and an EGL_BAD_PARAMETER
+     *         error is generated.
+     *       * If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of <sync> is
+     *         EGL_NO_NATIVE_FENCE_FD_ANDROID, an {@link SyncFence#isValid() invalid} SyncFence is
+     *         returned and an EGL_BAD_PARAMETER error is generated.
+     *       * If <display> does not match the display passed to eglCreateSync
+     *         when <sync> was created, the behaviour is undefined.
+     */
+    public static @NonNull SyncFence eglDupNativeFenceFDANDROID(@NonNull EGLDisplay display,
+            @NonNull EGLSync sync) {
+        int fd = eglDupNativeFenceFDANDROIDImpl(display, sync);
+        Log.d("EGL", "eglDupNativeFence returned " + fd);
+        if (fd >= 0) {
+            return SyncFence.create(ParcelFileDescriptor.adoptFd(fd));
+        } else {
+            return SyncFence.createEmpty();
+        }
+    }
+
+    private static native int eglDupNativeFenceFDANDROIDImpl(EGLDisplay display, EGLSync sync);
+
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index be8b3e3..f1f0ac5 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -17,6 +17,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
@@ -37,25 +38,12 @@
 #include <ui/ANativeObjectBase.h>
 
 static jclass egldisplayClass;
-static jclass eglcontextClass;
 static jclass eglsurfaceClass;
-static jclass eglconfigClass;
+static jclass eglsyncClass;
 
 static jmethodID egldisplayGetHandleID;
-static jmethodID eglcontextGetHandleID;
 static jmethodID eglsurfaceGetHandleID;
-static jmethodID eglconfigGetHandleID;
-
-static jmethodID egldisplayConstructor;
-static jmethodID eglcontextConstructor;
-static jmethodID eglsurfaceConstructor;
-static jmethodID eglconfigConstructor;
-
-static jobject eglNoContextObject;
-static jobject eglNoDisplayObject;
-static jobject eglNoSurfaceObject;
-
-
+static jmethodID eglsyncGetHandleID;
 
 /* Cache method IDs each time the class is loaded. */
 
@@ -64,37 +52,14 @@
 {
     jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
     egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal);
-    jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
-    eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal);
     jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
     eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal);
-    jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
-    eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
+    jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
+    eglsyncClass = (jclass) _env->NewGlobalRef(eglsyncClassLocal);
 
     egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
-    eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
     eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
-    eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
-
-
-    egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
-    eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
-    eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
-    eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
-
-
-    jclass eglClass = _env->FindClass("android/opengl/EGL14");
-    jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
-    jobject localeglNoContextObject = _env->GetStaticObjectField(eglClass, noContextFieldID);
-    eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
-
-    jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
-    jobject localeglNoDisplayObject = _env->GetStaticObjectField(eglClass, noDisplayFieldID);
-    eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
-
-    jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
-    jobject localeglNoSurfaceObject = _env->GetStaticObjectField(eglClass, noSurfaceFieldID);
-    eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
+    eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
 }
 
 static void *
@@ -108,24 +73,12 @@
     return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
 }
 
-static jobject
-toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) {
-    if (cls == eglcontextClass &&
-       (EGLContext)handle == EGL_NO_CONTEXT) {
-           return eglNoContextObject;
-    }
+// TODO: this should be generated from the .spec file, but needs to be renamed and made private
+static jint android_eglDupNativeFenceFDANDROID(JNIEnv *env, jobject, jobject dpy, jobject sync) {
+    EGLDisplay dpy_native = (EGLDisplay)fromEGLHandle(env, egldisplayGetHandleID, dpy);
+    EGLSync sync_native = (EGLSync)fromEGLHandle(env, eglsyncGetHandleID, sync);
 
-    if (cls == egldisplayClass &&
-       (EGLDisplay)handle == EGL_NO_DISPLAY) {
-           return eglNoDisplayObject;
-    }
-
-    if (cls == eglsurfaceClass &&
-       (EGLSurface)handle == EGL_NO_SURFACE) {
-           return eglNoSurfaceObject;
-    }
-
-    return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
+    return eglDupNativeFenceFDANDROID(dpy_native, sync_native);
 }
 
 // --------------------------------------------------------------------------
diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
index 85f743d..78b0819 100755
--- a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
+++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
@@ -7,7 +7,7 @@
     /**
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static native EGLDisplay eglGetDisplay(
         long display_id
     );
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
index dd17ca4..1fa9275 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
@@ -18,6 +18,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
index dd17ca4..1fa9275 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
@@ -18,6 +18,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
index dd17ca4..1fa9275 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
@@ -18,6 +18,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
index dd17ca4..1fa9275 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
@@ -18,6 +18,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
index b2bbdf6..4004a7d 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
@@ -18,6 +18,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES2/gl2.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
index b039bc9..c5bdf32 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
@@ -18,6 +18,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES3/gl3.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
index dd00e92..2260a80 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
@@ -17,6 +17,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES3/gl31.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
index 88e00be..130612d 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
@@ -17,6 +17,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <stdint.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
index 3e7ec8b..5446fc2 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
@@ -17,6 +17,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <stdint.h>
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 9cab1d6..c3534bf 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -17,6 +17,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 38974a2..3ef9e69 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -315,6 +315,7 @@
     if (obj.hasInputInfo()) {
         out << "\n    input{"
             << "(" << obj.inputInfo.inputConfig.string() << ")";
+        if (obj.inputInfo.canOccludePresentation) out << " canOccludePresentation";
         if (obj.touchCropId != UNASSIGNED_LAYER_ID) out << " touchCropId=" << obj.touchCropId;
         if (obj.inputInfo.replaceTouchableRegionWithCrop) out << " replaceTouchableRegionWithCrop";
         auto touchableRegion = obj.inputInfo.touchableRegion.getBounds();
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 8df5d8c..0966fe0 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -1044,6 +1044,8 @@
     snapshot.inputInfo.touchOcclusionMode = requested.hasInputInfo()
             ? requested.windowInfoHandle->getInfo()->touchOcclusionMode
             : parentSnapshot.inputInfo.touchOcclusionMode;
+    snapshot.inputInfo.canOccludePresentation = parentSnapshot.inputInfo.canOccludePresentation ||
+            (requested.flags & layer_state_t::eCanOccludePresentation);
     if (requested.dropInputMode == gui::DropInputMode::ALL ||
         parentSnapshot.dropInputMode == gui::DropInputMode::ALL) {
         snapshot.dropInputMode = gui::DropInputMode::ALL;
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 209df79..2cf4c1b 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -170,6 +170,9 @@
         if ((oldFlags ^ flags) & layer_state_t::eIgnoreDestinationFrame) {
             changes |= RequestedLayerState::Changes::Geometry;
         }
+        if ((oldFlags ^ flags) & layer_state_t::eCanOccludePresentation) {
+            changes |= RequestedLayerState::Changes::Input;
+        }
     }
 
     if (clientState.what & layer_state_t::eBufferChanged) {
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 13b47ff..3baa48d 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1237,4 +1237,25 @@
     EXPECT_TRUE(foundInputLayer);
 }
 
+TEST_F(LayerSnapshotTest, canOccludePresentation) {
+    setFlags(12, layer_state_t::eCanOccludePresentation, layer_state_t::eCanOccludePresentation);
+    LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
+                                    .layerLifecycleManager = mLifecycleManager,
+                                    .includeMetadata = false,
+                                    .displays = mFrontEndDisplayInfos,
+                                    .displayChanges = false,
+                                    .globalShadowSettings = globalShadowSettings,
+                                    .supportsBlur = true,
+                                    .supportedLayerGenericMetadata = {},
+                                    .genericLayerMetadataKeyMap = {}};
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+    EXPECT_EQ(getSnapshot(1)->inputInfo.canOccludePresentation, false);
+
+    // ensure we can set the property on the window info for layer and all its children
+    EXPECT_EQ(getSnapshot(12)->inputInfo.canOccludePresentation, true);
+    EXPECT_EQ(getSnapshot(121)->inputInfo.canOccludePresentation, true);
+    EXPECT_EQ(getSnapshot(1221)->inputInfo.canOccludePresentation, true);
+}
+
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
index 93c2829..19f8deb 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
@@ -17,11 +17,15 @@
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 
+#include <com_android_graphics_surfaceflinger_flags.h>
+#include <common/test/FlagUtils.h>
 #include "DualDisplayTransactionTest.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+using namespace com::android::graphics::surfaceflinger;
+
 namespace android {
 namespace {
 
@@ -163,6 +167,7 @@
 }
 
 TEST_F(FoldableTest, requestVsyncOnPowerOn) {
+    SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
     EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
             .Times(1);
     EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
@@ -173,6 +178,7 @@
 }
 
 TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) {
+    SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
     // When the device boots, the inner display should be the pacesetter.
     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
 
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 15fe600..83e2f98 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -17,11 +17,15 @@
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 
+#include <com_android_graphics_surfaceflinger_flags.h>
+#include <common/test/FlagUtils.h>
 #include "DisplayTransactionTestHelpers.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+using namespace com::android::graphics::surfaceflinger;
+
 namespace android {
 namespace {
 
@@ -453,6 +457,7 @@
 }
 
 TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) {
+    SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
     transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>();
 }
 
@@ -461,6 +466,7 @@
 }
 
 TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) {
+    SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
     transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>();
 }
 
@@ -473,6 +479,7 @@
 }
 
 TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
+    SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
     transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
 }
 
@@ -481,10 +488,12 @@
 }
 
 TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
+    SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
     transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
 }
 
 TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
+    SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
     transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
 }