Merge "Ensure onHandleDestroyed drops reference before releasing lock."
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 19c2830..53b3a00 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -228,6 +228,10 @@
         { OPT,      "events/kmem/rss_stat/enable" },
         { OPT,      "events/kmem/ion_heap_grow/enable" },
         { OPT,      "events/kmem/ion_heap_shrink/enable" },
+        { OPT,      "events/oom/oom_score_adj_update/enable" },
+        { OPT,      "events/sched/sched_process_exit/enable" },
+        { OPT,      "events/task/task_rename/enable" },
+        { OPT,      "events/task/task_newtask/enable" },
     } },
 };
 
@@ -435,14 +439,10 @@
         const char* path = category.sysfiles[i].path;
         bool req = category.sysfiles[i].required == REQ;
         if (path != nullptr) {
-            if (req) {
-                if (!fileIsWritable(path)) {
-                    return false;
-                } else {
-                    ok = true;
-                }
-            } else {
+            if (fileIsWritable(path)) {
                 ok = true;
+            } else if (req) {
+                return false;
             }
         }
     }
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index ed9531e..fa7d908 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -131,7 +131,7 @@
  * POSIX error code (see errno.h) if an immediate error occurs.
  */
 int android_res_nsend(net_handle_t network,
-        const unsigned char *msg, int msglen) __INTRODUCED_IN(29);
+        const uint8_t *msg, size_t msglen) __INTRODUCED_IN(29);
 
 /**
  * Read a result for the query associated with the |fd| descriptor.
@@ -141,7 +141,7 @@
  *     >= 0: length of |answer|. |rcode| is the resolver return code (e.g., ns_r_nxdomain)
  */
 int android_res_nresult(int fd,
-        int *rcode, unsigned char *answer, int anslen) __INTRODUCED_IN(29);
+        int *rcode, uint8_t *answer, size_t anslen) __INTRODUCED_IN(29);
 
 /**
  * Attempts to cancel the in-progress query associated with the |nsend_fd|
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 95b1038..1be55e6 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -59,7 +59,15 @@
     if (err != NO_ERROR) {
         return err;
     }
-    err = output->writeInt64(presentTime);
+    if (presentFence) {
+        err = output->writeBool(true);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        err = output->write(*presentFence);
+    } else {
+        err = output->writeBool(false);
+    }
     if (err != NO_ERROR) {
         return err;
     }
@@ -71,10 +79,18 @@
     if (err != NO_ERROR) {
         return err;
     }
-    err = input->readInt64(&presentTime);
+    bool hasFence = false;
+    err = input->readBool(&hasFence);
     if (err != NO_ERROR) {
         return err;
     }
+    if (hasFence) {
+        presentFence = new Fence();
+        err = input->read(*presentFence);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
     return input->readParcelableVector(&surfaceStats);
 }
 
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 5c41c21..8acfa7a 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -21,6 +21,7 @@
 #include <binder/Parcelable.h>
 #include <binder/SafeInterface.h>
 
+#include <ui/Fence.h>
 #include <utils/Timers.h>
 
 #include <cstdint>
@@ -65,7 +66,7 @@
     status_t readFromParcel(const Parcel* input) override;
 
     nsecs_t latchTime = -1;
-    nsecs_t presentTime = -1;
+    sp<Fence> presentFence = nullptr;
     std::vector<SurfaceStats> surfaceStats;
 };
 
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 86e9c23..60542bd 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -24,11 +24,15 @@
 
 #include <memory>
 
+#include <android/native_window.h>
+
 #include <binder/Binder.h>
 #include <binder/IServiceManager.h>
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <gui/SurfaceControl.h>
 
@@ -37,6 +41,7 @@
 #include <input/InputTransport.h>
 #include <input/Input.h>
 
+#include <ui/DisplayInfo.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
@@ -44,6 +49,8 @@
 namespace android {
 namespace test {
 
+using Transaction = SurfaceComposerClient::Transaction;
+
 sp<IInputFlinger> getInputFlinger() {
    sp<IBinder> input(defaultServiceManager()->getService(
             String16("inputflinger")));
@@ -58,9 +65,8 @@
 
 class InputSurface {
 public:
-    InputSurface(const sp<SurfaceComposerClient>& scc, int width, int height) {
-        mSurfaceControl = scc->createSurface(String8("Test Surface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                             ISurfaceComposerClient::eFXSurfaceColor);
+    InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
+        mSurfaceControl = sc;
 
         InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
         mServerChannel->setToken(new BBinder());
@@ -73,6 +79,31 @@
         mInputConsumer = new InputConsumer(mClientChannel);
     }
 
+    static std::unique_ptr<InputSurface> makeColorInputSurface(const sp<SurfaceComposerClient> &scc,
+                                                               int width, int height) {
+        sp<SurfaceControl> surfaceControl =
+                scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */,
+                                   PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+        return std::make_unique<InputSurface>(surfaceControl, width, height);
+    }
+
+    static std::unique_ptr<InputSurface> makeBufferInputSurface(
+            const sp<SurfaceComposerClient> &scc, int width, int height) {
+        sp<SurfaceControl> surfaceControl =
+                scc->createSurface(String8("Test Buffer Surface"), width, height,
+                                   PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
+        return std::make_unique<InputSurface>(surfaceControl, width, height);
+    }
+
+    static std::unique_ptr<InputSurface> makeContainerInputSurface(
+            const sp<SurfaceComposerClient> &scc, int width, int height) {
+        sp<SurfaceControl> surfaceControl =
+                scc->createSurface(String8("Test Container Surface"), 0 /* bufHeight */,
+                                   0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceContainer);
+        return std::make_unique<InputSurface>(surfaceControl, width, height);
+    }
+
     InputEvent* consumeEvent() {
         waitForEventAvailable();
 
@@ -180,6 +211,15 @@
     void SetUp() {
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        DisplayInfo info;
+        auto display = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+        SurfaceComposerClient::getDisplayInfo(display, &info);
+
+        // After a new buffer is queued, SurfaceFlinger is notified and will
+        // latch the new buffer on next vsync.  Let's heuristically wait for 3
+        // vsyncs.
+        mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
     }
 
     void TearDown() {
@@ -187,10 +227,23 @@
     }
 
     std::unique_ptr<InputSurface> makeSurface(int width, int height) {
-        return std::make_unique<InputSurface>(mComposerClient, width, height);
+        return InputSurface::makeColorInputSurface(mComposerClient, width, height);
+    }
+
+    void postBuffer(const sp<SurfaceControl> &layer) {
+        // wait for previous transactions (such as setSize) to complete
+        Transaction().apply(true);
+        ANativeWindow_Buffer buffer = {};
+        EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
+        ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
+        // Request an empty transaction to get applied synchronously to ensure the buffer is
+        // latched.
+        Transaction().apply(true);
+        usleep(mBufferPostDelay);
     }
 
     sp<SurfaceComposerClient> mComposerClient;
+    int32_t mBufferPostDelay;
 };
 
 void injectTap(int x, int y) {
@@ -267,5 +320,124 @@
     surface->expectTap(1, 1);
 }
 
+// Surface Insets are set to offset the client content and draw a border around the client surface
+// (such as shadows in dialogs). Inputs sent to the client are offset such that 0,0 is the start
+// of the client content.
+TEST_F(InputSurfacesTest, input_respects_surface_insets) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+    bgSurface->showAt(100, 100);
+
+    fgSurface->mInputInfo.surfaceInset = 5;
+    fgSurface->showAt(100, 100);
+
+    injectTap(106, 106);
+    fgSurface->expectTap(1, 1);
+
+    injectTap(101, 101);
+    bgSurface->expectTap(1, 1);
+}
+
+// Ensure a surface whose insets are cropped, handles the touch offset correctly. ref:b/120413463
+TEST_F(InputSurfacesTest, input_respects_cropped_surface_insets) {
+    std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100);
+    parentSurface->showAt(100, 100);
+
+    childSurface->mInputInfo.surfaceInset = 10;
+    childSurface->showAt(100, 100);
+
+    childSurface->doTransaction([&](auto &t, auto &sc) {
+        t.setPosition(sc, -5, -5);
+        t.reparent(sc, parentSurface->mSurfaceControl->getHandle());
+    });
+
+    injectTap(106, 106);
+    childSurface->expectTap(1, 1);
+
+    injectTap(101, 101);
+    parentSurface->expectTap(1, 1);
+}
+
+// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
+TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->doTransaction([](auto &t, auto &sc) {
+        Region transparentRegion(Rect(0, 0, 10, 10));
+        t.setTransparentRegionHint(sc, transparentRegion);
+    });
+    surface->showAt(100, 100);
+    injectTap(101, 101);
+    surface->expectTap(1, 1);
+}
+
+// Ensure we send the input to the right surface when the surface visibility changes due to the
+// first buffer being submitted. ref: b/120839715
+TEST_F(InputSurfacesTest, input_respects_buffer_layer_buffer) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> bufferSurface =
+            InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
+
+    bgSurface->showAt(10, 10);
+    bufferSurface->showAt(10, 10);
+
+    injectTap(11, 11);
+    bgSurface->expectTap(1, 1);
+
+    postBuffer(bufferSurface->mSurfaceControl);
+    injectTap(11, 11);
+    bufferSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_buffer_layer_alpha) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> bufferSurface =
+            InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
+    postBuffer(bufferSurface->mSurfaceControl);
+
+    bgSurface->showAt(10, 10);
+    bufferSurface->showAt(10, 10);
+
+    injectTap(11, 11);
+    bufferSurface->expectTap(1, 1);
+
+    bufferSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
+
+    injectTap(11, 11);
+    bgSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_color_layer_alpha) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+
+    bgSurface->showAt(10, 10);
+    fgSurface->showAt(10, 10);
+
+    injectTap(11, 11);
+    fgSurface->expectTap(1, 1);
+
+    fgSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
+
+    injectTap(11, 11);
+    bgSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> containerSurface =
+            InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
+
+    bgSurface->showAt(10, 10);
+    containerSurface->showAt(10, 10);
+
+    injectTap(11, 11);
+    containerSurface->expectTap(1, 1);
+
+    containerSurface->doTransaction([](auto &t, auto &sc) { t.hide(sc); });
+
+    injectTap(11, 11);
+    bgSurface->expectTap(1, 1);
+}
 }
 }
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 226b6ee..0582e1a 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -169,6 +169,13 @@
     buffer_state_ = &metadata_header->buffer_state;
     fence_state_ = &metadata_header->fence_state;
     active_clients_bit_mask_ = &metadata_header->active_clients_bit_mask;
