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(