Merge "Fix signed/unsigned conversion warning"
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index baa05d0..685fdd8 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -990,14 +990,22 @@
   return oat_dir == nullptr || oat_dir[0] == '!';
 }
 
+// Best-effort check whether we can fit the the path into our buffers.
+// Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
+// without a swap file, if necessary. Reference profiles file also add an extra ".prof"
+// extension to the cache path (5 bytes).
+// TODO(calin): move away from char* buffers and PKG_PATH_MAX.
+static bool validate_dex_path_size(const std::string& dex_path) {
+    if (dex_path.size() >= (PKG_PATH_MAX - 8)) {
+        LOG(ERROR) << "dex_path too long: " << dex_path;
+        return false;
+    }
+    return true;
+}
+
 static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
             const char* oat_dir, bool is_secondary_dex, /*out*/ char* out_oat_path) {
-    // Early best-effort check whether we can fit the the path into our buffers.
-    // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
-    // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
-    // extension to the cache path (5 bytes).
-    if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
-        ALOGE("apk_path too long '%s'\n", apk_path);
+    if (!validate_dex_path_size(apk_path)) {
         return false;
     }
 
@@ -1350,33 +1358,29 @@
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
 // the profile has changed.
-static void exec_dexoptanalyzer(const std::string& dex_file, const char* instruction_set,
-        const char* compiler_filter, bool profile_was_updated) {
+static void exec_dexoptanalyzer(const std::string& dex_file, const std::string& instruction_set,
+        const std::string& compiler_filter, bool profile_was_updated) {
     static const char* DEXOPTANALYZER_BIN = "/system/bin/dexoptanalyzer";
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
-    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        ALOGE("Instruction set %s longer than max length of %d",
-              instruction_set, MAX_INSTRUCTION_SET_LEN);
+    if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
+        LOG(ERROR) << "Instruction set " << instruction_set
+                << " longer than max length of " << MAX_INSTRUCTION_SET_LEN;
         return;
     }
 
-    char dex_file_arg[strlen("--dex-file=") + PKG_PATH_MAX];
-    char isa_arg[strlen("--isa=") + MAX_INSTRUCTION_SET_LEN];
-    char compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax];
+    std::string dex_file_arg = "--dex-file=" + dex_file;
+    std::string isa_arg = "--isa=" + instruction_set;
+    std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
     const char* assume_profile_changed = "--assume-profile-changed";
 
-    sprintf(dex_file_arg, "--dex-file=%s", dex_file.c_str());
-    sprintf(isa_arg, "--isa=%s", instruction_set);
-    sprintf(compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
-
     // program name, dex file, isa, filter, the final NULL
     const char* argv[5 + (profile_was_updated ? 1 : 0)];
     int i = 0;
     argv[i++] = DEXOPTANALYZER_BIN;
-    argv[i++] = dex_file_arg;
-    argv[i++] = isa_arg;
-    argv[i++] = compiler_filter_arg;
+    argv[i++] = dex_file_arg.c_str();
+    argv[i++] = isa_arg.c_str();
+    argv[i++] = compiler_filter_arg.c_str();
     if (profile_was_updated) {
         argv[i++] = assume_profile_changed;
     }
@@ -1490,6 +1494,9 @@
         }
     }
     const std::string& dex_path = *dex_path_out;
+    if (!validate_dex_path_size(dex_path)) {
+        return false;
+    }
     if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
         LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
         return false;
@@ -1560,6 +1567,10 @@
         LOG_FATAL("dexopt flags contains unknown fields\n");
     }
 
+    if (!validate_dex_path_size(dex_path)) {
+        return false;
+    }
+
     bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
     bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
     bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
