Merge "SurfaceFlinger: Fix triple buffering variable naming confusion"
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 2e9701f..854244f 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -139,7 +139,16 @@
     srcs: ["otapreopt_chroot.cpp"],
     shared_libs: [
         "libbase",
+        "libjsoncpp",
         "liblog",
+        "libselinux",
+        "libziparchive",
+    ],
+    static_libs: [
+        "libapex",
+        "libapexd",
+        "libavb",
+        "libdm",
     ],
 }
 
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index e90cf3b..a3dfa2d 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -17,6 +17,7 @@
 #include <fcntl.h>
 #include <linux/unistd.h>
 #include <sys/mount.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 
 #include <sstream>
@@ -24,6 +25,9 @@
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
+#include <selinux/android.h>
+
+#include <apexd.h>
 
 #include "installd_constants.h"
 #include "otapreopt_utils.h"
@@ -138,6 +142,32 @@
       UNUSED(product_result);
     }
 
+    // Setup APEX mount point and its security context.
+    // The logic here is similar to the one in system/core/rootdir/init.rc:
+    //
+    //   mount tmpfs tmpfs /apex nodev noexec nosuid
+    //   chmod 0755 /apex
+    //   chown root root /apex
+    //   restorecon /apex
+    //
+    if (mount("tmpfs", "/postinstall/apex", "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr)
+        != 0) {
+      PLOG(ERROR) << "Failed to mount tmpfs in /postinstall/apex";
+      exit(209);
+    }
+    if (chmod("/postinstall/apex", 0755) != 0) {
+      PLOG(ERROR) << "Failed to chmod /postinstall/apex to 0755";
+      exit(210);
+    }
+    if (chown("/postinstall/apex", 0, 0) != 0) {
+      PLOG(ERROR) << "Failed to chown /postinstall/apex to root:root";
+      exit(211);
+    }
+    if (selinux_android_restorecon("/postinstall/apex", 0) < 0) {
+      PLOG(ERROR) << "Failed to restorecon /postinstall/apex";
+      exit(212);
+    }
+
     // Chdir into /postinstall.
     if (chdir("/postinstall") != 0) {
         PLOG(ERROR) << "Unable to chdir into /postinstall.";
@@ -155,6 +185,18 @@
         exit(205);
     }
 
+    // Try to mount APEX packages in "/apex" in the chroot dir. We need at least
+    // the Android Runtime APEX, as it is required by otapreopt to run dex2oat.
+    {
+      // The logic here is (partially) copied and adapted from
+      // system/apex/apexd/apexd_main.cpp.
+
+      // Only scan the APEX directory under /system (within the chroot dir).
+      // Note that this leaves around the loop devices created and used by
+      // libapexd's code, but this is fine, as we expect to reboot soon after.
+      apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
+    }
+
     // Now go on and run otapreopt.
 
     // Incoming:  cmd + status-fd + target-slot + cmd... + null      | Incoming | = argc + 1
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index a6d7a78..c706d91 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -376,23 +376,23 @@
     }
 
     mServicesTable.setDescription(
-            "All binderized services (registered services through hwservicemanager)");
+            "| All binderized services (registered with hwservicemanager)");
     mPassthroughRefTable.setDescription(
-            "All interfaces that getService() has ever return as a passthrough interface;\n"
-            "PIDs / processes shown below might be inaccurate because the process\n"
-            "might have relinquished the interface or might have died.\n"
-            "The Server / Server CMD column can be ignored.\n"
-            "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
-            "the library and successfully fetched the passthrough implementation.");
+            "| All interfaces that getService() has ever returned as a passthrough interface;\n"
+            "| PIDs / processes shown below might be inaccurate because the process\n"
+            "| might have relinquished the interface or might have died.\n"
+            "| The Server / Server CMD column can be ignored.\n"
+            "| The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
+            "| the library and successfully fetched the passthrough implementation.");
     mImplementationsTable.setDescription(
-            "All available passthrough implementations (all -impl.so files).\n"
-            "These may return subclasses through their respective HIDL_FETCH_I* functions.");
+            "| All available passthrough implementations (all -impl.so files).\n"
+            "| These may return subclasses through their respective HIDL_FETCH_I* functions.");
     mManifestHalsTable.setDescription(
-            "All HALs that are in VINTF manifest.");
+            "| All HALs that are in VINTF manifest.");
     mLazyHalsTable.setDescription(
-            "All HALs that are declared in VINTF manifest:\n"
-            "   - as hwbinder HALs but are not registered to hwservicemanager, and\n"
-            "   - as hwbinder/passthrough HALs with no implementation.");
+            "| All HALs that are declared in VINTF manifest:\n"
+            "|    - as hwbinder HALs but are not registered to hwservicemanager, and\n"
+            "|    - as hwbinder/passthrough HALs with no implementation.");
 }
 
 bool ListCommand::addEntryWithInstance(const TableEntry& entry,
@@ -972,10 +972,10 @@
         thiz->mSelectedColumns.push_back(TableColumnType::VINTF);
         return OK;
     }, "print VINTF info. This column contains a comma-separated list of:\n"
-       "    - DM: device manifest\n"
-       "    - DC: device compatibility matrix\n"
-       "    - FM: framework manifest\n"
-       "    - FC: framework compatibility matrix"});
+       "    - DM: if the HAL is in the device manifest\n"
+       "    - DC: if the HAL is in the device compatibility matrix\n"
+       "    - FM: if the HAL is in the framework manifest\n"
+       "    - FC: if the HAL is in the framework compatibility matrix"});
     mOptions.push_back({'S', "service-status", no_argument, v++, [](ListCommand* thiz, const char*) {
         thiz->mSelectedColumns.push_back(TableColumnType::SERVICE_STATUS);
         return OK;
@@ -1054,7 +1054,7 @@
         return OK;
     }, "comma-separated list of one or more sections.\nThe output is restricted to the selected "
        "section(s). Valid options\nare: (b|binderized), (c|passthrough_clients), (l|"
-       "passthrough_libs), and (v|vintf).\nDefault is `bcl`."});
+       "passthrough_libs), (v|vintf), and (z|lazy).\nDefault is `bcl`."});
 }
 
 // Create 'longopts' argument to getopt_long. Caller is responsible for maintaining
@@ -1150,7 +1150,7 @@
     }
 
     if (mSelectedColumns.empty()) {
-        mSelectedColumns = {TableColumnType::RELEASED,
+        mSelectedColumns = {TableColumnType::VINTF, TableColumnType::RELEASED,
                             TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
                             TableColumnType::SERVER_PID, TableColumnType::CLIENT_PIDS};
     }
@@ -1210,7 +1210,7 @@
     err() << "list:" << std::endl
           << "    lshal" << std::endl
           << "    lshal list" << std::endl
-          << "        List all hals with default ordering and columns (`lshal list -liepc`)" << std::endl
+          << "        List all hals with default ordering and columns (`lshal list -Vliepc`)" << std::endl
           << "    lshal list [-h|--help]" << std::endl
           << "        -h, --help: Print help message for list (`lshal help list`)" << std::endl
           << "    lshal [list] [OPTIONS...]" << std::endl;
diff --git a/cmds/rss_hwm_reset/Android.bp b/cmds/rss_hwm_reset/Android.bp
new file mode 100644
index 0000000..15f10ef
--- /dev/null
+++ b/cmds/rss_hwm_reset/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "rss_hwm_reset",
+
+    srcs: [
+        "rss_hwm_reset.cc",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+
+    init_rc: ["rss_hwm_reset.rc"],
+}
diff --git a/cmds/rss_hwm_reset/rss_hwm_reset.cc b/cmds/rss_hwm_reset/rss_hwm_reset.cc
new file mode 100644
index 0000000..1626e7e
--- /dev/null
+++ b/cmds/rss_hwm_reset/rss_hwm_reset.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ /*
+  * rss_hwm_reset clears the RSS high-water mark counters for all currently
+  * running processes. It writes "5" to /proc/PID/clear_refs for every PID.
+  *
+  * It runs in its own process becuase dac_override capability is required
+  * in order to write to other processes' clear_refs.
+  *
+  * It is invoked from a system service by flipping sys.rss_hwm_reset.on
+  * property to "1".
+  */
+
+#define LOG_TAG "rss_hwm_reset"
+
+#include <dirent.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+
+namespace {
+// Resets RSS HWM counter for the selected process by writing 5 to
+// /proc/PID/clear_refs.
+void reset_rss_hwm(const char* pid) {
+    std::string clear_refs_path =
+            ::android::base::StringPrintf("/proc/%s/clear_refs", pid);
+    ::android::base::WriteStringToFile("5", clear_refs_path);
+}
+}
+
+// Clears RSS HWM counters for all currently running processes.
+int main(int /* argc */, char** /* argv[] */) {
+    DIR* dirp = opendir("/proc");
+    if (dirp == nullptr) {
+        ALOGE("unable to read /proc");
+        return 1;
+    }
+    struct dirent* entry;
+    while ((entry = readdir(dirp)) != nullptr) {
+        // Skip entries that are not directories.
+        if (entry->d_type != DT_DIR) continue;
+        // Skip entries that do not contain only numbers.
+        const char* pid = entry->d_name;
+        while (*pid) {
+            if (*pid < '0' || *pid > '9') break;
+            pid++;
+        }
+        if (*pid != 0) continue;
+
+        pid = entry->d_name;
+        reset_rss_hwm(pid);
+    }
+    closedir(dirp);
+    return 0;
+}
diff --git a/cmds/rss_hwm_reset/rss_hwm_reset.rc b/cmds/rss_hwm_reset/rss_hwm_reset.rc
new file mode 100644
index 0000000..fbbc820
--- /dev/null
+++ b/cmds/rss_hwm_reset/rss_hwm_reset.rc
@@ -0,0 +1,26 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+service rss_hwm_reset /system/bin/rss_hwm_reset
+    class late_start
+    disabled
+    oneshot
+    user nobody
+    group nobody readproc
+    writepid /dev/cpuset/system-background/tasks
+    capabilities DAC_OVERRIDE
+
+on property:sys.rss_hwm_reset.on=1
+    start rss_hwm_reset
+    setprop sys.rss_hwm_reset.on 0
diff --git a/data/etc/android.hardware.face.xml b/data/etc/android.hardware.biometrics.face.xml
similarity index 93%
rename from data/etc/android.hardware.face.xml
rename to data/etc/android.hardware.biometrics.face.xml
index abd23fb..7fa0bf9 100644
--- a/data/etc/android.hardware.face.xml
+++ b/data/etc/android.hardware.biometrics.face.xml
@@ -16,5 +16,5 @@
 
 <!-- This is the standard set of features for a biometric face authentication sensor. -->
 <permissions>
-    <feature name="android.hardware.face" />
+    <feature name="android.hardware.biometrics.face" />
 </permissions>
diff --git a/data/etc/android.hardware.biometrics.fingerprint.xml b/data/etc/android.hardware.biometrics.fingerprint.xml
new file mode 100644
index 0000000..e5af541
--- /dev/null
+++ b/data/etc/android.hardware.biometrics.fingerprint.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- This is the standard set of features for a biometric fingerprint sensor. -->
+<permissions>
+    <feature name="android.hardware.biometrics.fingerprint" />
+</permissions>
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index dc4e000..1b69dfd 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -23,6 +23,8 @@
         "include_apex",
     ],
 
+    cflags: ["-Wall", "-Wextra", "-Werror"],
+
     srcs: [
         "ibinder.cpp",
         "ibinder_jni.cpp",
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 866af70..2258210 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -149,7 +149,49 @@
  * not required to be null-terminated. If the object at index is null, then this should be null.
  */
 typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index,
-                                                        size_t* outLength);
+                                                        int32_t* outLength);
+
+/**
+ * This is called to allocate an array of size 'length'. If length is -1, then a 'null' array (or
+ * equivalent) should be created.
+ *
+ * See also AParcel_readParcelableArray
+ *
+ * \param arrayData some external representation of an array
+ * \param length the length to allocate this array to
+ *
+ * \return true if allocation succeeded. If length is -1, a true return here means that a 'null'
+ * value (or equivalent) was successfully stored.
+ */
+typedef bool (*AParcel_parcelableArrayAllocator)(void* arrayData, int32_t length);
+
+/**
+ * This is called to parcel the underlying data from an arrayData object at index.
+ *
+ * See also AParcel_writeParcelableArray
+ *
+ * \param parcel parcel to write the parcelable to
+ * \param arrayData some external representation of an array of parcelables (a user-defined type).
+ * \param index the index of the value to be retrieved.
+ *
+ * \return status (usually returned from other parceling functions). STATUS_OK for success.
+ */
+typedef binder_status_t (*AParcel_writeParcelableElement)(AParcel* parcel, const void* arrayData,
+                                                          size_t index);
+
+/**
+ * This is called to set an underlying value in an arrayData object at index.
+ *
+ * See also AParcel_readParcelableArray
+ *
+ * \param parcel parcel to read the parcelable from
+ * \param arrayData some external representation of an array of parcelables (a user-defined type).
+ * \param index the index of the value to be set.
+ *
+ * \return status (usually returned from other parceling functions). STATUS_OK for success.
+ */
+typedef binder_status_t (*AParcel_readParcelableElement)(const AParcel* parcel, void* arrayData,
+                                                         size_t index);
 
 // @START-PRIMITIVE-VECTOR-GETTERS
 /**
@@ -497,6 +539,40 @@
                                         AParcel_stringArrayElementAllocator elementAllocator)
         __INTRODUCED_IN(29);
 
+/**
+ * Writes an array of parcelables (user-defined types) to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ * \param elementWriter function to be called for every array index to write the user-defined type
+ * at that location.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                             AParcel_writeParcelableElement elementWriter)
+        __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of parcelables (user-defined types) from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, elementReader will be called for every index to read the
+ * corresponding parcelable.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ * \param elementReader the callback that will be called to fill out individual elements.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayData,
+                                            AParcel_parcelableArrayAllocator allocator,
+                                            AParcel_readParcelableElement elementReader)
+        __INTRODUCED_IN(29);
+
 // @START-PRIMITIVE-READ-WRITE
 /**
  * Writes int32_t value to the next location in a non-null parcel.
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index f99c3a9..fcdf7af 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -299,7 +299,7 @@
  * index.
  */
 static inline const char* AParcel_stdVectorStringElementGetter(const void* vectorData, size_t index,
-                                                               size_t* outLength) {
+                                                               int32_t* outLength) {
     const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData);
     const std::string& element = vec->at(index);
 
@@ -327,7 +327,7 @@
  */
 static inline const char* AParcel_nullableStdVectorStringElementGetter(const void* vectorData,
                                                                        size_t index,
-                                                                       size_t* outLength) {
+                                                                       int32_t* outLength) {
     const std::optional<std::vector<std::optional<std::string>>>* vec =
             static_cast<const std::optional<std::vector<std::optional<std::string>>>*>(vectorData);
     const std::optional<std::string>& element = vec->value().at(index);
@@ -420,6 +420,46 @@
             AParcel_nullableStdVectorStringElementAllocator);
 }
 
