Merge "Add frame rate flexibility token" into rvc-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index b475c90..c85c7cf 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2677,15 +2677,6 @@
             MYLOGI("User denied consent. Returning\n");
             return status;
         }
-        if (options_->do_screenshot &&
-            options_->screenshot_fd.get() != -1 &&
-            !options_->is_screenshot_copied) {
-            bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
-                                                            options_->screenshot_fd.get());
-            if (copy_succeeded) {
-                android::os::UnlinkAndLogOnError(screenshot_path_);
-            }
-        }
         if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
             MYLOGI(
                 "Did not receive user consent yet."
@@ -2815,6 +2806,16 @@
         bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
         if (copy_succeeded) {
             android::os::UnlinkAndLogOnError(path_);
+            if (options_->do_screenshot &&
+                options_->screenshot_fd.get() != -1 &&
+                !options_->is_screenshot_copied) {
+                copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
+                                                           options_->screenshot_fd.get());
+                options_->is_screenshot_copied = copy_succeeded;
+                if (copy_succeeded) {
+                    android::os::UnlinkAndLogOnError(screenshot_path_);
+                }
+            }
         }
         return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
     } else if (consent_result == UserConsentResult::UNAVAILABLE) {
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 1af6edd..5ee6a9f 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -374,6 +374,14 @@
         bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
                                 vold_decrypt == "1";
 
+        std::string updatable_bcp_packages =
+            MapPropertyToArg("dalvik.vm.dex2oat-updatable-bcp-packages-file",
+                             "--updatable-bcp-packages-file=%s");
+        if (updatable_bcp_packages.empty()) {
+          // Make dex2oat fail by providing non-existent file name.
+          updatable_bcp_packages = "--updatable-bcp-packages-file=/nonx/updatable-bcp-packages.txt";
+        }
+
         std::string resolve_startup_string_arg =
                 MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
                                  "--resolve-startup-const-strings=%s");
@@ -520,6 +528,7 @@
         AddRuntimeArg(dex2oat_Xms_arg);
         AddRuntimeArg(dex2oat_Xmx_arg);
 
+        AddArg(updatable_bcp_packages);
         AddArg(resolve_startup_string_arg);
         AddArg(image_block_size_arg);
         AddArg(dex2oat_compiler_filter_arg);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 3ee8187..c7b7551 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -40,7 +40,7 @@
     },
 
     srcs: ["binderDriverInterfaceTest.cpp"],
-    test_suites: ["device-tests", "vts-core"],
+    test_suites: ["device-tests", "vts"],
 }
 
 cc_test {
@@ -69,7 +69,7 @@
         "libbinder",
         "libutils",
     ],
-    test_suites: ["device-tests", "vts-core"],
+    test_suites: ["device-tests", "vts"],
     require_root: true,
 }
 
@@ -131,7 +131,7 @@
         "liblog",
         "libutils",
     ],
-    test_suites: ["device-tests", "vts-core"],
+    test_suites: ["device-tests", "vts"],
     require_root: true,
 }
 
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
index be2e19e..71731b0 100644
--- a/services/inputflinger/tests/EventHub_test.cpp
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -34,6 +34,7 @@
 using android::sp;
 using android::UinputHomeKey;
 using std::chrono_literals::operator""ms;
+using std::chrono_literals::operator""s;
 
 static constexpr bool DEBUG = false;
 
@@ -70,11 +71,12 @@
         mEventHub = std::make_unique<EventHub>();
         consumeInitialDeviceAddedEvents();
         mKeyboard = createUinputDevice<UinputHomeKey>();
-        mDeviceId = waitForDeviceCreation();
+        ASSERT_NO_FATAL_FAILURE(mDeviceId = waitForDeviceCreation());
     }
     virtual void TearDown() override {
         mKeyboard.reset();
         waitForDeviceClose(mDeviceId);
+        assertNoMoreEvents();
     }
 
     /**
@@ -83,21 +85,38 @@
     int32_t waitForDeviceCreation();
     void waitForDeviceClose(int32_t deviceId);
     void consumeInitialDeviceAddedEvents();
-    std::vector<RawEvent> getEvents(std::chrono::milliseconds timeout = 5ms);
+    void assertNoMoreEvents();
+    /**
+     * Read events from the EventHub.
+     *
+     * If expectedEvents is set, wait for a significant period of time to try and ensure that
+     * the expected number of events has been read. The number of returned events
+     * may be smaller (if timeout has been reached) or larger than expectedEvents.
+     *
+     * If expectedEvents is not set, return all of the immediately available events.
+     */
+    std::vector<RawEvent> getEvents(std::optional<size_t> expectedEvents = std::nullopt);
 };
 