@@ -1749,6 +1760,10 @@
         /*out*/bool* out_secondary_dex_exists) {
     // Set out to false to start with, just in case we have validation errors.
     *out_secondary_dex_exists = false;
+    if (!validate_dex_path_size(dex_path)) {
+        return false;
+    }
+
     if (isas.size() == 0) {
         LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
         return false;
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 6a81cfc..2597c79 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -31,7 +31,7 @@
 constexpr const char* DALVIK_CACHE_POSTFIX = "@classes.dex";
 
 constexpr size_t PKG_NAME_MAX = 128u;   /* largest allowed package name */
-constexpr size_t PKG_PATH_MAX = 256u;   /* max size of any path we use */
+constexpr size_t PKG_PATH_MAX = 1024u;  /* max size of any path we use */
 
 /****************************************************************************
  * IMPORTANT: These values are passed from Java code. Keep them in sync with
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index aec211a..d336a43 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -12,3 +12,4 @@
     onrestart restart drm
     onrestart restart cameraserver
     writepid /dev/cpuset/system-background/tasks
+    shutdown critical
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index d5ddaaf..3fa4d7d 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -3,4 +3,4 @@
     user system
     group system readproc
     writepid /dev/cpuset/system-background/tasks
-
+    shutdown critical
diff --git a/headers/Android.bp b/headers/Android.bp
index 1ea1ea5..bcbbbc3 100644
--- a/headers/Android.bp
+++ b/headers/Android.bp
@@ -1,5 +1,6 @@
 cc_library_headers {
     name: "media_plugin_headers",
+    vendor_available: true,
     export_include_dirs: ["media_plugin"],
     header_libs: [
         "libstagefright_headers",
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index bef9505..3071408 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -42,6 +42,23 @@
 }
 
 cc_test {
+    name: "binderLibTest_IPC_32",
+    srcs: ["binderLibTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+    compile_multilib: "32",
+    cflags: ["-DBINDER_IPC_32BIT=1"],
+}
+
+cc_test {
+    product_variables: {
+        binder32bit: {
+            cflags: ["-DBINDER_IPC_32BIT=1"],
+        },
+    },
+
     name: "binderLibTest",
     srcs: ["binderLibTest.cpp"],
     shared_libs: [
diff --git a/libs/sensor/ISensorEventConnection.cpp b/libs/sensor/ISensorEventConnection.cpp
index 8a3a623..1cd8e01 100644
--- a/libs/sensor/ISensorEventConnection.cpp
+++ b/libs/sensor/ISensorEventConnection.cpp
@@ -36,7 +36,8 @@
     ENABLE_DISABLE,
     SET_EVENT_RATE,
     FLUSH_SENSOR,
-    CONFIGURE_CHANNEL
+    CONFIGURE_CHANNEL,
+    DESTROY,
 };
 
 class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
@@ -96,11 +97,22 @@
         remote()->transact(CONFIGURE_CHANNEL, data, &reply);
         return reply.readInt32();
     }
+
+    virtual void onLastStrongRef(const void* id) {
+        destroy();
+        BpInterface<ISensorEventConnection>::onLastStrongRef(id);
+    }
+
+protected:
+    virtual void destroy() {
+        Parcel data, reply;
+        remote()->transact(DESTROY, data, &reply);
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
 // translation unit (see clang warning -Wweak-vtables)
-BpSensorEventConnection::~BpSensorEventConnection() {}
+BpSensorEventConnection::~BpSensorEventConnection() { }
 
 IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection");
 
@@ -150,6 +162,10 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
+        case DESTROY: {
+            destroy();
+            return NO_ERROR;
+        }
 
     }
     return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/sensor/include/sensor/ISensorEventConnection.h b/libs/sensor/include/sensor/ISensorEventConnection.h
index 07cc7e8..b62e18c 100644
--- a/libs/sensor/include/sensor/ISensorEventConnection.h
+++ b/libs/sensor/include/sensor/ISensorEventConnection.h
@@ -42,6 +42,8 @@
     virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
     virtual status_t flush() = 0;
     virtual int32_t configureChannel(int32_t handle, int32_t rateLevel) = 0;
+protected:
+    virtual void destroy() = 0; // synchronously release resource hold by remote object
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 87dbaf4..0eb08e5 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "Gralloc2"
 
+#include <hidl/ServiceManagement.h>
 #include <hwbinder/IPCThreadState.h>
 #include <ui/Gralloc2.h>
 
@@ -31,6 +32,10 @@
 
 static constexpr Error kTransactionError = Error::NO_RESOURCES;
 
+void Mapper::preload() {
+    android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
+}
+
 Mapper::Mapper()
 {
     mMapper = IMapper::getService();
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index b9fa640..d52c508 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -42,6 +42,10 @@
 
 ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
 
+void GraphicBufferMapper::preloadHal() {
+    Gralloc2::Mapper::preload();
+}
+
 GraphicBufferMapper::GraphicBufferMapper()
   : mMapper(std::make_unique<const Gralloc2::Mapper>())
 {
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index e7b8ca9..8aee160 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -38,6 +38,8 @@
 // A wrapper to IMapper
 class Mapper {
 public:
+    static void preload();
+
     Mapper();
 
     Error createDescriptor(
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index e0702e9..06961b1 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -43,6 +43,7 @@
 class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
 {
 public:
+    static void preloadHal();
     static inline GraphicBufferMapper& get() { return getInstance(); }
 
     // The imported outHandle must be freed with freeBuffer when no longer
diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp
index fa61c4a..1daa5d6 100644
--- a/libs/vr/libbufferhub/bufferhub_tests.cpp
+++ b/libs/vr/libbufferhub/bufferhub_tests.cpp
@@ -62,6 +62,57 @@
   EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
 }
 
+TEST_F(LibBufferHubTest, TestStateTransitions) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  uint64_t context;
+  LocalHandle fence;
+
+  // The producer buffer starts in gained state.
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EALREADY, p->Gain(&fence));
+
+  // Post in gained state should succeed.
+  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+
+  // Post, release, and gain in posted state should fail.
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+  // Acquire in posted state should succeed.
+  EXPECT_LE(0, c->Acquire(&fence, &context));
+
+  // Acquire, post, and gain in acquired state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+  // Release in acquired state should succeed.
+  EXPECT_EQ(0, c->Release(LocalHandle()));
+
+  // Release, acquire, and post in released state should fail.
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+
+  // Gain in released state should succeed.
+  EXPECT_EQ(0, p->Gain(&fence));
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EALREADY, p->Gain(&fence));
+}
+
 TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
   struct Metadata {
     int64_t field1;
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index aa2ed94..2e1655f 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -313,7 +313,10 @@
 int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
                               DvrReadBuffer* read_buffer, int* out_fence_fd,
                               void* out_meta, size_t meta_size_bytes) {
-  if (!read_queue || !read_buffer || !out_fence_fd || !out_meta)
+  if (!read_queue || !read_buffer || !out_fence_fd)
+    return -EINVAL;
+
+  if (meta_size_bytes != 0 && !out_meta)
     return -EINVAL;
 
   return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
diff --git a/libs/vr/libdvr/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
index 46d72ca..4e87cf6 100644
--- a/libs/vr/libdvr/dvr_hardware_composer_client.cpp
+++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
@@ -100,10 +100,13 @@
 }
 
 void dvrHwcClientDestroy(DvrHwcClient* client) {
+  client->composer->clearObserver();
+
   // NOTE: Deleting DvrHwcClient* isn't enough since DvrHwcClient::callback is a
   // shared pointer that could be referenced from a binder thread. But the
   // client callback isn't valid past this calls so that needs to be reset.
   client->callback->Shutdown();
+
   delete client;
 }
 
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index caf208d..95c04f1 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -124,6 +124,8 @@
 //     signals the release of underlying buffer. The consumer should wait until
 //     this fence clears before reading data from it.
 // @param out_meta The memory area where a metadata object will be filled.
+//     Can be nullptr iff |meta_size_bytes| is zero (i.e., there is no
+//     metadata).
 // @param meta_size_bytes Size of the metadata object caller expects. If it
 //     doesn't match the size of actually metadata transported by the buffer
 //     queue, the method returns -EINVAL.
diff --git a/libs/vr/libdvr/include/dvr/dvr_pose.h b/libs/vr/libdvr/include/dvr/dvr_pose.h
index 4256cf9..b3df028 100644
--- a/libs/vr/libdvr/include/dvr/dvr_pose.h
+++ b/libs/vr/libdvr/include/dvr/dvr_pose.h
@@ -43,16 +43,24 @@
 } DvrPoseAsync;
 
 enum {
-  DVR_POSE_FLAG_INVALID = (1UL << 0),       // This pose is invalid.
-  DVR_POSE_FLAG_INITIALIZING = (1UL << 1),  // The pose delivered during
-                                            // initialization and it may not be
-                                            // correct.
+  DVR_POSE_FLAG_INVALID = (1ULL << 0),       // This pose is invalid.
+  DVR_POSE_FLAG_INITIALIZING = (1ULL << 1),  // The pose delivered during
+                                             // initialization and it may not be
+                                             // correct.
   DVR_POSE_FLAG_3DOF =
-      (1UL << 2),  // This pose is derived from 3Dof sensors. If
-                   // this is not set, pose is derived using
-                   // 3Dof and 6Dof sensors.
+      (1ULL << 2),  // This pose is derived from 3Dof sensors. If
+                    // this is not set, pose is derived using
+                    // 3Dof and 6Dof sensors.
   DVR_POSE_FLAG_FLOOR_HEIGHT_INVALID =
-      (1UL << 3),  // If set the floor height is invalid.
+      (1ULL << 3),  // If set the floor height is invalid.
+
+  // Bits that indicate the tracking system state.
+  DVR_POSE_FLAG_SERVICE_EXCEPTION = (1ULL << 32),
+  DVR_POSE_FLAG_FISHEYE_OVER_EXPOSED = (1ULL << 33),
+  DVR_POSE_FLAG_FISHEYE_UNDER_EXPOSED = (1ULL << 34),
+  DVR_POSE_FLAG_COLOR_OVER_EXPOSED = (1ULL << 35),
+  DVR_POSE_FLAG_COLOR_UNDER_EXPOSED = (1ULL << 36),
+  DVR_POSE_FLAG_TOO_FEW_FEATURES_TRACKED = (1ULL << 37)
 };
 
 // Represents a sensor pose sample.
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 5158612..497b1cb 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -37,15 +37,11 @@
 
  protected:
   void SetUp() override {
-    auto config = ProducerQueueConfigBuilder()
-                      .SetDefaultWidth(kBufferWidth)
-                      .SetDefaultHeight(kBufferHeight)
-                      .SetDefaultFormat(kBufferFormat)
-                      .SetMetadata<TestMeta>()
-                      .Build();
-    write_queue_ =
-        new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{}));
-    ASSERT_NE(nullptr, write_queue_);
+    config_builder_ = ProducerQueueConfigBuilder()
+                          .SetDefaultWidth(kBufferWidth)
+                          .SetDefaultHeight(kBufferHeight)
+                          .SetDefaultFormat(kBufferFormat)
+                          .SetMetadata<TestMeta>();
   }
 
   void TearDown() override {
@@ -55,6 +51,12 @@
     }
   }
 
+  void CreateWriteBufferQueue() {
+    write_queue_ = new DvrWriteBufferQueue(
+        ProducerQueue::Create(config_builder_.Build(), UsagePolicy{}));
+    ASSERT_NE(nullptr, write_queue_);
+  }
+
   void AllocateBuffers(size_t buffer_count) {
     auto status = write_queue_->producer_queue()->AllocateBuffers(
         kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
@@ -73,18 +75,23 @@
              buffer_removed_count_);
   }
 
+  ProducerQueueConfigBuilder config_builder_;
   DvrWriteBufferQueue* write_queue_{nullptr};
   int buffer_available_count_{0};
   int buffer_removed_count_{0};
 };
 
-TEST_F(DvrBufferQueueTest, TestWrite_QueueDestroy) {
+TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
   dvrWriteBufferQueueDestroy(write_queue_);
   write_queue_ = nullptr;
 }
 
 TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
-  AllocateBuffers(kQueueCapacity);
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
   size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
 
   ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
@@ -92,6 +99,8 @@
 }
 
 TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
   DvrReadBufferQueue* read_queue = nullptr;
   int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
@@ -102,6 +111,8 @@
 }
 
 TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
   DvrReadBufferQueue* read_queue1 = nullptr;
   DvrReadBufferQueue* read_queue2 = nullptr;
   int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
@@ -119,7 +130,8 @@
 }
 
 TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) {
-  AllocateBuffers(3);
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(3));
 
   DvrReadBuffer* read_buffer = nullptr;
   DvrWriteBuffer* write_buffer = nullptr;
@@ -152,6 +164,9 @@
 }
 
 TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
   static constexpr int kTimeout = 0;
   DvrReadBufferQueue* read_queue = nullptr;
   DvrReadBuffer* rb = nullptr;
@@ -172,8 +187,6 @@
   dvrReadBufferCreateEmpty(&rb);
   ASSERT_NE(nullptr, rb);
 
-  AllocateBuffers(kQueueCapacity);
-
   // Gain buffer for writing.
   ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb, &fence_fd);
   ASSERT_EQ(0, ret);
@@ -221,6 +234,8 @@
 }
 
 TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
   ANativeWindow* window = nullptr;
 
   // The |write_queue_| doesn't have proper metadata (must be
@@ -251,6 +266,9 @@
 // Before each dequeue operation, we resize the buffer queue and expect the
 // queue always return buffer with desired dimension.
 TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
   static constexpr int kTimeout = 0;
   int fence_fd = -1;
 
@@ -278,8 +296,6 @@
   dvrWriteBufferCreateEmpty(&wb3);
   ASSERT_NE(nullptr, wb3);
 
-  AllocateBuffers(kQueueCapacity);
-
   // Handle all pending events on the read queue.
   ret = dvrReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
@@ -369,6 +385,71 @@
   dvrReadBufferQueueDestroy(read_queue);
 }
 
+TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) {
+  // Overrides default queue parameters: Empty metadata.
+  config_builder_.SetMetadata<void>();
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+
+  DvrReadBuffer* rb = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  dvrReadBufferCreateEmpty(&rb);
+  dvrWriteBufferCreateEmpty(&wb);
+
+  DvrReadBufferQueue* read_queue = nullptr;
+  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+  const int kTimeoutMs = 0;
+  int fence_fd = -1;
+  EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
+
+  EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, nullptr, 0));
+  EXPECT_EQ(0, dvrWriteBufferClear(wb));
+  dvrWriteBufferDestroy(wb);
+  wb = nullptr;
+
+  // When acquire buffer, it's legit to pass nullptr as out_meta iff metadata
+  // size is Zero.
+  EXPECT_EQ(0, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
+                                         nullptr, 0));
+  EXPECT_TRUE(dvrReadBufferIsValid(rb));
+}
+
+TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+
+  DvrReadBuffer* rb = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  dvrReadBufferCreateEmpty(&rb);
+  dvrWriteBufferCreateEmpty(&wb);
+
+  DvrReadBufferQueue* read_queue = nullptr;
+  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+  const int kTimeoutMs = 0;
+  int fence_fd = -1;
+  EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
+
+  TestMeta seq = 42U;
+  EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, &seq, sizeof(seq)));
+  EXPECT_EQ(0, dvrWriteBufferClear(wb));
+  dvrWriteBufferDestroy(wb);
+  wb = nullptr;
+
+  // Dequeue with wrong metadata will cause EINVAL.
+  int8_t wrong_metadata;
+  EXPECT_EQ(-EINVAL,
+            dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
+                                      &wrong_metadata, sizeof(wrong_metadata)));
+  EXPECT_FALSE(dvrReadBufferIsValid(rb));
+
+  // Dequeue with empty metadata will cause EINVAL.
+  EXPECT_EQ(-EINVAL, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb,
+                                               &fence_fd, nullptr, 0));
+  EXPECT_FALSE(dvrReadBufferIsValid(rb));
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 6e18781..04e3d5f 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -248,11 +248,12 @@
            "ApplicationDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
            consumer_queue->id(), events);
 
+  std::lock_guard<std::mutex> autolock(lock_);
+
   // Always give the queue a chance to handle its internal bookkeeping.
   consumer_queue->HandleQueueEvents();
 
   // Check for hangup and remove a queue that is no longer needed.
-  std::lock_guard<std::mutex> autolock(lock_);
   if (consumer_queue->hung_up()) {
     ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnQueueEvent: Removing queue.");
     UnregisterQueue(consumer_queue);
@@ -317,11 +318,12 @@
   ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
            consumer_queue->id(), events);
 
+  std::lock_guard<std::mutex> autolock(lock_);
+
   // Always give the queue a chance to handle its internal bookkeeping.
   consumer_queue->HandleQueueEvents();
 
   // Check for hangup and remove a queue that is no longer needed.
-  std::lock_guard<std::mutex> autolock(lock_);
   if (consumer_queue->hung_up()) {
     ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: Removing queue.");
     UnregisterQueue(consumer_queue);
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index a344636..b4cc211 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -127,7 +127,14 @@
         "EGL/Loader.cpp",
         "EGL/BlobCache.cpp",
     ],
-    shared_libs: ["libvndksupport"],
+    shared_libs: [
+        "libvndksupport",
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+    ],
     static_libs: ["libEGL_getProcAddress"],
     ldflags: ["-Wl,--exclude-libs=ALL"],
     export_include_dirs: ["EGL/include"],
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 2fa36fa..0214b0e 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -87,10 +87,6 @@
         "EGL_ANDROID_get_native_client_buffer "
         "EGL_ANDROID_front_buffer_auto_refresh "
         "EGL_ANDROID_get_frame_timestamps "
-        "EGL_EXT_gl_colorspace_scrgb "
-        "EGL_EXT_gl_colorspace_scrgb_linear "
-        "EGL_EXT_gl_colorspace_display_p3_linear "
-        "EGL_EXT_gl_colorspace_display_p3 "
         ;
 
 char const * const gExtensionString  =
@@ -529,19 +525,25 @@
     return stripped;
 }
 
-static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
-                                         EGLint& colorSpace, android_dataspace& dataSpace) {
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType window,
+                                         const EGLint* attrib_list, EGLint& colorSpace,
+                                         android_dataspace& dataSpace) {
     colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
     dataSpace = HAL_DATASPACE_UNKNOWN;
+
     if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
         for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
             if (*attr == EGL_GL_COLORSPACE_KHR) {
                 colorSpace = attr[1];
                 bool found = false;
+                bool verify = true;
                 // Verify that color space is allowed
                 if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
                     colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) {
+                    // SRGB and LINEAR are always supported when EGL_KHR_gl_colorspace
+                    // is available, so no need to verify.
                     found = true;
+                    verify = false;
                 } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_linear &&
                            dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) {
                     found = true;
@@ -564,6 +566,31 @@
                 if (!found) {
                     return false;
                 }
+                if (verify && window) {
+                    bool wide_color_support = true;
+                    // Ordinarily we'd put a call to native_window_get_wide_color_support
+                    // at the beginning of the function so that we'll have the
+                    // result when needed elsewhere in the function.
+                    // However, because eglCreateWindowSurface is called by SurfaceFlinger and
+                    // SurfaceFlinger is required to answer the call below we would
+                    // end up in a deadlock situation. By moving the call to only happen
+                    // if the application has specifically asked for wide-color we avoid
+                    // the deadlock with SurfaceFlinger since it will not ask for a
+                    // wide-color surface.
+                    int err = native_window_get_wide_color_support(window, &wide_color_support);
+
+                    if (err) {
+                        ALOGE("getColorSpaceAttribute: invalid window (win=%p) "
+                              "failed (%#x) (already connected to another API?)",
+                              window, err);
+                        return false;
+                    }
+                    if (!wide_color_support) {
+                        // Application has asked for a wide-color colorspace but
+                        // wide-color support isn't available on the display the window is on.
+                        return false;
+                    }
+                }
                 // Only change the dataSpace from default if the application
                 // has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute.
                 dataSpace = modifyBufferDataspace(dataSpace, colorSpace);
@@ -573,6 +600,11 @@
     return true;
 }
 
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+                                         EGLint& colorSpace, android_dataspace& dataSpace) {
+    return getColorSpaceAttribute(dp, NULL, attrib_list, colorSpace, dataSpace);
+}
+
 void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) {
     // Set the native window's buffers format to match what this config requests.
     // Whether to use sRGB gamma is not part of the EGLconfig, but is part
@@ -667,7 +699,7 @@
         // now select correct colorspace and dataspace based on user's attribute list
         EGLint colorSpace;
         android_dataspace dataSpace;
-        if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+        if (!getColorSpaceAttribute(dp, window, attrib_list, colorSpace, dataSpace)) {
             ALOGE("error invalid colorspace: %d", colorSpace);
             return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
         }
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index b696920..4e5833a 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -30,6 +30,12 @@
 #include "Loader.h"
 #include <cutils/properties.h>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
@@ -192,6 +198,18 @@
         mClientApiString = sClientApiString;
 
         mExtensionString = gBuiltinExtensionString;
+
+        bool wideColorBoardConfig =
+                getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
+                        false);
+
+        // Add wide-color extensions if device can support wide-color
+        if (wideColorBoardConfig) {
+            mExtensionString.append(
+                    "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear "
+                    "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 ");
+        }
+
         char const* start = gExtensionString;
         do {
             // length of the extension name
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 62e6bd3..b67a053 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -200,6 +200,7 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
@@ -285,6 +286,7 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
@@ -370,6 +372,7 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
@@ -431,9 +434,10 @@
     EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
 }
 
-TEST_F(EGLTest, EGL_KHR_no_config_context) {
+TEST_F(EGLTest, EGLNoConfigContext) {
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
@@ -471,6 +475,7 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
+        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
         return;
     }
 
diff --git a/opengl/tests/gl_perf/filltest.cpp b/opengl/tests/gl_perf/filltest.cpp
index 3f8faca..4135c62 100644
--- a/opengl/tests/gl_perf/filltest.cpp
+++ b/opengl/tests/gl_perf/filltest.cpp
@@ -27,10 +27,6 @@
 #include <EGL/egl.h>
 #include <utils/Log.h>
 
-
-using namespace android;
-
-
 #include "fill_common.cpp"
 
 
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 870635b..538d728 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -27,12 +27,21 @@
         const String16& opPackageName)
         : mService(service), mUid(uid), mMem(*mem),
         mHalChannelHandle(halChannelHandle),
-        mOpPackageName(opPackageName) {
+        mOpPackageName(opPackageName), mDestroyed(false) {
     ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
 }
 
 SensorService::SensorDirectConnection::~SensorDirectConnection() {
     ALOGD_IF(DEBUG_CONNECTIONS, "~SensorDirectConnection %p", this);
+    destroy();
+}
+
+void SensorService::SensorDirectConnection::destroy() {
+    Mutex::Autolock _l(mDestroyLock);
+    // destroy once only
+    if (mDestroyed) {
+        return;
+    }
 
     stopAll();
     mService->cleanupConnection(this);
@@ -40,6 +49,7 @@
         native_handle_close(mMem.handle);
         native_handle_delete(const_cast<struct native_handle*>(mMem.handle));
     }
+    mDestroyed = true;
 }
 
 void SensorService::SensorDirectConnection::onFirstRef() {
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 27458d4..5c398a8 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -47,7 +47,7 @@
     // stop all active sensor report. if backupRecord is set to false,
     // those report can be recovered by recoverAll
     // called by SensorService when enter restricted mode
-    void stopAll(bool clearRecord = false);
+    void stopAll(bool backupRecord = false);
 
     // recover sensor reports previously stopped by stopAll(true)
     // called by SensorService when return to NORMAL mode.
@@ -63,7 +63,7 @@
     virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
     virtual status_t flush();
     virtual int32_t configureChannel(int handle, int rateLevel);
-
+    virtual void destroy();
 private:
     const sp<SensorService> mService;
     const uid_t mUid;
@@ -74,6 +74,9 @@
     mutable Mutex mConnectionLock;
     std::unordered_map<int, int> mActivated;
     std::unordered_map<int, int> mActivatedBackup;
+
+    mutable Mutex mDestroyLock;
+    bool mDestroyed;
 };
 
 } // namepsace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index bfe4c09..0a05dd1 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -32,7 +32,8 @@
         const String16& opPackageName)
     : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
       mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
-      mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) {
+      mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
+      mDestroyed(false) {
     mChannel = new BitTube(mService->mSocketBufferSize);
 #if DEBUG_CONNECTIONS
     mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -42,10 +43,22 @@
 
 SensorService::SensorEventConnection::~SensorEventConnection() {
     ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
+    destroy();
+}
+
+void SensorService::SensorEventConnection::destroy() {
+    Mutex::Autolock _l(mDestroyLock);
+
+    // destroy once only
+    if (mDestroyed) {
+        return;
+    }
+
     mService->cleanupConnection(this);
     if (mEventCache != NULL) {
         delete mEventCache;
     }
+    mDestroyed = true;
 }
 
 void SensorService::SensorEventConnection::onFirstRef() {
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index c81e015..6f282cd 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -75,6 +75,7 @@
     virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
     virtual status_t flush();
     virtual int32_t configureChannel(int handle, int rateLevel);
+    virtual void destroy();
 
     // Count the number of flush complete events which are about to be dropped in the buffer.
     // Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be sent
@@ -164,6 +165,8 @@
     int mTotalAcksNeeded, mTotalAcksReceived;
 #endif
 
+    mutable Mutex mDestroyLock;
+    bool mDestroyed;
 };
 
 } // namepsace android
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 08b2790..ac6896a 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -8,9 +8,9 @@
 #include <private/dvr/bufferhub_rpc.h>
 #include "producer_channel.h"
 
-using android::pdx::ErrorStatus;
 using android::pdx::BorrowedHandle;
 using android::pdx::Channel;
+using android::pdx::ErrorStatus;
 using android::pdx::Message;
 using android::pdx::Status;
 using android::pdx::rpc::DispatchRemoteMethod;
@@ -22,8 +22,6 @@
                                  int channel_id,
                                  const std::shared_ptr<Channel> producer)
     : BufferHubChannel(service, buffer_id, channel_id, kConsumerType),
-      handled_(true),
-      ignored_(false),
       producer_(producer) {
   GetProducer()->AddConsumer(this);
 }
@@ -34,7 +32,7 @@
            channel_id(), buffer_id());
 
   if (auto producer = GetProducer()) {
-    if (!handled_)  // Producer is waiting for our Release.
+    if (!released_)  // Producer is waiting for our Release.
       producer->OnConsumerIgnored();
     producer->RemoveConsumer(this);
   }
@@ -108,15 +106,20 @@
   if (!producer)
     return ErrorStatus(EPIPE);
 
-  if (ignored_ || handled_) {
+  if (acquired_ || released_) {
     ALOGE(
         "ConsumerChannel::OnConsumerAcquire: Acquire when not posted: "
-        "ignored=%d handled=%d channel_id=%d buffer_id=%d",
-        ignored_, handled_, message.GetChannelId(), producer->buffer_id());
+        "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
+        ignored_, acquired_, released_, message.GetChannelId(),
+        producer->buffer_id());
     return ErrorStatus(EBUSY);
   } else {
-    ClearAvailable();
-    return producer->OnConsumerAcquire(message, metadata_size);
+    auto status = producer->OnConsumerAcquire(message, metadata_size);
+    if (status) {
+      ClearAvailable();
+      acquired_ = true;
+    }
+    return status;
   }
 }
 
@@ -127,17 +130,21 @@
   if (!producer)
     return ErrorStatus(EPIPE);
 
-  if (ignored_ || handled_) {
+  if (!acquired_ || released_) {
     ALOGE(
         "ConsumerChannel::OnConsumerRelease: Release when not acquired: "
-        "ignored=%d handled=%d channel_id=%d buffer_id=%d",
-        ignored_, handled_, message.GetChannelId(), producer->buffer_id());
+        "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
+        ignored_, acquired_, released_, message.GetChannelId(),
+        producer->buffer_id());
     return ErrorStatus(EBUSY);
   } else {
-    ClearAvailable();
     auto status =
         producer->OnConsumerRelease(message, std::move(release_fence));
-    handled_ = !!status;
+    if (status) {
+      ClearAvailable();
+      acquired_ = false;
+      released_ = true;
+    }
     return status;
   }
 }
@@ -149,12 +156,13 @@
     return ErrorStatus(EPIPE);
 
   ignored_ = ignored;
-  if (ignored_ && !handled_) {
+  if (ignored_ && acquired_) {
     // Update the producer if ignore is set after the consumer acquires the
     // buffer.
     ClearAvailable();
     producer->OnConsumerIgnored();
-    handled_ = false;
+    acquired_ = false;
+    released_ = true;
   }
 
   return {};
@@ -162,10 +170,12 @@
 
 bool ConsumerChannel::OnProducerPosted() {
   if (ignored_) {
-    handled_ = true;
+    acquired_ = false;
+    released_ = true;
     return false;
   } else {
-    handled_ = false;
+    acquired_ = false;
+    released_ = false;
     SignalAvailable();
     return true;
   }
diff --git a/services/vr/bufferhubd/consumer_channel.h b/services/vr/bufferhubd/consumer_channel.h
index d84055c..208a002 100644
--- a/services/vr/bufferhubd/consumer_channel.h
+++ b/services/vr/bufferhubd/consumer_channel.h
@@ -38,8 +38,9 @@
                                       LocalFence release_fence);
   pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore);
 
-  bool handled_;  // True if we have processed RELEASE.
-  bool ignored_;  // True if we are ignoring events.
+  bool acquired_{false};
+  bool released_{true};
+  bool ignored_{false};  // True if we are ignoring events.
   std::weak_ptr<Channel> producer_;
 
   ConsumerChannel(const ConsumerChannel&) = delete;
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b9984a0..b2db795 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -122,7 +122,7 @@
 }
 
 Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer(
-    Message& message) {
+    Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnGetBuffer");
   ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
   return {NativeBufferHandle<BorrowedHandle>(buffer_, buffer_id())};
@@ -204,7 +204,7 @@
   return {};
 }
 
-Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) {
+Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnGain");
   ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
   if (producer_owns_) {
@@ -224,7 +224,7 @@
 }
 
 Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
-ProducerChannel::OnConsumerAcquire(Message& message,
+ProducerChannel::OnConsumerAcquire(Message& /*message*/,
                                    std::size_t metadata_size) {
   ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
   ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
index 5fd5c36..be1ec5b 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
@@ -17,4 +17,9 @@
    * Registers a callback used to receive frame notifications.
    */
   void registerObserver(in IVrComposerCallback callback);
+
+  /**
+   * Clears a previously registered frame notification callback.
+   */
+  void clearObserver();
 }
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
index c45fbf4..36a313a 100644
--- a/services/vr/hardware_composer/vr_composer.cpp
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -42,6 +42,12 @@
   return binder::Status::ok();
 }
 