+/**
+ * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_writeStdVectorParcelableElement(AParcel* parcel, const void* vectorData,
+                                                        size_t index) {
+    const std::vector<P>* vector = static_cast<const std::vector<P>*>(vectorData);
+    return vector->at(index).writeToParcel(parcel);
+}
+
+/**
+ * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, void* vectorData,
+                                                       size_t index) {
+    std::vector<P>* vector = static_cast<std::vector<P>*>(vectorData);
+    return vector->at(index).readFromParcel(parcel);
+}
+
+/**
+ * Convenience API for writing a std::vector<P>
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) {
+    const void* vectorData = static_cast<const void*>(&vec);
+    return AParcel_writeParcelableArray(parcel, vectorData, vec.size(),
+                                        AParcel_writeStdVectorParcelableElement<P>);
+}
+
+/**
+ * Convenience API for reading a std::vector<P>
+ */
+template <typename P>
+static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<P>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readParcelableArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<P>,
+                                       AParcel_readStdVectorParcelableElement<P>);
+}
+
 // @START
 /**
  * Writes a vector of int32_t to the next location in a non-null parcel.
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 4328b6e..ee7132f 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -40,6 +40,7 @@
     AParcel_readInt32Array;
     AParcel_readInt64;
     AParcel_readInt64Array;
+    AParcel_readParcelableArray;
     AParcel_readParcelFileDescriptor;
     AParcel_readStatusHeader;
     AParcel_readString;
@@ -64,6 +65,7 @@
     AParcel_writeInt32Array;
     AParcel_writeInt64;
     AParcel_writeInt64Array;
+    AParcel_writeParcelableArray;
     AParcel_writeParcelFileDescriptor;
     AParcel_writeStatusHeader;
     AParcel_writeString;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 2d68559..ae2276e 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -173,7 +173,7 @@
 
     Parcel* rawParcel = parcel->get();
 
-    for (size_t i = 0; i < length; i++) {
+    for (int32_t i = 0; i < length; i++) {
         status = (rawParcel->*write)(getter(arrayData, i));
 
         if (status != STATUS_OK) return PruneStatusT(status);
@@ -197,7 +197,7 @@
 
     if (length <= 0) return STATUS_OK;
 
-    for (size_t i = 0; i < length; i++) {
+    for (int32_t i = 0; i < length; i++) {
         T readTarget;
         status = (rawParcel->*read)(&readTarget);
         if (status != STATUS_OK) return PruneStatusT(status);
@@ -376,12 +376,12 @@
     if (status != STATUS_OK) return status;
     if (length <= 0) return STATUS_OK;
 
-    for (size_t i = 0; i < length; i++) {
-        size_t length = 0;
-        const char* str = getter(arrayData, i, &length);
-        if (str == nullptr && length != -1) return STATUS_BAD_VALUE;
+    for (int32_t i = 0; i < length; i++) {
+        int32_t elementLength = 0;
+        const char* str = getter(arrayData, i, &elementLength);
+        if (str == nullptr && elementLength != -1) return STATUS_BAD_VALUE;
 
-        binder_status_t status = AParcel_writeString(parcel, str, length);
+        binder_status_t status = AParcel_writeString(parcel, str, elementLength);
         if (status != STATUS_OK) return status;
     }
 
@@ -392,7 +392,7 @@
 // allocator.
 struct StringArrayElementAllocationAdapter {
     void* arrayData;  // stringData from the NDK
-    size_t index;     // index into the string array
+    int32_t index;    // index into the string array
     AParcel_stringArrayElementAllocator elementAllocator;
 
     static bool Allocator(void* stringData, int32_t length, char** buffer) {
@@ -433,6 +433,45 @@
     return STATUS_OK;
 }
 
+binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                             AParcel_writeParcelableElement elementWriter) {
+    // we have no clue if arrayData represents a null object or not, we can only infer from length
+    bool arrayIsNull = length < 0;
+    binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    for (int32_t i = 0; i < length; i++) {
+        binder_status_t status = elementWriter(parcel, arrayData, i);
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayData,
+                                            AParcel_parcelableArrayAllocator allocator,
+                                            AParcel_readParcelableElement elementReader) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+    if (length == -1) return STATUS_OK;  // null array
+
+    for (int32_t i = 0; i < length; i++) {
+        binder_status_t status = elementReader(parcel, arrayData, i);
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
 // See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
 // libbinder and this library.
 // @START
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index f23ed5d..ae04b0f 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1446,7 +1446,7 @@
         }
         IPCThreadState::self()->flushCommands(); // flush BC_ENTER_LOOPER
 
-        epoll_fd = epoll_create1(0);
+        epoll_fd = epoll_create1(EPOLL_CLOEXEC);
         if (epoll_fd == -1) {
             return 1;
         }
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index ed773e0..16952a6 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -520,7 +520,7 @@
     }
 
     auto buffer_producer = buffers_[slot].mBufferProducer;
-    queue_->Enqueue(buffer_producer, size_t(slot), 0ULL);
+    queue_->Enqueue(buffer_producer, size_t(slot), 0U);
     buffers_[slot].mBufferState.cancel();
     buffers_[slot].mFence = fence;
     ALOGV("cancelBuffer: slot %d", slot);
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 1395551..53b0e4c 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -242,23 +242,43 @@
 
     bool useContextPriority = extensions.hasContextPriority() &&
             (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
-    EGLContext ctxt = createEglContext(display, config, EGL_NO_CONTEXT, useContextPriority);
+    EGLContext protectedContext = EGL_NO_CONTEXT;
+    if (extensions.hasProtectedContent()) {
+        protectedContext = createEglContext(display, config, nullptr, useContextPriority,
+                                            Protection::PROTECTED);
+        ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
+    }
+
+    EGLContext ctxt = createEglContext(display, config, protectedContext, useContextPriority,
+                                       Protection::UNPROTECTED);
 
     // if can't create a GL context, we can only abort.
     LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
 
     EGLSurface dummy = EGL_NO_SURFACE;
     if (!extensions.hasSurfacelessContext()) {
-        dummy = createDummyEglPbufferSurface(display, config, hwcFormat);
+        dummy = createDummyEglPbufferSurface(display, config, hwcFormat, Protection::UNPROTECTED);
         LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
     }
-
     EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
     LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
-
     extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
                                  glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
 
+    // In order to have protected contents in GPU composition, the OpenGL ES extension
+    // GL_EXT_protected_textures must be supported. If it's not supported, reset
+    // protected context to EGL_NO_CONTEXT to indicate that protected contents is not supported.
+    if (!extensions.hasProtectedTexture()) {
+        protectedContext = EGL_NO_CONTEXT;
+    }
+
+    EGLSurface protectedDummy = EGL_NO_SURFACE;
+    if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
+        protectedDummy =
+                createDummyEglPbufferSurface(display, config, hwcFormat, Protection::PROTECTED);
+        ALOGE_IF(protectedDummy == EGL_NO_SURFACE, "can't create protected dummy pbuffer");
+    }
+
     // now figure out what version of GL did we actually get
     GlesVersion version = parseGlesVersion(extensions.getVersion());
 
@@ -271,7 +291,8 @@
             break;
         case GLES_VERSION_2_0:
         case GLES_VERSION_3_0:
-            engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy);
+            engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy,
+                                                        protectedContext, protectedDummy);
             break;
     }
 
@@ -326,12 +347,15 @@
 }
 
 GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
-                                   EGLContext ctxt, EGLSurface dummy)
+                                   EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
+                                   EGLSurface protectedDummy)
       : renderengine::impl::RenderEngine(featureFlags),
         mEGLDisplay(display),
         mEGLConfig(config),
         mEGLContext(ctxt),
         mDummySurface(dummy),
+        mProtectedEGLContext(protectedContext),
+        mProtectedDummySurface(protectedDummy),
         mVpWidth(0),
         mVpHeight(0),
         mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
@@ -341,6 +365,17 @@
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
     glPixelStorei(GL_PACK_ALIGNMENT, 4);
 
+    // Initialize protected EGL Context.
+    if (mProtectedEGLContext != EGL_NO_CONTEXT) {
+        EGLBoolean success = eglMakeCurrent(display, mProtectedDummySurface, mProtectedDummySurface,
+                                            mProtectedEGLContext);
+        ALOGE_IF(!success, "can't make protected context current");
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+        glPixelStorei(GL_PACK_ALIGNMENT, 4);
+        success = eglMakeCurrent(display, mDummySurface, mDummySurface, mEGLContext);
+        LOG_ALWAYS_FATAL_IF(!success, "can't make default context current");
+    }
+
     const uint16_t protTexData[] = {0};
     glGenTextures(1, &mProtectedTexName);
     glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
@@ -395,7 +430,8 @@
 }
 
 void GLESRenderEngine::primeCache() const {
-    ProgramCache::getInstance().primeCache(mFeatureFlags & USE_COLOR_MANAGEMENT);
+    ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
+                                           mFeatureFlags & USE_COLOR_MANAGEMENT);
 }
 
 bool GLESRenderEngine::isCurrent() const {
@@ -539,6 +575,10 @@
     const GLenum target = GL_TEXTURE_EXTERNAL_OES;
 
     glBindTexture(target, texName);
+    if (supportsProtectedContent()) {
+        glTexParameteri(target, GL_TEXTURE_PROTECTED_EXT,
+                        glImage.isProtected() ? GL_TRUE : GL_FALSE);
+    }
     if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) {
         glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(glImage.getEGLImage()));
     }
@@ -552,6 +592,10 @@
 
     // Bind the texture and turn our EGLImage into a texture
     glBindTexture(GL_TEXTURE_2D, textureName);
+    if (supportsProtectedContent()) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_PROTECTED_EXT,
+                        mInProtectedContext ? GL_TRUE : GL_FALSE);
+    }
     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage);
 
     // Bind the Framebuffer to render into
@@ -584,6 +628,26 @@
     } while (true);
 }
 
+bool GLESRenderEngine::supportsProtectedContent() const {
+    return mProtectedEGLContext != EGL_NO_CONTEXT;
+}
+
+bool GLESRenderEngine::useProtectedContext(bool useProtectedContext) {
+    if (useProtectedContext == mInProtectedContext) {
+        return true;
+    }
+    if (useProtectedContext && mProtectedEGLContext == EGL_NO_CONTEXT) {
+        return false;
+    }
+    const EGLSurface surface = useProtectedContext ? mProtectedDummySurface : mDummySurface;
+    const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
+    const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
+    if (success) {
+        mInProtectedContext = useProtectedContext;
+    }
+    return success;
+}
+
 status_t GLESRenderEngine::drawLayers(const DisplaySettings& /*settings*/,
                                       const std::vector<LayerSettings>& /*layers*/,
                                       ANativeWindowBuffer* const /*buffer*/,
@@ -822,7 +886,9 @@
                     Description::dataSpaceToTransferFunction(outputTransfer);
         }
 
-        ProgramCache::getInstance().useProgram(managedState);
+        ProgramCache::getInstance().useProgram(mInProtectedContext ? mProtectedEGLContext
+                                                                   : mEGLContext,
+                                               managedState);
 
         glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
 
@@ -833,7 +899,9 @@
             writePPM(out.str().c_str(), mVpWidth, mVpHeight);
         }
     } else {
-        ProgramCache::getInstance().useProgram(mState);
+        ProgramCache::getInstance().useProgram(mInProtectedContext ? mProtectedEGLContext
+                                                                   : mEGLContext,
+                                               mState);
 
         glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
     }
@@ -857,17 +925,18 @@
 
 void GLESRenderEngine::dump(std::string& result) {
     const GLExtensions& extensions = GLExtensions::getInstance();
+    ProgramCache& cache = ProgramCache::getInstance();
 
     StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion());
     StringAppendF(&result, "%s\n", extensions.getEGLExtensions());
-
     StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
                   extensions.getVersion());
     StringAppendF(&result, "%s\n", extensions.getExtensions());
-
-    StringAppendF(&result, "RenderEngine program cache size: %zu\n",
-                  ProgramCache::getInstance().getSize());
-
+    StringAppendF(&result, "RenderEngine is in protected context : %d\n", mInProtectedContext);
+    StringAppendF(&result, "RenderEngine program cache size for unprotected context: %zu\n",
+                  cache.getSize(mEGLContext));
+    StringAppendF(&result, "RenderEngine program cache size for protected context: %zu\n",
+                  cache.getSize(mProtectedEGLContext));
     StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n",
                   dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
                   dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
@@ -892,7 +961,8 @@
 }
 
 EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
-                                              EGLContext shareContext, bool useContextPriority) {
+                                              EGLContext shareContext, bool useContextPriority,
+                                              Protection protection) {
     EGLint renderableType = 0;
     if (config == EGL_NO_CONFIG) {
         renderableType = EGL_OPENGL_ES3_BIT;
@@ -911,13 +981,17 @@
     }
 
     std::vector<EGLint> contextAttributes;
-    contextAttributes.reserve(5);
+    contextAttributes.reserve(7);
     contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
     contextAttributes.push_back(contextClientVersion);
     if (useContextPriority) {
         contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
         contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
     }
+    if (protection == Protection::PROTECTED) {
+        contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT);
+        contextAttributes.push_back(EGL_TRUE);
+    }
     contextAttributes.push_back(EGL_NONE);
 
     EGLContext context = eglCreateContext(display, config, shareContext, contextAttributes.data());
@@ -938,17 +1012,21 @@
 }
 
 EGLSurface GLESRenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
-                                                          int hwcFormat) {
+                                                          int hwcFormat, Protection protection) {
     EGLConfig dummyConfig = config;
     if (dummyConfig == EGL_NO_CONFIG) {
         dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
     }
     std::vector<EGLint> attributes;
-    attributes.reserve(5);
+    attributes.reserve(7);
     attributes.push_back(EGL_WIDTH);
     attributes.push_back(1);
     attributes.push_back(EGL_HEIGHT);
     attributes.push_back(1);
+    if (protection == Protection::PROTECTED) {
+        attributes.push_back(EGL_PROTECTED_CONTENT_EXT);
+        attributes.push_back(EGL_TRUE);
+    }
     attributes.push_back(EGL_NONE);
 
     return eglCreatePbufferSurface(display, dummyConfig, attributes.data());
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 21d5b81..07e5585 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -45,7 +45,8 @@
     static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
 
     GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
-                     EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
+                     EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy,
+                     EGLContext protectedContext, EGLSurface protectedDummy);
     ~GLESRenderEngine() override;
 
     std::unique_ptr<Framebuffer> createFramebuffer() override;
@@ -68,6 +69,9 @@
     void unbindFrameBuffer(Framebuffer* framebuffer) override;
     void checkErrors() const override;
 
+    bool isProtected() const override { return mInProtectedContext; }
+    bool supportsProtectedContent() const override;
+    bool useProtectedContext(bool useProtectedContext) override;
     status_t drawLayers(const DisplaySettings& settings, const std::vector<LayerSettings>& layers,
                         ANativeWindowBuffer* const buffer,
                         base::unique_fd* displayFence) const override;
@@ -112,20 +116,22 @@
 
     static GlesVersion parseGlesVersion(const char* str);
     static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
-                                       EGLContext shareContext, bool useContextPriority);
+                                       EGLContext shareContext, bool useContextPriority,
+                                       Protection protection);
     static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
-                                                   int hwcFormat);
+                                                   int hwcFormat, Protection protection);
 
     // A data space is considered HDR data space if it has BT2020 color space
     // with PQ or HLG transfer function.
     bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
     bool needsXYZTransformMatrix() const;
-    void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
 
     EGLDisplay mEGLDisplay;
     EGLConfig mEGLConfig;
     EGLContext mEGLContext;
     EGLSurface mDummySurface;
+    EGLContext mProtectedEGLContext;
+    EGLSurface mProtectedDummySurface;
     GLuint mProtectedTexName;
     GLint mMaxViewportDims[2];
     GLint mMaxTextureSize;
@@ -146,6 +152,7 @@
     mat4 mBt2020ToSrgb;
     mat4 mBt2020ToDisplayP3;
 
+    bool mInProtectedContext = false;
     int32_t mFboHeight = 0;
 
     // Current dataspace of layer being rendered
diff --git a/libs/renderengine/gl/GLExtensions.cpp b/libs/renderengine/gl/GLExtensions.cpp
index ce83dd5..2924b0e 100644
--- a/libs/renderengine/gl/GLExtensions.cpp
+++ b/libs/renderengine/gl/GLExtensions.cpp
@@ -60,6 +60,11 @@
     mRenderer = (char const*)renderer;
     mVersion = (char const*)version;
     mExtensions = (char const*)extensions;
+
+    ExtensionSet extensionSet(mExtensions.c_str());
+    if (extensionSet.hasExtension("GL_EXT_protected_textures")) {
+        mHasProtectedTexture = true;
+    }
 }
 
 char const* GLExtensions::getVendor() const {
diff --git a/libs/renderengine/gl/GLExtensions.h b/libs/renderengine/gl/GLExtensions.h
index 2a654d5..ef00009 100644
--- a/libs/renderengine/gl/GLExtensions.h
+++ b/libs/renderengine/gl/GLExtensions.h
@@ -40,6 +40,7 @@
     bool hasProtectedContent() const { return mHasProtectedContent; }
     bool hasContextPriority() const { return mHasContextPriority; }
     bool hasSurfacelessContext() const { return mHasSurfacelessContext; }
+    bool hasProtectedTexture() const { return mHasProtectedTexture; }
 
     void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
                            GLubyte const* extensions);
@@ -65,12 +66,12 @@
     bool mHasProtectedContent = false;
     bool mHasContextPriority = false;
     bool mHasSurfacelessContext = false;
+    bool mHasProtectedTexture = false;
 
     String8 mVendor;
     String8 mRenderer;
     String8 mVersion;
     String8 mExtensions;
-
     String8 mEGLVersion;
     String8 mEGLExtensions;
 
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index f4de91a..4a519bb 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -39,7 +39,7 @@
     eglDestroyImageKHR(mEGLDisplay, mEGLImage);
 }
 
-bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) {
+bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) {
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
         eglDestroyImageKHR(mEGLDisplay, mEGLImage);
         mEGLImage = EGL_NO_IMAGE_KHR;
@@ -48,8 +48,13 @@
     }
 
     if (nativeBuffer) {
+        EGLint attributes[] = {
+                isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+                isProtected ? EGL_TRUE : EGL_NONE,
+                EGL_NONE,
+        };
         mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-                                      nativeBuffer, nullptr);
+                                      nativeBuffer, attributes);
         if (mEGLImage == EGL_NO_IMAGE_KHR) {
             return false;
         }
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index 358ab47..5043c59 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -35,7 +35,7 @@
     explicit GLFramebuffer(const GLESRenderEngine& engine);
     ~GLFramebuffer() override;
 
-    bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) override;
+    bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) override;
     EGLImageKHR getEGLImage() const { return mEGLImage; }
     uint32_t getTextureName() const { return mTextureName; }
     uint32_t getFramebufferName() const { return mFramebufferName; }
diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp
index a9529a7..587cb31 100644
--- a/libs/renderengine/gl/GLImage.cpp
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -65,6 +65,7 @@
             ALOGE("failed to create EGLImage: %#x", eglGetError());
             return false;
         }
+        mProtected = isProtected;
     }
 
     return true;
diff --git a/libs/renderengine/gl/GLImage.h b/libs/renderengine/gl/GLImage.h
index c897d8e..59d6ce3 100644
--- a/libs/renderengine/gl/GLImage.h
+++ b/libs/renderengine/gl/GLImage.h
@@ -39,10 +39,12 @@
     bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override;
 
     EGLImageKHR getEGLImage() const { return mEGLImage; }
+    bool isProtected() const { return mProtected; }
 
 private:
     EGLDisplay mEGLDisplay;
     EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
+    bool mProtected = false;
 
     DISALLOW_COPY_AND_ASSIGN(GLImage);
 };
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 41870d2..bf2354d 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -77,7 +77,8 @@
     return f;
 }
 
-void ProgramCache::primeCache(bool useColorManagement) {
+void ProgramCache::primeCache(EGLContext context, bool useColorManagement) {
+    auto& cache = mCaches[context];
     uint32_t shaderCount = 0;
     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK
         | Key::ROUNDED_CORNERS_MASK;
@@ -92,8 +93,8 @@
         if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) {
             continue;
         }
-        if (mCache.count(shaderKey) == 0) {
-            mCache.emplace(shaderKey, generateProgram(shaderKey));
+        if (cache.count(shaderKey) == 0) {
+            cache.emplace(shaderKey, generateProgram(shaderKey));
             shaderCount++;
         }
     }
@@ -109,8 +110,8 @@
             shaderKey.set(Key::OPACITY_MASK,
                           (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
             shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE);
-            if (mCache.count(shaderKey) == 0) {
-                mCache.emplace(shaderKey, generateProgram(shaderKey));
+            if (cache.count(shaderKey) == 0) {
+                cache.emplace(shaderKey, generateProgram(shaderKey));
                 shaderCount++;
             }
         }
@@ -695,20 +696,21 @@
     return std::make_unique<Program>(needs, vs.string(), fs.string());
 }
 
-void ProgramCache::useProgram(const Description& description) {
+void ProgramCache::useProgram(EGLContext context, const Description& description) {
     // generate the key for the shader based on the description
     Key needs(computeKey(description));
 
     // look-up the program in the cache
-    auto it = mCache.find(needs);
-    if (it == mCache.end()) {
+    auto& cache = mCaches[context];
+    auto it = cache.find(needs);
+    if (it == cache.end()) {
         // we didn't find our program, so generate one...
         nsecs_t time = systemTime();
-        it = mCache.emplace(needs, generateProgram(needs)).first;
+        it = cache.emplace(needs, generateProgram(needs)).first;
         time = systemTime() - time;
 
-        ALOGV(">>> generated new program: needs=%08X, time=%u ms (%zu programs)", needs.mKey,
-              uint32_t(ns2ms(time)), mCache.size());
+        ALOGV(">>> generated new program for context %p: needs=%08X, time=%u ms (%zu programs)",
+              context, needs.mKey, uint32_t(ns2ms(time)), cache.size());
     }
 
     // here we have a suitable program for this description
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index 653aaf0..400ad74 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -20,6 +20,7 @@
 #include <memory>
 #include <unordered_map>
 
+#include <EGL/egl.h>
 #include <GLES2/gl2.h>
 #include <renderengine/private/Description.h>
 #include <utils/Singleton.h>
@@ -178,13 +179,13 @@
     ~ProgramCache() = default;
 
     // Generate shaders to populate the cache
-    void primeCache(bool useColorManagement);
+    void primeCache(const EGLContext context, bool useColorManagement);
 
-    size_t getSize() const { return mCache.size(); }
+    size_t getSize(const EGLContext context) { return mCaches[context].size(); }
 
     // useProgram lookup a suitable program in the cache or generates one
     // if none can be found.
-    void useProgram(const Description& description);
+    void useProgram(const EGLContext context, const Description& description);
 
 private:
     // compute a cache Key from a Description
@@ -206,7 +207,8 @@
 
     // Key/Value map used for caching Programs. Currently the cache
     // is never shrunk (and the GL program objects are never deleted).
-    std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash> mCache;
+    std::unordered_map<EGLContext, std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash>>
+            mCaches;
 };
 
 } // namespace gl
diff --git a/libs/renderengine/include/renderengine/Framebuffer.h b/libs/renderengine/include/renderengine/Framebuffer.h
index 558b9c7..66eb9ef 100644
--- a/libs/renderengine/include/renderengine/Framebuffer.h
+++ b/libs/renderengine/include/renderengine/Framebuffer.h
@@ -27,7 +27,7 @@
 public:
     virtual ~Framebuffer() = default;
 
-    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) = 0;
+    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) = 0;
 };
 
 } // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 8eaa2d2..5e88159 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -53,6 +53,11 @@
 class RenderEngine;
 }
 
