Merge "Trace drawing state"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index f908cbf..ce3a6aa 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -24,20 +24,6 @@
     ],
 }
 
-cc_library_headers {
-    name: "dumpstate_headers",
-    vendor_available: true,
-    export_include_dirs: ["."],
-    header_libs: [
-        "libbase_headers",
-        "libutils_headers",
-    ],
-    export_header_lib_headers: [
-        "libbase_headers",
-        "libutils_headers",
-    ],
-}
-
 cc_library_shared {
     name: "libdumpstateutil",
     defaults: ["dumpstate_defaults"],
@@ -45,8 +31,6 @@
     vndk: {
         enabled: true,
     },
-    header_libs: ["dumpstate_headers"],
-    export_header_lib_headers: ["dumpstate_headers"],
     srcs: [
         "DumpstateInternal.cpp",
         "DumpstateUtil.cpp",
@@ -55,6 +39,10 @@
         "libbase",
         "liblog",
     ],
+    export_include_dirs: ["."],
+    export_shared_lib_headers: [
+        "libbase",
+    ],
 }
 
 cc_library_shared {
@@ -78,7 +66,6 @@
 cc_binary {
     name: "dumpstate",
     defaults: ["dumpstate_defaults"],
-    header_libs: ["dumpstate_headers"],
     shared_libs: [
         "android.hardware.dumpstate@1.0",
         "libziparchive",
@@ -106,7 +93,6 @@
 cc_test {
     name: "dumpstate_test",
     defaults: ["dumpstate_defaults"],
-    header_libs: ["dumpstate_headers"],
     shared_libs: [
         "libziparchive",
         "libbase",
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 56470d6..bb2187a 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -18,6 +18,7 @@
     shared_libs: [
         "libbase",
         "libbinder",
+        "libcrypto",
         "libcutils",
         "liblog",
         "liblogwrap",
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 1d21b3c..b3dc5ec 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -27,6 +27,7 @@
 LOCAL_HEADER_LIBRARIES := dex2oat_headers
 LOCAL_SHARED_LIBRARIES := \
     libbase \
+    libcrypto \
     libcutils \
     liblog \
     liblogwrap \
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 4246536..e10fb6c 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -2312,6 +2312,22 @@
     return result ? ok() : error();
 }
 
+binder::Status InstalldNativeService::hashSecondaryDexFile(
+        const std::string& dexPath, const std::string& packageName, int32_t uid,
+        const std::unique_ptr<std::string>& volumeUuid, int32_t storageFlag,
+        std::vector<uint8_t>* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(volumeUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+
+    // mLock is not taken here since we will never modify the file system.
+    // If a file is modified just as we are reading it this may result in an
+    // anomalous hash, but that's ok.
+    bool result = android::installd::hash_secondary_dex_file(
+        dexPath, packageName, uid, volumeUuid, storageFlag, _aidl_return);
+    return result ? ok() : error();
+}
+
 binder::Status InstalldNativeService::invalidateMounts() {
     ENFORCE_UID(AID_SYSTEM);
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index c8db3df..5167a14 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -115,6 +115,9 @@
     binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
         const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
         const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
+    binder::Status hashSecondaryDexFile(const std::string& dexPath,
+        const std::string& packageName, int32_t uid, const std::unique_ptr<std::string>& volumeUuid,
+        int32_t storageFlag, std::vector<uint8_t>* _aidl_return);
 
     binder::Status invalidateMounts();
     binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 452a2b1..0f9862d 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -82,6 +82,9 @@
         int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,
         int storage_flag);
 
+    byte[] hashSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
+        int uid, @nullable @utf8InCpp String volumeUuid, int storageFlag);
+
     void invalidateMounts();
     boolean isQuotaSupported(@nullable @utf8InCpp String uuid);
 }
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index af2c527..6f160b9 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -15,6 +15,7 @@
  */
 #define LOG_TAG "installed"
 
+#include <array>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
@@ -27,6 +28,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
@@ -36,6 +38,7 @@
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <log/log.h>               // TODO: Move everything to base/logging.
+#include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
 #include <selinux/android.h>
 #include <system/thread_defs.h>
@@ -46,8 +49,10 @@
 #include "otapreopt_utils.h"
 #include "utils.h"
 
-using android::base::StringPrintf;
 using android::base::EndsWith;
+using android::base::ReadFully;
+using android::base::StringPrintf;
+using android::base::WriteFully;
 using android::base::unique_fd;
 
 namespace android {
@@ -2052,6 +2057,90 @@
     }
 }
 
+// Compute and return the hash (SHA-256) of the secondary dex file at dex_path.
+// Returns true if all parameters are valid and the hash successfully computed and stored in
+// out_secondary_dex_hash.
+// Also returns true with an empty hash if the file does not currently exist or is not accessible to
+// the app.
+// For any other errors (e.g. if any of the parameters are invalid) returns false.
+bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid,
+        const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
+        std::vector<uint8_t>* out_secondary_dex_hash) {
+    out_secondary_dex_hash->clear();
+
+    const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+
+    if (storage_flag != FLAG_STORAGE_CE && storage_flag != FLAG_STORAGE_DE) {
+        LOG(ERROR) << "hash_secondary_dex_file called with invalid storage_flag: "
+                << storage_flag;
+        return false;
+    }
+
+    // Pipe to get the hash result back from our child process.
+    unique_fd pipe_read, pipe_write;
+    if (!Pipe(&pipe_read, &pipe_write)) {
+        PLOG(ERROR) << "Failed to create pipe";
+        return false;
+    }
+
+    // Fork so that actual access to the files is done in the app's own UID, to ensure we only
+    // access data the app itself can access.
+    pid_t pid = fork();
+    if (pid == 0) {
+        // child -- drop privileges before continuing
+        drop_capabilities(uid);
+        pipe_read.reset();
+
+        if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
+            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+            _exit(1);
+        }
+
+        unique_fd fd(TEMP_FAILURE_RETRY(open(dex_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
+        if (fd == -1) {
+            if (errno == EACCES || errno == ENOENT) {
+                // Not treated as an error.
+                _exit(0);
+            }
+            PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
+            _exit(1);
+        }
+
+        SHA256_CTX ctx;
+        SHA256_Init(&ctx);
+
+        std::vector<uint8_t> buffer(65536);
+        while (true) {
+            ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
+            if (bytes_read == 0) {
+                break;
+            } else if (bytes_read == -1) {
+                PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
+                _exit(1);
+            }
+
+            SHA256_Update(&ctx, buffer.data(), bytes_read);
+        }
+
+        std::array<uint8_t, SHA256_DIGEST_LENGTH> hash;
+        SHA256_Final(hash.data(), &ctx);
+        if (!WriteFully(pipe_write, hash.data(), hash.size())) {
+            _exit(1);
+        }
+
+        _exit(0);
+    }
+
+    // parent
+    pipe_write.reset();
+
+    out_secondary_dex_hash->resize(SHA256_DIGEST_LENGTH);
+    if (!ReadFully(pipe_read, out_secondary_dex_hash->data(), out_secondary_dex_hash->size())) {
+        out_secondary_dex_hash->clear();
+    }
+    return wait_child(pid) == 0;
+}
+
 // Helper for move_ab, so that we can have common failure-case cleanup.
 static bool unlink_and_rename(const char* from, const char* to) {
     // Check whether "from" exists, and if so whether it's regular. If it is, unlink. Otherwise,
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 1f41e67..798e211 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -63,6 +63,10 @@
         const std::unique_ptr<std::string>& volumeUuid, int storage_flag,
         /*out*/bool* out_secondary_dex_exists);
 
+bool hash_secondary_dex_file(const std::string& dex_path,
+        const std::string& pkgname, int uid, const std::unique_ptr<std::string>& volume_uuid,
+        int storage_flag, std::vector<uint8_t>* out_secondary_dex_hash);
+
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 1a22992..47346fb 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -24,6 +24,7 @@
     shared_libs: [
         "libbase",
         "libbinder",
+        "libcrypto",
         "libcutils",
         "libselinux",
         "libutils",
@@ -44,6 +45,7 @@
     shared_libs: [
         "libbase",
         "libbinder",
+        "libcrypto",
         "libcutils",
         "libselinux",
         "libutils",
@@ -64,6 +66,7 @@
     shared_libs: [
         "libbase",
         "libbinder",
+        "libcrypto",
         "libcutils",
         "libselinux",
         "libutils",
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index ca812bd..a5af5d7 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <sstream>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/statvfs.h>
@@ -56,16 +57,19 @@
     return create_cache_path_default(path, src, instruction_set);
 }
 
+static std::string get_full_path(const char* path) {
+    return StringPrintf("/data/local/tmp/user/0/%s", path);
+}
+
 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    ::mkdir(fullPath, mode);
-    ::chown(fullPath, owner, group);
-    ::chmod(fullPath, mode);
+    const std::string fullPath = get_full_path(path);
+    ::mkdir(fullPath.c_str(), mode);
+    ::chown(fullPath.c_str(), owner, group);
+    ::chmod(fullPath.c_str(), mode);
 }
 
 static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
-    int fd = ::open(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(),
-            O_RDWR | O_CREAT, mode);
+    int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
     ::fchown(fd, owner, group);
     ::fchmod(fd, mode);
     ::close(fd);
@@ -73,13 +77,13 @@
 
 static int stat_gid(const char* path) {
     struct stat buf;
-    ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf);
+    ::stat(get_full_path(path).c_str(), &buf);
     return buf.st_gid;
 }
 
 static int stat_mode(const char* path) {
     struct stat buf;
-    ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf);
+    ::stat(get_full_path(path).c_str(), &buf);
     return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
 }
 
@@ -149,6 +153,69 @@
     EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
 }
 
+TEST_F(ServiceTest, HashSecondaryDex) {
+    LOG(INFO) << "HashSecondaryDex";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0700);
+
+    std::vector<uint8_t> result;
+    std::string dexPath = get_full_path("com.example/foo/file");
+    EXPECT_TRUE(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+
+    EXPECT_EQ(result.size(), 32U);
+
+    std::ostringstream output;
+    output << std::hex << std::setfill('0');
+    for (auto b : result) {
+        output << std::setw(2) << +b;
+    }
+
+    // This is the SHA256 of an empty string (sha256sum /dev/null)
+    EXPECT_EQ(output.str(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+}
+
+TEST_F(ServiceTest, HashSecondaryDex_NoSuch) {
+    LOG(INFO) << "HashSecondaryDex_NoSuch";
+
+    std::vector<uint8_t> result;
+    std::string dexPath = get_full_path("com.example/foo/file");
+    EXPECT_TRUE(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+
+    EXPECT_EQ(result.size(), 0U);
+}
+
+TEST_F(ServiceTest, HashSecondaryDex_Unreadable) {
+    LOG(INFO) << "HashSecondaryDex_Unreadable";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0300);
+
+    std::vector<uint8_t> result;
+    std::string dexPath = get_full_path("com.example/foo/file");
+    EXPECT_TRUE(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+
+    EXPECT_EQ(result.size(), 0U);
+}
+
+TEST_F(ServiceTest, HashSecondaryDex_WrongApp) {
+    LOG(INFO) << "HashSecondaryDex_WrongApp";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0700);
+
+    std::vector<uint8_t> result;
+    std::string dexPath = get_full_path("com.example/foo/file");
+    EXPECT_FALSE(service->hashSecondaryDexFile(
+        dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+}
+
 TEST_F(ServiceTest, CalculateOat) {
     char buf[PKG_PATH_MAX];
 
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 221bc4f..ace01a6 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -9,16 +9,6 @@
 namespace dvr {
 
 /* static */
-sp<BufferHubQueueProducer> BufferHubQueueProducer::Create() {
-  sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
-  auto config = ProducerQueueConfigBuilder()
-                    .SetMetadata<DvrNativeBufferMetadata>()
-                    .Build();
-  producer->queue_ = ProducerQueue::Create(config, UsagePolicy{});
-  return producer;
-}
-
-/* static */
 sp<BufferHubQueueProducer> BufferHubQueueProducer::Create(
     const std::shared_ptr<ProducerQueue>& queue) {
   if (queue->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
@@ -33,6 +23,19 @@
   return producer;
 }
 
+/* static */
+sp<BufferHubQueueProducer> BufferHubQueueProducer::Create(
+    ProducerQueueParcelable parcelable) {
+  if (!parcelable.IsValid()) {
+    ALOGE("BufferHubQueueProducer::Create: Invalid producer parcelable.");
+    return nullptr;
+  }
+
+  sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
+  producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle());
+  return producer;
+}
+
 status_t BufferHubQueueProducer::requestBuffer(int slot,
                                                sp<GraphicBuffer>* buf) {
   ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot);
@@ -475,6 +478,13 @@
     return BAD_VALUE;
   }
 
+  if (!queue_->is_connected()) {
+    ALOGE(
+        "BufferHubQueueProducer::connect: This BufferHubQueueProducer is not "
+        "connected to bufferhud. Has it been taken out as a parcelable?");
+    return BAD_VALUE;
+  }
+
   switch (api) {
     case NATIVE_WINDOW_API_EGL:
     case NATIVE_WINDOW_API_CPU:
@@ -617,6 +627,39 @@
   return NO_ERROR;
 }
 
+status_t BufferHubQueueProducer::TakeAsParcelable(
+    ProducerQueueParcelable* out_parcelable) {
+  if (!out_parcelable || out_parcelable->IsValid())
+    return BAD_VALUE;
+
+  if (connected_api_ != kNoConnectedApi) {
+    ALOGE(
+        "BufferHubQueueProducer::TakeAsParcelable: BufferHubQueueProducer has "
+        "connected client. Must disconnect first.");
+    return BAD_VALUE;
+  }
+
+  if (!queue_->is_connected()) {
+    ALOGE(
+        "BufferHubQueueProducer::TakeAsParcelable: This BufferHubQueueProducer "
+        "is not connected to bufferhud. Has it been taken out as a "
+        "parcelable?");
+    return BAD_VALUE;
+  }
+
+  auto status = queue_->TakeAsParcelable();
+  if (!status) {
+    ALOGE(
+        "BufferHubQueueProducer::TakeAsParcelable: Failed to take out "
+        "ProducuerQueueParcelable from the producer queue, error: %s.",
+        status.GetErrorMessage().c_str());
+    return BAD_VALUE;
+  }
+
+  *out_parcelable = status.take();
+  return NO_ERROR;
+}
+
 status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height,
                                                 uint32_t layer_count,
                                                 PixelFormat format,
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index c8e31c7..5b320a4 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -74,7 +74,8 @@
     return available_buffers_.size() >= kMaxQueueCapacity;
   }
 
-  explicit operator bool() const { return epoll_fd_.IsValid(); }
+  // Returns whether the buffer queue is connected to bufferhubd.
+  bool is_connected() const { return !!GetChannel(); }
 
   int GetBufferId(size_t slot) const {
     return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
index 7ed55fb..9c85048 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
@@ -3,6 +3,7 @@
 
 #include <gui/IGraphicBufferProducer.h>
 #include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/buffer_hub_queue_parcelable.h>
 
 namespace android {
 namespace dvr {
@@ -17,14 +18,16 @@
   // that.
   static constexpr int kDefaultUndequeuedBuffers = 1;
 
-  // Create a BufferHubQueueProducer instance by creating a new producer queue.
-  static sp<BufferHubQueueProducer> Create();
-
-  // Create a BufferHubQueueProducer instance by importing an existing prodcuer
+  // Creates a BufferHubQueueProducer instance by importing an existing prodcuer
   // queue.
   static sp<BufferHubQueueProducer> Create(
       const std::shared_ptr<ProducerQueue>& producer);
 
+  // Creates a BufferHubQueueProducer instance by importing an existing prodcuer
+  // parcelable. Note that this call takes the ownership of the parcelable
+  // object and is guaranteed to succeed if parcelable object is valid.
+  static sp<BufferHubQueueProducer> Create(ProducerQueueParcelable parcelable);
+
   // See |IGraphicBufferProducer::requestBuffer|
   status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
 
@@ -115,6 +118,14 @@
   // See |IGraphicBufferProducer::getConsumerUsage|
   status_t getConsumerUsage(uint64_t* out_usage) const override;
 
+  // Takes out the current producer as a binder parcelable object. Note that the
+  // producer must be disconnected to be exportable. After successful export,
+  // the producer queue can no longer be connected again. Returns NO_ERROR when
+  // takeout is successful and out_parcelable will hold the new parcelable
+  // object. Also note that out_parcelable cannot be NULL and must points to an
+  // invalid parcelable.
+  status_t TakeAsParcelable(ProducerQueueParcelable* out_parcelable);
+
  private:
   using LocalHandle = pdx::LocalHandle;
 
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index 28cd63a..96f5404 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -3,12 +3,15 @@
 #include <base/logging.h>
 #include <gui/IProducerListener.h>
 #include <gui/Surface.h>
+#include <pdx/default_transport/channel_parcelable.h>
 
 #include <gtest/gtest.h>
 
 namespace android {
 namespace dvr {
 
+using pdx::LocalHandle;
+
 namespace {
 
 // Default dimensions before setDefaultBufferSize is called by the consumer.
@@ -92,7 +95,13 @@
     ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(),
              testInfo->name());
 
-    mProducer = BufferHubQueueProducer::Create();
+    auto config = ProducerQueueConfigBuilder()
+                      .SetMetadata<DvrNativeBufferMetadata>()
+                      .Build();
+    auto queue = ProducerQueue::Create(config, UsagePolicy{});
+    ASSERT_TRUE(queue != nullptr);
+
+    mProducer = BufferHubQueueProducer::Create(std::move(queue));
     ASSERT_TRUE(mProducer != nullptr);
     mSurface = new Surface(mProducer, true);
     ASSERT_TRUE(mSurface != nullptr);
@@ -546,6 +555,55 @@
   EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
 }
 
+TEST_F(BufferHubQueueProducerTest, TakeAsParcelable) {
+  // Connected producer cannot be taken out as a parcelable.
+  EXPECT_NO_FATAL_FAILURE(ConnectProducer());
+  ProducerQueueParcelable producer_parcelable;
+  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), BAD_VALUE);
+
+  // Create a valid dummy producer parcelable.
+  auto dummy_channel_parcelable =
+      std::make_unique<pdx::default_transport::ChannelParcelable>(
+          LocalHandle(0), LocalHandle(0), LocalHandle(0));
+  EXPECT_TRUE(dummy_channel_parcelable->IsValid());
+  ProducerQueueParcelable dummy_producer_parcelable(
+      std::move(dummy_channel_parcelable));
+  EXPECT_TRUE(dummy_producer_parcelable.IsValid());
+
+  // Disconnect producer can be taken out, but only to an invalid parcelable.
+  ASSERT_EQ(mProducer->disconnect(kTestApi), NO_ERROR);
+  EXPECT_EQ(mProducer->TakeAsParcelable(&dummy_producer_parcelable), BAD_VALUE);
+  EXPECT_FALSE(producer_parcelable.IsValid());
+  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), NO_ERROR);
+  EXPECT_TRUE(producer_parcelable.IsValid());
+
+  // Should still be able to query buffer dimension after disconnect.
+  int32_t value = -1;
+  EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_WIDTH, &value));
+  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultWidth);
+
+  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_HEIGHT, &value), NO_ERROR);
+  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultHeight);
+
+  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_FORMAT, &value), NO_ERROR);
+  EXPECT_EQ(value, kDefaultFormat);
+
+  // But connect to API will fail.
+  IGraphicBufferProducer::QueueBufferOutput output;
+  EXPECT_EQ(mProducer->connect(kDummyListener, kTestApi, kTestControlledByApp,
+                               &output),
+            BAD_VALUE);
+
+  // Create a new producer from the parcelable and connect to kTestApi should
+  // succeed.
+  sp<BufferHubQueueProducer> new_producer =
+      BufferHubQueueProducer::Create(std::move(producer_parcelable));
+  ASSERT_TRUE(new_producer != nullptr);
+  EXPECT_EQ(new_producer->connect(kDummyListener, kTestApi,
+                                  kTestControlledByApp, &output),
+            NO_ERROR);
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index d85af81..f246077 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -8,6 +8,11 @@
         "EGL_test.cpp",
     ],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     shared_libs: [
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
diff --git a/opengl/tests/angeles/Android.bp b/opengl/tests/angeles/Android.bp
index bbbc447..5c398a6 100644
--- a/opengl/tests/angeles/Android.bp
+++ b/opengl/tests/angeles/Android.bp
@@ -8,6 +8,11 @@
         "demo.c",
     ],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     gtest: false,
 
     shared_libs: [
diff --git a/opengl/tests/angeles/app-linux.cpp b/opengl/tests/angeles/app-linux.cpp
index ced8786..9d2c98f 100644
--- a/opengl/tests/angeles/app-linux.cpp
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -62,9 +62,6 @@
 
 int gAppAlive = 1;
 
-static const char sAppName[] =
-        "San Angeles Observation OpenGL ES version example (Linux)";
-
 static int sWindowWidth = WINDOW_DEFAULT_WIDTH;
 static int sWindowHeight = WINDOW_DEFAULT_HEIGHT;
 static EGLDisplay sEglDisplay = EGL_NO_DISPLAY;
@@ -132,7 +129,6 @@
     EGLContext context;
     EGLConfig config;
     EGLSurface surface;
-    EGLint w, h;
     EGLDisplay dpy;
 
     EGLNativeWindowType window = windowSurface.getSurface();
diff --git a/opengl/tests/configdump/Android.bp b/opengl/tests/configdump/Android.bp
index c46477c..ee967970 100644
--- a/opengl/tests/configdump/Android.bp
+++ b/opengl/tests/configdump/Android.bp
@@ -5,6 +5,11 @@
 
     srcs: ["configdump.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     shared_libs: [
         "libcutils",
         "libEGL",
diff --git a/opengl/tests/fillrate/Android.bp b/opengl/tests/fillrate/Android.bp
index 543f1e3..689cee4 100644
--- a/opengl/tests/fillrate/Android.bp
+++ b/opengl/tests/fillrate/Android.bp
@@ -3,6 +3,11 @@
 
     srcs: ["fillrate.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     gtest: false,
 
     shared_libs: [
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
index a42f3f2..f022069 100644
--- a/opengl/tests/fillrate/fillrate.cpp
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -153,7 +153,7 @@
 
      for (int c=1, j=0 ; c<32 ; c++, j++) {
          nsecs_t t = times[j];
-         printf("%ld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0);
+         printf("%lld\t%d\t%f\n", (long long)t, c, (double(t)/c)/1000000.0);
      }
 
 
diff --git a/opengl/tests/filter/Android.bp b/opengl/tests/filter/Android.bp
index 5f925c8..23241e1 100644
--- a/opengl/tests/filter/Android.bp
+++ b/opengl/tests/filter/Android.bp
@@ -16,5 +16,10 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
+
 }
diff --git a/opengl/tests/filter/filter.cpp b/opengl/tests/filter/filter.cpp
index 287ee93..49778a0 100644
--- a/opengl/tests/filter/filter.cpp
+++ b/opengl/tests/filter/filter.cpp
@@ -140,6 +140,7 @@
 
      //glDrawTexiOES(0, 0, 0, dim, dim);
      
+#if !USE_DRAW_TEXTURE || !GL_OES_draw_texture
      const GLfloat fdim = dim;
      const GLfloat vertices[4][2] = {
              { 0,     0    },
@@ -154,6 +155,7 @@
              { 1,  1 },
              { 1,  0 }
      };
+#endif
      
      if (!usePbuffer) {
          eglSwapBuffers(dpy, surface);
diff --git a/opengl/tests/finish/Android.bp b/opengl/tests/finish/Android.bp
index fb5671d..be20851 100644
--- a/opengl/tests/finish/Android.bp
+++ b/opengl/tests/finish/Android.bp
@@ -16,5 +16,10 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
+
 }
diff --git a/opengl/tests/finish/finish.cpp b/opengl/tests/finish/finish.cpp
index ab955fe..63ea822 100644
--- a/opengl/tests/finish/finish.cpp
+++ b/opengl/tests/finish/finish.cpp
@@ -64,7 +64,6 @@
      eglMakeCurrent(dpy, surface, surface, context);   
      eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
      eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
-     GLint dim = w<h ? w : h;
 
      glBindTexture(GL_TEXTURE_2D, 0);
      glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
diff --git a/opengl/tests/gl2_basic/Android.bp b/opengl/tests/gl2_basic/Android.bp
index 7403271..f4538ad 100644
--- a/opengl/tests/gl2_basic/Android.bp
+++ b/opengl/tests/gl2_basic/Android.bp
@@ -16,5 +16,10 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
+
 }
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index 67c0969..13f6fba 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -340,7 +340,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
diff --git a/opengl/tests/gl2_copyTexImage/Android.bp b/opengl/tests/gl2_copyTexImage/Android.bp
index 51e269c..87fa7ea 100644
--- a/opengl/tests/gl2_copyTexImage/Android.bp
+++ b/opengl/tests/gl2_copyTexImage/Android.bp
@@ -16,5 +16,9 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
 }
diff --git a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
index e0aafa2..ada98aa 100644
--- a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
+++ b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
@@ -444,7 +444,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
diff --git a/opengl/tests/gl2_yuvtex/Android.bp b/opengl/tests/gl2_yuvtex/Android.bp
index 613d678..b64d94d 100644
--- a/opengl/tests/gl2_yuvtex/Android.bp
+++ b/opengl/tests/gl2_yuvtex/Android.bp
@@ -20,5 +20,7 @@
     cflags: [
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
     ],
 }
diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
index 22128ab..850a615 100644
--- a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
+++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
@@ -190,7 +190,7 @@
 static sp<GraphicBuffer> yuvTexBuffer;
 static GLuint yuvTex;
 
-bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) {
+bool setupYuvTexSurface(EGLDisplay dpy, EGLContext /*context*/) {
     int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1;
     int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1;
     yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat,
@@ -399,7 +399,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
diff --git a/opengl/tests/gl_basic/Android.bp b/opengl/tests/gl_basic/Android.bp
index 881d8ce..5eed17e 100644
--- a/opengl/tests/gl_basic/Android.bp
+++ b/opengl/tests/gl_basic/Android.bp
@@ -3,6 +3,11 @@
 
     srcs: ["gl_basic.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     gtest: false,
 
     shared_libs: [
diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp
index 0b663f7..a675c7c 100644
--- a/opengl/tests/gl_basic/gl_basic.cpp
+++ b/opengl/tests/gl_basic/gl_basic.cpp
@@ -191,8 +191,6 @@
 
 int main(int /*argc*/, char **/*argv*/)
 {
-    int q;
-    int start, end;
     printf("Initializing EGL...\n");
     WindowSurface windowSurface;
     if(!init_gl_surface(windowSurface))
@@ -212,7 +210,6 @@
 
 int init_gl_surface(const WindowSurface& windowSurface)
 {
-    EGLint numConfigs = 1;
     EGLConfig myConfig = {0};
     EGLint attrib[] =
     {
@@ -265,7 +262,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(eglDisplay, eglSurface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
     
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
@@ -336,9 +332,6 @@
 
 void render()
 {
-    int i, j;
-    int quads = 1;
-
     const GLfloat vertices[] = {
             -1,  -1,  0,
              1,  -1,  0,
diff --git a/opengl/tests/gl_perf/Android.bp b/opengl/tests/gl_perf/Android.bp
index 0ffb121..25a317c 100644
--- a/opengl/tests/gl_perf/Android.bp
+++ b/opengl/tests/gl_perf/Android.bp
@@ -20,5 +20,9 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
 }
diff --git a/opengl/tests/gl_perf/gl2_perf.cpp b/opengl/tests/gl_perf/gl2_perf.cpp
index 2998864..047db20 100644
--- a/opengl/tests/gl_perf/gl2_perf.cpp
+++ b/opengl/tests/gl_perf/gl2_perf.cpp
@@ -44,13 +44,6 @@
     }
 }
 
-static void checkGlError(const char* op) {
-    for (GLint error = glGetError(); error; error
-            = glGetError()) {
-        fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
-    }
-}
-
 bool doTest(uint32_t w, uint32_t h);
 
 static EGLDisplay dpy;
@@ -118,7 +111,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     glViewport(0, 0, w, h);
 
diff --git a/opengl/tests/gl_yuvtex/Android.bp b/opengl/tests/gl_yuvtex/Android.bp
index b6be327..9b4924a 100644
--- a/opengl/tests/gl_yuvtex/Android.bp
+++ b/opengl/tests/gl_yuvtex/Android.bp
@@ -19,5 +19,7 @@
     cflags: [
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
     ],
 }
diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
index 7ef3f4e..2c9640b 100644
--- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
+++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
@@ -289,7 +289,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
diff --git a/opengl/tests/gralloc/Android.bp b/opengl/tests/gralloc/Android.bp
index 414c804..33c3dba 100644
--- a/opengl/tests/gralloc/Android.bp
+++ b/opengl/tests/gralloc/Android.bp
@@ -3,6 +3,11 @@
 
     srcs: ["gralloc.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     gtest: false,
 
     shared_libs: [
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
index 968756a..3df0a0f 100644
--- a/opengl/tests/linetex/Android.mk
+++ b/opengl/tests/linetex/Android.mk
@@ -4,6 +4,8 @@
 LOCAL_SRC_FILES:= \
 	linetex.cpp
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
     libEGL \
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
index b0b15eb..2a2c12f 100644
--- a/opengl/tests/swapinterval/Android.mk
+++ b/opengl/tests/swapinterval/Android.mk
@@ -4,6 +4,8 @@
 LOCAL_SRC_FILES:= \
 	swapinterval.cpp
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libutils \
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index bee61f9..629a2d2 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -21,5 +21,6 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+LOCAL_CFLAGS += -Wall -Werror
 
 include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/textures/textures.cpp b/opengl/tests/textures/textures.cpp
index 7be942a..bdb5c82 100644
--- a/opengl/tests/textures/textures.cpp
+++ b/opengl/tests/textures/textures.cpp
@@ -87,12 +87,6 @@
              0x0000, 0x5555, 0x0000, 0x5555, 
              0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF  };
 
-     uint16_t t5551[]  = { 
-             0x0000, 0xFFFF, 0x0000, 0xFFFF, 
-             0xFFFF, 0x0000, 0xFFFF, 0x0000,
-             0x0000, 0xFFFF, 0x0000, 0xFFFF, 
-             0xFFFF, 0x0000, 0xFFFF, 0x0000  };
-
      uint32_t t32[]  = { 
              0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 
              0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF, 
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
index 64382ed..7055afa 100644
--- a/opengl/tests/tritex/Android.mk
+++ b/opengl/tests/tritex/Android.mk
@@ -4,6 +4,8 @@
 LOCAL_SRC_FILES:= \
 	tritex.cpp
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
     libEGL \
diff --git a/opengl/tests/tritex/tritex.cpp b/opengl/tests/tritex/tritex.cpp
index 2db73ef..c008003 100644
--- a/opengl/tests/tritex/tritex.cpp
+++ b/opengl/tests/tritex/tritex.cpp
@@ -93,9 +93,6 @@
 

 int main(int argc, char **argv)

 {

-    int q;
-    int start, end;

-
     printf("Initializing EGL...\n");
 

     WindowSurface windowSurface;
@@ -120,7 +117,6 @@
 

 int init_gl_surface(const WindowSurface& windowSurface)

 {

-    EGLint numConfigs = 1;

     EGLConfig myConfig = {0};

     EGLint attrib[] =

     {

diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 0c1693b..c477a3b 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -613,14 +613,6 @@
         return;
     }
 
-    // Client layers
-    if (hwcInfo.forceClientComposition ||
-        (mActiveBuffer != nullptr && mActiveBuffer->handle == nullptr)) {
-        ALOGV("[%s] Requesting Client composition", mName.string());
-        setCompositionType(hwcId, HWC2::Composition::Client);
-        return;
-    }
-
     // Device or Cursor layers
     if (mPotentialCursor) {
         ALOGV("[%s] Requesting Cursor composition", mName.string());
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f5fb109..5b40aea 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -621,6 +621,15 @@
     mHwcLayers[hwcId].forceClientComposition = true;
 }
 
+bool Layer::getForceClientComposition(int32_t hwcId) {
+    if (mHwcLayers.count(hwcId) == 0) {
+        ALOGE("getForceClientComposition: no HWC layer found (%d)", hwcId);
+        return false;
+    }
+
+    return mHwcLayers[hwcId].forceClientComposition;
+}
+
 void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) {
     auto hwcId = displayDevice->getHwcDisplayId();
     if (mHwcLayers.count(hwcId) == 0 || getCompositionType(hwcId) != HWC2::Composition::Cursor) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c125a3c..0fc5ad5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -299,6 +299,7 @@
 
     void setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z);
     void forceClientComposition(int32_t hwcId);
+    bool getForceClientComposition(int32_t hwcId);
     virtual void setPerFrameData(const sp<const DisplayDevice>& displayDevice) = 0;
 
     // callIntoHwc exists so we can update our local state and call
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index d0f8fbe..47156c1 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -37,8 +37,8 @@
     if (ls != rs)
         return (ls > rs) ? 1 : -1;
 
-    uint32_t lz = l->getCurrentState().z;
-    uint32_t rz = r->getCurrentState().z;
+    int32_t lz = l->getCurrentState().z;
+    int32_t rz = r->getCurrentState().z;
     if (lz != rz)
         return (lz > rz) ? 1 : -1;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9e7563c..5e1de75 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1956,6 +1956,12 @@
                     "display %zd: %d", displayId, result);
         }
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+            if (layer->getForceClientComposition(hwcId)) {
+                ALOGV("[%s] Requesting Client composition", layer->getName().string());
+                layer->setCompositionType(hwcId, HWC2::Composition::Client);
+                continue;
+            }
+
             layer->setPerFrameData(displayDevice);
         }
 
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index e6f2ce7..bf37e1e 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -29,9 +29,11 @@
     uint32_t rs = rhs->layerStack;
     if (ls != rs) return ls < rs;
 
-    uint32_t lz = lhs->z;
-    uint32_t rz = rhs->z;
-    if (lz != rz) return lz < rz;
+    int32_t lz = lhs->z;
+    int32_t rz = rhs->z;
+    if (lz != rz) {
+        return (lz > rz) ? 1 : -1;
+    }
 
     return lhs->id < rhs->id;
 }