Merge "Add logging for gesture monitors" into sc-dev
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index e13d4cc..4580751 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -95,4 +95,52 @@
  */
 bool AServiceManager_isDeclared(const char* instance) __INTRODUCED_IN(31);
 
+/**
+ * Prevent lazy services without client from shutting down their process
+ *
+ * \param persist 'true' if the process should not exit.
+ */
+void AServiceManager_forceLazyServicesPersist(bool persist) __INTRODUCED_IN(31);
+
+/**
+ * Set a callback that is invoked when the active service count (i.e. services with clients)
+ * registered with this process drops to zero (or becomes nonzero).
+ * The callback takes a boolean argument, which is 'true' if there is
+ * at least one service with clients.
+ *
+ * \param callback function to call when the number of services
+ *    with clients changes.
+ * \param context opaque pointer passed back as second parameter to the
+ * callback.
+ *
+ * The callback takes two arguments. The first is a boolean that represents if there are
+ * services with clients (true) or not (false).
+ * The second is the 'context' pointer passed during the registration.
+ *
+ * Callback return value:
+ * - false: Default behavior for lazy services (shut down the process if there
+ *          are no clients).
+ * - true:  Don't shut down the process even if there are no clients.
+ *
+ * This callback gives a chance to:
+ * 1 - Perform some additional operations before exiting;
+ * 2 - Prevent the process from exiting by returning "true" from the callback.
+ */
+void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context)
+        __INTRODUCED_IN(31);
+
+/**
+ * Try to unregister all services previously registered with 'registerService'.
+ *
+ * \return true on success.
+ */
+bool AServiceManager_tryUnregister() __INTRODUCED_IN(31);
+
+/**
+ * Re-register services that were unregistered by 'tryUnregister'.
+ * This method should be called in the case 'tryUnregister' fails
+ * (and should be called on the same thread).
+ */
+void AServiceManager_reRegister() __INTRODUCED_IN(31);
+
 __END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 9a93bf3..cef0bf3 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -120,6 +120,10 @@
     AServiceManager_isDeclared; # apex llndk
     AServiceManager_registerLazyService; # llndk
     AServiceManager_waitForService; # apex llndk
+    AServiceManager_forceLazyServicesPersist; # llndk
+    AServiceManager_setActiveServicesCallback; # llndk
+    AServiceManager_tryUnregister; # llndk
+    AServiceManager_reRegister; # llndk
 
     AIBinder_Class_getDescriptor;
     AIBinder_Weak_clone;
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index c782d47..cb0987e 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -92,3 +92,22 @@
     sp<IServiceManager> sm = defaultServiceManager();
     return sm->isDeclared(String16(instance));
 }
+void AServiceManager_forceLazyServicesPersist(bool persist) {
+    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+    serviceRegistrar.forcePersist(persist);
+}
+void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context) {
+    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+    std::function<bool(bool)> fn = [=](bool hasClients) -> bool {
+        return callback(hasClients, context);
+    };
+    serviceRegistrar.setActiveServicesCallback(fn);
+}
+bool AServiceManager_tryUnregister() {
+    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+    return serviceRegistrar.tryUnregister();
+}
+void AServiceManager_reRegister() {
+    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+    serviceRegistrar.reRegister();
+}
\ No newline at end of file
diff --git a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
index dc77467d..ecbd649 100644
--- a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
+++ b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
@@ -28,4 +28,7 @@
     void forceFlushCommands();
 
     boolean getsRequestedSid();
+
+    void forcePersist(boolean persist);
+    void setCustomActiveServicesCallback();
 }
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 0d1989e..de1a48d 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -46,6 +46,11 @@
 constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
 constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
 constexpr char kLazyBinderNdkUnitTestService[] = "LazyBinderNdkUnitTest";
+constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestService";
+constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService";
+
+constexpr unsigned int kShutdownWaitTime = 10;
+constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715;
 
 class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
     ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