+enum class Protection {
+    UNPROTECTED = 1,
+    PROTECTED = 2,
+};
+
 class RenderEngine {
 public:
     enum FeatureFlag {
@@ -150,6 +155,10 @@
 
     // ----- BEGIN NEW INTERFACE -----
 
+    virtual bool isProtected() const = 0;
+    virtual bool supportsProtectedContent() const = 0;
+    virtual bool useProtectedContext(bool useProtectedContext) = 0;
+
     // Renders layers for a particular display via GPU composition. This method
     // should be called for every display that needs to be rendered via the GPU.
     // @param settings The display-wide settings that should be applied prior to
@@ -182,12 +191,12 @@
 public:
     BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
           : mEngine(engine), mFramebuffer(mEngine.createFramebuffer()), mStatus(NO_ERROR) {
-        mStatus = mFramebuffer->setNativeWindowBuffer(buffer)
+        mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected())
                 ? mEngine.bindFrameBuffer(mFramebuffer.get())
                 : NO_MEMORY;
     }
     ~BindNativeBufferAsFramebuffer() {
-        mFramebuffer->setNativeWindowBuffer(nullptr);
+        mFramebuffer->setNativeWindowBuffer(nullptr, false);
         mEngine.unbindFrameBuffer(mFramebuffer.get());
     }
     status_t getStatus() const { return mStatus; }
diff --git a/libs/sensorprivacy/Android.bp b/libs/sensorprivacy/Android.bp
new file mode 100644
index 0000000..e0e3469
--- /dev/null
+++ b/libs/sensorprivacy/Android.bp
@@ -0,0 +1,47 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "libsensorprivacy",
+
+    aidl: {
+        export_aidl_headers: true,
+        local_include_dirs: ["aidl"],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wzero-as-null-pointer-constant",
+    ],
+
+    srcs: [
+        "aidl/android/hardware/ISensorPrivacyListener.aidl",
+        "aidl/android/hardware/ISensorPrivacyManager.aidl",
+        "SensorPrivacyManager.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libhardware",
+    ],
+
+    export_include_dirs: ["include"],
+
+    export_shared_lib_headers: ["libbinder"],
+}
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
new file mode 100644
index 0000000..1da79a0
--- /dev/null
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mutex>
+#include <unistd.h>
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <sensorprivacy/SensorPrivacyManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+SensorPrivacyManager::SensorPrivacyManager()
+{
+}
+
+sp<hardware::ISensorPrivacyManager> SensorPrivacyManager::getService()
+{
+    std::lock_guard<Mutex> scoped_lock(mLock);
+    int64_t startTime = 0;
+    sp<hardware::ISensorPrivacyManager> service = mService;
+    while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
+        sp<IBinder> binder = defaultServiceManager()->checkService(String16("sensor_privacy"));
+        if (binder == nullptr) {
+            // Wait for the sensor privacy service to come back...
+            if (startTime == 0) {
+                startTime = uptimeMillis();
+                ALOGI("Waiting for sensor privacy service");
+            } else if ((uptimeMillis() - startTime) > 1000000) {
+                ALOGW("Waiting too long for sensor privacy service, giving up");
+                service = nullptr;
+                break;
+            }
+            usleep(25000);
+        } else {
+            service = interface_cast<hardware::ISensorPrivacyManager>(binder);
+            mService = service;
+        }
+    }
+    return service;
+}
+
+void SensorPrivacyManager::addSensorPrivacyListener(
+        const sp<hardware::ISensorPrivacyListener>& listener)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        service->addSensorPrivacyListener(listener);
+    }
+}
+
+void SensorPrivacyManager::removeSensorPrivacyListener(
+        const sp<hardware::ISensorPrivacyListener>& listener)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        service->removeSensorPrivacyListener(listener);
+    }
+}
+
+bool SensorPrivacyManager::isSensorPrivacyEnabled()
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        bool result;
+        service->isSensorPrivacyEnabled(&result);
+        return result;
+    }
+    // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
+    return false;
+}
+
+}; // namespace android
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
new file mode 100644
index 0000000..58177d8
--- /dev/null
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/**
+ * @hide
+ */
+oneway interface ISensorPrivacyListener {
+    void onSensorPrivacyChanged(boolean enabled);
+}
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
new file mode 100644
index 0000000..4c2d5db
--- /dev/null
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+import android.hardware.ISensorPrivacyListener;
+
+/** @hide */
+interface ISensorPrivacyManager {
+    void addSensorPrivacyListener(in ISensorPrivacyListener listener);
+
+    void removeSensorPrivacyListener(in ISensorPrivacyListener listener);
+
+    boolean isSensorPrivacyEnabled();
+
+    void setSensorPrivacy(boolean enable);
+}
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
new file mode 100644
index 0000000..8826595
--- /dev/null
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSOR_PRIVACY_MANAGER_H
+#define ANDROID_SENSOR_PRIVACY_MANAGER_H
+
+#include "android/hardware/ISensorPrivacyListener.h"
+#include "android/hardware/ISensorPrivacyManager.h"
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class SensorPrivacyManager
+{
+public:
+    SensorPrivacyManager();
+
+    void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
+    void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
+    bool isSensorPrivacyEnabled();
+
+private:
+    Mutex mLock;
+    sp<hardware::ISensorPrivacyManager> mService;
+    sp<hardware::ISensorPrivacyManager> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SENSOR_PRIVACY_MANAGER_H
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 1464e48..226b6ee 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -95,22 +95,21 @@
 BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
                                  uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
     ATRACE_CALL();
-    ALOGD("BufferHubBuffer::BufferHubBuffer: width=%u height=%u layerCount=%u, format=%u "
-          "usage=%" PRIx64 " mUserMetadataSize=%zu",
-          width, height, layerCount, format, usage, mUserMetadataSize);
+    ALOGD("%s: width=%u height=%u layerCount=%u, format=%u usage=%" PRIx64 " mUserMetadataSize=%zu",
+          __FUNCTION__, width, height, layerCount, format, usage, mUserMetadataSize);
 
     auto status =
             mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
                                                                   usage, mUserMetadataSize);
     if (!status) {
-        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to create detached buffer: %s",
+        ALOGE("%s: Failed to create detached buffer: %s", __FUNCTION__,
               status.GetErrorMessage().c_str());
         mClient.Close(-status.error());
     }
 
     const int ret = ImportGraphicBuffer();
     if (ret < 0) {
-        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
+        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
         mClient.Close(ret);
     }
 }
@@ -119,7 +118,7 @@
       : mClient(std::move(mChannelHandle)) {
     const int ret = ImportGraphicBuffer();
     if (ret < 0) {
-        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
+        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
         mClient.Close(ret);
     }
 }
@@ -129,14 +128,14 @@
 
     auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
     if (!status) {
-        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import GraphicBuffer: %s",
+        ALOGE("%s: Failed to import GraphicBuffer: %s", __FUNCTION__,
               status.GetErrorMessage().c_str());
         return -status.error();
     }
 
     BufferTraits<LocalHandle> bufferTraits = status.take();
     if (bufferTraits.id() < 0) {
-        ALOGE("BufferHubBuffer::BufferHubBuffer: Received an invalid id!");
+        ALOGE("%s: Received an invalid id!", __FUNCTION__);
         return -EIO;
     }
 
@@ -149,20 +148,19 @@
     mMetadata = BufferHubMetadata::Import(std::move(metadataFd));
 
     if (!mMetadata.IsValid()) {
-        ALOGE("BufferHubBuffer::ImportGraphicBuffer: invalid metadata.");
+        ALOGE("%s: invalid metadata.", __FUNCTION__);
         return -ENOMEM;
     }
 
     if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
-        ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata buffer too small: "
-              "%zu, expected: %" PRIu64 ".",
+        ALOGE("%s: metadata buffer too small: %zu, expected: %" PRIu64 ".", __FUNCTION__,
               mMetadata.metadata_size(), bufferTraits.metadata_size());
         return -ENOMEM;
     }
 
     size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
     if (metadataSize < BufferHubDefs::kMetadataHeaderSize) {
-        ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata too small: %zu", metadataSize);
+        ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize);
         return -EINVAL;
     }
 
@@ -191,22 +189,22 @@
     mClientStateMask = bufferTraits.client_state_mask();
 
     // TODO(b/112012161) Set up shared fences.