+binder::Status VrComposer::clearObserver() {
+  std::lock_guard<std::mutex> guard(mutex_);
+  callback_ = nullptr;
+  return binder::Status::ok();
+}
+
 base::unique_fd VrComposer::OnNewFrame(const ComposerView::Frame& frame) {
   std::lock_guard<std::mutex> guard(mutex_);
 
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
index 93d1f2b..7b580c6 100644
--- a/services/vr/hardware_composer/vr_composer.h
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -27,6 +27,8 @@
   binder::Status registerObserver(
       const sp<IVrComposerCallback>& callback) override;
 
+  binder::Status clearObserver() override;
+
   // ComposerView::Observer:
   base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
 
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 3f7009a..4b9fbe0 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -63,7 +63,7 @@
 // Returns true if the sender's euid is trusted according to VR manager service.
 struct Trusted {
   static bool Check(const Message& sender, const Task&) {
-    return IsTrustedUid(sender.GetEffectiveUserId(), false);
+    return IsTrustedUid(sender.GetEffectiveUserId());
   }
 };
 
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index b812535..b28d94a 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -53,10 +53,13 @@
         permission_check;
 
     // Check the permisison of the given task to use this scheduler class. If a
-    // permission check function is not set then all tasks are allowed.
-    bool IsAllowed(const pdx::Message& message, const Task& task) const {
+    // permission check function is not set then operations are only allowed on
+    // tasks in the sender's process.
+    bool IsAllowed(const pdx::Message& sender, const Task& task) const {
       if (permission_check)
-        return permission_check(message, task);
+        return permission_check(sender, task);
+      else if (!task || task.thread_group_id() != sender.GetProcessId())
+        return false;
       else
         return true;
     }
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 7de1f08..274a1b3 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -183,6 +183,17 @@
   ASSERT_EQ(AID_ROOT, original_uid)
       << "This test must run as root to function correctly!";
 
+  // Test unprivileged policies on a task that does not belong to this process.
+  // Use the init process (task_id=1) as the target.
+  error = dvrSetSchedulerPolicy(1, "batch");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(1, "background");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(1, "foreground");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(1, "normal");
+  EXPECT_EQ(-EINVAL, error);
+
   // Switch the uid/gid to an id that should not have permission to access any
   // privileged actions.
   ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 0b39017..52c0b51 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -1352,6 +1352,7 @@
     VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT                      = 1000104011,
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT                   = 1000104012,
     VK_COLOR_SPACE_PASS_THROUGH_EXT                         = 1000104013,
+    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT              = 1000104014,
 }
 
 @extension("VK_EXT_debug_report") // 12
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index e28f7a7..4e7c2fc 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -3412,6 +3412,7 @@
     VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
     VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
+    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
     VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -5891,7 +5892,7 @@
 #endif
 
 #define VK_EXT_swapchain_colorspace 1
-#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 3
 #define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
 
 
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index ded9549..5f55f19 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -640,6 +640,8 @@
     const VkSurfaceFormatKHR kWideColorFormats[] = {
         {VK_FORMAT_R16G16B16A16_SFLOAT,
          VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
+        {VK_FORMAT_R16G16B16A16_SFLOAT,
+         VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
         {VK_FORMAT_A2R10G10B10_UNORM_PACK32,
          VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
     };