@@ -76,6 +81,46 @@
         fsync(out);
         return STATUS_OK;
     }
+    ndk::ScopedAStatus forcePersist(bool persist) {
+        AServiceManager_forceLazyServicesPersist(persist);
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus setCustomActiveServicesCallback() {
+        AServiceManager_setActiveServicesCallback(activeServicesCallback, this);
+        return ndk::ScopedAStatus::ok();
+    }
+    static bool activeServicesCallback(bool hasClients, void* context) {
+        if (hasClients) {
+            return false;
+        }
+
+        // Unregister all services
+        if (!AServiceManager_tryUnregister()) {
+            // Prevent shutdown (test will fail)
+            return false;
+        }
+
+        // Re-register all services
+        AServiceManager_reRegister();
+
+        // Unregister again before shutdown
+        if (!AServiceManager_tryUnregister()) {
+            // Prevent shutdown (test will fail)
+            return false;
+        }
+
+        // Check if the context was passed correctly
+        MyBinderNdkUnitTest* service = static_cast<MyBinderNdkUnitTest*>(context);
+        if (service->contextTestValue != kContextTestValue) {
+            // Prevent shutdown (test will fail)
+            return false;
+        }
+
+        exit(EXIT_SUCCESS);
+        // Unreachable
+    }
+
+    uint64_t contextTestValue = kContextTestValue;
 };
 
 int generatedService() {
@@ -168,6 +213,16 @@
     return 1;  // should not return
 }
 
+bool isServiceRunning(const char* serviceName) {
+    AIBinder* binder = AServiceManager_checkService(serviceName);
+    if (binder == nullptr) {
+        return false;
+    }
+    AIBinder_decStrong(binder);
+
+    return true;
+}
+
 TEST(NdkBinder, GetServiceThatDoesntExist) {
     sp<IFoo> foo = IFoo::getService("asdfghkl;");
     EXPECT_EQ(nullptr, foo.get());
@@ -238,10 +293,51 @@
     service = nullptr;
     IPCThreadState::self()->flushCommands();
     // Make sure the service is dead after some time of no use
-    sleep(10);
+    sleep(kShutdownWaitTime);
     ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService));
 }
 
+TEST(NdkBinder, ForcedPersistenceTest) {
+    for (int i = 0; i < 2; i++) {
+        ndk::SpAIBinder binder(AServiceManager_waitForService(kForcePersistNdkUnitTestService));
+        std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+                aidl::IBinderNdkUnitTest::fromBinder(binder);
+        ASSERT_NE(service, nullptr);
+        ASSERT_TRUE(service->forcePersist(i == 0).isOk());
+
+        binder = nullptr;
+        service = nullptr;
+        IPCThreadState::self()->flushCommands();
+
+        sleep(kShutdownWaitTime);
+
+        bool isRunning = isServiceRunning(kForcePersistNdkUnitTestService);
+
+        if (i == 0) {
+            ASSERT_TRUE(isRunning) << "Service shut down when it shouldn't have.";
+        } else {
+            ASSERT_FALSE(isRunning) << "Service failed to shut down.";
+        }
+    }
+}
+
+TEST(NdkBinder, ActiveServicesCallbackTest) {
+    ndk::SpAIBinder binder(AServiceManager_waitForService(kActiveServicesNdkUnitTestService));
+    std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+            aidl::IBinderNdkUnitTest::fromBinder(binder);
+    ASSERT_NE(service, nullptr);
+    ASSERT_TRUE(service->setCustomActiveServicesCallback().isOk());
+
+    binder = nullptr;
+    service = nullptr;
+    IPCThreadState::self()->flushCommands();
+
+    sleep(kShutdownWaitTime);
+
+    ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService))
+            << "Service failed to shut down.";
+}
+
 void LambdaOnDeath(void* cookie) {
     auto onDeath = static_cast<std::function<void(void)>*>(cookie);
     (*onDeath)();
@@ -564,10 +660,18 @@
     }
     if (fork() == 0) {
         prctl(PR_SET_PDEATHSIG, SIGHUP);
+        return lazyService(kForcePersistNdkUnitTestService);
+    }
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+        return lazyService(kActiveServicesNdkUnitTestService);
+    }
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
         return generatedService();
     }
 