-    ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
+    ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, id(),
           buffer_state_->load(std::memory_order_acquire));
     return 0;
 }
 
 int BufferHubBuffer::Gain() {
-    uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+    uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
     if (IsClientGained(current_buffer_state, mClientStateMask)) {
-        ALOGV("%s: Buffer is already gained by this client %" PRIx64 ".", __FUNCTION__,
+        ALOGV("%s: Buffer is already gained by this client %" PRIx32 ".", __FUNCTION__,
               mClientStateMask);
         return 0;
     }
     do {
         if (AnyClientGained(current_buffer_state & (~mClientStateMask)) ||
             AnyClientAcquired(current_buffer_state)) {
-            ALOGE("%s: Buffer is in use, id=%d mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
+            ALOGE("%s: Buffer is in use, id=%d mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
                   __FUNCTION__, mId, mClientStateMask, current_buffer_state);
             return -EBUSY;
         }
@@ -220,13 +218,13 @@
 }
 
 int BufferHubBuffer::Post() {
-    uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
-    uint64_t current_active_clients_bit_mask = 0ULL;
-    uint64_t updated_buffer_state = 0ULL;
+    uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+    uint32_t current_active_clients_bit_mask = 0U;
+    uint32_t updated_buffer_state = 0U;
     do {
         if (!IsClientGained(current_buffer_state, mClientStateMask)) {
             ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
-                  "mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
+                  "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
                   __FUNCTION__, mId, mClientStateMask, current_buffer_state);
             return -EBUSY;
         }
@@ -242,17 +240,17 @@
 }
 
 int BufferHubBuffer::Acquire() {
-    uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+    uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
     if (IsClientAcquired(current_buffer_state, mClientStateMask)) {
-        ALOGV("%s: Buffer is already acquired by this client %" PRIx64 ".", __FUNCTION__,
+        ALOGV("%s: Buffer is already acquired by this client %" PRIx32 ".", __FUNCTION__,
               mClientStateMask);
         return 0;
     }
-    uint64_t updated_buffer_state = 0ULL;
+    uint32_t updated_buffer_state = 0U;
     do {
         if (!IsClientPosted(current_buffer_state, mClientStateMask)) {
             ALOGE("%s: Cannot acquire a buffer that is not in posted state. buffer_id=%d "
-                  "mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
+                  "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
                   __FUNCTION__, mId, mClientStateMask, current_buffer_state);
             return -EBUSY;
         }
@@ -266,13 +264,13 @@
 }
 
 int BufferHubBuffer::Release() {
-    uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+    uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
     if (IsClientReleased(current_buffer_state, mClientStateMask)) {
-        ALOGV("%s: Buffer is already released by this client %" PRIx64 ".", __FUNCTION__,
+        ALOGV("%s: Buffer is already released by this client %" PRIx32 ".", __FUNCTION__,
               mClientStateMask);
         return 0;
     }
-    uint64_t updated_buffer_state = 0ULL;
+    uint32_t updated_buffer_state = 0U;
     do {
         updated_buffer_state = current_buffer_state & (~mClientStateMask);
     } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
@@ -291,12 +289,12 @@
 
 Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
     ATRACE_CALL();
-    ALOGD("BufferHubBuffer::Duplicate: id=%d.", mId);
+    ALOGD("%s: id=%d.", __FUNCTION__, mId);
 
     auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
 
     if (!statusOrHandle.ok()) {
-        ALOGE("BufferHubBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.", mId,
+        ALOGE("%s: Failed to duplicate buffer (id=%d): %s.", __FUNCTION__, mId,
               statusOrHandle.GetErrorMessage().c_str());
     }
     return statusOrHandle;
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index e606e26..f408fcb 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -104,6 +104,7 @@
                                 buffer->desc().width, buffer->desc().height,
                                 static_cast<PixelFormat>(buffer->desc().format),
                                 buffer->desc().layers, buffer->desc().usage, buffer->desc().stride);
+    mBufferId = buffer->id();
     mBufferHubBuffer = std::move(buffer);
 }
 #endif // LIBUI_IN_VNDK
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 11e9b5c..90dd391 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -86,13 +86,13 @@
     const native_handle_t* DuplicateHandle() { return mBufferHandle.DuplicateHandle(); }
 
     // Returns the current value of MetadataHeader::buffer_state.
-    uint64_t buffer_state() {
+    uint32_t buffer_state() {
         return mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire);
     }
 
     // A state mask which is unique to a buffer hub client among all its siblings sharing the same
     // concrete graphic buffer.
-    uint64_t client_state_mask() const { return mClientStateMask; }
+    uint32_t client_state_mask() const { return mClientStateMask; }
 
     size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
 
@@ -154,7 +154,7 @@
 
     // Client state mask of this BufferHubBuffer object. It is unique amoung all
     // clients/users of the buffer.
-    uint64_t mClientStateMask = 0;
+    uint32_t mClientStateMask = 0U;
 
     // Stores ground truth of the buffer.
     AHardwareBuffer_Desc mBufferDesc;
@@ -166,9 +166,9 @@
     // bufferhubd daemon and all buffer clients.
     BufferHubMetadata mMetadata;
     // Shortcuts to the atomics inside the header of mMetadata.
-    std::atomic<uint64_t>* buffer_state_{nullptr};
-    std::atomic<uint64_t>* fence_state_{nullptr};
-    std::atomic<uint64_t>* active_clients_bit_mask_{nullptr};
+    std::atomic<uint32_t>* buffer_state_ = nullptr;
+    std::atomic<uint32_t>* fence_state_ = nullptr;
+    std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
 
     // PDX backend.
     BufferHubClient mClient;
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
index ef6668b..d259fef 100644
--- a/libs/ui/include/ui/BufferHubDefs.h
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -29,10 +29,10 @@
 
 namespace BufferHubDefs {
 
-// Single buffer clients (up to 32) ownership signal.
-// 64-bit atomic unsigned int.
-// Each client takes 2 bits. The first bit locates in the first 32 bits of
-// buffer_state; the second bit locates in the last 32 bits of buffer_state.
+// Single buffer clients (up to 16) ownership signal.
+// 32-bit atomic unsigned int.
+// Each client takes 2 bits. The first bit locates in the first 16 bits of
+// buffer_state; the second bit locates in the last 16 bits of buffer_state.
 // Client states:
 // Gained state 11. Exclusive write state.
 // Posted state 10.
@@ -42,88 +42,88 @@
 //  MSB                        LSB
 //   |                          |
 //   v                          v
-// [C31|...|C1|C0|C31| ... |C1|C0]
+// [C15|...|C1|C0|C15| ... |C1|C0]
 
 // Maximum number of clients a buffer can have.
-static constexpr int kMaxNumberOfClients = 32;
+static constexpr int kMaxNumberOfClients = 16;
 
 // Definition of bit masks.
 //  MSB                            LSB
 //   | kHighBitsMask | kLowbitsMask |
 //   v               v              v
-// [b63|   ...   |b32|b31|   ...  |b0]
+// [b31|   ...   |b16|b15|   ...  |b0]
 
-// The location of lower 32 bits in the 64-bit buffer state.
-static constexpr uint64_t kLowbitsMask = (1ULL << kMaxNumberOfClients) - 1ULL;
+// The location of lower 16 bits in the 32-bit buffer state.
+static constexpr uint32_t kLowbitsMask = (1U << kMaxNumberOfClients) - 1U;
 
-// The location of higher 32 bits in the 64-bit buffer state.
-static constexpr uint64_t kHighBitsMask = ~kLowbitsMask;
+// The location of higher 16 bits in the 32-bit buffer state.
+static constexpr uint32_t kHighBitsMask = ~kLowbitsMask;
 
 // The client bit mask of the first client.
-static constexpr uint64_t kFirstClientBitMask = (1ULL << kMaxNumberOfClients) + 1ULL;
+static constexpr uint32_t kFirstClientBitMask = (1U << kMaxNumberOfClients) + 1U;
 
 // Returns true if any of the client is in gained state.
-static inline bool AnyClientGained(uint64_t state) {
-    uint64_t high_bits = state >> kMaxNumberOfClients;
-    uint64_t low_bits = state & kLowbitsMask;
-    return high_bits == low_bits && low_bits != 0ULL;
+static inline bool AnyClientGained(uint32_t state) {
+    uint32_t high_bits = state >> kMaxNumberOfClients;
+    uint32_t low_bits = state & kLowbitsMask;
+    return high_bits == low_bits && low_bits != 0U;
 }
 
 // Returns true if the input client is in gained state.
-static inline bool IsClientGained(uint64_t state, uint64_t client_bit_mask) {
+static inline bool IsClientGained(uint32_t state, uint32_t client_bit_mask) {
     return state == client_bit_mask;
 }
 
 // Returns true if any of the client is in posted state.
-static inline bool AnyClientPosted(uint64_t state) {
-    uint64_t high_bits = state >> kMaxNumberOfClients;
-    uint64_t low_bits = state & kLowbitsMask;
-    uint64_t posted_or_acquired = high_bits ^ low_bits;
+static inline bool AnyClientPosted(uint32_t state) {
+    uint32_t high_bits = state >> kMaxNumberOfClients;
+    uint32_t low_bits = state & kLowbitsMask;
+    uint32_t posted_or_acquired = high_bits ^ low_bits;
     return posted_or_acquired & high_bits;
 }
 
 // Returns true if the input client is in posted state.
-static inline bool IsClientPosted(uint64_t state, uint64_t client_bit_mask) {
-    uint64_t client_bits = state & client_bit_mask;
-    if (client_bits == 0ULL) return false;
-    uint64_t low_bits = client_bits & kLowbitsMask;
-    return low_bits == 0ULL;
+static inline bool IsClientPosted(uint32_t state, uint32_t client_bit_mask) {
+    uint32_t client_bits = state & client_bit_mask;
+    if (client_bits == 0U) return false;
+    uint32_t low_bits = client_bits & kLowbitsMask;
+    return low_bits == 0U;
 }
 
 // Return true if any of the client is in acquired state.
-static inline bool AnyClientAcquired(uint64_t state) {
-    uint64_t high_bits = state >> kMaxNumberOfClients;
-    uint64_t low_bits = state & kLowbitsMask;
-    uint64_t posted_or_acquired = high_bits ^ low_bits;
+static inline bool AnyClientAcquired(uint32_t state) {
+    uint32_t high_bits = state >> kMaxNumberOfClients;
+    uint32_t low_bits = state & kLowbitsMask;
+    uint32_t posted_or_acquired = high_bits ^ low_bits;
     return posted_or_acquired & low_bits;
 }
 
 // Return true if the input client is in acquired state.
-static inline bool IsClientAcquired(uint64_t state, uint64_t client_bit_mask) {
-    uint64_t client_bits = state & client_bit_mask;
-    if (client_bits == 0ULL) return false;
-    uint64_t high_bits = client_bits & kHighBitsMask;
-    return high_bits == 0ULL;
+static inline bool IsClientAcquired(uint32_t state, uint32_t client_bit_mask) {
+    uint32_t client_bits = state & client_bit_mask;
+    if (client_bits == 0U) return false;
+    uint32_t high_bits = client_bits & kHighBitsMask;
+    return high_bits == 0U;
 }
 
 // Returns true if all clients are in released state.
-static inline bool IsBufferReleased(uint64_t state) {
-    return state == 0ULL;
+static inline bool IsBufferReleased(uint32_t state) {
+    return state == 0U;
 }
 
 // Returns true if the input client is in released state.
-static inline bool IsClientReleased(uint64_t state, uint64_t client_bit_mask) {
-    return (state & client_bit_mask) == 0ULL;
+static inline bool IsClientReleased(uint32_t state, uint32_t client_bit_mask) {
+    return (state & client_bit_mask) == 0U;
 }
 
 // Returns the next available buffer client's client_state_masks.
 // @params union_bits. Union of all existing clients' client_state_masks.
-static inline uint64_t FindNextAvailableClientStateMask(uint64_t union_bits) {
-    uint64_t low_union = union_bits & kLowbitsMask;
-    if (low_union == kLowbitsMask) return 0ULL;
-    uint64_t incremented = low_union + 1ULL;
-    uint64_t difference = incremented ^ low_union;
-    uint64_t new_low_bit = (difference + 1ULL) >> 1;
+static inline uint32_t FindNextAvailableClientStateMask(uint32_t union_bits) {
+    uint32_t low_union = union_bits & kLowbitsMask;
+    if (low_union == kLowbitsMask) return 0U;
+    uint32_t incremented = low_union + 1U;
+    uint32_t difference = incremented ^ low_union;
+    uint32_t new_low_bit = (difference + 1U) >> 1;
     return new_low_bit + (new_low_bit << kMaxNumberOfClients);
 }
 
@@ -135,15 +135,18 @@
 
     // Every client takes up one bit from the higher 32 bits and one bit from the lower 32 bits in
     // buffer_state.
-    std::atomic<uint64_t> buffer_state;
+    std::atomic<uint32_t> buffer_state;
 
     // Every client takes up one bit in fence_state. Only the lower 32 bits are valid. The upper 32
     // bits are there for easier manipulation, but the value should be ignored.
-    std::atomic<uint64_t> fence_state;
+    std::atomic<uint32_t> fence_state;
 
     // Every client takes up one bit from the higher 32 bits and one bit from the lower 32 bits in
     // active_clients_bit_mask.
-    std::atomic<uint64_t> active_clients_bit_mask;
+    std::atomic<uint32_t> active_clients_bit_mask;
+
+    // Explicit padding 4 bytes.
+    uint32_t padding;
 
     // The index of the buffer queue where the buffer belongs to.
     uint64_t queue_index;
@@ -152,7 +155,7 @@
     DvrNativeBufferMetadata metadata;
 };
 
-static_assert(sizeof(MetadataHeader) == 136, "Unexpected MetadataHeader size");
+static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
 static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
 
 } // namespace BufferHubDefs
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 81f6cd9..b73ca2b 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -153,6 +153,7 @@
     uint32_t getLayerCount() const      { return static_cast<uint32_t>(layerCount); }
     Rect getBounds() const              { return Rect(width, height); }
     uint64_t getId() const              { return mId; }
+    int32_t getBufferId() const { return mBufferId; }
 
     uint32_t getGenerationNumber() const { return mGenerationNumber; }
     void setGenerationNumber(uint32_t generation) {
@@ -247,6 +248,12 @@
 
     uint64_t mId;
 
+    // System unique buffer ID. Note that this is different from mId, which is process unique. For
+    // GraphicBuffer backed by BufferHub, the mBufferId is a system unique identifier that stays the
+    // same cross process for the same chunck of underlying memory. Also note that this only applies
+    // to GraphicBuffers that are backed by BufferHub.
+    int32_t mBufferId = -1;
+
     // Stores the generation number of this buffer. If this number does not
     // match the BufferQueue's internal generation number (set through
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index c0f4c89..a670b3c 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -45,7 +45,7 @@
 }
 
 cc_test {
-    name: "BufferHubBuffer_test",
+    name: "BufferHub_test",
     header_libs: [
         "libbufferhub_headers",
         "libdvr_headers",
@@ -67,18 +67,7 @@
     srcs: [
         "BufferHubBuffer_test.cpp",
         "BufferHubEventFd_test.cpp",
+        "BufferHubMetadata_test.cpp",
     ],
     cflags: ["-Wall", "-Werror"],
 }
-
-cc_test {
-    name: "BufferHubMetadata_test",
-    header_libs: ["libdvr_headers"],
-    shared_libs: [
-        "libbase",
-        "libui",
-        "libutils",
-    ],
-    srcs: ["BufferHubMetadata_test.cpp"],
-    cflags: ["-Wall", "-Werror"],
-}
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index f616785..1b339a0 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -67,9 +67,9 @@
     }
 
     std::unique_ptr<BufferHubBuffer> b1;
-    uint64_t b1ClientMask = 0ULL;
+    uint64_t b1ClientMask = 0U;
     std::unique_ptr<BufferHubBuffer> b2;
-    uint64_t b2ClientMask = 0ULL;
+    uint64_t b2ClientMask = 0U;
 
 private:
     // Creates b1 and b2 as the clients of the same buffer for testing.
@@ -79,13 +79,13 @@
 void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() {
     b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
     b1ClientMask = b1->client_state_mask();
-    ASSERT_NE(b1ClientMask, 0ULL);
+    ASSERT_NE(b1ClientMask, 0U);
     auto statusOrHandle = b1->Duplicate();
     ASSERT_TRUE(statusOrHandle);
     LocalChannelHandle h2 = statusOrHandle.take();
     b2 = BufferHubBuffer::Import(std::move(h2));
     b2ClientMask = b2->client_state_mask();
-    ASSERT_NE(b2ClientMask, 0ULL);
+    ASSERT_NE(b2ClientMask, 0U);
     ASSERT_NE(b2ClientMask, b1ClientMask);
 }
 
@@ -126,7 +126,7 @@
                                       kUserMetadataSize);
     int id1 = b1->id();
     uint64_t bufferStateMask1 = b1->client_state_mask();
-    EXPECT_NE(bufferStateMask1, 0ULL);
+    EXPECT_NE(bufferStateMask1, 0U);
     EXPECT_TRUE(b1->IsValid());
     EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
 
@@ -149,7 +149,7 @@
 
     int id2 = b2->id();
     uint64_t bufferStateMask2 = b2->client_state_mask();
-    EXPECT_NE(bufferStateMask2, 0ULL);
+    EXPECT_NE(bufferStateMask2, 0U);
 
     // These two buffer instances are based on the same physical buffer under the
     // hood, so they should share the same id.
@@ -165,194 +165,6 @@
     return;
 }
 
-TEST_F(BufferHubBufferTest, AllocateAndFreeBuffer) {
-    // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
-    sp<IBufferHub> bufferHub = IBufferHub::getService();
-    ASSERT_NE(nullptr, bufferHub.get());
-
-    // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
-    AHardwareBuffer_Desc aDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
-                                  kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
-    HardwareBufferDescription desc;
-    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
-
-    sp<IBufferClient> client;
-    BufferHubStatus ret;
-    IBufferHub::allocateBuffer_cb callback = [&](const auto& outClient, const auto& outStatus) {
-        client = outClient;
-        ret = outStatus;
-    };
-    EXPECT_TRUE(bufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
-    ASSERT_NE(nullptr, client.get());
-
-    EXPECT_EQ(BufferHubStatus::NO_ERROR, client->close());
-    EXPECT_EQ(BufferHubStatus::CLIENT_CLOSED, client->close());
-}
-
-TEST_F(BufferHubBufferTest, DuplicateFreedBuffer) {
-    // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
-    sp<IBufferHub> bufferHub = IBufferHub::getService();
-    ASSERT_NE(nullptr, bufferHub.get());
-
-    // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
-    AHardwareBuffer_Desc aDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
-                                  kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
-    HardwareBufferDescription desc;
-    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
-
-    sp<IBufferClient> client;
-    BufferHubStatus ret;
-    IBufferHub::allocateBuffer_cb callback = [&](const auto& outClient, const auto& outStatus) {
-        client = outClient;
-        ret = outStatus;
-    };
-    EXPECT_TRUE(bufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
-    ASSERT_NE(nullptr, client.get());
-
-    EXPECT_EQ(BufferHubStatus::NO_ERROR, client->close());
-
-    hidl_handle token;
-    IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
-        token = outToken;
-        ret = status;
-    };
-    EXPECT_TRUE(client->duplicate(dup_cb).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::CLIENT_CLOSED);
-    EXPECT_EQ(token.getNativeHandle(), nullptr);
-}
-
-TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) {
-    // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
-    sp<IBufferHub> bufferhub = IBufferHub::getService();
-    ASSERT_NE(nullptr, bufferhub.get());
-
-    // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
-    AHardwareBuffer_Desc aDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
-                                  kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
-    HardwareBufferDescription desc;
-    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
-
-    sp<IBufferClient> client;
-    BufferHubStatus ret;
-    IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& outClient, const auto& status) {
-        client = outClient;
-        ret = status;
-    };
-    ASSERT_TRUE(bufferhub->allocateBuffer(desc, kUserMetadataSize, alloc_cb).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
-    ASSERT_NE(nullptr, client.get());
-
-    hidl_handle token;
-    IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
-        token = outToken;
-        ret = status;
-    };
-    ASSERT_TRUE(client->duplicate(dup_cb).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
-    ASSERT_NE(token.getNativeHandle(), nullptr);
-    EXPECT_EQ(token->numInts, 1);
-    EXPECT_EQ(token->numFds, 0);
-
-    sp<IBufferClient> client2;
-    IBufferHub::importBuffer_cb import_cb = [&](const auto& outClient, const auto& status) {
-        ret = status;
-        client2 = outClient;
-    };
-    ASSERT_TRUE(bufferhub->importBuffer(token, import_cb).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
-    EXPECT_NE(nullptr, client2.get());
-    // TODO(b/116681016): once BufferNode.id() is exposed via BufferHubBuffer, check origin.id =
-    // improted.id here.
-}
-
-// nullptr must not crash the service
-TEST_F(BufferHubBufferTest, ImportNullToken) {
-    // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
-    sp<IBufferHub> bufferhub = IBufferHub::getService();
-    ASSERT_NE(nullptr, bufferhub.get());
-
-    hidl_handle nullToken;
-    sp<IBufferClient> client;
-    BufferHubStatus ret;
-    IBufferHub::importBuffer_cb import_cb = [&](const auto& outClient, const auto& status) {
-        client = outClient;
-        ret = status;
-    };
-    ASSERT_TRUE(bufferhub->importBuffer(nullToken, import_cb).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::INVALID_TOKEN);
-    EXPECT_EQ(nullptr, client.get());
-}
-
-// This test has a very little chance to fail (number of existing tokens / 2 ^ 32)
-TEST_F(BufferHubBufferTest, ImportInvalidToken) {
-    // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
-    sp<IBufferHub> bufferhub = IBufferHub::getService();
-    ASSERT_NE(nullptr, bufferhub.get());
-
-    native_handle_t* tokenHandle = native_handle_create(/*numFds=*/0, /*numInts=*/1);
-    tokenHandle->data[0] = 0;
-
-    hidl_handle invalidToken(tokenHandle);
-    sp<IBufferClient> client;
-    BufferHubStatus ret;
-    IBufferHub::importBuffer_cb import_cb = [&](const auto& outClient, const auto& status) {
-        client = outClient;
-        ret = status;
-    };
-    ASSERT_TRUE(bufferhub->importBuffer(invalidToken, import_cb).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::INVALID_TOKEN);
-    EXPECT_EQ(nullptr, client.get());
-
-    native_handle_delete(tokenHandle);
-}
-
-TEST_F(BufferHubBufferTest, ImportFreedBuffer) {
-    // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
-    sp<IBufferHub> bufferhub = IBufferHub::getService();
-    ASSERT_NE(nullptr, bufferhub.get());
-
-    // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
-    AHardwareBuffer_Desc aDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
-                                  kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
-    HardwareBufferDescription desc;
-    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
-
-    sp<IBufferClient> client;
-    BufferHubStatus ret;
-    IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& outClient, const auto& status) {
-        client = outClient;
-        ret = status;
-    };
-    ASSERT_TRUE(bufferhub->allocateBuffer(desc, kUserMetadataSize, alloc_cb).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
-    ASSERT_NE(nullptr, client.get());
-
-    hidl_handle token;
-    IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
-        token = outToken;
-        ret = status;
-    };
-    ASSERT_TRUE(client->duplicate(dup_cb).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
-    ASSERT_NE(token.getNativeHandle(), nullptr);
-    EXPECT_EQ(token->numInts, 1);
-    EXPECT_EQ(token->numFds, 0);
-
-    // Close the client. Now the token should be invalid.
-    client->close();
-
-    sp<IBufferClient> client2;
-    IBufferHub::importBuffer_cb import_cb = [&](const auto& outClient, const auto& status) {
-        client2 = outClient;
-        ret = status;
-    };
-    EXPECT_TRUE(bufferhub->importBuffer(token, import_cb).isOk());
-    EXPECT_EQ(ret, BufferHubStatus::INVALID_TOKEN);
-    EXPECT_EQ(nullptr, client2.get());
-}
-
 TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) {
     ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
 
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index 95ca2c1..81ab3ac 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -39,6 +39,7 @@
     std::unique_ptr<BufferHubBuffer> b1 =
             BufferHubBuffer::Create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
                                     kTestUsage, /*userMetadataSize=*/0);
+    EXPECT_NE(b1, nullptr);
     EXPECT_TRUE(b1->IsValid());
 
     sp<GraphicBuffer> gb(new GraphicBuffer(std::move(b1)));
@@ -51,4 +52,26 @@
     EXPECT_EQ(gb->getLayerCount(), kTestLayerCount);
 }
 
+TEST_F(GraphicBufferTest, InvalidBufferIdForNoneBufferHubBuffer) {
+    sp<GraphicBuffer> gb(
+            new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage));
+    EXPECT_FALSE(gb->isBufferHubBuffer());
+    EXPECT_EQ(gb->getBufferId(), -1);
+}
+
+TEST_F(GraphicBufferTest, BufferIdMatchesBufferHubBufferId) {
+    std::unique_ptr<BufferHubBuffer> b1 =
+            BufferHubBuffer::Create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
+                                    kTestUsage, /*userMetadataSize=*/0);
+    EXPECT_NE(b1, nullptr);
+    EXPECT_TRUE(b1->IsValid());
+
+    int b1_id = b1->id();
+    EXPECT_GE(b1_id, 0);
+
+    sp<GraphicBuffer> gb(new GraphicBuffer(std::move(b1)));
+    EXPECT_TRUE(gb->isBufferHubBuffer());
+    EXPECT_EQ(gb->getBufferId(), b1_id);
+}
+
 } // namespace android
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index c3fa77b..6cb6541 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -175,7 +175,7 @@
   ASSERT_TRUE(p.get() != nullptr);
 
   // It's ok to create up to kMaxConsumerCount consumer buffers.
-  uint64_t client_state_masks = p->client_state_mask();
+  uint32_t client_state_masks = p->client_state_mask();
   std::array<std::unique_ptr<ConsumerBuffer>, kMaxConsumerCount> cs;
   for (size_t i = 0; i < kMaxConsumerCount; i++) {
     cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
@@ -184,7 +184,7 @@
     EXPECT_EQ(client_state_masks & cs[i]->client_state_mask(), 0U);
     client_state_masks |= cs[i]->client_state_mask();
   }
-  EXPECT_EQ(client_state_masks, ~0ULL);
+  EXPECT_EQ(client_state_masks, ~0U);
 
   // The 64th creation will fail with out-of-memory error.
   auto state = p->CreateConsumer();
@@ -373,7 +373,7 @@
   std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
-  uint64_t producer_state_mask = p->client_state_mask();
+  uint32_t producer_state_mask = p->client_state_mask();
 
   std::array<std::unique_ptr<ConsumerBuffer>, kMaxConsumerCount> cs;
   for (size_t i = 0; i < kMaxConsumerCount; ++i) {
@@ -719,7 +719,7 @@
   std::unique_ptr<ConsumerBuffer> c1 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c1.get() != nullptr);
-  const uint64_t client_state_mask1 = c1->client_state_mask();
+  const uint32_t client_state_mask1 = c1->client_state_mask();
 
   EXPECT_EQ(0, p->GainAsync());
   DvrNativeBufferMetadata meta;
@@ -739,7 +739,7 @@
   std::unique_ptr<ConsumerBuffer> c2 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c2.get() != nullptr);
-  const uint64_t client_state_mask2 = c2->client_state_mask();
+  const uint32_t client_state_mask2 = c2->client_state_mask();
   EXPECT_NE(client_state_mask1, client_state_mask2);
   EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
   EXPECT_EQ(-EBUSY, c2->AcquireAsync(&meta, &fence));
@@ -755,7 +755,7 @@
   std::unique_ptr<ConsumerBuffer> c1 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c1.get() != nullptr);
-  const uint64_t client_state_mask1 = c1->client_state_mask();
+  const uint32_t client_state_mask1 = c1->client_state_mask();
 
   EXPECT_EQ(0, p->GainAsync());
   DvrNativeBufferMetadata meta;
@@ -767,7 +767,7 @@
   std::unique_ptr<ConsumerBuffer> c2 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c2.get() != nullptr);
-  const uint64_t client_state_mask2 = c2->client_state_mask();
+  const uint32_t client_state_mask2 = c2->client_state_mask();
   EXPECT_NE(client_state_mask1, client_state_mask2);
   EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
   LocalHandle invalid_fence;
@@ -781,7 +781,7 @@
   std::unique_ptr<ConsumerBuffer> c3 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c3.get() != nullptr);
-  const uint64_t client_state_mask3 = c3->client_state_mask();
+  const uint32_t client_state_mask3 = c3->client_state_mask();
   EXPECT_NE(client_state_mask1, client_state_mask3);
   EXPECT_NE(client_state_mask2, client_state_mask3);
   EXPECT_LT(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
@@ -802,7 +802,7 @@
   std::unique_ptr<ConsumerBuffer> c4 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c4.get() != nullptr);
-  const uint64_t client_state_mask4 = c4->client_state_mask();
+  const uint32_t client_state_mask4 = c4->client_state_mask();
   EXPECT_NE(client_state_mask3, client_state_mask4);
   EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
   EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &invalid_fence));
@@ -952,7 +952,7 @@
   int b1_id = b1->id();
   EXPECT_TRUE(b1->IsValid());
   EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
-  EXPECT_NE(b1->client_state_mask(), 0ULL);
+  EXPECT_NE(b1->client_state_mask(), 0U);
 
   auto status_or_handle = b1->Duplicate();
   EXPECT_TRUE(status_or_handle);
@@ -970,7 +970,7 @@
   ASSERT_TRUE(b2 != nullptr);
   EXPECT_TRUE(b2->IsValid());
   EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
-  EXPECT_NE(b2->client_state_mask(), 0ULL);
+  EXPECT_NE(b2->client_state_mask(), 0U);
 
   int b2_id = b2->id();
 
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index 2dc427a..8497f3e 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -124,16 +124,16 @@
   // memory region will be preserved.
   buffer_state_ = &metadata_header_->buffer_state;
   ALOGD_IF(TRACE,
-           "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
+           "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx32 ".",
            id(), buffer_state_->load(std::memory_order_acquire));
   fence_state_ = &metadata_header_->fence_state;
   ALOGD_IF(TRACE,
-           "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
+           "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx32 ".", id(),
            fence_state_->load(std::memory_order_acquire));
   active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
   ALOGD_IF(
       TRACE,
-      "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx64
+      "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx32
       ".",
       id(), active_clients_bit_mask_->load(std::memory_order_acquire));
 
@@ -171,7 +171,7 @@
       // If ready fence is valid, we put that into the epoll set.
       epoll_event event;
       event.events = EPOLLIN;
-      event.data.u64 = client_state_mask();
+      event.data.u32 = client_state_mask();
       pending_fence_fd_ = new_fence.Duplicate();
       if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
                     &event) < 0) {
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index 62fb5fd..b6ca64e 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -36,33 +36,33 @@
     return -EINVAL;
 
   // The buffer can be acquired iff the buffer state for this client is posted.
-  uint64_t current_buffer_state =
+  uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
   if (!BufferHubDefs::IsClientPosted(current_buffer_state,
                                      client_state_mask())) {
     ALOGE(
         "%s: Failed to acquire the buffer. The buffer is not posted, id=%d "
-        "state=%" PRIx64 " client_state_mask=%" PRIx64 ".",
+        "state=%" PRIx32 " client_state_mask=%" PRIx32 ".",
         __FUNCTION__, id(), current_buffer_state, client_state_mask());
     return -EBUSY;
   }
 
   // Change the buffer state for this consumer from posted to acquired.
-  uint64_t updated_buffer_state = current_buffer_state ^ client_state_mask();
+  uint32_t updated_buffer_state = current_buffer_state ^ client_state_mask();
   while (!buffer_state_->compare_exchange_weak(
       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
       std::memory_order_acquire)) {
     ALOGD(
         "%s Failed to acquire the buffer. Current buffer state was changed to "
-        "%" PRIx64
+        "%" PRIx32
         " when trying to acquire the buffer and modify the buffer state to "
-        "%" PRIx64 ". About to try again if the buffer is still posted.",
+        "%" PRIx32 ". About to try again if the buffer is still posted.",
         __FUNCTION__, current_buffer_state, updated_buffer_state);
     if (!BufferHubDefs::IsClientPosted(current_buffer_state,
                                        client_state_mask())) {
       ALOGE(
           "%s: Failed to acquire the buffer. The buffer is no longer posted, "
-          "id=%d state=%" PRIx64 " client_state_mask=%" PRIx64 ".",
+          "id=%d state=%" PRIx32 " client_state_mask=%" PRIx32 ".",
           __FUNCTION__, id(), current_buffer_state, client_state_mask());
       return -EBUSY;
     }
@@ -81,7 +81,7 @@
     out_meta->user_metadata_ptr = 0;
   }
 
-  uint64_t fence_state = fence_state_->load(std::memory_order_acquire);
+  uint32_t fence_state = fence_state_->load(std::memory_order_acquire);
   // If there is an acquire fence from producer, we need to return it.
   // The producer state bit mask is kFirstClientBitMask for now.
   if (fence_state & BufferHubDefs::kFirstClientBitMask) {
@@ -142,21 +142,21 @@
 
   // Set the buffer state of this client to released if it is not already in
   // released state.
-  uint64_t current_buffer_state =
+  uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
   if (BufferHubDefs::IsClientReleased(current_buffer_state,
                                       client_state_mask())) {
     return 0;
   }
-  uint64_t updated_buffer_state = current_buffer_state & (~client_state_mask());
+  uint32_t updated_buffer_state = current_buffer_state & (~client_state_mask());
   while (!buffer_state_->compare_exchange_weak(
       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
       std::memory_order_acquire)) {
     ALOGD(
         "%s: Failed to release the buffer. Current buffer state was changed to "
-        "%" PRIx64
+        "%" PRIx32
         " when trying to release the buffer and modify the buffer state to "
-        "%" PRIx64 ". About to try again.",
+        "%" PRIx32 ". About to try again.",
         __FUNCTION__, current_buffer_state, updated_buffer_state);
     // The failure of compare_exchange_weak updates current_buffer_state.
     updated_buffer_state = current_buffer_state & (~client_state_mask());
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 09feb73..440a59d 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -90,13 +90,13 @@
   int cid() const { return cid_; }
 
   // Returns the buffer buffer state.
-  uint64_t buffer_state() {
+  uint32_t buffer_state() {
     return buffer_state_->load(std::memory_order_acquire);
   };
 
   // A state mask which is unique to a buffer hub client among all its siblings
   // sharing the same concrete graphic buffer.
-  uint64_t client_state_mask() const { return client_state_mask_; }
+  uint32_t client_state_mask() const { return client_state_mask_; }
 
   // The following methods return settings of the first buffer. Currently,
   // it is only possible to create multi-buffer BufferHubBases with the same
@@ -132,11 +132,11 @@
   // IonBuffer that is shared between bufferhubd, producer, and consumers.
   size_t metadata_buf_size_{0};
   size_t user_metadata_size_{0};
-  BufferHubDefs::MetadataHeader* metadata_header_{nullptr};
-  void* user_metadata_ptr_{nullptr};
-  std::atomic<uint64_t>* buffer_state_{nullptr};
-  std::atomic<uint64_t>* fence_state_{nullptr};
-  std::atomic<uint64_t>* active_clients_bit_mask_{nullptr};
+  BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
+  void* user_metadata_ptr_ = nullptr;
+  std::atomic<uint32_t>* buffer_state_ = nullptr;
+  std::atomic<uint32_t>* fence_state_ = nullptr;
+  std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
 
   LocalHandle shared_acquire_fence_;
   LocalHandle shared_release_fence_;
@@ -159,7 +159,7 @@
 
   // Client bit mask which indicates the locations of this client object in the
   // buffer_state_.
-  uint64_t client_state_mask_{0ULL};
+  uint32_t client_state_mask_{0U};
   IonBuffer buffer_;
   IonBuffer metadata_buffer_;
 };
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 2de36f2..f2c40fe 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -22,46 +22,46 @@
 // See more details in libs/ui/include/ui/BufferHubDefs.h
 static constexpr int kMaxNumberOfClients =
     android::BufferHubDefs::kMaxNumberOfClients;
-static constexpr uint64_t kLowbitsMask = android::BufferHubDefs::kLowbitsMask;
-static constexpr uint64_t kHighBitsMask = android::BufferHubDefs::kHighBitsMask;
-static constexpr uint64_t kFirstClientBitMask =
+static constexpr uint32_t kLowbitsMask = android::BufferHubDefs::kLowbitsMask;
+static constexpr uint32_t kHighBitsMask = android::BufferHubDefs::kHighBitsMask;
+static constexpr uint32_t kFirstClientBitMask =
     android::BufferHubDefs::kFirstClientBitMask;
 
-static inline bool AnyClientGained(uint64_t state) {
+static inline bool AnyClientGained(uint32_t state) {
   return android::BufferHubDefs::AnyClientGained(state);
 }
 
-static inline bool IsClientGained(uint64_t state, uint64_t client_bit_mask) {
+static inline bool IsClientGained(uint32_t state, uint32_t client_bit_mask) {
   return android::BufferHubDefs::IsClientGained(state, client_bit_mask);
 }
 
-static inline bool AnyClientPosted(uint64_t state) {
+static inline bool AnyClientPosted(uint32_t state) {
   return android::BufferHubDefs::AnyClientPosted(state);
 }
 
-static inline bool IsClientPosted(uint64_t state, uint64_t client_bit_mask) {
+static inline bool IsClientPosted(uint32_t state, uint32_t client_bit_mask) {
   return android::BufferHubDefs::IsClientPosted(state, client_bit_mask);
 }
 
-static inline bool AnyClientAcquired(uint64_t state) {
+static inline bool AnyClientAcquired(uint32_t state) {
   return android::BufferHubDefs::AnyClientAcquired(state);
 }
 
-static inline bool IsClientAcquired(uint64_t state, uint64_t client_bit_mask) {
+static inline bool IsClientAcquired(uint32_t state, uint32_t client_bit_mask) {
   return android::BufferHubDefs::IsClientAcquired(state, client_bit_mask);
 }
 
-static inline bool IsBufferReleased(uint64_t state) {
+static inline bool IsBufferReleased(uint32_t state) {
   return android::BufferHubDefs::IsBufferReleased(state);
 }
 
-static inline bool IsClientReleased(uint64_t state, uint64_t client_bit_mask) {
+static inline bool IsClientReleased(uint32_t state, uint32_t client_bit_mask) {
   return android::BufferHubDefs::IsClientReleased(state, client_bit_mask);
 }
 
 // Returns the next available buffer client's client_state_masks.
 // @params union_bits. Union of all existing clients' client_state_masks.
-static inline uint64_t FindNextAvailableClientStateMask(uint64_t union_bits) {
+static inline uint32_t FindNextAvailableClientStateMask(uint32_t union_bits) {
   return android::BufferHubDefs::FindNextAvailableClientStateMask(union_bits);
 }
 
@@ -77,7 +77,7 @@
   BufferTraits() = default;
   BufferTraits(const native_handle_t* buffer_handle,
                const FileHandleType& metadata_handle, int id,
-               uint64_t client_state_mask, uint64_t metadata_size,
+               uint32_t client_state_mask, uint64_t metadata_size,
                uint32_t width, uint32_t height, uint32_t layer_count,
                uint32_t format, uint64_t usage, uint32_t stride,
                const FileHandleType& acquire_fence_fd,
@@ -107,7 +107,7 @@
   // same buffer channel has uniqued state bit among its siblings. For a
   // producer buffer the bit must be kFirstClientBitMask; for a consumer the bit
   // must be one of the kConsumerStateMask.
-  uint64_t client_state_mask() const { return client_state_mask_; }
+  uint32_t client_state_mask() const { return client_state_mask_; }
   uint64_t metadata_size() const { return metadata_size_; }
 
   uint32_t width() { return width_; }
@@ -131,7 +131,7 @@
  private:
   // BufferHub specific traits.
   int id_ = -1;
-  uint64_t client_state_mask_;
+  uint32_t client_state_mask_;
   uint64_t metadata_size_;
 
   // Traits for a GraphicBuffer.
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index 5ff4e00..f1cd0b4 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -99,7 +99,7 @@
  public:
   BufferDescription() = default;
   BufferDescription(const IonBuffer& buffer, const IonBuffer& metadata, int id,
-                    int buffer_cid, uint64_t client_state_mask,
+                    int buffer_cid, uint32_t client_state_mask,
                     const FileHandleType& acquire_fence_fd,
                     const FileHandleType& release_fence_fd)
       : id_(id),
@@ -123,7 +123,7 @@
 
   // State mask of the buffer client. Each BufferHub client backed by the
   // same buffer channel has uniqued state bit among its siblings.
-  uint64_t client_state_mask() const { return client_state_mask_; }
+  uint32_t client_state_mask() const { return client_state_mask_; }
   FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); }
   FileHandleType take_release_fence() { return std::move(release_fence_fd_); }
 
@@ -133,7 +133,7 @@
  private:
   int id_{-1};
   int buffer_cid_{-1};
-  uint64_t client_state_mask_{0};
+  uint32_t client_state_mask_{0U};
   // Two IonBuffers: one for the graphic buffer and one for metadata.
   NativeBufferHandle<FileHandleType> buffer_;
   NativeBufferHandle<FileHandleType> metadata_;
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index cd92b62..5274bf2 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -80,20 +80,20 @@
     return error;
 
   // The buffer can be posted iff the buffer state for this client is gained.
-  uint64_t current_buffer_state =
+  uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
   if (!BufferHubDefs::IsClientGained(current_buffer_state,
                                      client_state_mask())) {
-    ALOGE("%s: not gained, id=%d state=%" PRIx64 ".", __FUNCTION__, id(),
+    ALOGE("%s: not gained, id=%d state=%" PRIx32 ".", __FUNCTION__, id(),
           current_buffer_state);
     return -EBUSY;
   }
 
   // Set the producer client buffer state to released, other clients' buffer
   // state to posted.
-  uint64_t current_active_clients_bit_mask =
+  uint32_t current_active_clients_bit_mask =
       active_clients_bit_mask_->load(std::memory_order_acquire);
-  uint64_t updated_buffer_state = current_active_clients_bit_mask &
+  uint32_t updated_buffer_state = current_active_clients_bit_mask &
                                   (~client_state_mask()) &
                                   BufferHubDefs::kHighBitsMask;
   while (!buffer_state_->compare_exchange_weak(
@@ -101,16 +101,16 @@
       std::memory_order_acquire)) {
     ALOGD(
         "%s: Failed to post the buffer. Current buffer state was changed to "
-        "%" PRIx64
+        "%" PRIx32
         " when trying to post the buffer and modify the buffer state to "
-        "%" PRIx64
+        "%" PRIx32
         ". About to try again if the buffer is still gained by this client.",
         __FUNCTION__, current_buffer_state, updated_buffer_state);
     if (!BufferHubDefs::IsClientGained(current_buffer_state,
                                        client_state_mask())) {
       ALOGE(
           "%s: Failed to post the buffer. The buffer is no longer gained, "
-          "id=%d state=%" PRIx64 ".",
+          "id=%d state=%" PRIx32 ".",
           __FUNCTION__, id(), current_buffer_state);
       return -EBUSY;
     }
@@ -164,9 +164,9 @@
   if (!out_meta)
     return -EINVAL;
 
-  uint64_t current_buffer_state =
+  uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
-  ALOGD_IF(TRACE, "%s: buffer=%d, state=%" PRIx64 ".", __FUNCTION__, id(),
+  ALOGD_IF(TRACE, "%s: buffer=%d, state=%" PRIx32 ".", __FUNCTION__, id(),
            current_buffer_state);
 
   if (BufferHubDefs::IsClientGained(current_buffer_state,
@@ -178,20 +178,20 @@
       BufferHubDefs::AnyClientGained(current_buffer_state) ||
       (BufferHubDefs::AnyClientPosted(current_buffer_state) &&
        !gain_posted_buffer)) {
-    ALOGE("%s: not released id=%d state=%" PRIx64 ".", __FUNCTION__, id(),
+    ALOGE("%s: not released id=%d state=%" PRIx32 ".", __FUNCTION__, id(),
           current_buffer_state);
     return -EBUSY;
   }
   // Change the buffer state to gained state.
-  uint64_t updated_buffer_state = client_state_mask();
+  uint32_t updated_buffer_state = client_state_mask();
   while (!buffer_state_->compare_exchange_weak(
       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
       std::memory_order_acquire)) {
     ALOGD(
         "%s: Failed to gain the buffer. Current buffer state was changed to "
-        "%" PRIx64
+        "%" PRIx32
         " when trying to gain the buffer and modify the buffer state to "
-        "%" PRIx64
+        "%" PRIx32
         ". About to try again if the buffer is still not read by other "
         "clients.",
         __FUNCTION__, current_buffer_state, updated_buffer_state);
@@ -202,7 +202,7 @@
          !gain_posted_buffer)) {
       ALOGE(
           "%s: Failed to gain the buffer. The buffer is no longer released. "
-          "id=%d state=%" PRIx64 ".",
+          "id=%d state=%" PRIx32 ".",
           __FUNCTION__, id(), current_buffer_state);
       return -EBUSY;
     }
@@ -221,8 +221,8 @@
     out_meta->user_metadata_ptr = 0;
   }
 
-  uint64_t current_fence_state = fence_state_->load(std::memory_order_acquire);
-  uint64_t current_active_clients_bit_mask =
+  uint32_t current_fence_state = fence_state_->load(std::memory_order_acquire);
+  uint32_t current_active_clients_bit_mask =
       active_clients_bit_mask_->load(std::memory_order_acquire);
   // If there are release fence(s) from consumer(s), we need to return it to the
   // consumer(s).
@@ -289,11 +289,11 @@
 
   // TODO(b/112338294) Keep here for reference. Remove it after new logic is
   // written.
-  /* uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
+  /* uint32_t buffer_state = buffer_state_->load(std::memory_order_acquire);
   if (!BufferHubDefs::IsClientGained(
       buffer_state, BufferHubDefs::kFirstClientStateMask)) {
     // Can only detach a ProducerBuffer when it's in gained state.
-    ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx64
+    ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx32
           ") is not in gained state.",
           id(), buffer_state);
     return {};
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
index 6e303a5..2f14f7c 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
@@ -28,7 +28,7 @@
       return -EALREADY;
     }
 
-    fd_.reset(epoll_create(64));
+    fd_.reset(epoll_create1(EPOLL_CLOEXEC));
 
     if (fd_.get() < 0)
       return -errno;
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index a204f62..e383bb2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -466,11 +466,11 @@
 
   // Only applicable for metadata retrieved from GainAsync. This indicates which
   // consumer has pending fence that producer should epoll on.
-  uint64_t release_fence_mask;
+  uint32_t release_fence_mask;
 
   // Reserved bytes for so that the struct is forward compatible and padding to
   // 104 bytes so the size is a multiple of 8.
-  int32_t reserved[8];
+  int32_t reserved[9];
 };
 
 #ifdef __cplusplus
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 2d5f004..df06097 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -62,7 +62,7 @@
              buffer_removed_count_);
   }
 
-  DvrWriteBufferQueue* write_queue_{nullptr};
+  DvrWriteBufferQueue* write_queue_ = nullptr;
   int buffer_available_count_{0};
   int buffer_removed_count_{0};
 };
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
index 962c745..1cf5f17 100644
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
+++ b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
@@ -11,7 +11,7 @@
 namespace dvr {
 
 EpollEventDispatcher::EpollEventDispatcher() {
-  epoll_fd_.Reset(epoll_create(64));
+  epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
   if (!epoll_fd_) {
     ALOGE("Failed to create epoll fd: %s", strerror(errno));
     return;
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 50e30c2..f5cf3dc 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -554,33 +554,17 @@
     property_get("ro.product.manufacturer", manufacturer, "UNSET");
     property_get("ro.product.model", model, "UNSET");
 
-    // TODO: Replace this with the new function name once the version-1 API is removed:
-    fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
-            (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
+    fpANGLEGetFeatureSupportUtilAPIVersion ANGLEGetFeatureSupportUtilAPIVersion =
+            (fpANGLEGetFeatureSupportUtilAPIVersion)dlsym(so, "ANGLEGetFeatureSupportUtilAPIVersion");
 
-    if (ANGLEGetUtilityAPI) {
+    if (ANGLEGetFeatureSupportUtilAPIVersion) {
 
         // Negotiate the interface version by requesting most recent known to the platform
         unsigned int versionToUse = 2;
-        // TODO: Replace this with the new function name once the version-1 API is removed:
-        if ((ANGLEGetUtilityAPI)(&versionToUse)) {
+        if ((ANGLEGetFeatureSupportUtilAPIVersion)(&versionToUse)) {
 
             // Add and remove versions below as needed
             switch(versionToUse) {
-            case 1: {
-                ALOGV("Using version 1 of ANGLE feature-support library");
-                fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
-                        (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
-
-                if (AndroidUseANGLEForApplication) {
-                    use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
-                                                                rules_length, app_name_str.c_str(),
-                                                                manufacturer, model);
-                } else {
-                    ALOGW("Cannot find AndroidUseANGLEForApplication in ANGLE feature-support library");
-                }
-            }
-            break;
             case 2: {
                 ALOGV("Using version 2 of ANGLE feature-support library");
                 void* rules_handle = nullptr;
@@ -647,7 +631,7 @@
             ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, requested version %u", versionToUse);
         }
     } else {
-        ALOGW("Cannot find ANGLEGetUtilityAPI function");
+        ALOGW("Cannot find ANGLEGetFeatureSupportUtilAPIVersion function");
     }
 
     ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index 4bad829..cc87e15 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -14,10 +14,10 @@
     // Using placement new here to reuse shared memory instead of new allocation
     // Initialize the atomic variables to zero.
     BufferHubDefs::MetadataHeader* metadata_header = metadata_.metadata_header();
-    buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint64_t>(0);
-    fence_state_ = new (&metadata_header->fence_state) std::atomic<uint64_t>(0);
+    buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint32_t>(0);
+    fence_state_ = new (&metadata_header->fence_state) std::atomic<uint32_t>(0);
     active_clients_bit_mask_ =
-            new (&metadata_header->active_clients_bit_mask) std::atomic<uint64_t>(0);
+            new (&metadata_header->active_clients_bit_mask) std::atomic<uint32_t>(0);
 }
 
 // Allocates a new BufferNode.
@@ -74,22 +74,22 @@
     }
 }
 
-uint64_t BufferNode::GetActiveClientsBitMask() const {
+uint32_t BufferNode::GetActiveClientsBitMask() const {
     return active_clients_bit_mask_->load(std::memory_order_acquire);
 }
 
-uint64_t BufferNode::AddNewActiveClientsBitToMask() {
-    uint64_t current_active_clients_bit_mask = GetActiveClientsBitMask();
-    uint64_t client_state_mask = 0ULL;
-    uint64_t updated_active_clients_bit_mask = 0ULL;
+uint32_t BufferNode::AddNewActiveClientsBitToMask() {
+    uint32_t current_active_clients_bit_mask = GetActiveClientsBitMask();
+    uint32_t client_state_mask = 0U;
+    uint32_t updated_active_clients_bit_mask = 0U;
     do {
         client_state_mask =
                 BufferHubDefs::FindNextAvailableClientStateMask(current_active_clients_bit_mask);
-        if (client_state_mask == 0ULL) {
+        if (client_state_mask == 0U) {
             ALOGE("%s: reached the maximum number of channels per buffer node: %d.", __FUNCTION__,
                   BufferHubDefs::kMaxNumberOfClients);
             errno = E2BIG;
-            return 0ULL;
+            return 0U;
         }
         updated_active_clients_bit_mask = current_active_clients_bit_mask | client_state_mask;
     } while (!(active_clients_bit_mask_->compare_exchange_weak(current_active_clients_bit_mask,
@@ -99,7 +99,7 @@
     return client_state_mask;
 }
 
-void BufferNode::RemoveClientsBitFromMask(const uint64_t& value) {
+void BufferNode::RemoveClientsBitFromMask(const uint32_t& value) {
     active_clients_bit_mask_->fetch_and(~value);
 }
 
diff --git a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
index c5b2cde..b51fcda 100644
--- a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
+++ b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
@@ -32,7 +32,7 @@
 class BufferHubIdGenerator {
 public:
     // 0 is considered invalid
-    static constexpr uint32_t kInvalidId = 0UL;
+    static constexpr uint32_t kInvalidId = 0U;
 
     // Get the singleton instance of this class
     static BufferHubIdGenerator& getInstance();
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
index 02bb5af..cf56c33 100644
--- a/services/bufferhub/include/bufferhub/BufferNode.h
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -38,19 +38,19 @@
     // Gets the current value of active_clients_bit_mask in metadata_ with
     // std::memory_order_acquire, so that all previous releases of
     // active_clients_bit_mask from all threads will be returned here.
-    uint64_t GetActiveClientsBitMask() const;
+    uint32_t GetActiveClientsBitMask() const;
 
     // Find and add a new client_state_mask to active_clients_bit_mask in
     // metadata_.
     // Return the new client_state_mask that is added to active_clients_bit_mask.
-    // Return 0ULL if there are already 32 bp clients of the buffer.
-    uint64_t AddNewActiveClientsBitToMask();
+    // Return 0U if there are already 16 clients of the buffer.
+    uint32_t AddNewActiveClientsBitToMask();
 
     // Removes the value from active_clients_bit_mask in metadata_ with
     // std::memory_order_release, so that the change will be visible to any
     // acquire of active_clients_bit_mask_ in any threads after the succeed of
     // this operation.
-    void RemoveClientsBitFromMask(const uint64_t& value);
+    void RemoveClientsBitFromMask(const uint32_t& value);
 
 private:
     // Helper method for constructors to initialize atomic metadata header
@@ -75,14 +75,14 @@
 
     // buffer_state_ tracks the state of the buffer. Buffer can be in one of these
     // four states: gained, posted, acquired, released.
-    std::atomic<uint64_t>* buffer_state_ = nullptr;
+    std::atomic<uint32_t>* buffer_state_ = nullptr;
 
     // TODO(b/112012161): add comments to fence_state_.
-    std::atomic<uint64_t>* fence_state_ = nullptr;
+    std::atomic<uint32_t>* fence_state_ = nullptr;
 
     // active_clients_bit_mask_ tracks all the bp clients of the buffer. It is the
     // union of all client_state_mask of all bp clients.
-    std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
+    std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
 };
 
 } // namespace implementation
diff --git a/services/bufferhub/tests/Android.bp b/services/bufferhub/tests/Android.bp
index bf65469..e565374 100644
--- a/services/bufferhub/tests/Android.bp
+++ b/services/bufferhub/tests/Android.bp
@@ -1,8 +1,11 @@
 cc_test {
-    name: "BufferNode_test",
-    srcs: ["BufferNode_test.cpp"],
+    name: "BufferHubServer_test",
+    srcs: [
+        "BufferNode_test.cpp",
+        "BufferHubIdGenerator_test.cpp",
+    ],
     cflags: [
-        "-DLOG_TAG=\"BufferNode_test\"",
+        "-DLOG_TAG=\"BufferHubServer_test\"",
         "-DTRACE=0",
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     ],
@@ -18,19 +21,3 @@
         "libgmock",
     ],
 }
-
-cc_test {
-    name: "BufferHubIdGenerator_test",
-    srcs: ["BufferHubIdGenerator_test.cpp"],
-    cflags: [
-        "-DLOG_TAG=\"BufferHubIdGenerator_test\"",
-        "-DTRACE=0",
-        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
-    ],
-    shared_libs: [
-        "libbufferhubservice",
-    ],
-    static_libs: [
-        "libgmock",
-    ],
-}
\ No newline at end of file
diff --git a/services/bufferhub/tests/BufferNode_test.cpp b/services/bufferhub/tests/BufferNode_test.cpp
index 8555eb7..dbf10e8 100644
--- a/services/bufferhub/tests/BufferNode_test.cpp
+++ b/services/bufferhub/tests/BufferNode_test.cpp
@@ -56,21 +56,21 @@
 }
 
 TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
-    uint64_t new_client_state_mask_1 = buffer_node->AddNewActiveClientsBitToMask();
+    uint32_t new_client_state_mask_1 = buffer_node->AddNewActiveClientsBitToMask();
     EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), new_client_state_mask_1);
 
     // Request and add a new client_state_mask again.
     // Active clients bit mask should be the union of the two new
     // client_state_masks.
-    uint64_t new_client_state_mask_2 = buffer_node->AddNewActiveClientsBitToMask();
+    uint32_t new_client_state_mask_2 = buffer_node->AddNewActiveClientsBitToMask();
     EXPECT_EQ(buffer_node->GetActiveClientsBitMask(),
               new_client_state_mask_1 | new_client_state_mask_2);
 }
 
 TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_32NewClients) {
-    uint64_t new_client_state_mask = 0ULL;
-    uint64_t current_mask = 0ULL;
-    uint64_t expected_mask = 0ULL;
+    uint32_t new_client_state_mask = 0U;
+    uint32_t current_mask = 0U;
+    uint32_t expected_mask = 0U;
 
     for (int i = 0; i < BufferHubDefs::kMaxNumberOfClients; ++i) {
         new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
@@ -83,14 +83,14 @@
 
     // Method should fail upon requesting for more than maximum allowable clients.
     new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
-    EXPECT_EQ(new_client_state_mask, 0ULL);
+    EXPECT_EQ(new_client_state_mask, 0U);
     EXPECT_EQ(errno, E2BIG);
 }
 
 TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) {
     buffer_node->AddNewActiveClientsBitToMask();
-    uint64_t current_mask = buffer_node->GetActiveClientsBitMask();
-    uint64_t new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
+    uint32_t current_mask = buffer_node->GetActiveClientsBitMask();
+    uint32_t new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
     EXPECT_NE(buffer_node->GetActiveClientsBitMask(), current_mask);
 
     buffer_node->RemoveClientsBitFromMask(new_client_state_mask);
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 31057f6..a025f31 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -69,6 +69,8 @@
 
 namespace android {
 
+static constexpr bool DEBUG = false;
+
 static const char *WAKE_LOCK_ID = "KeyEvents";
 static const char *DEVICE_PATH = "/dev/input";
 
@@ -203,7 +205,7 @@
         mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
-    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
     LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
 
     mINotifyFd = inotify_init();
@@ -1063,26 +1065,45 @@
         AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE,
 };
 
-status_t EventHub::registerDeviceForEpollLocked(Device* device) {
-    struct epoll_event eventItem;
-    memset(&eventItem, 0, sizeof(eventItem));
-    eventItem.events = EPOLLIN;
-    if (mUsingEpollWakeup) {
-        eventItem.events |= EPOLLWAKEUP;
-    }
-    eventItem.data.fd = device->fd;
-    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) {
-        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
+status_t EventHub::registerFdForEpoll(int fd) {
+    struct epoll_event eventItem = {};
+    eventItem.events = EPOLLIN | EPOLLWAKEUP;
+    eventItem.data.fd = fd;
+    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
+        ALOGE("Could not add fd to epoll instance: %s", strerror(errno));
         return -errno;
     }
     return OK;
 }
 
+status_t EventHub::unregisterFdFromEpoll(int fd) {
+    if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, nullptr)) {
+        ALOGW("Could not remove fd from epoll instance: %s", strerror(errno));
+        return -errno;
+    }
+    return OK;
+}
+
+status_t EventHub::registerDeviceForEpollLocked(Device* device) {
+    if (device == nullptr) {
+        if (DEBUG) {
+            LOG_ALWAYS_FATAL("Cannot call registerDeviceForEpollLocked with null Device");
+        }
+        return BAD_VALUE;
+    }
+    status_t result = registerFdForEpoll(device->fd);
+    if (result != OK) {
+        ALOGE("Could not add input device fd to epoll for device %" PRId32, device->id);
+    }
+    return result;
+}
+
 status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) {
     if (device->hasValidFd()) {
-        if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, nullptr)) {
-            ALOGW("Could not remove device fd from epoll instance.  errno=%d", errno);
-            return -errno;
+        status_t result = unregisterFdFromEpoll(device->fd);
+        if (result != OK) {
+            ALOGW("Could not remove input device fd from epoll for device %" PRId32, device->id);
+            return result;
         }
     }
     return OK;
@@ -1103,7 +1124,7 @@
 
     // Get device name.
     if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
-        //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
+        ALOGE("Could not get device name for %s: %s", devicePath, strerror(errno));
     } else {
         buffer[sizeof(buffer) - 1] = '\0';
         identifier.name = buffer;
@@ -1669,7 +1690,6 @@
 
     while(res >= (int)sizeof(*event)) {
         event = (struct inotify_event *)(event_buf + event_pos);
-        //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
         if(event->len) {
             strcpy(filename, event->name);
             if(event->mask & IN_CREATE) {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 7e00f42..5d0b894 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2642,7 +2642,6 @@
                 mOrientation = internalViewport->orientation;
             }
         }
-        getPolicy()->updatePointerDisplay();
         bumpGeneration();
     }
 }
@@ -2788,7 +2787,7 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
-        displayId = mPointerController->getDisplayId();
+        displayId = ADISPLAY_ID_DEFAULT;
     } else {
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
@@ -3609,9 +3608,6 @@
             (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
         if (mPointerController == nullptr) {
             mPointerController = getPolicy()->obtainPointerController(getDeviceId());
-            getPolicy()->updatePointerDisplay();
-        } else if (viewportChanged) {
-            getPolicy()->updatePointerDisplay();
         }
     } else {
         mPointerController.clear();
@@ -5399,9 +5395,9 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
 
-        int32_t displayId = mPointerController->getDisplayId();
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, displayId, mSource,
-                mViewport.displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
+                mSource, mViewport.displayId, policyFlags,
+                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
                 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, mPointerGesture.downTime);
@@ -6307,7 +6303,6 @@
 void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
         bool down, bool hovering) {
     int32_t metaState = getContext()->getGlobalMetaState();
-    int32_t displayId = mViewport.displayId;
 
     if (mPointerController != nullptr) {
         if (down || hovering) {
@@ -6318,20 +6313,19 @@
         } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
             mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
         }
-        displayId = mPointerController->getDisplayId();
     }
 
     if (mPointerSimple.down && !down) {
         mPointerSimple.down = false;
 
         // Send up.
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
-                 AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
-                 /* deviceTimestamp */ 0,
-                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
-                 mOrientedXPrecision, mOrientedYPrecision,
-                 mPointerSimple.downTime);
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), 
+                mSource, mViewport.displayId, policyFlags,
+                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
+                /* deviceTimestamp */ 0,
+                1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
+                mOrientedXPrecision, mOrientedYPrecision,
+                mPointerSimple.downTime);
         getListener()->notifyMotion(&args);
     }
 
@@ -6339,8 +6333,8 @@
         mPointerSimple.hovering = false;
 
         // Send hover exit.
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), 
+                mSource, mViewport.displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
                 /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
@@ -6355,8 +6349,8 @@
             mPointerSimple.downTime = when;
 
             // Send down.
-            NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                    mSource, displayId, policyFlags,
+            NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), 
+                    mSource, mViewport.displayId, policyFlags,
                     AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
                     /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
@@ -6366,8 +6360,8 @@
         }
 
         // Send move.
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), 
+                mSource, mViewport.displayId, policyFlags,
                 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
                 /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
@@ -6381,8 +6375,8 @@
             mPointerSimple.hovering = true;
 
             // Send hover enter.
-            NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                    mSource, displayId, policyFlags,
+            NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), 
+                    mSource, mViewport.displayId, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
                     mCurrentRawState.buttonState, 0,
                     /* deviceTimestamp */ 0,
@@ -6393,8 +6387,8 @@
         }
 
         // Send hover move.
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), 
+                mSource, mViewport.displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
                 mCurrentRawState.buttonState, 0,
                 /* deviceTimestamp */ 0,
@@ -6416,8 +6410,8 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), 
+                mSource, mViewport.displayId, policyFlags,
                 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
                 /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &pointerCoords,
@@ -6479,10 +6473,9 @@
             ALOG_ASSERT(false);
         }
     }