+    // The C++ standard recommends (but does not require) that lock-free atomic operations are
+    // also address-free, that is, suitable for communication between processes using shared
+    // memory.
+    LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(buffer_state_) ||
+                                !std::atomic_is_lock_free(fence_state_) ||
+                                !std::atomic_is_lock_free(active_clients_bit_mask_),
+                        "Atomic variables in ashmen are not lock free.");
 
     // Import the buffer: We only need to hold on the native_handle_t here so that
     // GraphicBuffer instance can be created in future.
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index b0869fe..2663812 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -39,7 +39,8 @@
                                          BufferHubIdGenerator::getInstance().getId());
     if (node == nullptr || !node->IsValid()) {
         ALOGE("%s: creating BufferNode failed.", __FUNCTION__);
-        _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::ALLOCATION_FAILED);
+        _hidl_cb(/*status=*/BufferHubStatus::ALLOCATION_FAILED, /*bufferClient=*/nullptr,
+                 /*bufferTraits=*/{});
         return Void();
     }
 
@@ -48,7 +49,13 @@
     std::lock_guard<std::mutex> lock(mClientSetMutex);
     mClientSet.emplace(client);
 
-    _hidl_cb(/*bufferClient=*/client, /*status=*/BufferHubStatus::NO_ERROR);
+    BufferTraits bufferTraits = {/*bufferDesc=*/description,
+                                 /*bufferHandle=*/hidl_handle(node->buffer_handle()),
+                                 // TODO(b/116681016): return real data to client
+                                 /*bufferInfo=*/hidl_handle()};
+
+    _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
+             /*bufferTraits=*/bufferTraits);
     return Void();
 }
 