-std::vector<RawEvent> EventHubTest::getEvents(std::chrono::milliseconds timeout) {
+std::vector<RawEvent> EventHubTest::getEvents(std::optional<size_t> expectedEvents) {
     static constexpr size_t EVENT_BUFFER_SIZE = 256;
     std::array<RawEvent, EVENT_BUFFER_SIZE> eventBuffer;
     std::vector<RawEvent> events;
 
     while (true) {
-        size_t count =
+        std::chrono::milliseconds timeout = 0s;
+        if (expectedEvents) {
+            timeout = 2s;
+        }
+        const size_t count =
                 mEventHub->getEvents(timeout.count(), eventBuffer.data(), eventBuffer.size());
         if (count == 0) {
             break;
         }
         events.insert(events.end(), eventBuffer.begin(), eventBuffer.begin() + count);
+        if (expectedEvents && events.size() >= *expectedEvents) {
+            break;
+        }
     }
     if (DEBUG) {
         dumpEvents(events);
@@ -111,7 +130,7 @@
  * it will return a lot of "device added" type of events.
  */
 void EventHubTest::consumeInitialDeviceAddedEvents() {
-    std::vector<RawEvent> events = getEvents(0ms);
+    std::vector<RawEvent> events = getEvents();
     std::set<int32_t /*deviceId*/> existingDevices;
     // All of the events should be DEVICE_ADDED type, except the last one.
     for (size_t i = 0; i < events.size() - 1; i++) {
@@ -128,8 +147,11 @@
 
 int32_t EventHubTest::waitForDeviceCreation() {
     // Wait a little longer than usual, to ensure input device has time to be created
-    std::vector<RawEvent> events = getEvents(20ms);
-    EXPECT_EQ(2U, events.size()); // Using "expect" because the function is non-void.
+    std::vector<RawEvent> events = getEvents(2);
+    if (events.size() != 2) {
+        ADD_FAILURE() << "Instead of 2 events, received " << events.size();
+        return 0; // this value is unused
+    }
     const RawEvent& deviceAddedEvent = events[0];
     EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_ADDED), deviceAddedEvent.type);
     InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceAddedEvent.deviceId);
@@ -142,7 +164,7 @@
 }
 
 void EventHubTest::waitForDeviceClose(int32_t deviceId) {
-    std::vector<RawEvent> events = getEvents(20ms);
+    std::vector<RawEvent> events = getEvents(2);
     ASSERT_EQ(2U, events.size());
     const RawEvent& deviceRemovedEvent = events[0];
     EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_REMOVED), deviceRemovedEvent.type);
@@ -152,6 +174,11 @@
               finishedDeviceScanEvent.type);
 }
 