-    int32_t displayId = mPointerController != nullptr ?
-            mPointerController->getDisplayId() : mViewport.displayId;
-    NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-            source, displayId, policyFlags,
+
+    NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), 
+            source, mViewport.displayId, policyFlags,
             action, actionButton, flags, metaState, buttonState, edgeFlags,
             deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
             xPrecision, yPrecision, downTime);
diff --git a/services/inputflinger/include/EventHub.h b/services/inputflinger/include/EventHub.h
index e2c7e82..5db7c0a 100644
--- a/services/inputflinger/include/EventHub.h
+++ b/services/inputflinger/include/EventHub.h
@@ -391,6 +391,8 @@
     bool isDeviceEnabled(int32_t deviceId);
     status_t enableDevice(int32_t deviceId);
     status_t disableDevice(int32_t deviceId);
+    status_t registerFdForEpoll(int fd);
+    status_t unregisterFdFromEpoll(int fd);
     status_t registerDeviceForEpollLocked(Device* device);
     status_t unregisterDeviceFromEpollLocked(Device* device);
 
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 5a78df7..fe1c50b 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -342,9 +342,6 @@
     /* Gets the affine calibration associated with the specified device. */
     virtual TouchAffineTransformation getTouchAffineTransformation(
             const std::string& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
-
-    /* Update the pointer controller associated with the specified display. */
-    virtual void updatePointerDisplay() = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index e60b3f4..e94dd94 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -58,9 +58,6 @@
     /* Gets the absolute location of the pointer. */
     virtual void getPosition(float* outX, float* outY) const = 0;
 
-    /* Gets the id of the display where the pointer should be shown. */
-    virtual int32_t getDisplayId() const = 0;
-
     enum Transition {
         // Fade/unfade immediately.
         TRANSITION_IMMEDIATE,
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 855247f..167a624 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -57,7 +57,6 @@
     float mMinX, mMinY, mMaxX, mMaxY;
     float mX, mY;
     int32_t mButtonState;
-    int32_t mDisplayId;
 
 protected:
     virtual ~FakePointerController() { }
@@ -65,7 +64,7 @@
 public:
     FakePointerController() :
         mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0),
-        mButtonState(0), mDisplayId(ADISPLAY_ID_DEFAULT) {
+        mButtonState(0) {
     }
 
     void setBounds(float minX, float minY, float maxX, float maxY) {
@@ -76,10 +75,6 @@
         mMaxY = maxY;
     }
 
-    void setDisplayId(int32_t displayId) {
-        mDisplayId = displayId;
-    }
-
     virtual void setPosition(float x, float y) {
         mX = x;
         mY = y;
@@ -98,10 +93,6 @@
         *outY = mY;
     }
 
-    virtual int32_t getDisplayId() const {
-        return mDisplayId;
-    }
-
 private:
     virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const {
         *outMinX = mMinX;
@@ -271,9 +262,6 @@
     virtual std::string getDeviceAlias(const InputDeviceIdentifier&) {
         return "";
     }
-
-    virtual void updatePointerDisplay() {
-    }
 };
 
 
@@ -3177,30 +3165,6 @@
     ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
 }
 
-TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
-    CursorInputMapper* mapper = new CursorInputMapper(mDevice);
-    addMapperAndConfigure(mapper);
-
-    // Setup PointerController for second display.
-    constexpr int32_t SECOND_DISPLAY_ID = 1;
-    mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
-    mFakePointerController->setPosition(100, 200);
-    mFakePointerController->setButtonState(0);
-    mFakePointerController->setDisplayId(SECOND_DISPLAY_ID);
-
-    NotifyMotionArgs args;
-    process(mapper, ARBITRARY_TIME, EV_REL, REL_X, 10);
-    process(mapper, ARBITRARY_TIME, EV_REL, REL_Y, 20);
-    process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
-    ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
-}
-
 
 // --- TouchInputMapperTest ---
 