@@ -56,7 +63,8 @@
                                             importBuffer_cb _hidl_cb) {
     if (!tokenHandle.getNativeHandle() || tokenHandle->numFds != 0 || tokenHandle->numInts != 1) {
         // nullptr handle or wrong format
-        _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::INVALID_TOKEN);
+        _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+                 /*bufferTraits=*/{});
         return Void();
     }
 
@@ -68,7 +76,8 @@
         auto iter = mTokenMap.find(token);
         if (iter == mTokenMap.end()) {
             // Invalid token
-            _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::INVALID_TOKEN);
+            _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+                     /*bufferTraits=*/{});
             return Void();
         }
 
@@ -81,15 +90,37 @@
     if (!originClient) {
         // Should not happen since token should be removed if already gone
         ALOGE("%s: original client %p gone!", __FUNCTION__, originClientWp.unsafe_get());
-        _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::BUFFER_FREED);
+        _hidl_cb(/*status=*/BufferHubStatus::BUFFER_FREED, /*bufferClient=*/nullptr,
+                 /*bufferTraits=*/{});
         return Void();
     }
 
     sp<BufferClient> client = new BufferClient(*originClient);
+    uint32_t clientStateMask = client->getBufferNode()->AddNewActiveClientsBitToMask();
+    if (clientStateMask == 0U) {
+        // Reach max client count
+        ALOGE("%s: import failed, BufferNode#%u reached maximum clients.", __FUNCTION__,
+              client->getBufferNode()->id());
+        _hidl_cb(/*status=*/BufferHubStatus::MAX_CLIENT, /*bufferClient=*/nullptr,
+                 /*bufferTraits=*/{});
+        return Void();
+    }
 
     std::lock_guard<std::mutex> lock(mClientSetMutex);
     mClientSet.emplace(client);