+void EventHubTest::assertNoMoreEvents() {
+    std::vector<RawEvent> events = getEvents();
+    ASSERT_TRUE(events.empty());
+}
+
 /**
  * Ensure that input_events are generated with monotonic clock.
  * That means input_event should receive a timestamp that is in the future of the time
@@ -162,7 +189,7 @@
     nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
     ASSERT_NO_FATAL_FAILURE(mKeyboard->pressAndReleaseHomeKey());
 
-    std::vector<RawEvent> events = getEvents();
+    std::vector<RawEvent> events = getEvents(4);
     ASSERT_EQ(4U, events.size()) << "Expected to receive 2 keys and 2 syncs, total of 4 events";
     for (const RawEvent& event : events) {
         // Cannot use strict comparison because the events may happen too quickly
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index 99480b7..10e7293 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -44,9 +44,7 @@
     device.id.product = 0x01;
     device.id.version = 1;
 
-    // Using EXPECT instead of ASSERT to allow the device creation to continue even when
-    // some failures are reported when configuring the device.
-    EXPECT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device));
+    ASSERT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device));
 
     if (write(mDeviceFd, &device, sizeof(device)) < 0) {
         FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: "
@@ -70,7 +68,7 @@
                                              " with value %" PRId32 " : %s",
                                              type, code, value, strerror(errno));
         ALOGE("%s", msg.c_str());
-        ADD_FAILURE() << msg.c_str();
+        FAIL() << msg.c_str();
     }
 }
 
@@ -82,41 +80,41 @@
 void UinputKeyboard::configureDevice(int fd, uinput_user_dev* device) {
     // enable key press/release event
     if (ioctl(fd, UI_SET_EVBIT, EV_KEY)) {
-        ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
+        FAIL() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
     }
 
     // enable set of KEY events
     std::for_each(mKeys.begin(), mKeys.end(), [fd](int key) {
         if (ioctl(fd, UI_SET_KEYBIT, key)) {
-            ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : " << key << " : " << strerror(errno);
+            FAIL() << "Error in ioctl : UI_SET_KEYBIT : " << key << " : " << strerror(errno);
         }
     });
 
     // enable synchronization event
     if (ioctl(fd, UI_SET_EVBIT, EV_SYN)) {
-        ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
+        FAIL() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
     }
 }
 
 void UinputKeyboard::pressKey(int key) {
     if (mKeys.find(key) == mKeys.end()) {
-        ADD_FAILURE() << mName << ": Cannot inject key press: Key not found: " << key;
+        FAIL() << mName << ": Cannot inject key press: Key not found: " << key;
     }
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 1));
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+    injectEvent(EV_KEY, key, 1);
+    injectEvent(EV_SYN, SYN_REPORT, 0);
 }
 
 void UinputKeyboard::releaseKey(int key) {
     if (mKeys.find(key) == mKeys.end()) {
-        ADD_FAILURE() << mName << ": Cannot inject key release: Key not found: " << key;
+        FAIL() << mName << ": Cannot inject key release: Key not found: " << key;
     }
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 0));
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+    injectEvent(EV_KEY, key, 0);
+    injectEvent(EV_SYN, SYN_REPORT, 0);
 }
 
 void UinputKeyboard::pressAndReleaseKey(int key) {
-    EXPECT_NO_FATAL_FAILURE(pressKey(key));
-    EXPECT_NO_FATAL_FAILURE(releaseKey(key));
+    pressKey(key);
+    releaseKey(key);
 }
 
 // --- UinputHomeKey ---
@@ -124,7 +122,7 @@
 UinputHomeKey::UinputHomeKey() : UinputKeyboard({KEY_HOME}) {}
 
 void UinputHomeKey::pressAndReleaseHomeKey() {
-    EXPECT_NO_FATAL_FAILURE(pressAndReleaseKey(KEY_HOME));
+    pressAndReleaseKey(KEY_HOME);
 }
 
 // --- UinputTouchScreen ---
@@ -158,35 +156,35 @@
 }
 
 void UinputTouchScreen::sendSlot(int32_t slot) {
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_SLOT, slot));
+    injectEvent(EV_ABS, ABS_MT_SLOT, slot);
 }
 
 void UinputTouchScreen::sendTrackingId(int32_t trackingId) {
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TRACKING_ID, trackingId));
+    injectEvent(EV_ABS, ABS_MT_TRACKING_ID, trackingId);
 }
 
 void UinputTouchScreen::sendDown(const Point& point) {
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 1));
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x));
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y));
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+    injectEvent(EV_KEY, BTN_TOUCH, 1);
+    injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x);
+    injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y);
+    injectEvent(EV_SYN, SYN_REPORT, 0);
 }
 
 void UinputTouchScreen::sendMove(const Point& point) {
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x));
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y));
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+    injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x);
+    injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y);
+    injectEvent(EV_SYN, SYN_REPORT, 0);
 }
 
 void UinputTouchScreen::sendUp() {
     sendTrackingId(0xffffffff);
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 0));
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+    injectEvent(EV_KEY, BTN_TOUCH, 0);
+    injectEvent(EV_SYN, SYN_REPORT, 0);
 }
 
 void UinputTouchScreen::sendToolType(int32_t toolType) {
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType));
-    EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+    injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType);
+    injectEvent(EV_SYN, SYN_REPORT, 0);
 }
 
 // Get the center x, y base on the range definition.
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 106efd6..1622e77 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -93,6 +93,23 @@
     return nullptr;
 }
 
+void SensorService::SensorDirectConnection::updateSensorSubscriptions() {
+    if (!hasSensorAccess()) {
+        stopAll(true /* backupRecord */);
+    } else {
+        recoverAll();
+    }
+}
+
+void SensorService::SensorDirectConnection::setSensorAccess(bool hasAccess) {
+    mHasSensorAccess = hasAccess;
+    updateSensorSubscriptions();
+}
+
+bool SensorService::SensorDirectConnection::hasSensorAccess() const {
+    return mHasSensorAccess && !mService->mSensorPrivacyPolicy->isSensorPrivacyEnabled();
+}
+
 status_t SensorService::SensorDirectConnection::enableDisable(
         int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs,
         int reservedFlags) {
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index ead08d3..fa88fbc 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -54,6 +54,9 @@
     // called by SensorService when return to NORMAL mode.
     void recoverAll();
 
+    void updateSensorSubscriptions();
+
+    void setSensorAccess(bool hasAccess);
 protected:
     virtual ~SensorDirectConnection();
     // ISensorEventConnection functions
@@ -66,6 +69,7 @@
     virtual int32_t configureChannel(int handle, int rateLevel);
     virtual void destroy();
 private:
+    bool hasSensorAccess() const;
     const sp<SensorService> mService;
     const uid_t mUid;
     const sensors_direct_mem_t mMem;
@@ -76,6 +80,8 @@
     std::unordered_map<int, int> mActivated;
     std::unordered_map<int, int> mActivatedBackup;
 
+    std::atomic_bool mHasSensorAccess = true;
+
     mutable Mutex mDestroyLock;
     bool mDestroyed;
 };
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 77d8c11..5be4ccd 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -70,17 +70,16 @@
 }
 
 bool SensorService::SensorEventConnection::needsWakeLock() {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     return !mDead && mWakeLockRefCount > 0;
 }
 
 void SensorService::SensorEventConnection::resetWakeLockRefCount() {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     mWakeLockRefCount = 0;
 }
 
 void SensorService::SensorEventConnection::dump(String8& result) {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
     result.appendFormat("\tOperating Mode: ");
     if (!mService->isWhiteListedPackage(getPackageName())) {
         result.append("RESTRICTED\n");
@@ -92,6 +91,8 @@
     result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | "
             "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize,
             mMaxCacheSize);
+
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     for (auto& it : mSensorInfo) {
         const FlushInfo& flushInfo = it.second.flushInfo;
         result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n",
@@ -122,7 +123,7 @@
  */
 void SensorService::SensorEventConnection::dump(util::ProtoOutputStream* proto) const {
     using namespace service::SensorEventConnectionProto;
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
 
     if (!mService->isWhiteListedPackage(getPackageName())) {
         proto->write(OPERATING_MODE, OP_MODE_RESTRICTED);
@@ -160,7 +161,7 @@
 
 bool SensorService::SensorEventConnection::addSensor(
     int32_t handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
     if (si == nullptr ||
         !canAccessSensor(si->getSensor(), "Tried adding", mOpPackageName) ||
@@ -179,12 +180,12 @@
 }
 
 bool SensorService::SensorEventConnection::removeSensor(int32_t handle) {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     return mSensorInfo.erase(handle) > 0;
 }
 
 std::vector<int32_t> SensorService::SensorEventConnection::getActiveSensorHandles() const {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     std::vector<int32_t> list;
     for (auto& it : mSensorInfo) {
         list.push_back(it.first);
@@ -193,17 +194,19 @@
 }
 
 bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::recursive_mutex> _backlock(mBackupLock);
+    std::lock_guard<std::mutex> _lock(mConnectionLock);
     return mSensorInfo.count(handle) + mSensorInfoBackup.count(handle) > 0;
 }
 
 bool SensorService::SensorEventConnection::hasAnySensor() const {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::recursive_mutex> _backlock(mBackupLock);
+    std::lock_guard<std::mutex> _lock(mConnectionLock);
     return mSensorInfo.size() + mSensorInfoBackup.size() ? true : false;
 }
 
 bool SensorService::SensorEventConnection::hasOneShotSensors() const {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     for (auto &it : mSensorInfo) {
         const int handle = it.first;
         sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
@@ -220,7 +223,7 @@
 
 void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle,
                                 bool value) {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     if (mSensorInfo.count(handle) > 0) {
         FlushInfo& flushInfo = mSensorInfo[handle].flushInfo;
         flushInfo.mFirstFlushPending = value;
@@ -228,7 +231,7 @@
 }
 
 void SensorService::SensorEventConnection::updateLooperRegistration(const sp<Looper>& looper) {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     updateLooperRegistrationLocked(looper);
 }
 
@@ -279,7 +282,7 @@
 }
 
 void SensorService::SensorEventConnection::incrementPendingFlushCount(int32_t handle) {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     if (mSensorInfo.count(handle) > 0) {
         FlushInfo& flushInfo = mSensorInfo[handle].flushInfo;
         flushInfo.mPendingFlushEventsToSend++;
@@ -295,7 +298,7 @@
     std::unique_ptr<sensors_event_t[]> sanitizedBuffer;
 
     int count = 0;
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     if (scratch) {
         size_t i=0;
         while (i<numEvents) {
@@ -453,11 +456,18 @@
 }
 
 void SensorService::SensorEventConnection::stopAll() {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
-    if (!mSensorInfo.empty()) {
-        mSensorInfoBackup = mSensorInfo;
-        mSensorInfo.clear();
+    bool backupPerformed = false;
+    std::lock_guard<std::recursive_mutex> _backlock(mBackupLock);
+    {
+        std::lock_guard<std::mutex> _lock(mConnectionLock);
+        if (!mSensorInfo.empty()) {
+            mSensorInfoBackup = mSensorInfo;
+            mSensorInfo.clear();
+            backupPerformed = true;
+        }
+    }
 
+    if (backupPerformed) {
         for (auto& it : mSensorInfoBackup) {
             int32_t handle = it.first;
 
@@ -471,7 +481,7 @@
 }
 
 void SensorService::SensorEventConnection::recoverAll() {
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::recursive_mutex> _l(mBackupLock);
     for (auto& it : mSensorInfoBackup) {
         int32_t handle = it.first;
         SensorRequest &request = it.second;
@@ -612,7 +622,7 @@
     // half the size of the socket buffer allocated in BitTube whichever is smaller.
     const int maxWriteSize = helpers::min(SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT/2,
             int(mService->mSocketBufferSize/(sizeof(sensors_event_t)*2)));
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     // Send pending flush complete events (if any)
     sendPendingFlushEventsLocked();
     for (int numEventsSent = 0; numEventsSent < mCacheSize;) {
@@ -724,7 +734,7 @@
 {
     status_t err = mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
 
-    std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+    std::lock_guard<std::mutex> _l(mConnectionLock);
     if (err == NO_ERROR && mSensorInfo.count(handle) > 0) {
         mSensorInfo[handle].samplingPeriodNs = samplingPeriodNs;
     }
@@ -750,7 +760,7 @@
             // and remove the fd from Looper. Call checkWakeLockState to know if SensorService
             // can release the wake-lock.
             ALOGD_IF(DEBUG_CONNECTIONS, "%p Looper error %d", this, fd);
-            std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+            std::lock_guard<std::mutex> _l(mConnectionLock);
             mDead = true;
             mWakeLockRefCount = 0;
             updateLooperRegistrationLocked(mService->getLooper());
@@ -769,7 +779,7 @@
         unsigned char buf[sizeof(sensors_event_t)];
         ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
         {
-            std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+            std::lock_guard<std::mutex> _l(mConnectionLock);
             if (numBytesRead == sizeof(sensors_event_t)) {
                 if (!mDataInjectionMode) {
                     ALOGE("Data injected in normal mode, dropping event"
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 3ba5c07..80e7431 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -146,7 +146,13 @@
     sp<SensorService> const mService;
     sp<BitTube> mChannel;
     uid_t mUid;
-    mutable std::recursive_mutex mConnectionLock;
+
+    // A lock that should be used when modifying mSensorInfo
+    mutable std::mutex mConnectionLock;
+
+    // A lock that should be used when modifying mSensorInfoBackup
+    mutable std::recursive_mutex mBackupLock;
+
     // Number of events from wake up sensors which are still pending and haven't been delivered to
     // the corresponding application. It is incremented by one unit for each write to the socket.
     uint32_t mWakeLockRefCount;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 5ae7c51..29df825 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -302,6 +302,7 @@
 void SensorService::setSensorAccess(uid_t uid, bool hasAccess) {
     ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
     const auto& connections = connLock.getActiveConnections();
+    const auto& directConnections = connLock.getDirectConnections();
 
     mLock.unlock();
     for (const sp<SensorEventConnection>& conn : connections) {
@@ -309,6 +310,15 @@
             conn->setSensorAccess(hasAccess);
         }
     }
+
+    for (const sp<SensorDirectConnection>& conn : directConnections) {
+        if (conn->getUid() == uid) {
+            conn->setSensorAccess(hasAccess);
+        }
+    }
+
+    // Lock the mutex again for clean shutdown
+    mLock.lock();
 }
 
 const Sensor& SensorService::registerSensor(SensorInterface* s, bool isDebug, bool isVirtual) {
@@ -645,7 +655,7 @@
         connection->updateSensorSubscriptions();
     }
     for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
-        connection->stopAll(true /* backupRecord */);
+        connection->updateSensorSubscriptions();
     }
     dev.disableAllSensors();
     // Clear all pending flush connections for all active sensors. If one of the active
@@ -676,7 +686,7 @@
         connection->updateSensorSubscriptions();
     }
     for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
-        connection->recoverAll();
+        connection->updateSensorSubscriptions();
     }
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index f24f314..b6d904f 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -35,6 +35,7 @@
 
 using byte_view = std::basic_string_view<uint8_t>;
 
+constexpr size_t kEdidBlockSize = 128;
 constexpr size_t kEdidHeaderLength = 5;
 
 constexpr uint16_t kFallbackEdidManufacturerId = 0;
@@ -98,6 +99,57 @@
     return info;
 }
 
+Cea861ExtensionBlock parseCea861Block(const byte_view& block) {
+    Cea861ExtensionBlock cea861Block;
+
+    constexpr size_t kRevisionNumberOffset = 1;
+    cea861Block.revisionNumber = block[kRevisionNumberOffset];
+
+    constexpr size_t kDetailedTimingDescriptorsOffset = 2;
+    const size_t dtdStart =
+            std::min(kEdidBlockSize, static_cast<size_t>(block[kDetailedTimingDescriptorsOffset]));
+
+    // Parse data blocks.
+    for (size_t dataBlockOffset = 4; dataBlockOffset < dtdStart;) {
+        const uint8_t header = block[dataBlockOffset];
+        const uint8_t tag = header >> 5;
+        const size_t bodyLength = header & 0b11111;
+        constexpr size_t kDataBlockHeaderSize = 1;
+        const size_t dataBlockSize = bodyLength + kDataBlockHeaderSize;
+
+        if (block.size() < dataBlockOffset + dataBlockSize) {
+            ALOGW("Invalid EDID: CEA 861 data block is truncated.");
+            break;
+        }
+
+        const byte_view dataBlock(block.data() + dataBlockOffset, dataBlockSize);
+        constexpr uint8_t kVendorSpecificDataBlockTag = 0x3;
+
+        if (tag == kVendorSpecificDataBlockTag) {
+            const uint32_t ieeeRegistrationId =
+                    dataBlock[1] | (dataBlock[2] << 8) | (dataBlock[3] << 16);
+            constexpr uint32_t kHdmiIeeeRegistrationId = 0xc03;
+
+            if (ieeeRegistrationId == kHdmiIeeeRegistrationId) {
+                const uint8_t a = dataBlock[4] >> 4;
+                const uint8_t b = dataBlock[4] & 0b1111;
+                const uint8_t c = dataBlock[5] >> 4;
+                const uint8_t d = dataBlock[5] & 0b1111;
+                cea861Block.hdmiVendorDataBlock =
+                        HdmiVendorDataBlock{.physicalAddress = HdmiPhysicalAddress{a, b, c, d}};
+            } else {
+                ALOGV("Ignoring vendor specific data block for vendor with IEEE OUI %x",
+                      ieeeRegistrationId);
+            }
+        } else {
+            ALOGV("Ignoring CEA-861 data block with tag %x", tag);
+        }
+        dataBlockOffset += bodyLength + kDataBlockHeaderSize;
+    }
+
+    return cea861Block;
+}
+
 } // namespace
 
 uint16_t DisplayId::manufacturerId() const {
@@ -115,13 +167,12 @@
 }
 
 std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) {
-    constexpr size_t kMinLength = 128;
-    if (edid.size() < kMinLength) {
+    if (edid.size() < kEdidBlockSize) {
         ALOGW("Invalid EDID: structure is truncated.");
         // Attempt parsing even if EDID is malformed.
     } else {
-        ALOGW_IF(edid[126] != 0, "EDID extensions are currently unsupported.");
-        ALOGW_IF(std::accumulate(edid.begin(), edid.begin() + kMinLength, static_cast<uint8_t>(0)),
+        ALOGW_IF(std::accumulate(edid.begin(), edid.begin() + kEdidBlockSize,
+                                 static_cast<uint8_t>(0)),
                  "Invalid EDID: structure does not checksum.");
     }
 
@@ -227,13 +278,43 @@
     // have been observed to change on some displays with multiple inputs.
     const auto modelHash = static_cast<uint32_t>(std::hash<std::string_view>()(modelString));
 
+    // Parse extension blocks.
+    std::optional<Cea861ExtensionBlock> cea861Block;
+    if (edid.size() < kEdidBlockSize) {
+        ALOGW("Invalid EDID: block 0 is truncated.");
+    } else {
+        constexpr size_t kNumExtensionsOffset = 126;
+        const size_t numExtensions = edid[kNumExtensionsOffset];
+        view = byte_view(edid.data(), edid.size());
+        for (size_t blockNumber = 1; blockNumber <= numExtensions; blockNumber++) {
+            view.remove_prefix(kEdidBlockSize);
+            if (view.size() < kEdidBlockSize) {
+                ALOGW("Invalid EDID: block %zu is truncated.", blockNumber);
+                break;
+            }
+
+            const byte_view block(view.data(), kEdidBlockSize);
+            ALOGW_IF(std::accumulate(block.begin(), block.end(), static_cast<uint8_t>(0)),
+                     "Invalid EDID: block %zu does not checksum.", blockNumber);
+            const uint8_t tag = block[0];
+
+            constexpr uint8_t kCea861BlockTag = 0x2;
+            if (tag == kCea861BlockTag) {
+                cea861Block = parseCea861Block(block);
+            } else {
+                ALOGV("Ignoring block number %zu with tag %x.", blockNumber, tag);
+            }
+        }
+    }
+
     return Edid{.manufacturerId = manufacturerId,
                 .productId = productId,
                 .pnpId = *pnpId,
                 .modelHash = modelHash,
                 .displayName = displayName,
+                .manufactureOrModelYear = manufactureOrModelYear,
                 .manufactureWeek = manufactureWeek,
-                .manufactureOrModelYear = manufactureOrModelYear};
+                .cea861Block = cea861Block};
 }
 
 std::optional<PnpId> getPnpId(uint16_t manufacturerId) {
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index d91b957..fc2f72e 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -57,6 +57,26 @@
     std::optional<DeviceProductInfo> deviceProductInfo;
 };
 
+struct ExtensionBlock {
+    uint8_t tag;
+    uint8_t revisionNumber;
+};
+
+struct HdmiPhysicalAddress {
+    // The address describes the path from the display sink in the network of connected HDMI
+    // devices. The format of the address is "a.b.c.d". For example, address 2.1.0.0 means we are
+    // connected to port 1 of a device which is connected to port 2 of the sink.
+    uint8_t a, b, c, d;
+};
+
+struct HdmiVendorDataBlock {
+    std::optional<HdmiPhysicalAddress> physicalAddress;
+};
+
+struct Cea861ExtensionBlock : ExtensionBlock {
+    std::optional<HdmiVendorDataBlock> hdmiVendorDataBlock;
+};
+
 struct Edid {
     uint16_t manufacturerId;
     uint16_t productId;
@@ -65,6 +85,7 @@
     std::string_view displayName;
     uint8_t manufactureOrModelYear;
     uint8_t manufactureWeek;
+    std::optional<Cea861ExtensionBlock> cea861Block;
 };
 
 bool isEdid(const DisplayIdentificationData&);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3d67a6b..5039761 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2134,10 +2134,12 @@
     writeToProtoDrawingState(layerProto, traceFlags);
     writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
 
-    // Only populate for the primary display.
-    if (device) {
-        const Hwc2::IComposerClient::Composition compositionType = getCompositionType(device);
-        layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
+    if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) {
+        // Only populate for the primary display.
+        if (device) {
+            const Hwc2::IComposerClient::Composition compositionType = getCompositionType(device);
+            layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
+        }
     }
 
     for (const sp<Layer>& layer : mDrawingChildren) {
@@ -2180,8 +2182,10 @@
         LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
                                                [&]() { return layerInfo->mutable_position(); });
         LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
-        LayerProtoHelper::writeToProto(debugGetVisibleRegionOnDefaultDisplay(),
-                                       [&]() { return layerInfo->mutable_visible_region(); });
+        if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) {
+            LayerProtoHelper::writeToProto(debugGetVisibleRegionOnDefaultDisplay(),
+                                           [&]() { return layerInfo->mutable_visible_region(); });
+        }
         LayerProtoHelper::writeToProto(surfaceDamageRegion,
                                        [&]() { return layerInfo->mutable_damage_region(); });
 
@@ -2191,15 +2195,13 @@
         }
     }
 
-    if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
-        LayerProtoHelper::writeToProto(mSourceBounds,
-                                       [&]() { return layerInfo->mutable_source_bounds(); });
-        LayerProtoHelper::writeToProto(mScreenBounds,
-                                       [&]() { return layerInfo->mutable_screen_bounds(); });
-        LayerProtoHelper::writeToProto(getRoundedCornerState().cropRect,
-                                       [&]() { return layerInfo->mutable_corner_radius_crop(); });
-        layerInfo->set_shadow_radius(mEffectiveShadowRadius);
-    }
+    LayerProtoHelper::writeToProto(mSourceBounds,
+                                   [&]() { return layerInfo->mutable_source_bounds(); });
+    LayerProtoHelper::writeToProto(mScreenBounds,
+                                   [&]() { return layerInfo->mutable_screen_bounds(); });
+    LayerProtoHelper::writeToProto(getRoundedCornerState().cropRect,
+                                   [&]() { return layerInfo->mutable_corner_radius_crop(); });
+    layerInfo->set_shadow_radius(mEffectiveShadowRadius);
 }
 
 void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c47bf94..4ceac4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1947,8 +1947,18 @@
             // potentially trigger a display handoff.
             updateVrFlinger();
 
-            bool refreshNeeded = handleMessageTransaction();
-            refreshNeeded |= handleMessageInvalidate();
+            bool refreshNeeded;
+            withTracingLock([&]() {
+                refreshNeeded = handleMessageTransaction();
+                refreshNeeded |= handleMessageInvalidate();
+                if (mTracingEnabled) {
+                    mAddCompositionStateToTrace =
+                            mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
+                    if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
+                        mTracing.notifyLocked("visibleRegionsDirty");
+                    }
+                }
+            });
 
             // Layers need to get updated (in the previous line) before we can use them for
             // choosing the refresh rate.
@@ -2092,7 +2102,7 @@
     mLayersWithQueuedFrames.clear();
     if (mVisibleRegionsDirty) {
         mVisibleRegionsDirty = false;
-        if (mTracingEnabled) {
+        if (mTracingEnabled && mAddCompositionStateToTrace) {
             mTracing.notify("visibleRegionsDirty");
         }
     }
@@ -2974,8 +2984,7 @@
 
 void SurfaceFlinger::commitTransaction()
 {
-    withTracingLock([this]() { commitTransactionLocked(); });
-
+    commitTransactionLocked();
     mTransactionPending = false;
     mAnimTransactionPending = false;
     mTransactionCV.broadcast();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3997633..12efca1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1077,6 +1077,7 @@
     std::unique_ptr<SurfaceInterceptor> mInterceptor;
     SurfaceTracing mTracing{*this};
     bool mTracingEnabled = false;
+    bool mAddCompositionStateToTrace = false;
     bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false;
     const std::shared_ptr<TimeStats> mTimeStats;
     const std::unique_ptr<FrameTracer> mFrameTracer;
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index a9c3332..0b1251e 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -60,6 +60,8 @@
     mCanStartTrace.wait(lock);
     android::base::ScopedLockAssertion assumeLock(mSfLock);
     LayersTraceProto entry = traceLayersLocked(mWhere, displayDevice);
+    mTracingInProgress = false;
+    mMissedTraceEntries = 0;
     lock.unlock();
     return entry;
 }
@@ -76,7 +78,15 @@
 
 void SurfaceTracing::notify(const char* where) {
     std::scoped_lock lock(mSfLock);
+    notifyLocked(where);
+}
+
+void SurfaceTracing::notifyLocked(const char* where) {
     mWhere = where;
+    if (mTracingInProgress) {
+        mMissedTraceEntries++;
+    }
+    mTracingInProgress = true;
     mCanStartTrace.notify_one();
 }
 
@@ -175,7 +185,10 @@
     entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
     entry.set_where(where);
     LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags, displayDevice));
-    mFlinger.dumpOffscreenLayersProto(layers);
+
+    if (flagIsSetLocked(SurfaceTracing::TRACE_EXTRA)) {
+        mFlinger.dumpOffscreenLayersProto(layers);
+    }
     entry.mutable_layers()->Swap(&layers);
 
     if (mTraceFlags & SurfaceTracing::TRACE_HWC) {
@@ -183,6 +196,10 @@
         mFlinger.dumpHwc(hwcDump);
         entry.set_hwc_blob(hwcDump);
     }
+    if (!flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION)) {
+        entry.set_excludes_composition_state(true);
+    }
+    entry.set_missed_entries(mMissedTraceEntries);
 
     return entry;
 }
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 83872ed..a00e5d6 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -49,6 +49,7 @@
     status_t writeToFile();
     bool isEnabled() const;
     void notify(const char* where);
+    void notifyLocked(const char* where) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */;
 
     void setBufferSize(size_t bufferSizeInByte);
     void writeToFileAsync();
@@ -57,11 +58,15 @@
     enum : uint32_t {
         TRACE_CRITICAL = 1 << 0,
         TRACE_INPUT = 1 << 1,
-        TRACE_EXTRA = 1 << 2,
-        TRACE_HWC = 1 << 3,
+        TRACE_COMPOSITION = 1 << 2,
+        TRACE_EXTRA = 1 << 3,
+        TRACE_HWC = 1 << 4,
         TRACE_ALL = 0xffffffff
     };
     void setTraceFlags(uint32_t flags);
+    bool flagIsSetLocked(uint32_t flags) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */ {
+        return (mTraceFlags & flags) == flags;
+    }
 
 private:
     static constexpr auto kDefaultBufferCapInByte = 5_MB;
@@ -103,6 +108,8 @@
     std::mutex& mSfLock;
     uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT;
     const char* mWhere GUARDED_BY(mSfLock) = "";
+    uint32_t mMissedTraceEntries GUARDED_BY(mSfLock) = 0;
+    bool mTracingInProgress GUARDED_BY(mSfLock) = false;
 
     mutable std::mutex mTraceLock;
     LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock);
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index ac33a0e..acf621e 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -51,4 +51,10 @@
 
     // Blob for the current HWC information for all layers, reported by dumpsys.
     optional string hwc_blob = 4;
+
+    /* Includes state sent during composition like visible region and composition type. */
+    optional bool excludes_composition_state = 5;
+
+    /* Number of missed entries since the last entry was recorded. */
+    optional int32 missed_entries = 6;
 }
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index c2ddfce..cc11aa9 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -96,7 +96,7 @@
         "\x0a\x20\x20\x20\x20\x20\x01\x47\x02\x03\x2d\x71\x50\x90\x05"
         "\x04\x03\x07\x02\x06\x01\x1f\x14\x13\x12\x16\x11\x15\x20\x2c"
         "\x09\x07\x03\x15\x07\x50\x57\x07\x00\x39\x07\xbb\x66\x03\x0c"
-        "\x00\x20\x00\x00\x83\x01\x00\x00\x01\x1d\x00\x72\x51\xd0\x1e"
+        "\x00\x12\x34\x00\x83\x01\x00\x00\x01\x1d\x00\x72\x51\xd0\x1e"
         "\x20\x6e\x28\x55\x00\xc4\x8e\x21\x00\x00\x1e\x01\x1d\x80\x18"
         "\x71\x1c\x16\x20\x58\x2c\x25\x00\xc4\x8e\x21\x00\x00\x9e\x8c"
         "\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\x13\x8e\x21\x00"
@@ -185,6 +185,7 @@
     EXPECT_EQ(12610, edid->productId);
     EXPECT_EQ(21, edid->manufactureOrModelYear);
     EXPECT_EQ(0, edid->manufactureWeek);
+    EXPECT_FALSE(edid->cea861Block);
 
     edid = parseEdid(getExternalEdid());
     ASSERT_TRUE(edid);
@@ -195,6 +196,7 @@
     EXPECT_EQ(10348, edid->productId);
     EXPECT_EQ(22, edid->manufactureOrModelYear);
     EXPECT_EQ(2, edid->manufactureWeek);
+    EXPECT_FALSE(edid->cea861Block);
 
     edid = parseEdid(getExternalEedid());
     ASSERT_TRUE(edid);
@@ -205,6 +207,14 @@
     EXPECT_EQ(2302, edid->productId);
     EXPECT_EQ(21, edid->manufactureOrModelYear);
     EXPECT_EQ(41, edid->manufactureWeek);
+    ASSERT_TRUE(edid->cea861Block);
+    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
+    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock->physicalAddress);
+    auto physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
+    EXPECT_EQ(2, physicalAddress->a);
+    EXPECT_EQ(0, physicalAddress->b);
+    EXPECT_EQ(0, physicalAddress->c);
+    EXPECT_EQ(0, physicalAddress->d);
 
     edid = parseEdid(getPanasonicTvEdid());
     ASSERT_TRUE(edid);
@@ -215,6 +225,14 @@
     EXPECT_EQ(41622, edid->productId);
     EXPECT_EQ(29, edid->manufactureOrModelYear);
     EXPECT_EQ(0, edid->manufactureWeek);
+    ASSERT_TRUE(edid->cea861Block);
+    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
+    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock->physicalAddress);
+    physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
+    EXPECT_EQ(2, physicalAddress->a);
+    EXPECT_EQ(0, physicalAddress->b);
+    EXPECT_EQ(0, physicalAddress->c);
+    EXPECT_EQ(0, physicalAddress->d);
 
     edid = parseEdid(getHisenseTvEdid());
     ASSERT_TRUE(edid);
@@ -225,6 +243,14 @@
     EXPECT_EQ(0, edid->productId);
     EXPECT_EQ(29, edid->manufactureOrModelYear);
     EXPECT_EQ(18, edid->manufactureWeek);
+    ASSERT_TRUE(edid->cea861Block);
+    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
+    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock->physicalAddress);
+    physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
+    EXPECT_EQ(1, physicalAddress->a);
+    EXPECT_EQ(2, physicalAddress->b);
+    EXPECT_EQ(3, physicalAddress->c);
+    EXPECT_EQ(4, physicalAddress->d);
 
     edid = parseEdid(getCtlDisplayEdid());
     ASSERT_TRUE(edid);
@@ -235,6 +261,8 @@
     EXPECT_EQ(9373, edid->productId);
     EXPECT_EQ(23, edid->manufactureOrModelYear);
     EXPECT_EQ(0xff, edid->manufactureWeek);
+    ASSERT_TRUE(edid->cea861Block);
+    EXPECT_FALSE(edid->cea861Block->hdmiVendorDataBlock);
 }
 
 TEST(DisplayIdentificationTest, parseInvalidEdid) {