@@ -4699,6 +4663,7 @@
             toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
 }
 
+
 // --- MultiTouchInputMapperTest ---
 
 class MultiTouchInputMapperTest : public TouchInputMapperTest {
@@ -6319,30 +6284,4 @@
     ASSERT_EQ(DISPLAY_ID, args.displayId);
 }
 
-TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
-    // Setup PointerController for second display.
-    sp<FakePointerController> fakePointerController = new FakePointerController();
-    fakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
-    fakePointerController->setPosition(100, 200);
-    fakePointerController->setButtonState(0);
-    fakePointerController->setDisplayId(SECONDARY_DISPLAY_ID);
-    mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
-
-    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-    prepareDisplay(DISPLAY_ORIENTATION_0);
-    prepareAxes(POSITION);
-    addMapperAndConfigure(mapper);
-
-    // Check source is mouse that would obtain the PointerController.
-    ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources());
-
-    NotifyMotionArgs motionArgs;
-    processPosition(mapper, 100, 100);
-    processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
-    ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
-}
-
 } // namespace android
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index f87fcdc..33a2747 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -41,6 +41,7 @@
         "liblog",
         "libbinder",
         "libsensor",
+        "libsensorprivacy",
         "libcrypto",
         "libbase",
         "libhidlbase",
@@ -53,8 +54,8 @@
 
     static_libs: ["android.hardware.sensors@1.0-convert"],
 