-    _hidl_cb(/*bufferClient=*/client, /*status=*/BufferHubStatus::NO_ERROR);
+
+    std::shared_ptr<BufferNode> node = client->getBufferNode();
+
+    HardwareBufferDescription bufferDesc;
+    memcpy(&bufferDesc, &node->buffer_desc(), sizeof(HardwareBufferDescription));
+
+    BufferTraits bufferTraits = {/*bufferDesc=*/bufferDesc,
+                                 /*bufferHandle=*/hidl_handle(node->buffer_handle()),
+                                 // TODO(b/116681016): return real data to client
+                                 /*bufferInfo=*/hidl_handle()};
+
+    _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
+             /*bufferTraits=*/bufferTraits);
     return Void();
 }
 
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index cc87e15..da19a6f 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -2,6 +2,7 @@
 
 #include <bufferhub/BufferHubService.h>
 #include <bufferhub/BufferNode.h>
+#include <log/log.h>
 #include <ui/GraphicBufferAllocator.h>
 
 namespace android {
@@ -18,6 +19,13 @@
     fence_state_ = new (&metadata_header->fence_state) std::atomic<uint32_t>(0);
     active_clients_bit_mask_ =
             new (&metadata_header->active_clients_bit_mask) std::atomic<uint32_t>(0);
+    // The C++ standard recommends (but does not require) that lock-free atomic operations are
+    // also address-free, that is, suitable for communication between processes using shared
+    // memory.
+    LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(buffer_state_) ||
+                                !std::atomic_is_lock_free(fence_state_) ||
+                                !std::atomic_is_lock_free(active_clients_bit_mask_),
+                        "Atomic variables in ashmen are not lock free.");
 }
 
 // Allocates a new BufferNode.
diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h
index 7f5d3a6..66ed4bd 100644
--- a/services/bufferhub/include/bufferhub/BufferClient.h
+++ b/services/bufferhub/include/bufferhub/BufferClient.h
@@ -49,6 +49,9 @@
     Return<BufferHubStatus> close() override;
     Return<void> duplicate(duplicate_cb _hidl_cb) override;
 
+    // Non-binder functions
+    const std::shared_ptr<BufferNode>& getBufferNode() const { return mBufferNode; }
+
 private:
     BufferClient(wp<BufferHubService> service, const std::shared_ptr<BufferNode>& node)
           : mService(service), mBufferNode(node) {}
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index a025f31..f7802b9 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -73,6 +73,8 @@
 
 static const char *WAKE_LOCK_ID = "KeyEvents";
 static const char *DEVICE_PATH = "/dev/input";