-    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to recieve death notifications/callbacks
+    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to receive death notifications/callbacks
     ABinderProcess_startThreadPool();
 
     return RUN_ALL_TESTS();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index dc14fc2..55ec6ad 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -518,7 +518,7 @@
 }
 
 void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
-    if (mCapture->isCaptureRunning()) {
+    if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
         // Record display settings when capture is running.
         std::stringstream displaySettings;
         PrintTo(display, &displaySettings);
@@ -626,6 +626,7 @@
     // offscreen buffer and when to render to the native buffer.
     sk_sp<SkSurface> activeSurface(dstSurface);
     SkCanvas* canvas = dstCanvas;
+    SkiaCapture::OffscreenState offscreenCaptureState;
     const LayerSettings* blurCompositionLayer = nullptr;
     if (mBlurFilter) {
         bool requiresCompositionLayer = false;
@@ -642,7 +643,7 @@
             }
             if (requiresCompositionLayer) {
                 activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
-                canvas = activeSurface->getCanvas();
+                canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
                 blurCompositionLayer = layer;
                 break;
             }
@@ -692,7 +693,15 @@
             //  blit the offscreen framebuffer into the destination AHB
             SkPaint paint;
             paint.setBlendMode(SkBlendMode::kSrc);
-            activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+            if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+                uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
+                dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
+                                          String8::format("SurfaceID|%" PRId64, id).c_str(),
+                                          nullptr);
+                dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
+            } else {
+                activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+            }
 
             // assign dstCanvas to canvas and ensure that the canvas state is up to date
             canvas = dstCanvas;
@@ -709,7 +718,7 @@
         }
 
         canvas->save();
-        if (mCapture->isCaptureRunning()) {
+        if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
             // Record the name of the layer if the capture is running.
             std::stringstream layerSettings;
             PrintTo(*layer, &layerSettings);
diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
index e9cfead..40f5cf2 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.cpp
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -41,11 +41,11 @@
     mTimer.stop();
 }
 
-SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) {
+SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) NO_THREAD_SAFETY_ANALYSIS {
     ATRACE_CALL();
 
     // If we are not running yet, set up.
-    if (!mCaptureRunning) {
+    if (CC_LIKELY(!mCaptureRunning)) {
         mTimerInterval = std::chrono::milliseconds(
                 base::GetIntProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS, 0));
         // Set up the multi-frame capture. If we fail to set it up, then just return canvas.
@@ -56,7 +56,8 @@
         // Start the new timer. When timer expires, write to file.
         mTimer.setTimeout(
                 [this] {
-                    endCapture();
+                    const std::scoped_lock lock(mMutex);
+                    LOG_ALWAYS_FATAL_IF(mCurrentPageCanvas != nullptr);
                     writeToFile();
                     // To avoid going in circles, set the flag to 0. This way the capture can be
                     // restarted just by setting the flag and without restarting the process.
@@ -65,29 +66,82 @@
                 mTimerInterval);
     }
 
+    mMutex.lock();
+
     // Create a canvas pointer, fill it.
-    SkCanvas* pictureCanvas = mMultiPic->beginPage(surface->width(), surface->height());
+    mCurrentPageCanvas = mMultiPic->beginPage(surface->width(), surface->height());
 
     // Setting up an nway canvas is common to any kind of capture.
     mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
     mNwayCanvas->addCanvas(surface->getCanvas());
-    mNwayCanvas->addCanvas(pictureCanvas);
+    mNwayCanvas->addCanvas(mCurrentPageCanvas);
 
     return mNwayCanvas.get();
 }
 
-void SkiaCapture::endCapture() {
+void SkiaCapture::endCapture() NO_THREAD_SAFETY_ANALYSIS {
     ATRACE_CALL();
     // Don't end anything if we are not running.
-    if (!mCaptureRunning) {
+    if (CC_LIKELY(!mCaptureRunning)) {
         return;
     }
     // Reset the canvas pointer.
+    mCurrentPageCanvas = nullptr;
     mNwayCanvas.reset();
     // End page.
     if (mMultiPic) {
         mMultiPic->endPage();
     }
+    mMutex.unlock();
+}
+
+SkCanvas* SkiaCapture::tryOffscreenCapture(SkSurface* surface, OffscreenState* state) {
+    ATRACE_CALL();
+    // Don't start anything if we are not running.
+    if (CC_LIKELY(!mCaptureRunning)) {
+        return surface->getCanvas();
+    }
+
+    // Create a canvas pointer, fill it.
+    state->offscreenRecorder = std::make_unique<SkPictureRecorder>();
+    SkCanvas* pictureCanvas =
+            state->offscreenRecorder->beginRecording(surface->width(), surface->height());
+
+    // Setting up an nway canvas is common to any kind of capture.
+    state->offscreenCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+    state->offscreenCanvas->addCanvas(surface->getCanvas());
+    state->offscreenCanvas->addCanvas(pictureCanvas);
+
+    return state->offscreenCanvas.get();
+}
+
+uint64_t SkiaCapture::endOffscreenCapture(OffscreenState* state) {
+    ATRACE_CALL();
+    // Don't end anything if we are not running.
+    if (CC_LIKELY(!mCaptureRunning)) {
+        return 0;
+    }
+
+    // compute the uniqueID for this capture
+    static std::atomic<uint64_t> nextID{1};
+    const uint64_t uniqueID = nextID.fetch_add(1, std::memory_order_relaxed);
+
+    // Reset the canvas pointer as we are no longer drawing into it
+    state->offscreenCanvas.reset();
+
+    // Record the offscreen as a picture in the currently active page.
+    SkRect bounds =
+            SkRect::Make(state->offscreenRecorder->getRecordingCanvas()->imageInfo().dimensions());
+    mCurrentPageCanvas
+            ->drawAnnotation(bounds,
+                             String8::format("OffscreenLayerDraw|%" PRId64, uniqueID).c_str(),
+                             nullptr);
+    mCurrentPageCanvas->drawPicture(state->offscreenRecorder->finishRecordingAsPicture());
+
+    // Reset the offscreen picture recorder
+    state->offscreenRecorder.reset();
+
+    return uniqueID;
 }
 
 void SkiaCapture::writeToFile() {
diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h
index eaaf598..08a1359 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.h
+++ b/libs/renderengine/skia/debug/SkiaCapture.h
@@ -18,8 +18,12 @@
 
 #include <SkDocument.h>
 #include <SkNWayCanvas.h>
+#include <SkPictureRecorder.h>
 #include <SkSurface.h>
+
 #include <chrono>
+#include <mutex>
+
 #include "CaptureTimer.h"
 #include "tools/SkSharingProc.h"
 
@@ -48,6 +52,16 @@
     // Returns whether the capture is running.
     bool isCaptureRunning() { return mCaptureRunning; }
 
+    // Offscreen state member variables are private to SkiaCapture, but the allocation
+    // and lifetime is managed by the caller. This enables nested offscreen
+    // captures to occur.
+    struct OffscreenState {
+        std::unique_ptr<SkPictureRecorder> offscreenRecorder;
+        std::unique_ptr<SkNWayCanvas> offscreenCanvas;
+    };
+    SkCanvas* tryOffscreenCapture(SkSurface* surface, OffscreenState* state);
+    uint64_t endOffscreenCapture(OffscreenState* state);
+
 private:
     // Performs the first-frame work of a multi frame SKP capture. Returns true if successful.
     bool setupMultiFrameCapture();
@@ -61,10 +75,16 @@
     std::unique_ptr<SkSharingSerialContext> mSerialContext;
     std::unique_ptr<SkNWayCanvas> mNwayCanvas;
 
+    SkCanvas* mCurrentPageCanvas;
+
     // Capturing and interval control.
     bool mCaptureRunning = false;
     CaptureTimer mTimer;
     Interval mTimerInterval = 0ms;
+
+    // Mutex to ensure that a frame in progress when the timer fires is allowed to run to
+    // completion before we write the file to disk.
+    std::mutex mMutex;
 };
 
 } // namespace skia
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 01945db..f440f59 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -31,6 +31,7 @@
 using android::base::StringPrintf;
 using android::os::InputEventInjectionResult;
 using android::os::InputEventInjectionSync;
+using android::os::TouchOcclusionMode;
 using namespace android::flag_operators;
 
 namespace android::inputdispatcher {
@@ -727,8 +728,9 @@
         ASSERT_EQ(OK, status) << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
     }
 
-    void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
-                      int32_t expectedFlags) {
+    void consumeEvent(int32_t expectedEventType, int32_t expectedAction,
+                      std::optional<int32_t> expectedDisplayId,
+                      std::optional<int32_t> expectedFlags) {
         InputEvent* event = consume();
 
         ASSERT_NE(nullptr, event) << mName.c_str()
@@ -737,19 +739,25 @@
                 << mName.c_str() << " expected " << inputEventTypeToString(expectedEventType)
                 << " event, got " << inputEventTypeToString(event->getType()) << " event";
 
-        EXPECT_EQ(expectedDisplayId, event->getDisplayId());
+        if (expectedDisplayId.has_value()) {
+            EXPECT_EQ(expectedDisplayId, event->getDisplayId());
+        }
 
         switch (expectedEventType) {
             case AINPUT_EVENT_TYPE_KEY: {
                 const KeyEvent& keyEvent = static_cast<const KeyEvent&>(*event);
                 EXPECT_EQ(expectedAction, keyEvent.getAction());
-                EXPECT_EQ(expectedFlags, keyEvent.getFlags());
+                if (expectedFlags.has_value()) {
+                    EXPECT_EQ(expectedFlags.value(), keyEvent.getFlags());
+                }
                 break;
             }
             case AINPUT_EVENT_TYPE_MOTION: {
                 const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
                 EXPECT_EQ(expectedAction, motionEvent.getAction());
-                EXPECT_EQ(expectedFlags, motionEvent.getFlags());
+                if (expectedFlags.has_value()) {
+                    EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags());
+                }
                 break;
             }
             case AINPUT_EVENT_TYPE_FOCUS: {
@@ -854,6 +862,7 @@
         mInfo.name = name;
         mInfo.type = InputWindowInfo::Type::APPLICATION;
         mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+        mInfo.alpha = 1.0;
         mInfo.frameLeft = 0;
         mInfo.frameTop = 0;
         mInfo.frameRight = WIDTH;
@@ -883,6 +892,12 @@
 
     void setPaused(bool paused) { mInfo.paused = paused; }
 
+    void setAlpha(float alpha) { mInfo.alpha = alpha; }
+
+    void setTouchOcclusionMode(android::os::TouchOcclusionMode mode) {
+        mInfo.touchOcclusionMode = mode;
+    }
+
     void setFrame(const Rect& frame) {
         mInfo.frameLeft = frame.left;
         mInfo.frameTop = frame.top;
@@ -928,6 +943,11 @@
 
     void consumeMotionDown(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
                            int32_t expectedFlags = 0) {
+        consumeAnyMotionDown(expectedDisplayId, expectedFlags);
+    }
+
+    void consumeAnyMotionDown(std::optional<int32_t> expectedDisplayId = std::nullopt,
+                              std::optional<int32_t> expectedFlags = std::nullopt) {
         consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId,
                      expectedFlags);
     }
@@ -971,8 +991,9 @@
         mInputReceiver->consumeCaptureEvent(hasCapture);
     }
 
-    void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
-                      int32_t expectedFlags) {
+    void consumeEvent(int32_t expectedEventType, int32_t expectedAction,
+                      std::optional<int32_t> expectedDisplayId,
+                      std::optional<int32_t> expectedFlags) {
         ASSERT_NE(mInputReceiver, nullptr) << "Invalid consume event on window with no receiver";
         mInputReceiver->consumeEvent(expectedEventType, expectedAction, expectedDisplayId,
                                      expectedFlags);
@@ -4240,4 +4261,183 @@
     mSecondWindow->consumeCaptureEvent(true);
 }
 
+class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
+protected:
+    constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
+    static const int32_t APP_A_UID = 10001;
+    static const int32_t APP_B_UID = 10002;
+    static const int32_t APP_C_UID = 10003;
+
+    sp<FakeWindowHandle> mTouchWindow;
+
+    virtual void SetUp() override {
+        InputDispatcherTest::SetUp();
+        mTouchWindow = getWindow(APP_A_UID, "Touched");
+        mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK);
+        mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
+    }
+
+    virtual void TearDown() override {
+        InputDispatcherTest::TearDown();
+        mTouchWindow.clear();
+    }
+
+    sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name,
+                                            os::TouchOcclusionMode mode, float alpha = 1.0f) {
+        sp<FakeWindowHandle> window = getWindow(uid, name);
+        window->setFlags(InputWindowInfo::Flag::NOT_TOUCHABLE);
+        window->setTouchOcclusionMode(mode);
+        window->setAlpha(alpha);
+        return window;
+    }
+
+    sp<FakeWindowHandle> getWindow(int32_t uid, std::string name) {
+        std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
+        sp<FakeWindowHandle> window =
+                new FakeWindowHandle(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
+        // Generate an arbitrary PID based on the UID
+        window->setOwnerInfo(1777 + (uid % 10000), uid);
+        return window;
+    }
+
+    void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
+        NotifyMotionArgs args =
+                generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                                   ADISPLAY_ID_DEFAULT, points);
+        mDispatcher->notifyMotion(&args);
+    }
+};
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
+    const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
+    w->setFrame(Rect(0, 0, 50, 50));
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch({PointF{100, 100}});
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_A_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               MAXIMUM_OBSCURING_OPACITY);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
+    // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
+    const sp<FakeWindowHandle>& w1 =
+            getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    const sp<FakeWindowHandle>& w2 =
+            getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
+    // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
+    const sp<FakeWindowHandle>& w1 =
+            getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, 0.5f);
+    const sp<FakeWindowHandle>& w2 =
+            getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, 0.5f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
+    const sp<FakeWindowHandle>& wB =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    const sp<FakeWindowHandle>& wC =
+            getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
+    const sp<FakeWindowHandle>& wB =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    const sp<FakeWindowHandle>& wC =
+            getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, 0.9f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 579130a..f30e1eb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -236,10 +236,6 @@
 bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
     mCurrentStateModified = mCurrentState.modified;
     bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit);