-    // our public headers depend on libsensor
-    export_shared_lib_headers: ["libsensor"],
+    // our public headers depend on libsensor and libsensorprivacy
+    export_shared_lib_headers: ["libsensor", "libsensorprivacy"],
 }
 
 cc_binary {
@@ -64,6 +65,7 @@
 
     shared_libs: [
         "libsensorservice",
+        "libsensorprivacy",
         "libbinder",
         "libutils",
     ],
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 776efab..b66cbcf 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -279,7 +279,7 @@
                     }
                 } else {
                     // Regular sensor event, just copy it to the scratch buffer.
-                    if (mHasSensorAccess) {
+                    if (hasSensorAccess()) {
                         scratch[count++] = buffer[i];
                     }
                 }
@@ -290,7 +290,7 @@
                                         buffer[i].meta_data.sensor == sensor_handle)));
         }
     } else {
-        if (mHasSensorAccess) {
+        if (hasSensorAccess()) {
             scratch = const_cast<sensors_event_t *>(buffer);
             count = numEvents;
         } else {
@@ -321,7 +321,7 @@
     }
 
     int index_wake_up_event = -1;
-    if (mHasSensorAccess) {
+    if (hasSensorAccess()) {
         index_wake_up_event = findWakeUpSensorEventLocked(scratch, count);
         if (index_wake_up_event >= 0) {
             scratch[index_wake_up_event].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
@@ -375,6 +375,10 @@
     mHasSensorAccess = hasAccess;
 }
 
+bool SensorService::SensorEventConnection::hasSensorAccess() {
+    return mHasSensorAccess && !mService->mSensorPrivacyPolicy->isSensorPrivacyEnabled();
+}
+
 void SensorService::SensorEventConnection::reAllocateCacheLocked(sensors_event_t const* scratch,
                                                                  int count) {
     sensors_event_t *eventCache_new;
@@ -491,7 +495,7 @@
     for (int numEventsSent = 0; numEventsSent < mCacheSize;) {
         const int numEventsToWrite = helpers::min(mCacheSize - numEventsSent, maxWriteSize);
         int index_wake_up_event = -1;
-        if (mHasSensorAccess) {
+        if (hasSensorAccess()) {
             index_wake_up_event =
                       findWakeUpSensorEventLocked(mEventCache + numEventsSent, numEventsToWrite);
             if (index_wake_up_event >= 0) {
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 061809f..7077880 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -130,6 +130,10 @@
     void updateLooperRegistration(const sp<Looper>& looper); void
             updateLooperRegistrationLocked(const sp<Looper>& looper);
 
+    // Returns whether sensor access is available based on both the uid being active and sensor
+    // privacy not being enabled.
+    bool hasSensorAccess();
+
     sp<SensorService> const mService;
     sp<BitTube> mChannel;
     uid_t mUid;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 85450f8..9a37ff1 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -29,6 +29,7 @@
 #include <openssl/hmac.h>
 #include <openssl/rand.h>
 #include <sensor/SensorEventQueue.h>
+#include <sensorprivacy/SensorPrivacyManager.h>
 #include <utils/SystemClock.h>
 
 #include "BatteryService.h"
@@ -88,6 +89,7 @@
     : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
       mWakeLockAcquired(false) {
     mUidPolicy = new UidPolicy(this);
+    mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
 }
 
 bool SensorService::initializeHmacKey() {
@@ -286,6 +288,9 @@
 
             // Start watching UID changes to apply policy.
             mUidPolicy->registerSelf();
+
+            // Start watching sensor privacy changes
+            mSensorPrivacyPolicy->registerSelf();
         }
     }
 }
@@ -338,6 +343,7 @@
         delete entry.second;
     }
     mUidPolicy->unregisterSelf();
+    mSensorPrivacyPolicy->unregisterSelf();
 }
 
 status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -364,35 +370,16 @@
             }
 
             mCurrentOperatingMode = RESTRICTED;
-            // temporarily stop all sensor direct report
-            for (auto &i : mDirectConnections) {
-                sp<SensorDirectConnection> connection(i.promote());
-                if (connection != nullptr) {
-                    connection->stopAll(true /* backupRecord */);
-                }
-            }
-
-            dev.disableAllSensors();
-            // Clear all pending flush connections for all active sensors. If one of the active
-            // connections has called flush() and the underlying sensor has been disabled before a
-            // flush complete event is returned, we need to remove the connection from this queue.
-            for (size_t i=0 ; i< mActiveSensors.size(); ++i) {
-                mActiveSensors.valueAt(i)->clearAllPendingFlushConnections();
-            }
+            // temporarily stop all sensor direct report and disable sensors
+            disableAllSensorsLocked();
             mWhiteListedPackage.setTo(String8(args[1]));
             return status_t(NO_ERROR);
         } else if (args.size() == 1 && args[0] == String16("enable")) {
             // If currently in restricted mode, reset back to NORMAL mode else ignore.
             if (mCurrentOperatingMode == RESTRICTED) {
                 mCurrentOperatingMode = NORMAL;
-                dev.enableAllSensors();
-                // recover all sensor direct report
-                for (auto &i : mDirectConnections) {
-                    sp<SensorDirectConnection> connection(i.promote());
-                    if (connection != nullptr) {
-                        connection->recoverAll();
-                    }
-                }
+                // enable sensors and recover all sensor direct report
+                enableAllSensorsLocked();
             }
             if (mCurrentOperatingMode == DATA_INJECTION) {
                resetToNormalModeLocked();
@@ -477,6 +464,8 @@
                case DATA_INJECTION:
                    result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string());
             }
+            result.appendFormat("Sensor Privacy: %s\n",
+                    mSensorPrivacyPolicy->isSensorPrivacyEnabled() ? "enabled" : "disabled");
 
             result.appendFormat("%zd active connections\n", mActiveConnections.size());
             for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
@@ -519,6 +508,52 @@
     return NO_ERROR;
 }
 
+void SensorService::disableAllSensors() {
+    Mutex::Autolock _l(mLock);
+    disableAllSensorsLocked();
+}
+
+void SensorService::disableAllSensorsLocked() {
+    SensorDevice& dev(SensorDevice::getInstance());
+    for (auto &i : mDirectConnections) {
+        sp<SensorDirectConnection> connection(i.promote());
+        if (connection != nullptr) {
+            connection->stopAll(true /* backupRecord */);
+        }
+    }
+    dev.disableAllSensors();
+    // Clear all pending flush connections for all active sensors. If one of the active
+    // connections has called flush() and the underlying sensor has been disabled before a
+    // flush complete event is returned, we need to remove the connection from this queue.
+    for (size_t i=0 ; i< mActiveSensors.size(); ++i) {
+        mActiveSensors.valueAt(i)->clearAllPendingFlushConnections();
+    }
+}
+
+void SensorService::enableAllSensors() {
+    Mutex::Autolock _l(mLock);
+    enableAllSensorsLocked();
+}
+
+void SensorService::enableAllSensorsLocked() {
+    // sensors should only be enabled if the operating state is not restricted and sensor
+    // privacy is not enabled.
+    if (mCurrentOperatingMode == RESTRICTED || mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
+        ALOGW("Sensors cannot be enabled: mCurrentOperatingMode = %d, sensor privacy = %s",
+              mCurrentOperatingMode,
+              mSensorPrivacyPolicy->isSensorPrivacyEnabled() ? "enabled" : "disabled");
+        return;
+    }
+    SensorDevice& dev(SensorDevice::getInstance());
+    dev.enableAllSensors();
+    for (auto &i : mDirectConnections) {
+        sp<SensorDirectConnection> connection(i.promote());
+        if (connection != nullptr) {
+            connection->recoverAll();
+        }
+    }
+}
+
 // NOTE: This is a remote API - make sure all args are validated
 status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) {
     if (!checkCallingPermission(sManageSensorsPermission, nullptr, nullptr)) {
@@ -1076,6 +1111,12 @@
         const native_handle *resource) {
     Mutex::Autolock _l(mLock);
 
+    // No new direct connections are allowed when sensor privacy is enabled
+    if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
+        ALOGE("Cannot create new direct connections when sensor privacy is enabled");
+        return nullptr;
+    }
+
     struct sensors_direct_mem_t mem = {
         .type = type,
         .format = format,
@@ -1753,4 +1794,31 @@
     return mActiveUids.find(uid) != mActiveUids.end();
 }
 
+void SensorService::SensorPrivacyPolicy::registerSelf() {
+    SensorPrivacyManager spm;
+    mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
+    spm.addSensorPrivacyListener(this);
+}
+
+void SensorService::SensorPrivacyPolicy::unregisterSelf() {
+    SensorPrivacyManager spm;
+    spm.removeSensorPrivacyListener(this);
+}
+
+bool SensorService::SensorPrivacyPolicy::isSensorPrivacyEnabled() {
+    return mSensorPrivacyEnabled;
+}
+
+binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool enabled) {
+    mSensorPrivacyEnabled = enabled;
+    sp<SensorService> service = mService.promote();
+    if (service != nullptr) {
+        if (enabled) {
+            service->disableAllSensors();
+        } else {
+            service->enableAllSensors();
+        }
+    }
+    return binder::Status::ok();
+}
 }; // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 24b0dd7..136ee27 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -26,6 +26,7 @@
 #include <sensor/ISensorServer.h>
 #include <sensor/ISensorEventConnection.h>
 #include <sensor/Sensor.h>
+#include "android/hardware/BnSensorPrivacyListener.h"
 
 #include <utils/AndroidThreads.h>
 #include <utils/KeyedVector.h>
@@ -132,6 +133,30 @@
             std::unordered_map<uid_t, bool> mOverrideUids;
     };
 
+    // Sensor privacy allows a user to disable access to all sensors on the device. When
+    // enabled sensor privacy will prevent all apps, including active apps, from accessing
+    // sensors, they will not receive trigger nor on-change events, flush event behavior
+    // does not change, and recurring events are the same as the first one delivered when
+    // sensor privacy was enabled. All sensor direct connections will be stopped as well
+    // and new direct connections will not be allowed while sensor privacy is enabled.
+    // Once sensor privacy is disabled access to sensors will be restored for active
+    // apps, previously stopped direct connections will be restarted, and new direct
+    // connections will be allowed again.
+    class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener {
+        public:
+            explicit SensorPrivacyPolicy(wp<SensorService> service) : mService(service) {}
+            void registerSelf();
+            void unregisterSelf();
+
+            bool isSensorPrivacyEnabled();
+
+            binder::Status onSensorPrivacyChanged(bool enabled);
+
+        private:
+            wp<SensorService> mService;
+            std::atomic_bool mSensorPrivacyEnabled;
+    };
+
     enum Mode {
        // The regular operating mode where any application can register/unregister/call flush on
        // sensors.
@@ -275,6 +300,13 @@
     // Prints the shell command help
     status_t printHelp(int out);
 
+    // temporarily stops all active direct connections and disables all sensors
+    void disableAllSensors();
+    void disableAllSensorsLocked();
+    // restarts the previously stopped direct connections and enables all sensors
+    void enableAllSensors();
+    void enableAllSensorsLocked();
+
     static uint8_t sHmacGlobalKey[128];
     static bool sHmacGlobalKeyIsValid;
 
@@ -309,6 +341,7 @@
     Vector<SensorRegistrationInfo> mLastNSensorRegistrations;
 
     sp<UidPolicy> mUidPolicy;
+    sp<SensorPrivacyPolicy> mSensorPrivacyPolicy;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 22e4d1e..0106b25 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -139,6 +139,7 @@
         "Scheduler/DispSyncSource.cpp",
         "Scheduler/EventControlThread.cpp",
         "Scheduler/EventThread.cpp",
+        "Scheduler/IdleTimer.cpp",
         "Scheduler/LayerHistory.cpp",
         "Scheduler/MessageQueue.cpp",
         "Scheduler/Scheduler.cpp",
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 55d68f6..98ae286 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -71,6 +71,10 @@
     // isVisible - true if this layer is visible, false otherwise
     bool isVisible() const override EXCLUDES(mStateMutex);
 
+    // isProtected - true if the layer may contain protected content in the
+    // GRALLOC_USAGE_PROTECTED sense.
+    bool isProtected() const override;
+
     // isFixedSize - true if content has a fixed size
     bool isFixedSize() const override;
 
@@ -155,13 +159,6 @@
 
     virtual void setHwcLayerBuffer(DisplayId displayId) EXCLUDES(mStateMutex) = 0;
 
-    // -----------------------------------------------------------------------
-
-public:
-    // isProtected - true if the layer may contain protected content in the
-    // GRALLOC_USAGE_PROTECTED sense.
-    bool isProtected() const;
-
 protected:
     // Loads the corresponding system property once per process
     static bool latchUnsignaledBuffers();
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 3ad07ae..2003fb1 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -366,6 +366,15 @@
     return mDisplaySurface->prepareFrame(compositionType);
 }
 
+void DisplayDevice::setProtected(bool useProtected) {
+    uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
+    if (useProtected) {
+        usageFlags |= GRALLOC_USAGE_PROTECTED;
+    }
+    const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
+    ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
+}
+
 sp<GraphicBuffer> DisplayDevice::dequeueBuffer() {
     int fd;
     ANativeWindowBuffer* buffer;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index ba85432..2c2a3ab 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -146,6 +146,7 @@
                           ui::Dataspace* outDataspace, ui::ColorMode* outMode,
                           ui::RenderIntent* outIntent) const;
 
+    void setProtected(bool useProtected);
     // Queues the drawn buffer for consumption by HWC.
     void queueBuffer(HWComposer& hwc);
     // Allocates a buffer as scratch space for GPU composition
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 57ef65a..fb75e4c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -399,6 +399,12 @@
     bool isHiddenByPolicy() const EXCLUDES(mStateMutex);
 
     /*
+     * isProtected - true if the layer may contain protected content in the
+     * GRALLOC_USAGE_PROTECTED sense.
+     */
+    virtual bool isProtected() const { return false; }
+
+    /*
      * isFixedSize - true if content has a fixed size
      */
     virtual bool isFixedSize() const { return true; }
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 49e7ef6..1f08f4e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -48,10 +48,14 @@
 namespace impl {
 
 EventThread::EventThread(std::unique_ptr<VSyncSource> src,
-                         ResyncWithRateLimitCallback resyncWithRateLimitCallback,
-                         InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
+                         const ResyncWithRateLimitCallback& resyncWithRateLimitCallback,
+                         const InterceptVSyncsCallback& interceptVSyncsCallback,
+                         const ResetIdleTimerCallback& resetIdleTimerCallback,
+                         const char* threadName)
       : EventThread(nullptr, std::move(src), resyncWithRateLimitCallback, interceptVSyncsCallback,
-                    threadName) {}
+                    threadName) {
+    mResetIdleTimer = resetIdleTimerCallback;
+}
 
 EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
                          InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
@@ -150,6 +154,9 @@
 
 void EventThread::requestNextVsync(const sp<EventThread::Connection>& connection) {
     std::lock_guard<std::mutex> lock(mMutex);
+    if (mResetIdleTimer) {
+        mResetIdleTimer();
+    }
 
     if (mResyncWithRateLimitCallback) {
         mResyncWithRateLimitCallback();
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 15b5bba..0773c05 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -107,13 +107,15 @@
 public:
     using ResyncWithRateLimitCallback = std::function<void()>;
     using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
+    using ResetIdleTimerCallback = std::function<void()>;
 
     // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
     EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
                 InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
     EventThread(std::unique_ptr<VSyncSource> src,
-                ResyncWithRateLimitCallback resyncWithRateLimitCallback,
-                InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+                const ResyncWithRateLimitCallback& resyncWithRateLimitCallback,
+                const InterceptVSyncsCallback& interceptVSyncsCallback,
+                const ResetIdleTimerCallback& resetIdleTimerCallback, const char* threadName);
     ~EventThread();
 
     sp<BnDisplayEventConnection> createEventConnection() const override;
@@ -177,6 +179,9 @@
 
     // for debugging
     bool mDebugVsyncEnabled GUARDED_BY(mMutex) = false;
+
+    // Callback that resets the idle timer when the next vsync is received.
+    ResetIdleTimerCallback mResetIdleTimer;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/IdleTimer.cpp
new file mode 100644
index 0000000..5a76dbc
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/IdleTimer.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "IdleTimer.h"
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace scheduler {
+
+IdleTimer::IdleTimer(const Interval& interval, const TimeoutCallback& timeoutCallback)
+      : mInterval(interval), mTimeoutCallback(timeoutCallback) {}
+
+IdleTimer::~IdleTimer() {
+    stop();
+}
+
+void IdleTimer::start() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mState = TimerState::RESET;
+    }
+    mThread = std::thread(&IdleTimer::loop, this);
+}
+
+void IdleTimer::stop() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mState = TimerState::STOPPED;
+    }
+    mCondition.notify_all();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void IdleTimer::loop() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    while (mState != TimerState::STOPPED) {
+        if (mState == TimerState::IDLE) {
+            mCondition.wait(mMutex);
+        } else if (mState == TimerState::RESET) {
+            mState = TimerState::WAITING;
+            if (mCondition.wait_for(mMutex, mInterval) == std::cv_status::timeout) {
+                if (mTimeoutCallback) {
+                    mTimeoutCallback();
+                }
+            }
+            if (mState == TimerState::WAITING) {
+                mState = TimerState::IDLE;
+            }
+        }
+    }
+}
+
+void IdleTimer::reset() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mState = TimerState::RESET;
+    }
+    mCondition.notify_all();
+}
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.h b/services/surfaceflinger/Scheduler/IdleTimer.h
new file mode 100644
index 0000000..aee3fa3
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/IdleTimer.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <condition_variable>
+#include <thread>
+
+#include <android-base/thread_annotations.h>
+
+namespace android {
+namespace scheduler {
+
+/*
+ * Class that sets off a timer for a given interval, and fires a callback when the
+ * interval expires.
+ */
+class IdleTimer {
+public:
+    using Interval = std::chrono::milliseconds;
+    using TimeoutCallback = std::function<void()>;
+
+    IdleTimer(const Interval& interval, const TimeoutCallback& timeoutCallback);
+    ~IdleTimer();
+
+    void start();
+    void stop();
+    void reset();
+
+private:
+    // Enum to track in what state is the timer.
+    enum class TimerState { STOPPED = 0, RESET = 1, WAITING = 2, IDLE = 3 };
+
+    // Function that loops until the condition for stopping is met.
+    void loop();
+
+    // Thread waiting for timer to expire.
+    std::thread mThread;
+
+    // Condition used to notify mThread.
+    std::condition_variable_any mCondition;
+
+    // Lock used for synchronizing the waiting thread with the application thread.
+    std::mutex mMutex;
+
+    TimerState mState GUARDED_BY(mMutex) = TimerState::RESET;
+
+    // Interval after which timer expires.
+    const Interval mInterval;
+
+    // Callback that happens when timer expires.
+    const TimeoutCallback mTimeoutCallback;
+};
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5b8cc10..fad56e6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -29,6 +29,7 @@
 #include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
 
+#include <cutils/properties.h>
 #include <gui/ISurfaceComposer.h>
 #include <ui/DisplayStatInfo.h>
 #include <utils/Timers.h>
@@ -38,6 +39,7 @@
 #include "DispSyncSource.h"
 #include "EventControlThread.h"
 #include "EventThread.h"
+#include "IdleTimer.h"
 #include "InjectVSyncSource.h"
 #include "SchedulerUtils.h"
 
@@ -68,6 +70,17 @@
     primaryDispSync->init(mHasSyncFramework, mDispSyncPresentTimeOffset);
     mPrimaryDispSync = std::move(primaryDispSync);
     mEventControlThread = std::make_unique<impl::EventControlThread>(function);
+
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.sf.set_idle_timer_ms", value, "0");
+    mSetIdleTimerMs = atoi(value);
+
+    if (mSetIdleTimerMs > 0) {
+        mIdleTimer =
+                std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetIdleTimerMs),
+                                                       [this] { expiredTimerCallback(); });
+        mIdleTimer->start();
+    }
 }
 
 Scheduler::~Scheduler() = default;
@@ -98,7 +111,8 @@
             std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, sourceName.c_str());
     const std::string threadName = connectionName + "Thread";
     return std::make_unique<impl::EventThread>(std::move(eventThreadSource), resyncCallback,
-                                               interceptCallback, threadName.c_str());
+                                               interceptCallback, [this] { resetIdleTimer(); },
+                                               threadName.c_str());
 }
 
 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
@@ -309,4 +323,18 @@
     }
 }
 
+void Scheduler::resetIdleTimer() {
+    if (mIdleTimer) {
+        mIdleTimer->reset();
+        ATRACE_INT("ExpiredIdleTimer", 0);
+    }
+}
+
+void Scheduler::expiredTimerCallback() {
+    // TODO(b/113612090): Each time a timer expired, we should record the information into
+    // a circular buffer. Once this has happened a given amount (TBD) of times, we can comfortably
+    // say that the device is sitting in idle.
+    ATRACE_INT("ExpiredIdleTimer", 1);
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index ea90824..8d4514b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -25,6 +25,7 @@
 #include "DispSync.h"
 #include "EventControlThread.h"
 #include "EventThread.h"
+#include "IdleTimer.h"
 #include "InjectVSyncSource.h"
 #include "LayerHistory.h"
 #include "SchedulerUtils.h"
@@ -126,6 +127,10 @@
     // Collects the average difference between timestamps for each frame regardless
     // of which layer the timestamp came from.
     void determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime);
+    // Function that resets the idle timer.
+    void resetIdleTimer();
+    // Function that is called when the timer expires.
+    void expiredTimerCallback();
 
     // TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
     // should make request to Scheduler to compute next refresh.
@@ -163,6 +168,11 @@
     size_t mCounter = 0;
 
     LayerHistory mLayerHistory;
+
+    // Timer that records time between requests for next vsync. If the time is higher than a given
+    // interval, a callback is fired. Set this variable to >0 to use this feature.
+    int64_t mSetIdleTimerMs = 0;
+    std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6344f40..20e7f70 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5439,10 +5439,11 @@
         ALOGW("FB is protected: PERMISSION_DENIED");
         return PERMISSION_DENIED;
     }
+    auto& engine(getRenderEngine());
 
     // this binds the given EGLImage as a framebuffer for the
     // duration of this scope.
-    renderengine::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
+    renderengine::BindNativeBufferAsFramebuffer bufferBond(engine, buffer);
     if (bufferBond.getStatus() != NO_ERROR) {
         ALOGE("got ANWB binding error while taking screenshot");
         return INVALID_OPERATION;
@@ -5454,9 +5455,9 @@
     // dependent on the context's EGLConfig.
     renderScreenImplLocked(renderArea, traverseLayers, useIdentityTransform);
 
-    base::unique_fd syncFd = getRenderEngine().flush();
+    base::unique_fd syncFd = engine.flush();
     if (syncFd < 0) {
-        getRenderEngine().finish();
+        engine.finish();
     }
     *outSyncFd = syncFd.release();
 
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 1a13f77..2f35ae5 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -30,6 +30,7 @@
         "DisplayTransactionTest.cpp",
         "EventControlThreadTest.cpp",
         "EventThreadTest.cpp",
+        "IdleTimerTest.cpp",
         "LayerHistoryTest.cpp",
         "SchedulerTest.cpp",
         "SchedulerUtilsTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 5a6aa92..b7c09ed 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -286,8 +286,10 @@
     static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
         // Called once with a non-null value to set a framebuffer, and then
         // again with nullptr to clear it.
-        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true));
-        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true));
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull(), false))
+                .WillOnce(Return(true));
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull(), false))
+                .WillOnce(Return(true));
 
         EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
         EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
@@ -344,8 +346,10 @@
                                              Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                                              ui::Transform::ROT_0))
                 .Times(1);