+// v4l2 devices go directly into /dev
+static const char *VIDEO_DEVICE_PATH = "/dev";
 
 static inline const char* toString(bool value) {
     return value ? "true" : "false";
@@ -100,6 +102,13 @@
     }
 }
 
+/**
+ * Return true if name matches "v4l-touch*"
+ */
+static bool isV4lTouchNode(const char* name) {
+    return strstr(name, "v4l-touch") == name;
+}
+
 // --- Global Functions ---
 
 uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
@@ -206,18 +215,21 @@
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
     mEpollFd = epoll_create1(EPOLL_CLOEXEC);
-    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
+    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
 
     mINotifyFd = inotify_init();
-    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
-    LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",
-            DEVICE_PATH, errno);
+    mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
+    LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
+            DEVICE_PATH, strerror(errno));
+    mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
+    LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
+            VIDEO_DEVICE_PATH, strerror(errno));
 
     struct epoll_event eventItem;
     memset(&eventItem, 0, sizeof(eventItem));
     eventItem.events = EPOLLIN;
     eventItem.data.fd = mINotifyFd;
-    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
+    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
     LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);
 
     int wakeFds[2];
@@ -1667,8 +1679,6 @@
 
 status_t EventHub::readNotifyLocked() {
     int res;
-    char devname[PATH_MAX];
-    char *filename;
     char event_buf[512];
     int event_size;
     int event_pos = 0;
@@ -1682,21 +1692,27 @@
         ALOGW("could not get event, %s\n", strerror(errno));
         return -1;
     }
-    //printf("got %d bytes of event information\n", res);
-
-    strcpy(devname, DEVICE_PATH);
-    filename = devname + strlen(devname);
-    *filename++ = '/';
 
     while(res >= (int)sizeof(*event)) {
         event = (struct inotify_event *)(event_buf + event_pos);
         if(event->len) {
-            strcpy(filename, event->name);
-            if(event->mask & IN_CREATE) {
-                openDeviceLocked(devname);
-            } else {
-                ALOGI("Removing device '%s' due to inotify event\n", devname);
-                closeDeviceByPathLocked(devname);
+            if (event->wd == mInputWd) {
+                std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
+                if(event->mask & IN_CREATE) {
+                    openDeviceLocked(filename.c_str());
+                } else {
+                    ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
+                    closeDeviceByPathLocked(filename.c_str());
+                }
+            }
+            else if (event->wd == mVideoWd) {
+                if (isV4lTouchNode(event->name)) {
+                    std::string filename = StringPrintf("%s/%s", VIDEO_DEVICE_PATH, event->name);
+                    ALOGV("Received an inotify event for a video device %s", filename.c_str());
+                }
+            }
+            else {
+                LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd);
             }
         }
         event_size = sizeof(*event) + event->len;
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 2d342bc..73fcb11 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -254,7 +254,6 @@
 }
 
 
-
 // --- InputReader ---
 
 InputReader::InputReader(const sp<EventHubInterface>& eventHub,
@@ -3446,7 +3445,17 @@
         } else {
             viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
         }
-        return mConfig.getDisplayViewportByType(viewportTypeToUse);
+
+        std::optional<DisplayViewport> viewport =
+                mConfig.getDisplayViewportByType(viewportTypeToUse);
+        if (!viewport && viewportTypeToUse == ViewportType::VIEWPORT_EXTERNAL) {
+            ALOGW("Input device %s should be associated with external display, "
+                    "fallback to internal one for the external viewport is not found.",
+                        getDeviceName().c_str());
+            viewport = mConfig.getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+        }
+
+        return viewport;
     }
 
     DisplayViewport newViewport;
diff --git a/services/inputflinger/include/EventHub.h b/services/inputflinger/include/EventHub.h
index 5db7c0a..1ddb978 100644
--- a/services/inputflinger/include/EventHub.h
+++ b/services/inputflinger/include/EventHub.h
@@ -452,6 +452,9 @@
     int mWakeReadPipeFd;
     int mWakeWritePipeFd;
 