-    if (stateUpdateAvailable && mCallbackHandleAcquireTime != -1) {
-        // Update the acquire fence time if we have a buffer
-        mSurfaceFrame->setAcquireFenceTime(mCallbackHandleAcquireTime);
-    }
     mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified;
     mCurrentState.modified = false;
     return stateUpdateAvailable;
@@ -612,11 +608,12 @@
 }
 
 std::optional<nsecs_t> BufferStateLayer::nextPredictedPresentTime() const {
-    if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
+    const State& drawingState(getDrawingState());
+    if (!drawingState.isAutoTimestamp || !drawingState.bufferSurfaceFrameTX) {
         return std::nullopt;
     }
 
-    return mSurfaceFrame->getPredictions().presentTime;
+    return drawingState.bufferSurfaceFrameTX->getPredictions().presentTime;
 }
 
 status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index eb0c724..0a40388 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -327,7 +327,12 @@
 
 std::optional<int32_t> SurfaceFrame::getJankType() const {
     std::scoped_lock lock(mMutex);
+    if (mPresentState == PresentState::Dropped) {
+        // Return no jank if it's a dropped frame since we cannot attribute a jank to a it.
+        return JankType::None;
+    }
     if (mActuals.presentTime == 0) {
+        // Frame hasn't been presented yet.
         return std::nullopt;
     }
     return mJankType;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6a28da3..237aaff 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1583,7 +1583,7 @@
     surfaceFrame->setAcquireFenceTime(postTime);
     const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
     if (fps) {
-        mSurfaceFrame->setRenderRate(*fps);
+        surfaceFrame->setRenderRate(*fps);
     }
     onSurfaceFrameCreated(surfaceFrame);
     return surfaceFrame;
@@ -1598,7 +1598,7 @@
     surfaceFrame->setActualQueueTime(queueTime);
     const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
     if (fps) {
-        mSurfaceFrame->setRenderRate(*fps);
+        surfaceFrame->setRenderRate(*fps);
     }
     // TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well.
     onSurfaceFrameCreated(surfaceFrame);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index a1fdc3c..687f473 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1145,9 +1145,6 @@
     // Window types from WindowManager.LayoutParams
     const InputWindowInfo::Type mWindowType;
 
-    // Can only be accessed with the SF state lock held.
-    std::shared_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
-
     // The owner of the layer. If created from a non system process, it will be the calling uid.
     // If created from a system process, the value can be passed in.
     uid_t mOwnerUid;
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 1d1f0c5..b4d8a9a 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -71,12 +71,14 @@
 }
 
 void SurfaceTracing::notify(const char* where) {
+    std::scoped_lock lock(mTraceLock);
     if (mEnabled) {
         runner->notify(where);
     }
 }
 
 void SurfaceTracing::notifyLocked(const char* where) {
+    std::scoped_lock lock(mTraceLock);
     if (mEnabled) {
         runner->notifyLocked(where);
     }
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 497ebd3..15a503d 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -81,8 +81,8 @@
 
     SurfaceFlinger& mFlinger;
     mutable std::mutex mTraceLock;
-    bool mEnabled = false;
-    std::unique_ptr<Runner> runner;
+    bool mEnabled GUARDED_BY(mTraceLock) = false;
+    std::unique_ptr<Runner> runner GUARDED_BY(mTraceLock);
 
     struct Config {
         uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC;
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index aa6798d..a6a465e 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -328,6 +328,41 @@
         EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
         EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
     }
+
+    void PendingSurfaceFramesRemovedAfterClassification() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+
+        sp<Fence> fence1(new Fence());
+        auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
+        sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        sp<Fence> fence2(new Fence());
+        auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
+        sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        acquireFence2->signalForTest(12);
+
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        auto& presentedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        commitTransaction(layer.get());
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        // Both the droppedSurfaceFrame and presentedSurfaceFrame should be in
+        // pendingJankClassifications.
+        EXPECT_EQ(2u, layer->mPendingJankClassifications.size());
+        presentedSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+                                         /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0);
+        layer->releasePendingBuffer(25);
+
+        EXPECT_EQ(0u, layer->mPendingJankClassifications.size());
+    }
 };
 
 TEST_F(TransactionSurfaceFrameTest, PresentedBufferlessSurfaceFrame) {
@@ -364,4 +399,7 @@
     MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken();
 }
 
+TEST_F(TransactionSurfaceFrameTest, PendingSurfaceFramesRemovedAfterClassification) {
+    PendingSurfaceFramesRemovedAfterClassification();
+}
 } // namespace android
\ No newline at end of file