-        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true));
-        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true));
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull(), false))
+                .WillOnce(Return(true));
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull(), false))
+                .WillOnce(Return(true));
         EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
                 .WillOnce(Return(
                         ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
new file mode 100644
index 0000000..9fe9a18
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include "AsyncCallRecorder.h"
+#include "Scheduler/IdleTimer.h"
+
+using namespace std::chrono_literals;
+
+namespace android {
+namespace scheduler {
+
+class IdleTimerTest : public testing::Test {
+protected:
+    IdleTimerTest() = default;
+    ~IdleTimerTest() override = default;
+
+    AsyncCallRecorder<void (*)()> mExpiredTimerCallback;
+
+    std::unique_ptr<IdleTimer> mIdleTimer;
+};
+
+namespace {
+TEST_F(IdleTimerTest, createAndDestroyTest) {
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, [] {});
+}
+
+TEST_F(IdleTimerTest, startStopTest) {
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer->start();
+    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+    // The timer expires after 30 ms, so the call to the callback should not happen.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall().has_value());
+    mIdleTimer->stop();
+}
+
+TEST_F(IdleTimerTest, resetTest) {
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer->start();
+    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+    // The timer expires after 30 ms, so the call to the callback should not happen.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    mIdleTimer->reset();
+    // The timer was reset, so the call to the callback should not happen.
+    std::this_thread::sleep_for(std::chrono::milliseconds(15));
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    mIdleTimer->stop();
+}
+
+TEST_F(IdleTimerTest, startNotCalledTest) {
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+    std::this_thread::sleep_for(6ms);
+    // The start hasn't happened, so the callback does not happen.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    mIdleTimer->stop();
+}
+
+TEST_F(IdleTimerTest, idleTimerIdlesTest) {
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer->start();
+    std::this_thread::sleep_for(6ms);
+    // The timer expires after 3 ms, so the call to the callback happens.
+    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    std::this_thread::sleep_for(6ms);
+    // Timer can be idle.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    // Timer can be reset.
+    mIdleTimer->reset();
+    std::this_thread::sleep_for(6ms);
+    // Timer fires again.
+    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    mIdleTimer->stop();
+}
+
+TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) {
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+
+    mIdleTimer->start();
+    std::this_thread::sleep_for(6ms);
+    // The timer expires after 3 ms, so the call to the callback should happen.
+    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    mIdleTimer->stop();
+}
+
+TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer->start();
+    std::this_thread::sleep_for(6ms);
+    EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
+    mIdleTimer->stop();
+    mIdleTimer->reset();
+    std::this_thread::sleep_for(6ms);
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall().has_value());
+}
+
+TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer->start();
+    std::this_thread::sleep_for(1ms);
+    mIdleTimer->stop();
+    std::this_thread::sleep_for(3ms);
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+}
+
+} // namespace
+} // namespace scheduler
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 11e5631..1bee271 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -74,6 +74,9 @@
     MOCK_METHOD1(drawMesh, void(const Mesh&));
     MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
     MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
+    MOCK_CONST_METHOD0(isProtected, bool());
+    MOCK_CONST_METHOD0(supportsProtectedContent, bool());
+    MOCK_METHOD1(useProtectedContext, bool(bool));
     MOCK_CONST_METHOD4(drawLayers,
                        status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
                                 ANativeWindowBuffer* const, base::unique_fd*));
@@ -84,8 +87,7 @@
     Image();
     ~Image() override;
 
-    MOCK_METHOD2(setNativeWindowBuffer,
-                 bool(ANativeWindowBuffer* buffer, bool isProtected));
+    MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool));
 };
 
 class Framebuffer : public renderengine::Framebuffer {
@@ -93,7 +95,7 @@
     Framebuffer();
     ~Framebuffer() override;
 
-    MOCK_METHOD1(setNativeWindowBuffer, bool(ANativeWindowBuffer*));
+    MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool));
 };
 
 } // namespace mock
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
index cf072b6..695396c 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -32,7 +32,7 @@
     : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
       buffer_node_(buffer_node) {
   client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
-  if (client_state_mask_ == 0ULL) {
+  if (client_state_mask_ == 0U) {
     ALOGE("BufferChannel::BufferChannel: %s", strerror(errno));
     buffer_node_ = nullptr;
   }
@@ -41,7 +41,7 @@
 BufferChannel::~BufferChannel() {
   ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
            channel_id(), buffer_id());
-  if (client_state_mask_ != 0ULL) {
+  if (client_state_mask_ != 0U) {
     buffer_node_->RemoveClientsBitFromMask(client_state_mask_);
   }
   Hangup();
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 158ef9c..c7695bc 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -17,7 +17,7 @@
 namespace dvr {
 
 ConsumerChannel::ConsumerChannel(BufferHubService* service, int buffer_id,
-                                 int channel_id, uint64_t client_state_mask,
+                                 int channel_id, uint32_t client_state_mask,
                                  const std::shared_ptr<Channel> producer)
     : BufferHubChannel(service, buffer_id, channel_id, kConsumerType),
       client_state_mask_(client_state_mask),
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
index 744c095..9888db6 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
@@ -51,8 +51,8 @@
   // The concrete implementation of the Buffer object.
   std::shared_ptr<BufferNode> buffer_node_ = nullptr;
 
-  // The state bit of this buffer. Must be one the lower 63 bits.
-  uint64_t client_state_mask_ = 0ULL;
+  // The state bit of this buffer.
+  uint32_t client_state_mask_ = 0U;
 };
 
 }  // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
index 5fb4ec1..5ee551f 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
@@ -16,14 +16,14 @@
   using Message = pdx::Message;
 
   ConsumerChannel(BufferHubService* service, int buffer_id, int channel_id,
-                  uint64_t client_state_mask,
+                  uint32_t client_state_mask,
                   const std::shared_ptr<Channel> producer);
   ~ConsumerChannel() override;
 
   bool HandleMessage(Message& message) override;
   void HandleImpulse(Message& message) override;
 
-  uint64_t client_state_mask() const { return client_state_mask_; }
+  uint32_t client_state_mask() const { return client_state_mask_; }
   BufferInfo GetBufferInfo() const override;
 
   void OnProducerGained();
@@ -39,7 +39,7 @@
   pdx::Status<void> OnConsumerRelease(Message& message,
                                       LocalFence release_fence);
 
-  uint64_t client_state_mask_{0};
+  uint32_t client_state_mask_{0U};
   bool acquired_{false};
   bool released_{true};
   std::weak_ptr<Channel> producer_;
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 4734439..96ef1a2 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -42,7 +42,7 @@
 
   ~ProducerChannel() override;
 
-  uint64_t buffer_state() const {
+  uint32_t buffer_state() const {
     return buffer_state_->load(std::memory_order_acquire);
   }
 
@@ -51,18 +51,18 @@
 
   BufferInfo GetBufferInfo() const override;
 
-  BufferDescription<BorrowedHandle> GetBuffer(uint64_t client_state_mask);
+  BufferDescription<BorrowedHandle> GetBuffer(uint32_t client_state_mask);
 
   pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message,
-                                                  uint64_t consumer_state_mask);
-  pdx::Status<uint64_t> CreateConsumerStateMask();
+                                                  uint32_t consumer_state_mask);
+  pdx::Status<uint32_t> CreateConsumerStateMask();
   pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message);
 
   pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
   pdx::Status<void> OnConsumerRelease(Message& message,
                                       LocalFence release_fence);
 
-  void OnConsumerOrphaned(const uint64_t& consumer_state_mask);
+  void OnConsumerOrphaned(const uint32_t& consumer_state_mask);
 
   void AddConsumer(ConsumerChannel* channel);
   void RemoveConsumer(ConsumerChannel* channel);
@@ -79,13 +79,13 @@
   // IonBuffer that is shared between bufferhubd, producer, and consumers.
   IonBuffer metadata_buffer_;
   BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
-  std::atomic<uint64_t>* buffer_state_ = nullptr;
-  std::atomic<uint64_t>* fence_state_ = nullptr;
-  std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
+  std::atomic<uint32_t>* buffer_state_ = nullptr;
+  std::atomic<uint32_t>* fence_state_ = nullptr;
+  std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
 
   // All orphaned consumer bits. Valid bits are the lower 63 bits, while the
   // highest bit is reserved for the producer and should not be set.
-  uint64_t orphaned_consumer_bit_mask_{0ULL};
+  uint32_t orphaned_consumer_bit_mask_{0U};
 
   LocalFence post_fence_;
   LocalFence returned_fence_;
@@ -110,7 +110,7 @@
 
   // Remove consumer from atomics in shared memory based on consumer_state_mask.
   // This function is used for clean up for failures in CreateConsumer method.
-  void RemoveConsumerClientMask(uint64_t consumer_state_mask);
+  void RemoveConsumerClientMask(uint32_t consumer_state_mask);
 
   ProducerChannel(const ProducerChannel&) = delete;
   void operator=(const ProducerChannel&) = delete;
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b541fb3..1682bfe 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -93,10 +93,10 @@
   // Using placement new here to reuse shared memory instead of new allocation
   // and also initialize the value to zero.
   buffer_state_ =
-      new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
-  fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
+      new (&metadata_header_->buffer_state) std::atomic<uint32_t>(0);
+  fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint32_t>(0);
   active_clients_bit_mask_ =
-      new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
+      new (&metadata_header_->active_clients_bit_mask) std::atomic<uint32_t>(0);
 
   // Producer channel is never created after consumer channel, and one buffer
   // only have one fixed producer for now. Thus, it is correct to assume
@@ -119,7 +119,7 @@
 
   epoll_event event;
   event.events = 0;
-  event.data.u64 = 0ULL;
+  event.data.u32 = 0U;
   if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
                 &event) < 0) {
     ALOGE(
@@ -164,7 +164,7 @@
 ProducerChannel::~ProducerChannel() {
   ALOGD_IF(TRACE,
            "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
-           "state=%" PRIx64 ".",
+           "state=%" PRIx32 ".",
            channel_id(), buffer_id(),
            buffer_state_->load(std::memory_order_acquire));
   for (auto consumer : consumer_channels_) {
@@ -175,7 +175,7 @@
 
 BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
   // Derive the mask of signaled buffers in this producer / consumer set.
-  uint64_t signaled_mask = signaled() ? BufferHubDefs::kFirstClientBitMask : 0;
+  uint32_t signaled_mask = signaled() ? BufferHubDefs::kFirstClientBitMask : 0;
   for (const ConsumerChannel* consumer : consumer_channels_) {
     signaled_mask |= consumer->signaled() ? consumer->client_state_mask() : 0;
   }
@@ -228,7 +228,7 @@
 }
 
 BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
-    uint64_t client_state_mask) {
+    uint32_t client_state_mask) {
   return {buffer_,
           metadata_buffer_,
           buffer_id(),
@@ -241,27 +241,27 @@
 Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
     Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnGetBuffer");
-  ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
+  ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx32 ".",
            buffer_id(), buffer_state_->load(std::memory_order_acquire));
   return {GetBuffer(BufferHubDefs::kFirstClientBitMask)};
 }
 
-Status<uint64_t> ProducerChannel::CreateConsumerStateMask() {
+Status<uint32_t> ProducerChannel::CreateConsumerStateMask() {
   // Try find the next consumer state bit which has not been claimed by any
   // consumer yet.
   // memory_order_acquire is chosen here because all writes in other threads
   // that release active_clients_bit_mask_ need to be visible here.
-  uint64_t current_active_clients_bit_mask =
+  uint32_t current_active_clients_bit_mask =
       active_clients_bit_mask_->load(std::memory_order_acquire);
-  uint64_t consumer_state_mask =
+  uint32_t consumer_state_mask =
       BufferHubDefs::FindNextAvailableClientStateMask(
           current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
-  if (consumer_state_mask == 0ULL) {
+  if (consumer_state_mask == 0U) {
     ALOGE("%s: reached the maximum mumber of consumers per producer: 63.",
           __FUNCTION__);
     return ErrorStatus(E2BIG);
   }
-  uint64_t updated_active_clients_bit_mask =
+  uint32_t updated_active_clients_bit_mask =
       current_active_clients_bit_mask | consumer_state_mask;
   // Set the updated value only if the current value stays the same as what was
   // read before. If the comparison succeeds, update the value without
@@ -274,15 +274,15 @@
   while (!active_clients_bit_mask_->compare_exchange_weak(
       current_active_clients_bit_mask, updated_active_clients_bit_mask,
       std::memory_order_acq_rel, std::memory_order_acquire)) {
-    ALOGE("%s: Current active clients bit mask is changed to %" PRIx64
-          ", which was expected to be %" PRIx64
+    ALOGE("%s: Current active clients bit mask is changed to %" PRIx32
+          ", which was expected to be %" PRIx32
           ". Trying to generate a new client state mask to resolve race "
           "condition.",
           __FUNCTION__, updated_active_clients_bit_mask,
           current_active_clients_bit_mask);
     consumer_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
         current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
-    if (consumer_state_mask == 0ULL) {
+    if (consumer_state_mask == 0U) {
       ALOGE("%s: reached the maximum mumber of consumers per producer: %d.",
             __FUNCTION__, (BufferHubDefs::kMaxNumberOfClients - 1));
       return ErrorStatus(E2BIG);
@@ -294,7 +294,7 @@
   return {consumer_state_mask};
 }
 
-void ProducerChannel::RemoveConsumerClientMask(uint64_t consumer_state_mask) {
+void ProducerChannel::RemoveConsumerClientMask(uint32_t consumer_state_mask) {
   // Clear up the buffer state and fence state in case there is already
   // something there due to possible race condition between producer post and
   // consumer failed to create channel.
@@ -308,7 +308,7 @@
 }
 
 Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(
-    Message& message, uint64_t consumer_state_mask) {
+    Message& message, uint32_t consumer_state_mask) {
   ATRACE_NAME(__FUNCTION__);
   ALOGD_IF(TRACE, "%s: buffer_id=%d", __FUNCTION__, buffer_id());
 
@@ -332,7 +332,7 @@
     return ErrorStatus(ENOMEM);
   }
 
-  uint64_t current_buffer_state =
+  uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
   if (BufferHubDefs::IsBufferReleased(current_buffer_state) ||
       BufferHubDefs::AnyClientGained(current_buffer_state)) {
@@ -343,7 +343,7 @@
   bool update_buffer_state = true;
   if (!BufferHubDefs::IsClientPosted(current_buffer_state,
                                      consumer_state_mask)) {
-    uint64_t updated_buffer_state =
+    uint32_t updated_buffer_state =
         current_buffer_state ^
         (consumer_state_mask & BufferHubDefs::kHighBitsMask);
     while (!buffer_state_->compare_exchange_weak(
@@ -351,15 +351,15 @@
         std::memory_order_acquire)) {
       ALOGI(
           "%s: Failed to post to the new consumer. "
-          "Current buffer state was changed to %" PRIx64
+          "Current buffer state was changed to %" PRIx32
           " when trying to acquire the buffer and modify the buffer state to "
-          "%" PRIx64
+          "%" PRIx32
           ". About to try again if the buffer is still not gained nor fully "
           "released.",
           __FUNCTION__, current_buffer_state, updated_buffer_state);
       if (BufferHubDefs::IsBufferReleased(current_buffer_state) ||
           BufferHubDefs::AnyClientGained(current_buffer_state)) {
-        ALOGI("%s: buffer is gained or fully released, state=%" PRIx64 ".",
+        ALOGI("%s: buffer is gained or fully released, state=%" PRIx32 ".",
               __FUNCTION__, current_buffer_state);
         update_buffer_state = false;
         break;
@@ -393,7 +393,7 @@
 
   epoll_event event;
   event.events = 0;
-  event.data.u64 = 0ULL;
+  event.data.u32 = 0U;
   int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
                       dummy_fence_fd_.Get(), &event);
   ALOGE_IF(ret < 0,
@@ -401,7 +401,7 @@
            "release fence to include the dummy fence: %s",
            strerror(errno));
 
-  eventfd_t dummy_fence_count = 0ULL;
+  eventfd_t dummy_fence_count = 0U;
   if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
     const int error = errno;
     if (error != EAGAIN) {
@@ -451,13 +451,13 @@
   ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
            buffer_id());
 
-  uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
+  uint32_t buffer_state = buffer_state_->load(std::memory_order_acquire);
   if (!BufferHubDefs::IsClientGained(
       buffer_state, BufferHubDefs::kFirstClientStateMask)) {
     // Can only detach a BufferProducer when it's in gained state.
     ALOGW(
         "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=%"
-        PRIx64
+        PRIx32
         ") is not in gained state.",
         buffer_id(), buffer_state);
     return {};
@@ -534,7 +534,7 @@
     }
   }
 
-  uint64_t current_buffer_state =
+  uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
   if (BufferHubDefs::IsBufferReleased(current_buffer_state &
                                       ~orphaned_consumer_bit_mask_)) {
@@ -542,7 +542,7 @@
     if (orphaned_consumer_bit_mask_) {
       ALOGW(
           "%s: orphaned buffer detected during the this acquire/release cycle: "
-          "id=%d orphaned=0x%" PRIx64 " queue_index=%" PRIx64 ".",
+          "id=%d orphaned=0x%" PRIx32 " queue_index=%" PRIx64 ".",
           __FUNCTION__, buffer_id(), orphaned_consumer_bit_mask_,
           metadata_header_->queue_index);
       orphaned_consumer_bit_mask_ = 0;
@@ -552,16 +552,16 @@
   return {};
 }
 
-void ProducerChannel::OnConsumerOrphaned(const uint64_t& consumer_state_mask) {
+void ProducerChannel::OnConsumerOrphaned(const uint32_t& consumer_state_mask) {
   // Remember the ignored consumer so that newly added consumer won't be
   // taking the same state mask as this orphaned consumer.
   ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_mask,
-           "%s: Consumer (consumer_state_mask=%" PRIx64
+           "%s: Consumer (consumer_state_mask=%" PRIx32
            ") is already orphaned.",
            __FUNCTION__, consumer_state_mask);
   orphaned_consumer_bit_mask_ |= consumer_state_mask;
 
-  uint64_t current_buffer_state =
+  uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
   if (BufferHubDefs::IsBufferReleased(current_buffer_state &
                                       ~orphaned_consumer_bit_mask_)) {
@@ -577,8 +577,8 @@
 
   ALOGW(
       "%s: detected new orphaned consumer buffer_id=%d "
-      "consumer_state_mask=%" PRIx64 " queue_index=%" PRIx64
-      " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
+      "consumer_state_mask=%" PRIx32 " queue_index=%" PRIx64
+      " buffer_state=%" PRIx32 " fence_state=%" PRIx32 ".",
       __FUNCTION__, buffer_id(), consumer_state_mask,
       metadata_header_->queue_index,
       buffer_state_->load(std::memory_order_acquire),
@@ -594,18 +594,18 @@
       std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
   // Restore the consumer state bit and make it visible in other threads that
   // acquire the active_clients_bit_mask_.
-  uint64_t consumer_state_mask = channel->client_state_mask();
-  uint64_t current_active_clients_bit_mask =
+  uint32_t consumer_state_mask = channel->client_state_mask();
+  uint32_t current_active_clients_bit_mask =
       active_clients_bit_mask_->load(std::memory_order_acquire);
-  uint64_t updated_active_clients_bit_mask =
+  uint32_t updated_active_clients_bit_mask =
       current_active_clients_bit_mask & (~consumer_state_mask);
   while (!active_clients_bit_mask_->compare_exchange_weak(
       current_active_clients_bit_mask, updated_active_clients_bit_mask,
       std::memory_order_acq_rel, std::memory_order_acquire)) {
     ALOGI(
         "%s: Failed to remove consumer state mask. Current active clients bit "
-        "mask is changed to %" PRIu64
-        " when trying to acquire and modify it to %" PRIu64
+        "mask is changed to %" PRIx32
+        " when trying to acquire and modify it to %" PRIx32
         ". About to try again.",
         __FUNCTION__, current_active_clients_bit_mask,
         updated_active_clients_bit_mask);
@@ -613,7 +613,7 @@
         current_active_clients_bit_mask & (~consumer_state_mask);
   }
 
-  const uint64_t current_buffer_state =
+  const uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
   if (BufferHubDefs::IsClientPosted(current_buffer_state,
                                     consumer_state_mask) ||
@@ -634,7 +634,7 @@
     if (fence_state_->load(std::memory_order_acquire) & consumer_state_mask) {
       epoll_event event;
       event.events = EPOLLIN;
-      event.data.u64 = consumer_state_mask;
+      event.data.u32 = consumer_state_mask;
       if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
                     dummy_fence_fd_.Get(), &event) < 0) {
         ALOGE(