+    int mInputWd;
+    int mVideoWd;
+
     // Epoll FD list size hint.
     static const int EPOLL_SIZE_HINT = 8;
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 167a624..b5d2090 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -6284,4 +6284,34 @@
     ASSERT_EQ(DISPLAY_ID, args.displayId);
 }
 
+/**
+ * Expect fallback to internal viewport if device is external and external viewport is not present.
+ */
+TEST_F(MultiTouchInputMapperTest, Viewports_Fallback) {
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+    prepareAxes(POSITION);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    mDevice->setExternal(true);
+    addMapperAndConfigure(mapper);
+
+    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources());
+
+    NotifyMotionArgs motionArgs;
+
+    // Expect the event to be sent to the internal viewport,
+    // because an external viewport is not present.
+    processPosition(mapper, 100, 100);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(ADISPLAY_ID_DEFAULT, motionArgs.displayId);
+
+    // Expect the event to be sent to the external viewport if it is present.
+    prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL);
+    processPosition(mapper, 100, 100);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4537d23..4a93be6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2736,7 +2736,7 @@
 
     commitTransaction();
 
-    if ((inputChanged || mVisibleRegionsDirty) && mInputFlinger) {
+    if (inputChanged || mVisibleRegionsDirty) {
         updateInputWindows();
     }
 
@@ -2746,6 +2746,10 @@
 void SurfaceFlinger::updateInputWindows() {
     ATRACE_CALL();
 
+    if (mInputFlinger == nullptr) {
+        return;
+    }
+
     Vector<InputWindowInfo> inputHandles;
 
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3015,6 +3019,11 @@
 
     mVisibleRegionsDirty |= visibleRegions;
 
+    if (visibleRegions) {
+        // Update input window info if the layer receives its first buffer.
+        updateInputWindows();
+    }
+
     // If we will need to wake up at some time in the future to deal with a
     // queued frame that shouldn't be displayed during this vsync period, wake
     // up during the next vsync period to check again.
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 389118a..a1a8692 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -151,18 +151,6 @@
     while (mKeepRunning) {
         mConditionVariable.wait(mMutex);
 
-        // Present fence should fire almost immediately. If the fence has not signaled in 100ms,
-        // there is a major problem and it will probably never fire.
-        nsecs_t presentTime = -1;
-        if (mPresentFence) {
-            status_t status = mPresentFence->wait(100);
-            if (status == NO_ERROR) {
-                presentTime = mPresentFence->getSignalTime();
-            } else {
-                ALOGE("present fence has not signaled, err %d", status);
-            }
-        }
-
         // We should never hit this case. The release fences from the previous frame should have
         // signaled long before the current frame is presented.
         for (const auto& fence : mPreviousReleaseFences) {
@@ -188,17 +176,11 @@
 
                 // If the transaction has been latched
                 if (transactionStats.latchTime >= 0) {
-                    // If the present time is < 0, this transaction has been latched but not
-                    // presented. Skip it for now. This can happen when a new transaction comes
-                    // in between the latch and present steps. sendCallbacks is called by
-                    // SurfaceFlinger when the transaction is received to ensure that if the
-                    // transaction that didn't update state it still got a callback.
-                    if (presentTime < 0) {
+                    if (!mPresentFence) {
                         sendCallback = false;
                         break;
                     }
-
-                    transactionStats.presentTime = presentTime;
+                    transactionStats.presentFence = mPresentFence;
                 }
             }
             // If the listener has no pending transactions and all latched transactions have been
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index cef598c..e62fc6e 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2502,12 +2502,12 @@
     }
 
     void verifyTransactionStats(const TransactionStats& transactionStats) const {
-        const auto& [latchTime, presentTime, surfaceStats] = transactionStats;
+        const auto& [latchTime, presentFence, surfaceStats] = transactionStats;
         if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
             ASSERT_GE(latchTime, 0) << "bad latch time";
-            ASSERT_GE(presentTime, 0) << "bad present time";
+            ASSERT_NE(presentFence, nullptr);
         } else {
-            ASSERT_EQ(presentTime, -1) << "transaction shouldn't have been presented";
+            ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
             ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
         }