Sensor: use FlattenableUtils::align
am: dbd0eecfc7
Change-Id: If8a335380b5244315e792871a72c3d386b9cb4eb
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index 6c5869a..abf7b06 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -7,15 +7,16 @@
shared_libs: [
"libbinder",
"libhwbinder",
- "android.hidl.manager@1.0",
"libhidlbase",
"libhidltransport",
"liblog",
- "libcutils",
"libutils",
"libz",
"libbase",
],
+ static_libs: [
+ "libpdx_default_transport",
+ ],
init_rc: ["atrace.rc"],
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 47e04e7..2d9a98c 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -26,7 +26,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/sendfile.h>
#include <time.h>
#include <unistd.h>
#include <zlib.h>
@@ -40,18 +39,21 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
-#include <cutils/properties.h>
+#include <pdx/default_transport/service_utility.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Tokenizer.h>
#include <utils/Trace.h>
#include <android-base/file.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
using namespace android;
+using pdx::default_transport::ServiceUtility;
using std::string;
-#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#define MAX_SYS_FILES 10
#define MAX_PACKAGES 16
@@ -61,6 +63,7 @@
const char* k_traceAppsNumberProperty = "debug.atrace.app_number";
const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d";
const char* k_coreServiceCategory = "core_services";
+const char* k_pdxServiceCategory = "pdx";
const char* k_coreServicesProp = "ro.atrace.core.services";
typedef enum { OPT, REQ } requiredness ;
@@ -89,7 +92,9 @@
/* Tracing categories */
static const TracingCategory k_categories[] = {
- { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
+ { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, {
+ { OPT, "events/mdss/enable" },
+ } },
{ "input", "Input", ATRACE_TAG_INPUT, { } },
{ "view", "View System", ATRACE_TAG_VIEW, { } },
{ "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
@@ -112,6 +117,7 @@
{ "network", "Network", ATRACE_TAG_NETWORK, { } },
{ "adb", "ADB", ATRACE_TAG_ADB, { } },
{ k_coreServiceCategory, "Core services", 0, { } },
+ { k_pdxServiceCategory, "PDX services", 0, { } },
{ "sched", "CPU Scheduling", 0, {
{ REQ, "events/sched/sched_switch/enable" },
{ REQ, "events/sched/sched_wakeup/enable" },
@@ -174,6 +180,7 @@
{ REQ, "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
{ REQ, "events/vmscan/mm_vmscan_kswapd_wake/enable" },
{ REQ, "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
+ { REQ, "events/lowmemorykiller/enable" },
} },
{ "regulators", "Voltage and Current Regulators", 0, {
{ REQ, "events/regulator/enable" },
@@ -181,11 +188,12 @@
{ "binder_driver", "Binder Kernel driver", 0, {
{ REQ, "events/binder/binder_transaction/enable" },
{ REQ, "events/binder/binder_transaction_received/enable" },
+ { OPT, "events/binder/binder_set_priority/enable" },
} },
{ "binder_lock", "Binder global lock trace", 0, {
- { REQ, "events/binder/binder_lock/enable" },
- { REQ, "events/binder/binder_locked/enable" },
- { REQ, "events/binder/binder_unlock/enable" },
+ { OPT, "events/binder/binder_lock/enable" },
+ { OPT, "events/binder/binder_locked/enable" },
+ { OPT, "events/binder/binder_unlock/enable" },
} },
{ "pagecache", "Page cache", 0, {
{ REQ, "events/filemap/enable" },
@@ -205,8 +213,9 @@
static const char* g_outputFile = nullptr;
/* Global state */
+static bool g_tracePdx = false;
static bool g_traceAborted = false;
-static bool g_categoryEnables[NELEM(k_categories)] = {};
+static bool g_categoryEnables[arraysize(k_categories)] = {};
static std::string g_traceFolder;
/* Sys file paths */
@@ -361,9 +370,11 @@
static bool isCategorySupported(const TracingCategory& category)
{
if (strcmp(category.name, k_coreServiceCategory) == 0) {
- char value[PROPERTY_VALUE_MAX];
- property_get(k_coreServicesProp, value, "");
- return strlen(value) != 0;
+ return !android::base::GetProperty(k_coreServicesProp, "").empty();
+ }
+
+ if (strcmp(category.name, k_pdxServiceCategory) == 0) {
+ return true;
}
bool ok = category.tags != 0;
@@ -378,7 +389,7 @@
ok = true;
}
} else {
- ok |= fileIsWritable(path);
+ ok = true;
}
}
}
@@ -564,9 +575,8 @@
// processes to pick up the new value.
static bool setTagsProperty(uint64_t tags)
{
- char buf[PROPERTY_VALUE_MAX];
- snprintf(buf, sizeof(buf), "%#" PRIx64, tags);
- if (property_set(k_traceTagsProperty, buf) < 0) {
+ std::string value = android::base::StringPrintf("%#" PRIx64, tags);
+ if (!android::base::SetProperty(k_traceTagsProperty, value)) {
fprintf(stderr, "error setting trace tags system property\n");
return false;
}
@@ -575,14 +585,13 @@
static void clearAppProperties()
{
- char buf[PROPERTY_KEY_MAX];
for (int i = 0; i < MAX_PACKAGES; i++) {
- snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
- if (property_set(buf, "") < 0) {
- fprintf(stderr, "failed to clear system property: %s\n", buf);
+ std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
+ if (!android::base::SetProperty(key, "")) {
+ fprintf(stderr, "failed to clear system property: %s\n", key.c_str());
}
}
- if (property_set(k_traceAppsNumberProperty, "") < 0) {
+ if (!android::base::SetProperty(k_traceAppsNumberProperty, "")) {
fprintf(stderr, "failed to clear system property: %s",
k_traceAppsNumberProperty);
}
@@ -592,7 +601,6 @@
// application-level tracing.
static bool setAppCmdlineProperty(char* cmdline)
{
- char buf[PROPERTY_KEY_MAX];
int i = 0;
char* start = cmdline;
while (start != NULL) {
@@ -606,9 +614,9 @@
*end = '\0';
end++;
}
- snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
- if (property_set(buf, start) < 0) {
- fprintf(stderr, "error setting trace app %d property to %s\n", i, buf);
+ std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
+ if (!android::base::SetProperty(key, start)) {
+ fprintf(stderr, "error setting trace app %d property to %s\n", i, key.c_str());
clearAppProperties();
return false;
}
@@ -616,9 +624,9 @@
i++;
}
- snprintf(buf, sizeof(buf), "%d", i);
- if (property_set(k_traceAppsNumberProperty, buf) < 0) {
- fprintf(stderr, "error setting trace app number property to %s\n", buf);
+ std::string value = android::base::StringPrintf("%d", i);
+ if (!android::base::SetProperty(k_traceAppsNumberProperty, value)) {
+ fprintf(stderr, "error setting trace app number property to %s\n", value.c_str());
clearAppProperties();
return false;
}
@@ -628,7 +636,7 @@
// Disable all /sys/ enable files.
static bool disableKernelTraceEvents() {
bool ok = true;
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory &c = k_categories[i];
for (int j = 0; j < MAX_SYS_FILES; j++) {
const char* path = c.sysfiles[j].path;
@@ -716,7 +724,7 @@
static bool setCategoryEnable(const char* name, bool enable)
{
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory& c = k_categories[i];
if (strcmp(name, c.name) == 0) {
if (isCategorySupported(c)) {
@@ -778,7 +786,7 @@
// Set up the tags property.
uint64_t tags = 0;
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
if (g_categoryEnables[i]) {
const TracingCategory &c = k_categories[i];
tags |= c.tags;
@@ -787,31 +795,38 @@
ok &= setTagsProperty(tags);
bool coreServicesTagEnabled = false;
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
coreServicesTagEnabled = g_categoryEnables[i];
}
+
+ // Set whether to poke PDX services in this session.
+ if (strcmp(k_categories[i].name, k_pdxServiceCategory) == 0) {
+ g_tracePdx = g_categoryEnables[i];
+ }
}
std::string packageList(g_debugAppCmdLine);
if (coreServicesTagEnabled) {
- char value[PROPERTY_VALUE_MAX];
- property_get(k_coreServicesProp, value, "");
if (!packageList.empty()) {
packageList += ",";
}
- packageList += value;
+ packageList += android::base::GetProperty(k_coreServicesProp, "");
}
ok &= setAppCmdlineProperty(&packageList[0]);
ok &= pokeBinderServices();
pokeHalServices();
+ if (g_tracePdx) {
+ ok &= ServiceUtility::PokeServices();
+ }
+
// Disable all the sysfs enables. This is done as a separate loop from
// the enables to allow the same enable to exist in multiple categories.
ok &= disableKernelTraceEvents();
// Enable all the sysfs enables that are in an enabled category.
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
if (g_categoryEnables[i]) {
const TracingCategory &c = k_categories[i];
for (int j = 0; j < MAX_SYS_FILES; j++) {
@@ -843,6 +858,10 @@
clearAppProperties();
pokeBinderServices();
+ if (g_tracePdx) {
+ ServiceUtility::PokeServices();
+ }
+
// Set the options back to their defaults.
setTraceOverwriteEnable(true);
setTraceBufferSizeKB(1);
@@ -976,11 +995,16 @@
fprintf(stderr, "error cleaning up zlib: %d\n", result);
}
} else {
- ssize_t sent = 0;
- while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0);
- if (sent == -1) {
- fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
- errno);
+ char buf[4096];
+ ssize_t rc;
+ while ((rc = TEMP_FAILURE_RETRY(read(traceFD, buf, sizeof(buf)))) > 0) {
+ if (!android::base::WriteFully(outFd, buf, rc)) {
+ fprintf(stderr, "error writing trace: %s\n", strerror(errno));
+ break;
+ }
+ }
+ if (rc == -1) {
+ fprintf(stderr, "error dumping trace: %s\n", strerror(errno));
}
}
@@ -1008,7 +1032,7 @@
static void listSupportedCategories()
{
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory& c = k_categories[i];
if (isCategorySupported(c)) {
printf(" %10s - %s\n", c.name, c.longname);
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index d538145..526fd19 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -53,6 +53,8 @@
chown root shell /sys/kernel/tracing/events/binder/binder_locked/enable
chown root shell /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
chown root shell /sys/kernel/tracing/events/binder/binder_unlock/enable
+ chown root shell /sys/kernel/debug/tracing/events/lowmemorykiller/enable
+ chown root shell /sys/kernel/tracing/events/lowmemorykiller/enable
chown root shell /sys/kernel/debug/tracing/tracing_on
chown root shell /sys/kernel/tracing/tracing_on
@@ -123,6 +125,8 @@
chmod 0664 /sys/kernel/tracing/events/i2c/smbus_result/enable
chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_reply/enable
chmod 0664 /sys/kernel/tracing/events/i2c/smbus_reply/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/lowmemorykiller/enable
+ chmod 0664 /sys/kernel/tracing/events/lowmemorykiller/enable
# Tracing disabled by default
write /sys/kernel/debug/tracing/tracing_on 0
diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk
index 880bc75..10dda56 100644
--- a/cmds/bugreportz/Android.mk
+++ b/cmds/bugreportz/Android.mk
@@ -25,6 +25,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := bugreportz_test
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
LOCAL_CFLAGS := -Werror -Wall
diff --git a/cmds/bugreportz/AndroidTest.xml b/cmds/bugreportz/AndroidTest.xml
new file mode 100644
index 0000000..38b6276
--- /dev/null
+++ b/cmds/bugreportz/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for bugreportz_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="bugreportz_test->/data/local/tmp/bugreportz_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="bugreportz_test" />
+ </test>
+</configuration>
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index a407ea2..a1b6a51 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -16,8 +16,8 @@
utils.cpp
COMMON_SHARED_LIBRARIES := \
android.hardware.dumpstate@1.0 \
- android.hidl.manager@1.0 \
libhidlbase \
+ libhidltransport \
libbase \
libbinder \
libcutils \
@@ -138,7 +138,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := dumpstate_test_fixture
-
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
diff --git a/cmds/dumpstate/AndroidTest.xml b/cmds/dumpstate/AndroidTest.xml
new file mode 100644
index 0000000..f189489
--- /dev/null
+++ b/cmds/dumpstate/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for dumpstate_test_fixture">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="dumpstate_test_fixture->/data/local/tmp/dumpstate_test_fixture" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="dumpstate_test_fixture" />
+ </test>
+</configuration>
diff --git a/cmds/dumpstate/DumpstateInternal.h b/cmds/dumpstate/DumpstateInternal.h
index 2f7704d..10db5d6 100644
--- a/cmds/dumpstate/DumpstateInternal.h
+++ b/cmds/dumpstate/DumpstateInternal.h
@@ -32,6 +32,12 @@
ALOGI(__VA_ARGS__);
#endif
+#ifndef MYLOGW
+#define MYLOGW(...) \
+ fprintf(stderr, __VA_ARGS__); \
+ ALOGW(__VA_ARGS__);
+#endif
+
#ifndef MYLOGE
#define MYLOGE(...) \
fprintf(stderr, __VA_ARGS__); \
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index f84d86d..4161bd7 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -21,13 +21,9 @@
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
-#include <memory>
-#include <regex>
-#include <set>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string>
#include <string.h>
#include <sys/prctl.h>
#include <sys/resource.h>
@@ -35,6 +31,11 @@
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <memory>
+#include <regex>
+#include <set>
+#include <string>
+#include <vector>
#include <android-base/file.h>
#include <android-base/properties.h>
@@ -71,6 +72,7 @@
#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
+#define BLK_DEV_SYS_DIR "/sys/block"
#define RAFT_DIR "/data/misc/raft"
#define RECOVERY_DIR "/cache/recovery"
@@ -78,19 +80,29 @@
#define LOGPERSIST_DATA_DIR "/data/misc/logd"
#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
-#define TOMBSTONE_DIR "/data/tombstones"
-#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
-/* Can accomodate a tombstone number up to 9999. */
-#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
-#define NUM_TOMBSTONES 10
#define WLUTIL "/vendor/xbin/wlutil"
-typedef struct {
- char name[TOMBSTONE_MAX_LEN];
- int fd;
-} tombstone_data_t;
+// TODO(narayan): Since this information has to be kept in sync
+// with tombstoned, we should just put it in a common header.
+//
+// File: system/core/debuggerd/tombstoned/tombstoned.cpp
+static const std::string TOMBSTONE_DIR = "/data/tombstones/";
+static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
+static const std::string ANR_DIR = "/data/anr/";
+static const std::string ANR_FILE_PREFIX = "anr_";
-static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
+struct DumpData {
+ std::string name;
+ int fd;
+ time_t mtime;
+};
+
+static bool operator<(const DumpData& d1, const DumpData& d2) {
+ return d1.mtime > d2.mtime;
+}
+
+static std::unique_ptr<std::vector<DumpData>> tombstone_data;
+static std::unique_ptr<std::vector<DumpData>> anr_data;
// TODO: temporary variables and functions used during C++ refactoring
static Dumpstate& ds = Dumpstate::GetInstance();
@@ -111,7 +123,14 @@
static const std::string ZIP_ROOT_DIR = "FS";
// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
-static const std::string kDumpstateBoardPath = "/bugreports/dumpstate_board.txt";
+static const std::string kDumpstateBoardPath = "/bugreports/";
+static const std::string kDumpstateBoardFiles[] = {
+ "dumpstate_board.txt",
+ // TODO: rename to dumpstate_board.bin once vendors can handle it
+ "modem_log_all.tar"
+};
+static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
+
static const std::string kLsHalDebugPath = "/bugreports/dumpstate_lshal.txt";
static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
@@ -122,23 +141,79 @@
static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
-/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
- * otherwise, gets just those modified in the last half an hour. */
-static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
- time_t thirty_minutes_ago = ds.now_ - 60 * 30;
- for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
- snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
- int fd = TEMP_FAILURE_RETRY(open(data[i].name,
- O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
- struct stat st;
- if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
- (ds.IsZipping() || st.st_mtime >= thirty_minutes_ago)) {
- data[i].fd = fd;
- } else {
- close(fd);
- data[i].fd = -1;
+/*
+ * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
+ * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
+ * is set, the vector only contains files that were written in the last 30 minutes.
+ */
+static std::vector<DumpData>* GetDumpFds(const std::string& dir_path,
+ const std::string& file_prefix,
+ bool limit_by_mtime) {
+ const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
+
+ std::unique_ptr<std::vector<DumpData>> dump_data(new std::vector<DumpData>());
+ std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
+
+ struct dirent* entry = nullptr;
+ while ((entry = readdir(dump_dir.get()))) {
+ if (entry->d_type != DT_REG) {
+ continue;
}
+
+ const std::string base_name(entry->d_name);
+ if (base_name.find(file_prefix) != 0) {
+ continue;
+ }
+
+ const std::string abs_path = dir_path + base_name;
+ android::base::unique_fd fd(
+ TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
+ if (fd == -1) {
+ MYLOGW("Unable to open dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+ break;
+ }
+
+ struct stat st = {};
+ if (fstat(fd, &st) == -1) {
+ MYLOGW("Unable to stat dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+ continue;
+ }
+
+ if (limit_by_mtime && st.st_mtime >= thirty_minutes_ago) {
+ MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
+ continue;
+ }
+
+ DumpData data = {.name = abs_path, .fd = fd.release(), .mtime = st.st_mtime};
+
+ dump_data->push_back(data);
}
+
+ std::sort(dump_data->begin(), dump_data->end());
+
+ return dump_data.release();
+}
+
+static bool AddDumps(const std::vector<DumpData>::const_iterator start,
+ const std::vector<DumpData>::const_iterator end,
+ const char* type_name, const bool add_to_zip) {
+ bool dumped = false;
+ for (auto it = start; it != end; ++it) {
+ const std::string& name = it->name;
+ const int fd = it->fd;
+ dumped = true;
+ if (ds.IsZipping() && add_to_zip) {
+ if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
+ MYLOGE("Unable to add %s %s to zip file\n", name.c_str(), type_name);
+ }
+ } else {
+ dump_file_from_fd(type_name, name.c_str(), fd);
+ }
+
+ close(fd);
+ }
+
+ return dumped;
}
// for_each_pid() callback to get mount info about a process.
@@ -377,88 +452,6 @@
}
}
-/**
- * Finds the last modified file in the directory dir whose name starts with file_prefix.
- *
- * Function returns empty string when it does not find a file
- */
-static std::string GetLastModifiedFileWithPrefix(const std::string& dir,
- const std::string& file_prefix) {
- std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
- if (d == nullptr) {
- MYLOGD("Error %d opening %s\n", errno, dir.c_str());
- return "";
- }
-
- // Find the newest file matching the file_prefix in dir
- struct dirent *de;
- time_t last_modified_time = 0;
- std::string last_modified_file = "";
- struct stat s;
-
- while ((de = readdir(d.get()))) {
- std::string file = std::string(de->d_name);
- if (!file_prefix.empty()) {
- if (!android::base::StartsWith(file, file_prefix.c_str())) continue;
- }
- file = dir + "/" + file;
- int ret = stat(file.c_str(), &s);
-
- if ((ret == 0) && (s.st_mtime > last_modified_time)) {
- last_modified_file = file;
- last_modified_time = s.st_mtime;
- }
- }
-
- return last_modified_file;
-}
-
-static void DumpModemLogs() {
- DurationReporter durationReporter("DUMP MODEM LOGS");
- if (PropertiesHelper::IsUserBuild()) {
- return;
- }
-
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
- return;
- }
-
- std::string file_prefix = android::base::GetProperty("ro.radio.log_prefix", "");
-
- if(file_prefix.empty()) {
- MYLOGD("No modem log : file_prefix is empty\n");
- return;
- }
-
- // TODO: b/33820081 we need to provide a right way to dump modem logs.
- std::string radio_bugreport_dir = android::base::GetProperty("ro.radio.log_loc", "");
- if (radio_bugreport_dir.empty()) {
- radio_bugreport_dir = dirname(ds.GetPath("").c_str());
- }
-
- MYLOGD("DumpModemLogs: directory is %s and file_prefix is %s\n",
- radio_bugreport_dir.c_str(), file_prefix.c_str());
-
- std::string modem_log_file = GetLastModifiedFileWithPrefix(radio_bugreport_dir, file_prefix);
-
- struct stat s;
- if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
- MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str());
- return;
- }
-
- std::string filename = basename(modem_log_file.c_str());
- if (!ds.AddZipEntry(filename, modem_log_file)) {
- MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
- } else {
- MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
- if (remove(modem_log_file.c_str())) {
- MYLOGE("Error removing modem log %s\n", modem_log_file.c_str());
- }
- }
-}
-
static bool skip_not_stat(const char *path) {
static const char stat[] = "/stat";
size_t len = strlen(path);
@@ -472,7 +465,6 @@
return false;
}
-static const char mmcblk0[] = "/sys/block/mmcblk0/";
unsigned long worst_write_perf = 20000; /* in KB/s */
//
@@ -586,11 +578,13 @@
return 0;
}
- if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
- path += sizeof(mmcblk0) - 1;
+ if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
+ path += sizeof(BLK_DEV_SYS_DIR) - 1;
}
- printf("%s: %s\n", path, buffer);
+ printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
+ "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
+ "W-wait", "in-fli", "activ", "T-wait", path, buffer);
free(buffer);
if (fields[__STAT_IO_TICKS]) {
@@ -627,9 +621,9 @@
/ fields[__STAT_IO_TICKS];
if (!write_perf && !write_ios) {
- printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
+ printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
} else {
- printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
+ printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
read_ios, write_perf, write_ios, queue);
}
@@ -849,7 +843,7 @@
"-d", "*:v"});
}
-static void DumpIpTables() {
+static void DumpIpTablesAsRoot() {
RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
@@ -860,11 +854,10 @@
RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
}
-static void AddAnrTraceFiles() {
- bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
+static void AddGlobalAnrTraceFile(const bool add_to_zip, const std::string& anr_traces_file,
+ const std::string& anr_traces_dir) {
std::string dump_traces_dir;
- /* show the traces we collected in main(), if that was done */
if (dump_traces_path != nullptr) {
if (add_to_zip) {
dump_traces_dir = dirname(dump_traces_path);
@@ -877,8 +870,6 @@
}
}
- std::string anr_traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
- std::string anr_traces_dir = dirname(anr_traces_path.c_str());
// Make sure directory is not added twice.
// TODO: this is an overzealous check because it's relying on dump_traces_path - which is
@@ -888,65 +879,164 @@
// be revisited.
bool already_dumped = anr_traces_dir == dump_traces_dir;
- MYLOGD("AddAnrTraceFiles(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
+ MYLOGD("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
- if (anr_traces_path.empty()) {
- printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
+ int fd = TEMP_FAILURE_RETRY(
+ open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
+ if (fd < 0) {
+ printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.c_str(), strerror(errno));
} else {
- int fd = TEMP_FAILURE_RETRY(
- open(anr_traces_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
- if (fd < 0) {
- printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path.c_str(),
- strerror(errno));
- } else {
- if (add_to_zip) {
- if (!already_dumped) {
- MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
- anr_traces_dir.c_str());
- ds.AddDir(anr_traces_dir, true);
- already_dumped = true;
- }
- } else {
- MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
- anr_traces_path.c_str());
- dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path.c_str(), fd);
+ if (add_to_zip) {
+ if (!already_dumped) {
+ MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
+ anr_traces_dir.c_str());
+ ds.AddDir(anr_traces_dir, true);
}
+ } else {
+ MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
+ anr_traces_file.c_str());
+ dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd);
+ }
+ }
+}
+
+static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
+ MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
+ anr_traces_dir.c_str());
+
+ // If we're here, dump_traces_path will always be a temporary file
+ // (created with mkostemp or similar) that contains dumps taken earlier
+ // on in the process.
+ if (dump_traces_path != nullptr) {
+ if (add_to_zip) {
+ ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
+ } else {
+ MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
+ dump_traces_path);
+ ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
+ }
+
+ const int ret = unlink(dump_traces_path);
+ if (ret == -1) {
+ MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
+ strerror(errno));
}
}
- if (add_to_zip && already_dumped) {
- MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str());
+ // Add a specific message for the first ANR Dump.
+ if (anr_data->size() > 0) {
+ AddDumps(anr_data->begin(), anr_data->begin() + 1,
+ "VM TRACES AT LAST ANR", add_to_zip);
+
+ if (anr_data->size() > 1) {
+ AddDumps(anr_data->begin() + 1, anr_data->end(),
+ "HISTORICAL ANR", add_to_zip);
+ }
+ } else {
+ printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
+ }
+}
+
+static void AddAnrTraceFiles() {
+ const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
+
+ std::string anr_traces_file;
+ std::string anr_traces_dir;
+ bool is_global_trace_file = true;
+
+ // First check whether the stack-trace-dir property is set. When it's set,
+ // each ANR trace will be written to a separate file and not to a global
+ // stack trace file.
+ anr_traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
+ if (anr_traces_dir.empty()) {
+ anr_traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
+ if (!anr_traces_file.empty()) {
+ anr_traces_dir = dirname(anr_traces_file.c_str());
+ }
+ } else {
+ is_global_trace_file = false;
+ }
+
+ // We have neither configured a global trace file nor a trace directory,
+ // there will be nothing to dump.
+ if (anr_traces_file.empty() && anr_traces_dir.empty()) {
+ printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
return;
}
+ if (is_global_trace_file) {
+ AddGlobalAnrTraceFile(add_to_zip, anr_traces_file, anr_traces_dir);
+ } else {
+ AddAnrTraceDir(add_to_zip, anr_traces_dir);
+ }
+
/* slow traces for slow operations */
struct stat st;
- if (!anr_traces_path.empty()) {
- int tail = anr_traces_path.size() - 1;
- while (tail > 0 && anr_traces_path.at(tail) != '/') {
- tail--;
- }
+ if (!anr_traces_dir.empty()) {
int i = 0;
- while (1) {
- anr_traces_path = anr_traces_path.substr(0, tail + 1) +
- android::base::StringPrintf("slow%02d.txt", i);
- if (stat(anr_traces_path.c_str(), &st)) {
+ while (true) {
+ const std::string slow_trace_path =
+ anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
+ if (stat(slow_trace_path.c_str(), &st)) {
// No traces file at this index, done with the files.
break;
}
- ds.DumpFile("VM TRACES WHEN SLOW", anr_traces_path.c_str());
+ ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
i++;
}
}
}
+static void DumpBlockStatFiles() {
+ DurationReporter duration_reporter("DUMP BLOCK STAT");
+
+ std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
+
+ if (dirptr == nullptr) {
+ MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
+ return;
+ }
+
+ printf("------ DUMP BLOCK STAT ------\n\n");
+ while (struct dirent *d = readdir(dirptr.get())) {
+ if ((d->d_name[0] == '.')
+ && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
+ || (d->d_name[1] == '\0'))) {
+ continue;
+ }
+ const std::string new_path =
+ android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
+ printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
+ dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
+ printf("\n");
+ }
+ return;
+}
+
+static void DumpPacketStats() {
+ DumpFile("NETWORK DEV INFO", "/proc/net/dev");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
+ DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
+ DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+}
+
+static void DumpIpAddrAndRules() {
+ /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
+ RunCommand("NETWORK INTERFACES", {"ip", "link"});
+ RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
+ RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
+ RunCommand("IP RULES", {"ip", "rule", "show"});
+ RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+}
+
static void dumpstate() {
DurationReporter duration_reporter("DUMPSTATE");
dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
RunCommand("UPTIME", {"uptime"});
- dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
+ DumpBlockStatFiles();
dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
DumpFile("MEMORY INFO", "/proc/meminfo");
RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
@@ -1010,52 +1100,25 @@
AddAnrTraceFiles();
- int dumped = 0;
- for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
- if (tombstone_data[i].fd != -1) {
- const char *name = tombstone_data[i].name;
- int fd = tombstone_data[i].fd;
- dumped = 1;
- if (ds.IsZipping()) {
- if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
- MYLOGE("Unable to add tombstone %s to zip file\n", name);
- }
- } else {
- dump_file_from_fd("TOMBSTONE", name, fd);
- }
- close(fd);
- tombstone_data[i].fd = -1;
- }
- }
- if (!dumped) {
- printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
+ // NOTE: tombstones are always added as separate entries in the zip archive
+ // and are not interspersed with the main report.
+ const bool tombstones_dumped = AddDumps(tombstone_data->begin(), tombstone_data->end(),
+ "TOMBSTONE", true /* add_to_zip */);
+ if (!tombstones_dumped) {
+ printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
}
- DumpFile("NETWORK DEV INFO", "/proc/net/dev");
- DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
- DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
- DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
- DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+ DumpPacketStats();
DoKmsg();
- /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
-
- RunCommand("NETWORK INTERFACES", {"ip", "link"});
-
- RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
- RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
-
- RunCommand("IP RULES", {"ip", "rule", "show"});
- RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+ DumpIpAddrAndRules();
dump_route_tables();
RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
- RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
- CommandOptions::WithTimeout(20).Build());
RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
CommandOptions::WithTimeout(10).Build());
@@ -1150,11 +1213,6 @@
RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
- // DumpModemLogs adds the modem logs if available to the bugreport.
- // Do this at the end to allow for sufficient time for the modem logs to be
- // collected.
- DumpModemLogs();
-
printf("========================================================\n");
printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
ds.progress_->GetMax(), ds.progress_->GetInitialMax());
@@ -1163,6 +1221,46 @@
printf("========================================================\n");
}
+// This method collects dumpsys for telephony debugging only
+static void DumpstateTelephonyOnly() {
+ DurationReporter duration_reporter("DUMPSTATE");
+
+ DumpIpTablesAsRoot();
+
+ if (!DropRootUser()) {
+ return;
+ }
+
+ do_dmesg();
+ DoLogcat();
+ DumpPacketStats();
+ DoKmsg();
+ DumpIpAddrAndRules();
+ dump_route_tables();
+
+ RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
+ CommandOptions::WithTimeout(10).Build());
+
+ RunCommand("SYSTEM PROPERTIES", {"getprop"});
+
+ printf("========================================================\n");
+ printf("== Android Framework Services\n");
+ printf("========================================================\n");
+
+ RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10);
+ RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10);
+
+ printf("========================================================\n");
+ printf("== Running Application Services\n");
+ printf("========================================================\n");
+
+ RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
+
+ printf("========================================================\n");
+ printf("== dumpstate: done (id %d)\n", ds.id_);
+ printf("========================================================\n");
+}
+
void Dumpstate::DumpstateBoard() {
DurationReporter duration_reporter("dumpstate_board()");
printf("========================================================\n");
@@ -1180,23 +1278,35 @@
return;
}
- std::string path = kDumpstateBoardPath;
- MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path.c_str());
+ std::string path[NUM_OF_DUMPS];
+ android::base::unique_fd fd[NUM_OF_DUMPS];
+ int numFds = 0;
- int fd =
- TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
- if (fd < 0) {
- MYLOGE("Could not open file %s: %s\n", path.c_str(), strerror(errno));
- return;
+ for (int i = 0; i < NUM_OF_DUMPS; i++) {
+ path[i] = kDumpstateBoardPath + kDumpstateBoardFiles[i];
+ MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path[i].c_str());
+
+ fd[i] = android::base::unique_fd(
+ TEMP_FAILURE_RETRY(open(path[i].c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ if (fd[i] < 0) {
+ MYLOGE("Could not open file %s: %s\n", path[i].c_str(), strerror(errno));
+ return;
+ } else {
+ numFds++;
+ }
}
- native_handle_t* handle = native_handle_create(1, 0);
+ native_handle_t *handle = native_handle_create(numFds, 0);
if (handle == nullptr) {
MYLOGE("Could not create native_handle\n");
return;
}
- handle->data[0] = fd;
+
+ for (int i = 0; i < numFds; i++) {
+ handle->data[i] = fd[i].release();
+ }
// TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
@@ -1207,14 +1317,26 @@
return;
}
- AddZipEntry("dumpstate-board.txt", path);
+ for (int i = 0; i < numFds; i++) {
+ struct stat s;
+ if (fstat(handle->data[i], &s) == -1) {
+ MYLOGE("Failed to fstat %s: %d\n", kDumpstateBoardFiles[i].c_str(), errno);
+ } else if (s.st_size > 0) {
+ AddZipEntry(kDumpstateBoardFiles[i], path[i]);
+ } else {
+ MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
+ }
+ }
+
printf("*** See dumpstate-board.txt entry ***\n");
native_handle_close(handle);
native_handle_delete(handle);
- if (remove(path.c_str()) != 0) {
- MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
+ for (int i = 0; i < numFds; i++) {
+ if (remove(path[i].c_str()) != 0) {
+ MYLOGE("Could not remove(%s): %s\n", path[i].c_str(), strerror(errno));
+ }
}
}
@@ -1676,15 +1798,8 @@
ds.PrintHeader();
if (telephony_only) {
- DumpIpTables();
- if (!DropRootUser()) {
- return -1;
- }
- do_dmesg();
- DoLogcat();
- DoKmsg();
+ DumpstateTelephonyOnly();
ds.DumpstateBoard();
- DumpModemLogs();
} else {
// Dumps systrace right away, otherwise it will be filled with unnecessary events.
// First try to dump anrd trace if the daemon is running. Otherwise, dump
@@ -1707,7 +1822,9 @@
dump_traces_path = dump_traces();
/* Run some operations that require root. */
- get_tombstone_fds(tombstone_data);
+ tombstone_data.reset(GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping()));
+ anr_data.reset(GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping()));
+
ds.AddDir(RECOVERY_DIR, true);
ds.AddDir(RECOVERY_DATA_DIR, true);
ds.AddDir(LOGPERSIST_DATA_DIR, false);
@@ -1716,7 +1833,7 @@
ds.AddDir(PROFILE_DATA_DIR_REF, true);
}
add_mountinfo();
- DumpIpTables();
+ DumpIpTablesAsRoot();
// Capture any IPSec policies in play. No keys are exposed here.
RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index eefdcbd..93f4c22 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -38,6 +38,7 @@
#include <time.h>
#include <unistd.h>
+#include <memory>
#include <set>
#include <string>
#include <vector>
@@ -46,6 +47,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
@@ -96,8 +98,9 @@
"android.hardware.bluetooth@1.0::IBluetoothHci",
"android.hardware.camera.provider@2.4::ICameraProvider",
"android.hardware.graphics.composer@2.1::IComposer",
- "android.hardware.vr@1.0::IVr",
"android.hardware.media.omx@1.0::IOmx",
+ "android.hardware.sensors@1.0::ISensors",
+ "android.hardware.vr@1.0::IVr",
NULL,
};
@@ -853,15 +856,143 @@
return pids; // whether it was okay or not
}
+const char* DumpTraces(const std::string& traces_path);
+const char* DumpTracesTombstoned(const std::string& traces_dir);
+
/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
const char *dump_traces() {
DurationReporter duration_reporter("DUMP TRACES");
- const char* result = nullptr;
+ const std::string traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
+ if (!traces_dir.empty()) {
+ return DumpTracesTombstoned(traces_dir);
+ }
- std::string traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
- if (traces_path.empty()) return nullptr;
+ const std::string traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
+ if (!traces_file.empty()) {
+ return DumpTraces(traces_file);
+ }
+ return nullptr;
+}
+
+static bool IsZygote(int pid) {
+ static const std::string kZygotePrefix = "zygote";
+
+ std::string cmdline;
+ if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
+ &cmdline)) {
+ return true;
+ }
+
+ return (cmdline.find(kZygotePrefix) == 0);
+}
+
+const char* DumpTracesTombstoned(const std::string& traces_dir) {
+ const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX";
+
+ const size_t buf_size = temp_file_pattern.length() + 1;
+ std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
+ memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
+
+ // Create a new, empty file to receive all trace dumps.
+ //
+ // TODO: This can be simplified once we remove support for the old style
+ // dumps. We can have a file descriptor passed in to dump_traces instead
+ // of creating a file, closing it and then reopening it again.
+ android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
+ if (fd < 0) {
+ MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
+ return nullptr;
+ }
+
+ // Nobody should have access to this temporary file except dumpstate, but we
+ // temporarily grant 'read' to 'others' here because this file is created
+ // when tombstoned is still running as root, but dumped after dropping. This
+ // can go away once support for old style dumping has.
+ const int chmod_ret = fchmod(fd, 0666);
+ if (chmod_ret < 0) {
+ MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
+ return nullptr;
+ }
+
+ std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
+ if (proc.get() == nullptr) {
+ MYLOGE("opendir /proc failed: %s\n", strerror(errno));
+ return nullptr;
+ }
+
+ // Number of times process dumping has timed out. If we encounter too many
+ // failures, we'll give up.
+ int timeout_failures = 0;
+ bool dalvik_found = false;
+
+ const std::set<int> hal_pids = get_interesting_hal_pids();
+
+ struct dirent* d;
+ while ((d = readdir(proc.get()))) {
+ int pid = atoi(d->d_name);
+ if (pid <= 0) {
+ continue;
+ }
+
+ const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
+ std::string exe;
+ if (!android::base::Readlink(link_name, &exe)) {
+ continue;
+ }
+
+ bool is_java_process;
+ if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
+ // Don't bother dumping backtraces for the zygote.
+ if (IsZygote(pid)) {
+ continue;
+ }
+
+ dalvik_found = true;
+ is_java_process = true;
+ } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
+ is_java_process = false;
+ } else {
+ // Probably a native process we don't care about, continue.
+ continue;
+ }
+
+ // If 3 backtrace dumps fail in a row, consider debuggerd dead.
+ if (timeout_failures == 3) {
+ dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
+ break;
+ }
+
+ const uint64_t start = Nanotime();
+ const int ret = dump_backtrace_to_file_timeout(
+ pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
+ is_java_process ? 5 : 20, fd);
+
+ if (ret == -1) {
+ dprintf(fd, "dumping failed, likely due to a timeout\n");
+ timeout_failures++;
+ continue;
+ }
+
+ // We've successfully dumped stack traces, reset the failure count
+ // and write a summary of the elapsed time to the file and continue with the
+ // next process.
+ timeout_failures = 0;
+
+ dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
+ pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
+ }
+
+ if (!dalvik_found) {
+ MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
+ }
+
+ return file_name_buf.release();
+}
+
+const char* DumpTraces(const std::string& traces_path) {
+ const char* result = NULL;
/* move the old traces.txt (if any) out of the way temporarily */
std::string anrtraces_path = traces_path + ".anr";
if (rename(traces_path.c_str(), anrtraces_path.c_str()) && errno != ENOENT) {
@@ -974,7 +1105,8 @@
/* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
if (timeout_failures == 3) {
dprintf(fd, "too many stack dump failures, skipping...\n");
- } else if (dump_backtrace_to_file_timeout(pid, fd, 20) == -1) {
+ } else if (dump_backtrace_to_file_timeout(
+ pid, kDebuggerdNativeBacktrace, 20, fd) == -1) {
dprintf(fd, "dumping failed, likely due to a timeout\n");
timeout_failures++;
} else {
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index 7698ed5..127e0f3 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -1,6 +1,7 @@
// Build the unit tests for dumpsys
cc_test {
name: "dumpsys_test",
+ test_suites: ["device-tests"],
srcs: ["dumpsys_test.cpp"],
diff --git a/cmds/dumpsys/tests/AndroidTest.xml b/cmds/dumpsys/tests/AndroidTest.xml
new file mode 100644
index 0000000..1a8c67f
--- /dev/null
+++ b/cmds/dumpsys/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for dumpsys_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="dumpsys_test->/data/local/tmp/dumpsys_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="dumpsys_test" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 60c89a9..e3021d8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1786,6 +1786,16 @@
return ok();
}
+// Copy the contents of a system profile over the data profile.
+binder::Status InstalldNativeService::copySystemProfile(const std::string& systemProfile,
+ int32_t packageUid, const std::string& packageName, bool* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+ *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName);
+ return ok();
+}
+
// TODO: Consider returning error codes.
binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
bool* _aidl_return) {
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 4011315..5756b82 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -91,6 +91,8 @@
binder::Status mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return);
binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
const std::string& codePaths, bool* _aidl_return);
+ binder::Status copySystemProfile(const std::string& systemProfile,
+ int32_t uid, const std::string& packageName, bool* _aidl_return);
binder::Status clearAppProfiles(const std::string& packageName);
binder::Status destroyAppProfiles(const std::string& packageName);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index f09a397..c8e76b0 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -57,6 +57,8 @@
boolean mergeProfiles(int uid, @utf8InCpp String packageName);
boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String codePaths);
+ boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
+ @utf8InCpp String packageName);
void clearAppProfiles(@utf8InCpp String packageName);
void destroyAppProfiles(@utf8InCpp String packageName);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 70cf35c..685fdd8 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -847,6 +847,70 @@
return true;
}
+bool copy_system_profile(const std::string& system_profile,
+ uid_t packageUid, const std::string& data_profile_location) {
+ unique_fd in_fd(open(system_profile.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+ unique_fd out_fd(open_reference_profile(packageUid,
+ data_profile_location,
+ /*read_write*/ true,
+ /*secondary*/ false));
+ if (in_fd.get() < 0) {
+ PLOG(WARNING) << "Could not open profile " << system_profile;
+ return false;
+ }
+ if (out_fd.get() < 0) {
+ PLOG(WARNING) << "Could not open profile " << data_profile_location;
+ return false;
+ }
+
+ // As a security measure we want to write the profile information with the reduced capabilities
+ // of the package user id. So we fork and drop capabilities in the child.
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ drop_capabilities(packageUid);
+
+ if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
+ if (errno != EWOULDBLOCK) {
+ PLOG(WARNING) << "Error locking profile " << data_profile_location;
+ }
+ // This implies that the app owning this profile is running
+ // (and has acquired the lock).
+ //
+ // The app never acquires the lock for the reference profiles of primary apks.
+ // Only dex2oat from installd will do that. Since installd is single threaded
+ // we should not see this case. Nevertheless be prepared for it.
+ PLOG(WARNING) << "Failed to flock " << data_profile_location;
+ return false;
+ }
+
+ bool truncated = ftruncate(out_fd.get(), 0) == 0;
+ if (!truncated) {
+ PLOG(WARNING) << "Could not truncate " << data_profile_location;
+ }
+
+ // Copy over data.
+ static constexpr size_t kBufferSize = 4 * 1024;
+ char buffer[kBufferSize];
+ while (true) {
+ ssize_t bytes = read(in_fd.get(), buffer, kBufferSize);
+ if (bytes == 0) {
+ break;
+ }
+ write(out_fd.get(), buffer, bytes);
+ }
+ if (flock(out_fd.get(), LOCK_UN) != 0) {
+ PLOG(WARNING) << "Error unlocking profile " << data_profile_location;
+ }
+ // Use _exit since we don't want to run the global destructors in the child.
+ // b/62597429
+ _exit(0);
+ }
+ /* parent */
+ int return_code = wait_child(pid);
+ return return_code == 0;
+}
+
static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) {
// A standard dalvik-cache entry. Replace ".dex" with `new_ext`.
if (EndsWith(oat_path, ".dex")) {
@@ -926,14 +990,22 @@
return oat_dir == nullptr || oat_dir[0] == '!';
}
+// Best-effort check whether we can fit the the path into our buffers.
+// Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
+// without a swap file, if necessary. Reference profiles file also add an extra ".prof"
+// extension to the cache path (5 bytes).
+// TODO(calin): move away from char* buffers and PKG_PATH_MAX.
+static bool validate_dex_path_size(const std::string& dex_path) {
+ if (dex_path.size() >= (PKG_PATH_MAX - 8)) {
+ LOG(ERROR) << "dex_path too long: " << dex_path;
+ return false;
+ }
+ return true;
+}
+
static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
const char* oat_dir, bool is_secondary_dex, /*out*/ char* out_oat_path) {
- // Early best-effort check whether we can fit the the path into our buffers.
- // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
- // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
- // extension to the cache path (5 bytes).
- if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
- ALOGE("apk_path too long '%s'\n", apk_path);
+ if (!validate_dex_path_size(apk_path)) {
return false;
}
@@ -1286,33 +1358,29 @@
// The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
// If this is for a profile guided compilation, profile_was_updated will tell whether or not
// the profile has changed.
-static void exec_dexoptanalyzer(const std::string& dex_file, const char* instruction_set,
- const char* compiler_filter, bool profile_was_updated) {
+static void exec_dexoptanalyzer(const std::string& dex_file, const std::string& instruction_set,
+ const std::string& compiler_filter, bool profile_was_updated) {
static const char* DEXOPTANALYZER_BIN = "/system/bin/dexoptanalyzer";
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
- if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
- ALOGE("Instruction set %s longer than max length of %d",
- instruction_set, MAX_INSTRUCTION_SET_LEN);
+ if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
+ LOG(ERROR) << "Instruction set " << instruction_set
+ << " longer than max length of " << MAX_INSTRUCTION_SET_LEN;
return;
}
- char dex_file_arg[strlen("--dex-file=") + PKG_PATH_MAX];
- char isa_arg[strlen("--isa=") + MAX_INSTRUCTION_SET_LEN];
- char compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax];
+ std::string dex_file_arg = "--dex-file=" + dex_file;
+ std::string isa_arg = "--isa=" + instruction_set;
+ std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
const char* assume_profile_changed = "--assume-profile-changed";
- sprintf(dex_file_arg, "--dex-file=%s", dex_file.c_str());
- sprintf(isa_arg, "--isa=%s", instruction_set);
- sprintf(compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
-
// program name, dex file, isa, filter, the final NULL
const char* argv[5 + (profile_was_updated ? 1 : 0)];
int i = 0;
argv[i++] = DEXOPTANALYZER_BIN;
- argv[i++] = dex_file_arg;
- argv[i++] = isa_arg;
- argv[i++] = compiler_filter_arg;
+ argv[i++] = dex_file_arg.c_str();
+ argv[i++] = isa_arg.c_str();
+ argv[i++] = compiler_filter_arg.c_str();
if (profile_was_updated) {
argv[i++] = assume_profile_changed;
}
@@ -1426,6 +1494,9 @@
}
}
const std::string& dex_path = *dex_path_out;
+ if (!validate_dex_path_size(dex_path)) {
+ return false;
+ }
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
return false;
@@ -1496,6 +1567,10 @@
LOG_FATAL("dexopt flags contains unknown fields\n");
}
+ if (!validate_dex_path_size(dex_path)) {
+ return false;
+ }
+
bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
@@ -1685,6 +1760,10 @@
/*out*/bool* out_secondary_dex_exists) {
// Set out to false to start with, just in case we have validation errors.
*out_secondary_dex_exists = false;
+ if (!validate_dex_path_size(dex_path)) {
+ return false;
+ }
+
if (isas.size() == 0) {
LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
return false;
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 355adb1..d171ee5 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -30,7 +30,6 @@
static constexpr int DEX2OAT_FOR_BOOT_IMAGE = 2;
static constexpr int DEX2OAT_FOR_FILTER = 3;
static constexpr int DEX2OAT_FOR_RELOCATION = 4;
-static constexpr int PATCHOAT_FOR_RELOCATION = 5;
// Clear the reference profile for the primary apk of the given package.
bool clear_primary_reference_profile(const std::string& pkgname);
@@ -51,6 +50,10 @@
bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
+bool copy_system_profile(const std::string& system_profile,
+ uid_t packageUid,
+ const std::string& data_profile_location);
+
bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
bool reconcile_secondary_dex_file(const std::string& dex_path,
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 6a81cfc..2597c79 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -31,7 +31,7 @@
constexpr const char* DALVIK_CACHE_POSTFIX = "@classes.dex";
constexpr size_t PKG_NAME_MAX = 128u; /* largest allowed package name */
-constexpr size_t PKG_PATH_MAX = 256u; /* max size of any path we use */
+constexpr size_t PKG_PATH_MAX = 1024u; /* max size of any path we use */
/****************************************************************************
* IMPORTANT: These values are passed from Java code. Keep them in sync with
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index c792082..7c05417 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -168,18 +168,19 @@
/**
* Create the path name for user data for a certain userid.
+ * Keep same implementation as vold to minimize path walking overhead
*/
std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) {
std::string data(create_data_path(volume_uuid));
- if (volume_uuid == nullptr) {
- if (userid == 0) {
- return StringPrintf("%s/data", data.c_str());
- } else {
- return StringPrintf("%s/user/%u", data.c_str(), userid);
+ if (volume_uuid == nullptr && userid == 0) {
+ std::string legacy = StringPrintf("%s/data", data.c_str());
+ struct stat sb;
+ if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ /* /data/data is dir, return /data/data for legacy system */
+ return legacy;
}
- } else {
- return StringPrintf("%s/user/%u", data.c_str(), userid);
}
+ return StringPrintf("%s/user/%u", data.c_str(), userid);
}
/**
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 38647eb..67b5b46 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -22,7 +22,6 @@
"libhidltransport",
"libhidl-gen-utils",
"libvintf",
- "android.hidl.manager@1.0",
],
srcs: [
"DebugCommand.cpp",
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 710b6e4..7c6cfd9 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -73,46 +73,92 @@
}), pids->end());
}
-bool ListCommand::getReferencedPids(
- pid_t serverPid, std::map<uint64_t, Pids> *objects) const {
-
- std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
+bool scanBinderContext(pid_t pid,
+ const std::string &contextName,
+ std::function<void(const std::string&)> eachLine) {
+ std::ifstream ifs("/d/binder/proc/" + std::to_string(pid));
if (!ifs.is_open()) {
return false;
}
- static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+ static const std::regex kContextLine("^context (\\w+)$");
+ bool isDesiredContext = false;
std::string line;
std::smatch match;
while(getline(ifs, line)) {
- if (!std::regex_search(line, match, prefix)) {
- // the line doesn't start with the correct prefix
+ if (std::regex_search(line, match, kContextLine)) {
+ isDesiredContext = match.str(1) == contextName;
continue;
}
- std::string ptrString = "0x" + match.str(2); // use number after c
- uint64_t ptr;
- if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
- // Should not reach here, but just be tolerant.
- mErr << "Could not parse number " << ptrString << std::endl;
+
+ if (!isDesiredContext) {
continue;
}
- const std::string proc = " proc ";
- auto pos = line.rfind(proc);
- if (pos != std::string::npos) {
- for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
- int32_t pid;
- if (!::android::base::ParseInt(pidStr, &pid)) {
- mErr << "Could not parse number " << pidStr << std::endl;
- continue;
- }
- (*objects)[ptr].push_back(pid);
- }
- }
+
+ eachLine(line);
}
return true;
}
+bool ListCommand::getPidInfo(
+ pid_t serverPid, PidInfo *pidInfo) const {
+ static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+ static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
+
+ std::smatch match;
+ return scanBinderContext(serverPid, "hwbinder", [&](const std::string& line) {
+ if (std::regex_search(line, match, kReferencePrefix)) {
+ const std::string &ptrString = "0x" + match.str(2); // use number after c
+ uint64_t ptr;
+ if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+ // Should not reach here, but just be tolerant.
+ mErr << "Could not parse number " << ptrString << std::endl;
+ return;
+ }
+ const std::string proc = " proc ";
+ auto pos = line.rfind(proc);
+ if (pos != std::string::npos) {
+ for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
+ int32_t pid;
+ if (!::android::base::ParseInt(pidStr, &pid)) {
+ mErr << "Could not parse number " << pidStr << std::endl;
+ return;
+ }
+ pidInfo->refPids[ptr].push_back(pid);
+ }
+ }
+
+ return;
+ }
+
+ if (std::regex_search(line, match, kThreadPrefix)) {
+ // "1" is waiting in binder driver
+ // "2" is poll. It's impossible to tell if these are in use.
+ // and HIDL default code doesn't use it.
+ bool isInUse = match.str(1) != "1";
+ // "0" is a thread that has called into binder
+ // "1" is looper thread
+ // "2" is main looper thread
+ bool isHwbinderThread = match.str(2) != "0";
+
+ if (!isHwbinderThread) {
+ return;
+ }
+
+ if (isInUse) {
+ pidInfo->threadUsage++;
+ }
+
+ pidInfo->threadCount++;
+ return;
+ }
+
+ // not reference or thread line
+ return;
+ });
+}
+
// Must process hwbinder services first, then passthrough services.
void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
f(mServicesTable);
@@ -164,9 +210,11 @@
const std::string &interfaceName,
const std::string &transport,
const std::string &arch,
+ const std::string &threadUsage,
const std::string &server,
const std::string &serverCmdline,
- const std::string &address, const std::string &clients,
+ const std::string &address,
+ const std::string &clients,
const std::string &clientCmdlines) const {
if (mSelectedColumns & ENABLE_INTERFACE_NAME)
mOut << std::setw(80) << interfaceName << "\t";
@@ -174,6 +222,9 @@
mOut << std::setw(10) << transport << "\t";
if (mSelectedColumns & ENABLE_ARCH)
mOut << std::setw(5) << arch << "\t";
+ if (mSelectedColumns & ENABLE_THREADS) {
+ mOut << std::setw(8) << threadUsage << "\t";
+ }
if (mSelectedColumns & ENABLE_SERVER_PID) {
if (mEnableCmdlines) {
mOut << std::setw(15) << serverCmdline << "\t";
@@ -193,7 +244,18 @@
mOut << std::endl;
}
+static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Version& version) {
+ for (vintf::Version& v : hal->versions) {
+ if (v.majorVer == version.majorVer) {
+ v.minorVer = std::max(v.minorVer, version.minorVer);
+ return true;
+ }
+ }
+ return false;
+}
+
void ListCommand::dumpVintf() const {
+ using vintf::operator|=;
mOut << "<!-- " << std::endl
<< " This is a skeleton device manifest. Notes: " << std::endl
<< " 1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
@@ -201,7 +263,9 @@
<< " only hwbinder is shown." << std::endl
<< " 3. It is likely that HALs in passthrough transport does not have" << std::endl
<< " <interface> declared; users will have to write them by hand." << std::endl
- << " 4. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
+ << " 4. A HAL with lower minor version can be overridden by a HAL with" << std::endl
+ << " higher minor version if they have the same name and major version." << std::endl
+ << " 5. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
<< " is removed from the manifest file and written by assemble_vintf" << std::endl
<< " at build time." << std::endl
<< "-->" << std::endl;
@@ -265,17 +329,19 @@
for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
if (hal->transport() != transport) {
if (transport != vintf::Transport::PASSTHROUGH) {
- mErr << "Fatal: should not reach here. Generated result may be wrong."
+ mErr << "Fatal: should not reach here. Generated result may be wrong for '"
+ << hal->name << "'."
<< std::endl;
}
done = true;
break;
}
- if (hal->hasVersion(version)) {
+ if (findAndBumpVersion(hal, version)) {
if (&table != &mImplementationsTable) {
hal->interfaces[interfaceName].name = interfaceName;
hal->interfaces[interfaceName].instances.insert(instanceName);
}
+ hal->transportArch.arch |= arch;
done = true;
break;
}
@@ -344,15 +410,20 @@
mImplementationsTable.description =
"All available passthrough implementations (all -impl.so files)";
forEachTable([this] (const Table &table) {
- mOut << table.description << std::endl;
+ if (!mNeat) {
+ mOut << table.description << std::endl;
+ }
mOut << std::left;
- printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
- "PTR", "Clients", "Clients CMD");
+ if (!mNeat) {
+ printLine("Interface", "Transport", "Arch", "Thread Use", "Server",
+ "Server CMD", "PTR", "Clients", "Clients CMD");
+ }
for (const auto &entry : table) {
printLine(entry.interfaceName,
entry.transport,
getArchString(entry.arch),
+ entry.getThreadUsage(),
entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
entry.serverCmdline,
entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
@@ -369,7 +440,9 @@
NullableOStream<std::ostream>(nullptr));
}
}
- mOut << std::endl;
+ if (!mNeat) {
+ mOut << std::endl;
+ }
});
}
@@ -409,7 +482,8 @@
using namespace ::android::hardware;
using namespace ::android::hidl::manager::V1_0;
using namespace ::android::hidl::base::V1_0;
- auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+ using std::literals::chrono_literals::operator""s;
+ auto ret = timeoutIPC(2s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
std::map<std::string, TableEntry> entries;
for (const auto &info : infos) {
std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
@@ -419,7 +493,7 @@
.transport = "passthrough",
.serverPid = NO_PID,
.serverObjectAddress = NO_PTR,
- .clientPids = {},
+ .clientPids = info.clientPids,
.arch = ARCH_UNKNOWN
}).first->second.arch |= fromBaseArchitecture(info.arch);
}
@@ -486,7 +560,7 @@
Status status = OK;
// server pid, .ptr value of binder object, child pids
std::map<std::string, DebugInfo> allDebugInfos;
- std::map<pid_t, std::map<uint64_t, Pids>> allPids;
+ std::map<pid_t, PidInfo> allPids;
for (const auto &fqInstanceName : fqInstanceNames) {
const auto pair = splitFirst(fqInstanceName, '/');
const auto &serviceName = pair.first;
@@ -510,7 +584,7 @@
auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
allDebugInfos[fqInstanceName] = debugInfo;
if (debugInfo.pid >= 0) {
- allPids[static_cast<pid_t>(debugInfo.pid)].clear();
+ allPids[static_cast<pid_t>(debugInfo.pid)] = PidInfo();
}
});
if (!debugRet.isOk()) {
@@ -520,9 +594,10 @@
status |= DUMP_BINDERIZED_ERROR;
}
}
+
for (auto &pair : allPids) {
pid_t serverPid = pair.first;
- if (!getReferencedPids(serverPid, &allPids[serverPid])) {
+ if (!getPidInfo(serverPid, &allPids[serverPid])) {
mErr << "Warning: no information for PID " << serverPid
<< ", are you root?" << std::endl;
status |= DUMP_BINDERIZED_ERROR;
@@ -537,18 +612,23 @@
.serverPid = NO_PID,
.serverObjectAddress = NO_PTR,
.clientPids = {},
+ .threadUsage = 0,
+ .threadCount = 0,
.arch = ARCH_UNKNOWN
});
continue;
}
const DebugInfo &info = it->second;
+ bool writePidInfo = info.pid != NO_PID && info.ptr != NO_PTR;
+
putEntry(HWSERVICEMANAGER_LIST, {
.interfaceName = fqInstanceName,
.transport = mode,
.serverPid = info.pid,
.serverObjectAddress = info.ptr,
- .clientPids = info.pid == NO_PID || info.ptr == NO_PTR
- ? Pids{} : allPids[info.pid][info.ptr],
+ .clientPids = writePidInfo ? allPids[info.pid].refPids[info.ptr] : Pids{},
+ .threadUsage = writePidInfo ? allPids[info.pid].threadUsage : 0,
+ .threadCount = writePidInfo ? allPids[info.pid].threadCount : 0,
.arch = fromBaseArchitecture(info.arch),
});
}
@@ -587,12 +667,14 @@
{"pid", no_argument, 0, 'p' },
{"address", no_argument, 0, 'a' },
{"clients", no_argument, 0, 'c' },
+ {"threads", no_argument, 0, 'e' },
{"cmdline", no_argument, 0, 'm' },
{"debug", optional_argument, 0, 'd' },
// long options without short alternatives
{"sort", required_argument, 0, 's' },
{"init-vintf",optional_argument, 0, 'v' },
+ {"neat", no_argument, 0, 'n' },
{ 0, 0, 0, 0 }
};
@@ -602,7 +684,7 @@
for (;;) {
// using getopt_long in case we want to add other options in the future
c = getopt_long(arg.argc, arg.argv,
- "hitrpacmd", longOptions, &optionIndex);
+ "hitrpacmde", longOptions, &optionIndex);
if (c == -1) {
break;
}
@@ -654,6 +736,10 @@
mSelectedColumns |= ENABLE_CLIENT_PIDS;
break;
}
+ case 'e': {
+ mSelectedColumns |= ENABLE_THREADS;
+ break;
+ }
case 'm': {
mEnableCmdlines = true;
break;
@@ -672,6 +758,10 @@
}
break;
}
+ case 'n': {
+ mNeat = true;
+ break;
+ }
case 'h': // falls through
default: // see unrecognized options
mLshal.usage(command);
@@ -684,7 +774,7 @@
}
if (mSelectedColumns == 0) {
- mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+ mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS | ENABLE_THREADS;
}
return OK;
}
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 42c965f..a75db04 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -48,18 +48,26 @@
Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
- bool getReferencedPids(
- pid_t serverPid, std::map<uint64_t, Pids> *objects) const;
+
+ struct PidInfo {
+ std::map<uint64_t, Pids> refPids; // pids that are referenced
+ uint32_t threadUsage; // number of threads in use
+ uint32_t threadCount; // number of threads total
+ };
+ bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+
void dumpTable();
void dumpVintf() const;
void printLine(
const std::string &interfaceName,
const std::string &transport,
const std::string &arch,
+ const std::string &threadUsage,
const std::string &server,
const std::string &serverCmdline,
- const std::string &address, const std::string &clients,
- const std::string &clientCmdlines) const ;
+ const std::string &address,
+ const std::string &clients,
+ const std::string &clientCmdlines) const;
// Return /proc/{pid}/cmdline if it exists, else empty string.
const std::string &getCmdline(pid_t pid);
// Call getCmdline on all pid in pids. If it returns empty string, the process might
@@ -85,7 +93,12 @@
// If true, calls IBase::debug(...) on each service.
bool mEmitDebugInfo = false;
+ // If true, output in VINTF format.
bool mVintf = false;
+
+ // If true, explanatory text are not emitted.
+ bool mNeat = false;
+
// If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
// If an entry exist but is an empty string, process might have died.
// If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 9db42f1..e2d5f6d 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -66,7 +66,7 @@
" List all hals with default ordering and columns (`lshal list -ipc`)\n"
" lshal list [-h|--help]\n"
" -h, --help: Print help message for list (`lshal help list`)\n"
- " lshal [list] [--interface|-i] [--transport|-t] [-r|--arch]\n"
+ " lshal [list] [--interface|-i] [--transport|-t] [-r|--arch] [-e|--threads]\n"
" [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]\n"
" [--sort={interface|i|pid|p}] [--init-vintf[=<output file>]]\n"
" [--debug|-d[=<output file>]]\n"
@@ -74,6 +74,8 @@
" -n, --instance: print the instance name column\n"
" -t, --transport: print the transport mode column\n"
" -r, --arch: print if the HAL is in 64-bit or 32-bit\n"
+ " -e, --threads: print currently used/available threads\n"
+ " (note, available threads created lazily)\n"
" -p, --pid: print the server PID, or server cmdline if -m is set\n"
" -a, --address: print the server object address column\n"
" -c, --clients: print the client PIDs, or client cmdlines if -m is set\n"
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 9ae8f78..e04c3ca 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -47,6 +47,8 @@
std::string interfaceName;
std::string transport;
int32_t serverPid;
+ uint32_t threadUsage;
+ uint32_t threadCount;
std::string serverCmdline;
uint64_t serverObjectAddress;
Pids clientPids;
@@ -59,6 +61,14 @@
static bool sortByServerPid(const TableEntry &a, const TableEntry &b) {
return a.serverPid < b.serverPid;
};
+
+ std::string getThreadUsage() const {
+ if (threadCount == 0) {
+ return "N/A";
+ }
+
+ return std::to_string(threadUsage) + "/" + std::to_string(threadCount);
+ }
};
struct Table {
@@ -80,7 +90,8 @@
ENABLE_SERVER_PID = 1 << 2,
ENABLE_SERVER_ADDR = 1 << 3,
ENABLE_CLIENT_PIDS = 1 << 4,
- ENABLE_ARCH = 1 << 5
+ ENABLE_ARCH = 1 << 5,
+ ENABLE_THREADS = 1 << 6,
};
using TableEntrySelect = unsigned int;
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index ca477bf..c940404 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -77,14 +77,15 @@
return success;
}
-template<class Function, class I, class... Args>
+template<class R, class P, class Function, class I, class... Args>
typename std::result_of<Function(I *, Args...)>::type
-timeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) {
+timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Function &&func,
+ Args &&... args) {
using ::android::hardware::Status;
typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
auto boundFunc = std::bind(std::forward<Function>(func),
interfaceObject.get(), std::forward<Args>(args)...);
- bool success = timeout(IPC_CALL_WAIT, [&ret, &boundFunc] {
+ bool success = timeout(wait, [&ret, &boundFunc] {
ret = std::move(boundFunc());
});
if (!success) {
@@ -93,5 +94,12 @@
return ret;
}
+template<class Function, class I, class... Args>
+typename std::result_of<Function(I *, Args...)>::type
+timeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) {
+ return timeoutIPC(IPC_CALL_WAIT, interfaceObject, func, args...);
+}
+
+
} // namespace lshal
} // namespace android
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 39d92a7..d3d396f 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -46,7 +46,6 @@
cflags: [
"-DVENDORSERVICEMANAGER=1",
],
- shared_libs: ["libcutils"],
- static_libs: ["libselinux"],
+ shared_libs: ["libcutils", "libselinux_vendor"],
init_rc: ["vndservicemanager.rc"],
}
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 45bb1d0..d5cfcaf 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -287,7 +287,11 @@
}
if (sehandle && selinux_status_updated() > 0) {
+#ifdef VENDORSERVICEMANAGER
+ struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle();
+#else
struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
+#endif
if (tmp_sehandle) {
selabel_close(sehandle);
sehandle = tmp_sehandle;
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index aec211a..d336a43 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -12,3 +12,4 @@
onrestart restart drm
onrestart restart cameraserver
writepid /dev/cpuset/system-background/tasks
+ shutdown critical
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index d5ddaaf..3fa4d7d 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -3,4 +3,4 @@
user system
group system readproc
writepid /dev/cpuset/system-background/tasks
-
+ shutdown critical
diff --git a/cmds/surfacereplayer/Android.bp b/cmds/surfacereplayer/Android.bp
new file mode 100644
index 0000000..d4c037a
--- /dev/null
+++ b/cmds/surfacereplayer/Android.bp
@@ -0,0 +1,4 @@
+subdirs = [
+ "proto",
+ "replayer",
+]
\ No newline at end of file
diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp
new file mode 100644
index 0000000..dda80bb
--- /dev/null
+++ b/cmds/surfacereplayer/proto/Android.bp
@@ -0,0 +1,10 @@
+cc_library_static {
+ name: "libtrace_proto",
+ srcs: [
+ "src/trace.proto",
+ ],
+ proto: {
+ type: "lite",
+ export_proto_headers: true,
+ },
+}
diff --git a/cmds/surfacereplayer/proto/Android.mk b/cmds/surfacereplayer/proto/Android.mk
deleted file mode 100644
index 3cf1148..0000000
--- a/cmds/surfacereplayer/proto/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Copyright (C) 2016 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.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-proto-files-under, src)
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := lite
-
-LOCAL_MODULE := libtrace_proto
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/cmds/surfacereplayer/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp
new file mode 100644
index 0000000..5caceec
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Android.bp
@@ -0,0 +1,66 @@
+cc_library_shared {
+ name: "libsurfacereplayer",
+ clang: true,
+ srcs: [
+ "BufferQueueScheduler.cpp",
+ "Event.cpp",
+ "Replayer.cpp",
+ ],
+ cppflags: [
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-format",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-float-conversion",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-float-equal",
+ "-Wno-sign-conversion",
+ "-Wno-padded",
+ "-std=c++14",
+ ],
+ static_libs: [
+ "libtrace_proto",
+ ],
+ shared_libs: [
+ "libEGL",
+ "libGLESv2",
+ "libbinder",
+ "liblog",
+ "libcutils",
+ "libgui",
+ "libui",
+ "libutils",
+ "libprotobuf-cpp-lite",
+ "libbase",
+ "libnativewindow",
+ ],
+ export_include_dirs: [
+ ".",
+ ],
+}
+
+cc_binary {
+ name: "surfacereplayer",
+ clang: true,
+ srcs: [
+ "Main.cpp",
+ ],
+ shared_libs: [
+ "libprotobuf-cpp-lite",
+ "libsurfacereplayer",
+ "libutils",
+ "libgui",
+ ],
+ static_libs: [
+ "libtrace_proto",
+ ],
+ cppflags: [
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-float-conversion",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-float-equal",
+ "-std=c++14",
+ ],
+}
diff --git a/cmds/surfacereplayer/replayer/Android.mk b/cmds/surfacereplayer/replayer/Android.mk
deleted file mode 100644
index 1dd926c..0000000
--- a/cmds/surfacereplayer/replayer/Android.mk
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright 2016 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.
-
-LOCAL_TARGET_DIR := $(TARGET_OUT_DATA)/local/tmp
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(call first-makefiles-under, /frameworks/native/cmds/surfacereplayer/proto)
-
-include $(CLEAR_VARS)
-
-LOCAL_CPPFLAGS := -Weverything -Werror
-LOCAL_CPPFLAGS := -Wno-unused-parameter
-LOCAL_CPPFLAGS := -Wno-format
-
-LOCAL_MODULE := libsurfacereplayer
-
-LOCAL_SRC_FILES := \
- BufferQueueScheduler.cpp \
- Event.cpp \
- Replayer.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libEGL \
- libGLESv2 \
- libbinder \
- liblog \
- libcutils \
- libgui \
- libui \
- libutils \
- libprotobuf-cpp-lite \
- libbase \
- libnativewindow \
-
-LOCAL_STATIC_LIBRARIES := \
- libtrace_proto \
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/..
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := surfacereplayer
-
-LOCAL_SRC_FILES := \
- Main.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libprotobuf-cpp-lite \
- libsurfacereplayer \
- libutils \
- libgui \
-
-LOCAL_STATIC_LIBRARIES := \
- libtrace_proto \
-
-LOCAL_CPPFLAGS := -Weverything -Werror
-LOCAL_CPPFLAGS := -Wno-unused-parameter
-
-LOCAL_MODULE_PATH := $(LOCAL_TARGET_DIR)
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/surfacereplayer/replayer/Main.cpp b/cmds/surfacereplayer/replayer/Main.cpp
index dd1dd7d..7090bdb 100644
--- a/cmds/surfacereplayer/replayer/Main.cpp
+++ b/cmds/surfacereplayer/replayer/Main.cpp
@@ -24,7 +24,7 @@
* 5. Exit successfully or print error statement
*/
-#include <replayer/Replayer.h>
+#include <Replayer.h>
#include <csignal>
#include <iostream>
diff --git a/data/etc/android.hardware.radio.xml b/data/etc/android.hardware.radio.xml
new file mode 100644
index 0000000..f718c47
--- /dev/null
+++ b/data/etc/android.hardware.radio.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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 broadcast radio. -->
+<permissions>
+ <feature name="android.hardware.radio" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.euicc.xml b/data/etc/android.hardware.telephony.euicc.xml
new file mode 100644
index 0000000..167ed6a
--- /dev/null
+++ b/data/etc/android.hardware.telephony.euicc.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<!-- Feature for devices with an eUICC. -->
+<permissions>
+ <feature name="android.hardware.telephony.euicc" />
+</permissions>
diff --git a/data/etc/android.hardware.wifi.passpoint.xml b/data/etc/android.hardware.wifi.passpoint.xml
new file mode 100644
index 0000000..4698bb3
--- /dev/null
+++ b/data/etc/android.hardware.wifi.passpoint.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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 feature indicating that the device includes WiFi Passpoint. -->
+<permissions>
+ <feature name="android.hardware.wifi.passpoint" />
+</permissions>
diff --git a/include/android/sensor.h b/include/android/sensor.h
index cdb3fff..97b4a2a 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -50,6 +50,7 @@
#include <android/looper.h>
+#include <stdbool.h>
#include <sys/types.h>
#include <math.h>
#include <stdint.h>
diff --git a/include/gui b/include/gui
new file mode 120000
index 0000000..3b796f3
--- /dev/null
+++ b/include/gui
@@ -0,0 +1 @@
+../libs/gui/include/gui
\ No newline at end of file
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 7d56bf5..949781c 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -73,6 +73,7 @@
nsecs_t eventTime __attribute__((aligned(8)));
int32_t deviceId;
int32_t source;
+ int32_t displayId;
int32_t action;
int32_t flags;
int32_t keyCode;
@@ -92,6 +93,7 @@
nsecs_t eventTime __attribute__((aligned(8)));
int32_t deviceId;
int32_t source;
+ int32_t displayId;
int32_t action;
int32_t actionButton;
int32_t flags;
@@ -243,6 +245,7 @@
uint32_t seq,
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t actionButton,
int32_t flags,
@@ -314,7 +317,7 @@
* Other errors probably indicate that the channel is broken.
*/
status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
/* Sends a finished signal to the publisher to inform it that the message
* with the specified sequence number has finished being process and whether
@@ -435,9 +438,10 @@
Vector<SeqChain> mSeqChains;
status_t consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
status_t consumeSamples(InputEventFactoryInterface* factory,
- Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
+ Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent,
+ int32_t* displayId);
void updateTouchState(InputMessage* msg);
void rewriteMessage(const TouchState& state, InputMessage* msg);
diff --git a/include/media/hardware/HDCPAPI.h b/include/media/hardware/HDCPAPI.h
index 30cd5fd..7797bb2 100644
--- a/include/media/hardware/HDCPAPI.h
+++ b/include/media/hardware/HDCPAPI.h
@@ -15,11 +15,10 @@
*/
#ifndef HDCP_API_H_
-
#define HDCP_API_H_
#include <utils/Errors.h>
-#include <system/window.h>
+#include <cutils/native_handle.h>
namespace android {
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index cecf715..6c1ba3d 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -20,13 +20,15 @@
#include <media/hardware/OMXPluginBase.h>
#include <media/hardware/MetadataBufferType.h>
-#include <system/window.h>
+#include <cutils/native_handle.h>
#include <utils/RefBase.h>
#include "VideoAPI.h"
#include <OMX_Component.h>
+struct ANativeWindowBuffer;
+
namespace android {
// This structure is used to enable Android native buffer use for either
diff --git a/include/private/gui b/include/private/gui
new file mode 120000
index 0000000..99de2dc
--- /dev/null
+++ b/include/private/gui
@@ -0,0 +1 @@
+../../libs/gui/include/private/gui
\ No newline at end of file
diff --git a/include/ui b/include/ui
new file mode 120000
index 0000000..2fb3147
--- /dev/null
+++ b/include/ui
@@ -0,0 +1 @@
+../libs/ui/include/ui
\ No newline at end of file
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 0d25176..a20154f 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -23,5 +23,6 @@
cc_library_static {
name: "libarect",
host_supported: true,
+ vendor_available: true,
export_include_dirs: ["include"],
}
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 204fdb5..3a353c2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -15,6 +15,7 @@
cc_library_headers {
name: "libbinder_headers",
export_include_dirs: ["include"],
+ vendor_available: true,
}
cc_library {
@@ -74,13 +75,18 @@
"libcutils",
"libutils",
],
+
+ header_libs: [
+ "libbinder_headers",
+ ],
+
export_shared_lib_headers: [
"libbase",
"libutils",
],
- export_include_dirs: [
- "include",
+ export_header_lib_headers: [
+ "libbinder_headers",
],
clang: true,
diff --git a/libs/binder/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h
index d5b57ac..a9166e2 100644
--- a/libs/binder/include/binder/Parcelable.h
+++ b/libs/binder/include/binder/Parcelable.h
@@ -36,6 +36,9 @@
public:
virtual ~Parcelable() = default;
+ Parcelable() = default;
+ Parcelable(const Parcelable&) = default;
+
// Write |this| parcelable to the given |parcel|. Keep in mind that
// implementations of writeToParcel must be manually kept in sync
// with readFromParcel and the Java equivalent versions of these methods.
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
new file mode 100644
index 0000000..f2686d5
--- /dev/null
+++ b/libs/graphicsenv/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2017 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: "libgraphicsenv",
+
+ srcs: [
+ "GraphicsEnv.cpp",
+ ],
+
+ shared_libs: [
+ "libnativeloader",
+ "liblog",
+ ],
+
+ export_include_dirs: ["include"],
+}
diff --git a/libs/ui/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
similarity index 98%
rename from libs/ui/GraphicsEnv.cpp
rename to libs/graphicsenv/GraphicsEnv.cpp
index 8182c07..39b5829 100644
--- a/libs/ui/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -16,7 +16,7 @@
//#define LOG_NDEBUG 1
#define LOG_TAG "GraphicsEnv"
-#include <ui/GraphicsEnv.h>
+#include <graphicsenv/GraphicsEnv.h>
#include <mutex>
diff --git a/include/ui/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
similarity index 100%
rename from include/ui/GraphicsEnv.h
rename to libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index a07726a..4558fe8 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -11,9 +11,15 @@
// 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_headers {
+ name: "libgui_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
cc_library_shared {
name: "libgui",
+ vendor_available: true,
clang: true,
cppflags: [
@@ -111,20 +117,30 @@
"liblog",
"libhidlbase",
"libhidltransport",
- "android.hidl.base@1.0",
"android.hidl.token@1.0-utils",
"android.hardware.graphics.bufferqueue@1.0",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
],
+ header_libs: [
+ "libnativebase_headers",
+ "libgui_headers",
+ ],
+
export_shared_lib_headers: [
"libbinder",
+ "libEGL",
+ "libnativewindow",
"libui",
"android.hidl.token@1.0-utils",
"android.hardware.graphics.bufferqueue@1.0",
],
+ export_header_lib_headers: [
+ "libgui_headers",
+ ],
+
export_include_dirs: [
"include",
],
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 5e5de44..168d355 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -36,6 +36,8 @@
#include <binder/PermissionCache.h>
#include <private/android_filesystem_config.h>
+#include <system/window.h>
+
namespace android {
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
@@ -701,9 +703,9 @@
return NO_ERROR;
}
-status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) {
+status_t BufferQueueConsumer::setConsumerUsageBits(uint64_t usage) {
ATRACE_CALL();
- BQ_LOGV("setConsumerUsageBits: %#x", usage);
+ BQ_LOGV("setConsumerUsageBits: %#" PRIx64, usage);
Mutex::Autolock lock(mCore->mMutex);
mCore->mConsumerUsageBits = usage;
return NO_ERROR;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index cfb25e0..bb703da 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -38,6 +38,8 @@
#include <gui/ISurfaceComposer.h>
#include <private/gui/ComposerService.h>
+#include <system/window.h>
+
namespace android {
static String8 getUniqueName() {
@@ -110,54 +112,60 @@
void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
Mutex::Autolock lock(mMutex);
- String8 fifo;
+ outResult->appendFormat("%s- BufferQueue ", prefix.string());
+ outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
+ mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
+ outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(),
+ mDequeueBufferCannotBlock, mAsyncMode);
+ outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(),
+ mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
+ outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint,
+ mFrameCounter);
+
+ outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size());
Fifo::const_iterator current(mQueue.begin());
while (current != mQueue.end()) {
- fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
- "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n",
- current->mSlot, current->mGraphicBuffer.get(),
- current->mCrop.left, current->mCrop.top, current->mCrop.right,
- current->mCrop.bottom, current->mTransform, current->mTimestamp,
- BufferItem::scalingModeName(current->mScalingMode));
+ double timestamp = current->mTimestamp / 1e9;
+ outResult->appendFormat("%s %02d:%p ", prefix.string(), current->mSlot,
+ current->mGraphicBuffer.get());
+ outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top,
+ current->mCrop.right, current->mCrop.bottom);
+ outResult->appendFormat("xform=0x%02x time=%.4f scale=%s\n", current->mTransform, timestamp,
+ BufferItem::scalingModeName(current->mScalingMode));
++current;
}
- outResult->appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
- "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d "
- "mAsyncMode=%d, default-size=[%dx%d], default-format=%d, "
- "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix.string(),
- mMaxAcquiredBufferCount, mMaxDequeuedBufferCount,
- mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth,
- mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(),
- fifo.string());
-
+ outResult->appendFormat("%sSlots:\n", prefix.string());
for (int s : mActiveBuffers) {
const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
// A dequeued buffer might be null if it's still being allocated
if (buffer.get()) {
- outResult->appendFormat("%s%s[%02d:%p] state=%-8s, %p "
- "[%4ux%4u:%4u,%3X]\n", prefix.string(),
- (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
- buffer.get(), mSlots[s].mBufferState.string(),
- buffer->handle, buffer->width, buffer->height,
- buffer->stride, buffer->format);
+ outResult->appendFormat("%s %s[%02d:%p] ", prefix.string(),
+ (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
+ buffer.get());
+ outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
+ buffer->handle, mSlots[s].mFrameNumber);
+ outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
+ buffer->stride, buffer->format);
} else {
- outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
- buffer.get(), mSlots[s].mBufferState.string());
+ outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get());
+ outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n",
+ mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber);
}
}
for (int s : mFreeBuffers) {
const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
- outResult->appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
- prefix.string(), s, buffer.get(), mSlots[s].mBufferState.string(),
- buffer->handle, buffer->width, buffer->height, buffer->stride,
- buffer->format);
+ outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get());
+ outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
+ buffer->handle, mSlots[s].mFrameNumber);
+ outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
+ buffer->stride, buffer->format);
}
for (int s : mFreeSlots) {
const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
- outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
- buffer.get(), mSlots[s].mBufferState.string());
+ outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s, buffer.get(),
+ mSlots[s].mBufferState.string());
}
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 8385864..3d94a02 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -39,6 +39,8 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <system/window.h>
+
namespace android {
static constexpr uint32_t BQ_LAYER_COUNT = 1;
@@ -347,7 +349,7 @@
status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
sp<android::Fence> *outFence, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage,
+ PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps) {
ATRACE_CALL();
{ // Autolock scope
@@ -365,8 +367,7 @@
}
} // Autolock scope
- BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#x", width, height,
- format, usage);
+ BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#" PRIx64, width, height, format, usage);
if ((width && !height) || (!width && height)) {
BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
@@ -416,11 +417,9 @@
// buffer. If this buffer would require reallocation to meet the
// requested attributes, we free it and attempt to get another one.
if (!mCore->mAllowAllocation) {
- if (buffer->needsReallocation(width, height, format,
- BQ_LAYER_COUNT, usage)) {
+ if (buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
if (mCore->mSharedBufferSlot == found) {
- BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
- "buffer");
+ BQ_LOGE("dequeueBuffer: cannot re-allocate a sharedbuffer");
return BAD_VALUE;
}
mCore->mFreeSlots.insert(found);
@@ -433,8 +432,7 @@
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if (mCore->mSharedBufferSlot == found &&
- buffer->needsReallocation(width, height, format,
- BQ_LAYER_COUNT, usage)) {
+ buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
"buffer");
@@ -468,8 +466,7 @@
} else {
// We add 1 because that will be the frame number when this buffer
// is queued
- mCore->mBufferAge =
- mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
+ mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
@@ -1319,14 +1316,14 @@
}
void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) {
+ PixelFormat format, uint64_t usage) {
ATRACE_CALL();
while (true) {
size_t newBufferCount = 0;
uint32_t allocWidth = 0;
uint32_t allocHeight = 0;
PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN;
- uint32_t allocUsage = 0;
+ uint64_t allocUsage = 0;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked();
@@ -1360,7 +1357,7 @@
if (result != NO_ERROR) {
BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
- " %u, usage %u)", width, height, format, usage);
+ " %u, usage %#" PRIx64 ")", width, height, format, usage);
Mutex::Autolock lock(mCore->mMutex);
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.broadcast();
@@ -1375,7 +1372,7 @@
uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
PixelFormat checkFormat = format != 0 ?
format : mCore->mDefaultBufferFormat;
- uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
+ uint64_t checkUsage = usage | mCore->mConsumerUsageBits;
if (checkWidth != allocWidth || checkHeight != allocHeight ||
checkFormat != allocFormat || checkUsage != allocUsage) {
// Something changed while we released the lock. Retry.
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index c654f08..34c9d78 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -21,6 +21,8 @@
#define GL_GLEXT_PROTOTYPES
#define EGL_EGLEXT_PROTOTYPES
+#include <inttypes.h>
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
@@ -1219,7 +1221,7 @@
mEglDisplay = EGL_NO_DISPLAY;
mCropRect.makeInvalid();
const sp<GraphicBuffer>& buffer = mGraphicBuffer;
- ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d",
+ ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
buffer->getUsage(), buffer->getPixelFormat());
return UNKNOWN_ERROR;
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index a573bee..c705d39 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -132,7 +132,7 @@
return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_DATA_SPACE, defaultDataSpace);
}
- status_t setConsumerUsageBits(uint32_t usage) override {
+ status_t setConsumerUsageBits(uint64_t usage) override {
using Signature = decltype(&IGraphicBufferConsumer::setConsumerUsageBits);
return callRemote<Signature>(Tag::SET_CONSUMER_USAGE_BITS, usage);
}
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index bca645f..1b0fe06 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -73,7 +73,7 @@
{
}
- virtual ~BpGraphicBufferProducer();
+ ~BpGraphicBufferProducer() override;
virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
Parcel data, reply;
@@ -125,7 +125,7 @@
}
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,
- uint32_t height, PixelFormat format, uint32_t usage,
+ uint32_t height, PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps) {
Parcel data, reply;
bool getFrameTimestamps = (outTimestamps != nullptr);
@@ -134,7 +134,7 @@
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
- data.writeUint32(usage);
+ data.writeUint64(usage);
data.writeBool(getFrameTimestamps);
status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
@@ -333,13 +333,13 @@
}
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) {
+ PixelFormat format, uint64_t usage) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
- data.writeUint32(usage);
+ data.writeUint64(usage);
status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply);
if (result != NO_ERROR) {
ALOGE("allocateBuffers failed to transact: %d", result);
@@ -517,7 +517,7 @@
}
status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
- PixelFormat format, uint32_t usage,
+ PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps) override {
return mBase->dequeueBuffer(
slot, fence, w, h, format, usage, outTimestamps);
@@ -569,7 +569,7 @@
}
void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) override {
+ PixelFormat format, uint64_t usage) override {
return mBase->allocateBuffers(width, height, format, usage);
}
@@ -654,7 +654,7 @@
uint32_t width = data.readUint32();
uint32_t height = data.readUint32();
PixelFormat format = static_cast<PixelFormat>(data.readInt32());
- uint32_t usage = data.readUint32();
+ uint64_t usage = data.readUint64();
bool getTimestamps = data.readBool();
int buf = 0;
@@ -777,7 +777,7 @@
uint32_t width = data.readUint32();
uint32_t height = data.readUint32();
PixelFormat format = static_cast<PixelFormat>(data.readInt32());
- uint32_t usage = data.readUint32();
+ uint64_t usage = data.readUint64();
allocateBuffers(width, height, format, usage);
return NO_ERROR;
}
diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp
index bafe947..52c9067 100644
--- a/libs/gui/StreamSplitter.cpp
+++ b/libs/gui/StreamSplitter.cpp
@@ -31,6 +31,8 @@
#include <utils/Trace.h>
+#include <system/window.h>
+
namespace android {
status_t StreamSplitter::createSplitter(
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 7b2b5c3..409a3cb 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -20,6 +20,8 @@
#include <gui/Surface.h>
+#include <inttypes.h>
+
#include <android/native_window.h>
#include <utils/Log.h>
@@ -471,7 +473,7 @@
uint32_t reqWidth;
uint32_t reqHeight;
PixelFormat reqFormat;
- uint32_t reqUsage;
+ uint64_t reqUsage;
bool enableFrameTimestamps;
{
@@ -511,8 +513,8 @@
if (result < 0) {
ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer"
- "(%d, %d, %d, %d) failed: %d", reqWidth, reqHeight, reqFormat,
- reqUsage, result);
+ "(%d, %d, %d, %#" PRIx64 ") failed: %d",
+ reqWidth, reqHeight, reqFormat, reqUsage, result);
return result;
}
@@ -962,6 +964,9 @@
case NATIVE_WINDOW_GET_HDR_SUPPORT:
res = dispatchGetHdrSupport(args);
break;
+ case NATIVE_WINDOW_SET_USAGE64:
+ res = dispatchSetUsage64(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -980,8 +985,13 @@
}
int Surface::dispatchSetUsage(va_list args) {
- int usage = va_arg(args, int);
- return setUsage(static_cast<uint32_t>(usage));
+ uint64_t usage = va_arg(args, uint32_t);
+ return setUsage(usage);
+}
+
+int Surface::dispatchSetUsage64(va_list args) {
+ uint64_t usage = va_arg(args, uint64_t);
+ return setUsage(usage);
}
int Surface::dispatchSetCrop(va_list args) {
@@ -1259,8 +1269,7 @@
uint32_t priorGeneration = graphicBuffer->mGenerationNumber;
graphicBuffer->mGenerationNumber = mGenerationNumber;
int32_t attachedSlot = -1;
- status_t result = mGraphicBufferProducer->attachBuffer(
- &attachedSlot, graphicBuffer);
+ status_t result = mGraphicBufferProducer->attachBuffer(&attachedSlot, graphicBuffer);
if (result != NO_ERROR) {
ALOGE("attachBuffer: IGraphicBufferProducer call failed (%d)", result);
graphicBuffer->mGenerationNumber = priorGeneration;
@@ -1274,7 +1283,7 @@
return NO_ERROR;
}
-int Surface::setUsage(uint32_t reqUsage)
+int Surface::setUsage(uint64_t reqUsage)
{
ALOGV("Surface::setUsage");
Mutex::Autolock lock(mMutex);
@@ -1521,6 +1530,9 @@
const Region& reg,
int *dstFenceFd)
{
+ if (dst->getId() == src->getId())
+ return OK;
+
// src and dst with, height and format must be identical. no verification
// is done here.
status_t err;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8c83843..7ae2672 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1080,5 +1080,9 @@
return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format);
}
+android_dataspace ScreenshotClient::getDataSpace() const {
+ return mBuffer.dataSpace;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index 24a51cd..9083d1d 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -125,7 +125,7 @@
t->attr.stride = l.getStride();
t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
t->attr.layerCount = l.getLayerCount();
- t->attr.usage = l.getUsage();
+ t->attr.usage = uint32_t(l.getUsage()); // FIXME: need 64-bits usage version
t->attr.id = l.getId();
t->attr.generationNumber = l.getGenerationNumber();
t->nativeHandle = hidl_handle(l.handle);
@@ -988,14 +988,15 @@
return toStatusT(mBase->setAsyncMode(async));
}
+// FIXME: usage bits truncated -- needs a 64-bits usage version
status_t H2BGraphicBufferProducer::dequeueBuffer(
int* slot, sp<Fence>* fence,
uint32_t w, uint32_t h, ::android::PixelFormat format,
- uint32_t usage, FrameEventHistoryDelta* outTimestamps) {
+ uint64_t usage, FrameEventHistoryDelta* outTimestamps) {
*fence = new Fence();
status_t fnStatus;
status_t transStatus = toStatusT(mBase->dequeueBuffer(
- w, h, static_cast<PixelFormat>(format), usage,
+ w, h, static_cast<PixelFormat>(format), uint32_t(usage),
outTimestamps != nullptr,
[&fnStatus, slot, fence, outTimestamps] (
Status status,
@@ -1144,10 +1145,11 @@
return toStatusT(mBase->setSidebandStream(stream == nullptr ? nullptr : stream->handle()));
}
+// FIXME: usage bits truncated -- needs a 64-bits usage version
void H2BGraphicBufferProducer::allocateBuffers(uint32_t width, uint32_t height,
- ::android::PixelFormat format, uint32_t usage) {
+ ::android::PixelFormat format, uint64_t usage) {
mBase->allocateBuffers(
- width, height, static_cast<PixelFormat>(format), usage);
+ width, height, static_cast<PixelFormat>(format), uint32_t(usage));
}
status_t H2BGraphicBufferProducer::allowAllocation(bool allow) {
diff --git a/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h
similarity index 100%
rename from include/gui/BufferItem.h
rename to libs/gui/include/gui/BufferItem.h
diff --git a/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
similarity index 98%
rename from include/gui/BufferItemConsumer.h
rename to libs/gui/include/gui/BufferItemConsumer.h
index db7e944..217fe6a 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -55,7 +55,7 @@
uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
bool controlledByApp = false);
- virtual ~BufferItemConsumer();
+ ~BufferItemConsumer() override;
// set the name of the BufferItemConsumer that will be used to identify it in
// log messages.
diff --git a/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
similarity index 98%
rename from include/gui/BufferQueue.h
rename to libs/gui/include/gui/BufferQueue.h
index bd62d85..ba5cbf7 100644
--- a/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -57,7 +57,7 @@
class ProxyConsumerListener : public BnConsumerListener {
public:
explicit ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
- virtual ~ProxyConsumerListener();
+ ~ProxyConsumerListener() override;
void onDisconnect() override;
void onFrameAvailable(const BufferItem& item) override;
void onFrameReplaced(const BufferItem& item) override;
diff --git a/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
similarity index 97%
rename from include/gui/BufferQueueConsumer.h
rename to libs/gui/include/gui/BufferQueueConsumer.h
index b383056..d108120 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -32,7 +32,7 @@
public:
BufferQueueConsumer(const sp<BufferQueueCore>& core);
- virtual ~BufferQueueConsumer();
+ ~BufferQueueConsumer() override;
// acquireBuffer attempts to acquire ownership of the next pending buffer in
// the BufferQueue. If no buffer is pending then it returns
@@ -121,13 +121,12 @@
// GraphicBuffers of a defaultDataSpace if no data space is specified
// in queueBuffer.
// The initial default is HAL_DATASPACE_UNKNOWN
- virtual status_t setDefaultBufferDataSpace(
- android_dataspace defaultDataSpace);
+ virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
// setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
// These are merged with the bits passed to dequeueBuffer. The values are
// enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
- virtual status_t setConsumerUsageBits(uint32_t usage);
+ virtual status_t setConsumerUsageBits(uint64_t usage) override;
// setConsumerIsProtected will turn on an internal bit that indicates whether
// the consumer can handle protected gralloc buffers (i.e. with
diff --git a/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
similarity index 99%
rename from include/gui/BufferQueueCore.h
rename to libs/gui/include/gui/BufferQueueCore.h
index dd8b992..537c957 100644
--- a/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -170,7 +170,7 @@
// mConsumerUsageBits contains flags that the consumer wants for
// GraphicBuffers.
- uint32_t mConsumerUsageBits;
+ uint64_t mConsumerUsageBits;
// mConsumerIsProtected indicates the consumer is ready to handle protected
// buffer.
diff --git a/include/gui/BufferQueueDefs.h b/libs/gui/include/gui/BufferQueueDefs.h
similarity index 100%
rename from include/gui/BufferQueueDefs.h
rename to libs/gui/include/gui/BufferQueueDefs.h
diff --git a/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
similarity index 97%
rename from include/gui/BufferQueueProducer.h
rename to libs/gui/include/gui/BufferQueueProducer.h
index 5541468..0f8917a 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -30,7 +30,7 @@
friend class BufferQueue; // Needed to access binderDied
BufferQueueProducer(const sp<BufferQueueCore>& core, bool consumerIsSurfaceFlinger = false);
- virtual ~BufferQueueProducer();
+ ~BufferQueueProducer() override;
// requestBuffer returns the GraphicBuffer for slot N.
//
@@ -80,9 +80,9 @@
//
// In both cases, the producer will need to call requestBuffer to get a
// GraphicBuffer handle for the returned slot.
- status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence,
+ virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
- uint32_t usage, FrameEventHistoryDelta* outTimestamps) override;
+ uint64_t usage, FrameEventHistoryDelta* outTimestamps) override;
// See IGraphicBufferProducer::detachBuffer
virtual status_t detachBuffer(int slot);
@@ -152,7 +152,7 @@
// See IGraphicBufferProducer::allocateBuffers
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage);
+ PixelFormat format, uint64_t usage) override;
// See IGraphicBufferProducer::allowAllocation
virtual status_t allowAllocation(bool allow);
diff --git a/include/gui/BufferSlot.h b/libs/gui/include/gui/BufferSlot.h
similarity index 100%
rename from include/gui/BufferSlot.h
rename to libs/gui/include/gui/BufferSlot.h
diff --git a/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
similarity index 99%
rename from include/gui/ConsumerBase.h
rename to libs/gui/include/gui/ConsumerBase.h
index 891290b..e9fc8fd 100644
--- a/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -47,7 +47,7 @@
virtual void onFrameReplaced(const BufferItem& /* item */) {}
};
- virtual ~ConsumerBase();
+ ~ConsumerBase() override;
// abandon frees all the buffers and puts the ConsumerBase into the
// 'abandoned' state. Once put in this state the ConsumerBase can never
diff --git a/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
similarity index 100%
rename from include/gui/CpuConsumer.h
rename to libs/gui/include/gui/CpuConsumer.h
diff --git a/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
similarity index 100%
rename from include/gui/DisplayEventReceiver.h
rename to libs/gui/include/gui/DisplayEventReceiver.h
diff --git a/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
similarity index 100%
rename from include/gui/FrameTimestamps.h
rename to libs/gui/include/gui/FrameTimestamps.h
diff --git a/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
similarity index 100%
rename from include/gui/GLConsumer.h
rename to libs/gui/include/gui/GLConsumer.h
diff --git a/include/gui/GuiConfig.h b/libs/gui/include/gui/GuiConfig.h
similarity index 100%
rename from include/gui/GuiConfig.h
rename to libs/gui/include/gui/GuiConfig.h
diff --git a/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
similarity index 100%
rename from include/gui/IConsumerListener.h
rename to libs/gui/include/gui/IConsumerListener.h
diff --git a/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
similarity index 100%
rename from include/gui/IDisplayEventConnection.h
rename to libs/gui/include/gui/IDisplayEventConnection.h
diff --git a/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
similarity index 99%
rename from include/gui/IGraphicBufferConsumer.h
rename to libs/gui/include/gui/IGraphicBufferConsumer.h
index 3d069df..9fb7580 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -241,7 +241,7 @@
// e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
//
// Return of a value other than NO_ERROR means an unknown error has occurred.
- virtual status_t setConsumerUsageBits(uint32_t usage) = 0;
+ virtual status_t setConsumerUsageBits(uint64_t usage) = 0;
// setConsumerIsProtected will turn on an internal bit that indicates whether
// the consumer can handle protected gralloc buffers (i.e. with
diff --git a/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
similarity index 99%
rename from include/gui/IGraphicBufferProducer.h
rename to libs/gui/include/gui/IGraphicBufferProducer.h
index 9250806..6d16e74 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -195,7 +195,7 @@
// All other negative values are an unknown error returned downstream
// from the graphics allocator (typically errno).
virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
- uint32_t h, PixelFormat format, uint32_t usage,
+ uint32_t h, PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps) = 0;
// detachBuffer attempts to remove all ownership of the buffer in the given
@@ -517,7 +517,7 @@
// dequeueBuffer. If there are already the maximum number of buffers
// allocated, this function has no effect.
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) = 0;
+ PixelFormat format, uint64_t usage) = 0;
// Sets whether dequeueBuffer is allowed to allocate new buffers.
//
diff --git a/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
similarity index 100%
rename from include/gui/IProducerListener.h
rename to libs/gui/include/gui/IProducerListener.h
diff --git a/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
similarity index 100%
rename from include/gui/ISurfaceComposer.h
rename to libs/gui/include/gui/ISurfaceComposer.h
diff --git a/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
similarity index 100%
rename from include/gui/ISurfaceComposerClient.h
rename to libs/gui/include/gui/ISurfaceComposerClient.h
diff --git a/include/gui/OccupancyTracker.h b/libs/gui/include/gui/OccupancyTracker.h
similarity index 100%
rename from include/gui/OccupancyTracker.h
rename to libs/gui/include/gui/OccupancyTracker.h
diff --git a/include/gui/StreamSplitter.h b/libs/gui/include/gui/StreamSplitter.h
similarity index 100%
rename from include/gui/StreamSplitter.h
rename to libs/gui/include/gui/StreamSplitter.h
diff --git a/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
similarity index 98%
rename from include/gui/Surface.h
rename to libs/gui/include/gui/Surface.h
index e8dc83e..0f7e12a 100644
--- a/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -27,7 +27,7 @@
#include <utils/Mutex.h>
#include <utils/RefBase.h>
-struct ANativeWindow_Buffer;
+#include <system/window.h>
namespace android {
@@ -207,8 +207,8 @@
int dispatchSetBuffersStickyTransform(va_list args);
int dispatchSetBuffersTimestamp(va_list args);
int dispatchSetCrop(va_list args);
- int dispatchSetPostTransformCrop(va_list args);
int dispatchSetUsage(va_list args);
+ int dispatchSetUsage64(va_list args);
int dispatchLock(va_list args);
int dispatchUnlockAndPost(va_list args);
int dispatchSetSidebandStream(va_list args);
@@ -242,7 +242,7 @@
virtual int setBuffersTimestamp(int64_t timestamp);
virtual int setBuffersDataSpace(android_dataspace dataSpace);
virtual int setCrop(Rect const* rect);
- virtual int setUsage(uint32_t reqUsage);
+ virtual int setUsage(uint64_t reqUsage);
virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
public:
@@ -321,7 +321,7 @@
// mReqUsage is the set of buffer usage flags that will be requested
// at the next deuque operation. It is initialized to 0.
- uint32_t mReqUsage;
+ uint64_t mReqUsage;
// mTimestamp is the timestamp that will be used for the next buffer queue
// operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
diff --git a/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
similarity index 99%
rename from include/gui/SurfaceComposerClient.h
rename to libs/gui/include/gui/SurfaceComposerClient.h
index ec310cf..145c059 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -271,6 +271,7 @@
uint32_t getStride() const;
// size of allocated memory in bytes
size_t getSize() const;
+ android_dataspace getDataSpace() const;
};
// ---------------------------------------------------------------------------
diff --git a/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
similarity index 100%
rename from include/gui/SurfaceControl.h
rename to libs/gui/include/gui/SurfaceControl.h
diff --git a/include/gui/bufferqueue/1.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
similarity index 100%
rename from include/gui/bufferqueue/1.0/B2HProducerListener.h
rename to libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
diff --git a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
similarity index 96%
rename from include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
rename to libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
index 93c452a..c3a9d44 100644
--- a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -65,7 +65,7 @@
status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
status_t setAsyncMode(bool async) override;
status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
- uint32_t h, ::android::PixelFormat format, uint32_t usage,
+ uint32_t h, ::android::PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps) override;
status_t detachBuffer(int slot) override;
status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence)
@@ -83,7 +83,7 @@
override;
status_t setSidebandStream(const sp<NativeHandle>& stream) override;
void allocateBuffers(uint32_t width, uint32_t height,
- ::android::PixelFormat format, uint32_t usage) override;
+ ::android::PixelFormat format, uint64_t usage) override;
status_t allowAllocation(bool allow) override;
status_t setGenerationNumber(uint32_t generationNumber) override;
String8 getConsumerName() const override;
diff --git a/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h
similarity index 100%
rename from include/gui/view/Surface.h
rename to libs/gui/include/gui/view/Surface.h
diff --git a/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h
similarity index 100%
rename from include/private/gui/ComposerService.h
rename to libs/gui/include/private/gui/ComposerService.h
diff --git a/include/private/gui/LayerState.h b/libs/gui/include/private/gui/LayerState.h
similarity index 100%
rename from include/private/gui/LayerState.h
rename to libs/gui/include/private/gui/LayerState.h
diff --git a/include/private/gui/SyncFeatures.h b/libs/gui/include/private/gui/SyncFeatures.h
similarity index 100%
rename from include/private/gui/SyncFeatures.h
rename to libs/gui/include/private/gui/SyncFeatures.h
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 7efdb14..fa87f29 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -4,6 +4,7 @@
// to integrate with auto-test framework.
cc_test {
name: "libgui_test",
+ test_suites: ["device-tests"],
clang: true,
diff --git a/libs/gui/tests/AndroidTest.xml b/libs/gui/tests/AndroidTest.xml
new file mode 100644
index 0000000..c02e020
--- /dev/null
+++ b/libs/gui/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for libgui_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libgui_test->/data/local/tmp/libgui_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="libgui_test" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 60c1277..4220aaf 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -32,6 +32,8 @@
#include <utils/String8.h>
#include <utils/threads.h>
+#include <system/window.h>
+
#include <gtest/gtest.h>
#include <thread>
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index aa071f6..bcfc91c 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -29,6 +29,8 @@
#include <gui/BufferQueue.h>
#include <gui/IProducerListener.h>
+#include <system/window.h>
+
#include <vector>
#define ASSERT_OK(x) ASSERT_EQ(OK, (x))
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
index 7ecf08c..6bc3ccf 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -38,7 +38,7 @@
}
status_t setAsyncMode(bool async) override { return mProducer->setAsyncMode(async); }
status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format,
- uint32_t usage, FrameEventHistoryDelta* outTimestamps) override {
+ uint64_t usage, FrameEventHistoryDelta* outTimestamps) override {
return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outTimestamps);
}
status_t detachBuffer(int slot) override { return mProducer->detachBuffer(slot); }
@@ -67,7 +67,7 @@
return mProducer->setSidebandStream(stream);
}
void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
- uint32_t usage) override {
+ uint64_t usage) override {
mProducer->allocateBuffers(width, height, format, usage);
}
status_t allowAllocation(bool allow) override { return mProducer->allowAllocation(allow); }
@@ -105,7 +105,7 @@
// Override dequeueBuffer, optionally corrupting the returned slot number
status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage,
+ PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps) override {
EXPECT_EQ(BUFFER_NEEDS_REALLOCATION,
mProducer->dequeueBuffer(buf, fence, width, height, format, usage,
diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp
index 80e30da..e2f4948 100644
--- a/libs/gui/tests/StreamSplitter_test.cpp
+++ b/libs/gui/tests/StreamSplitter_test.cpp
@@ -24,6 +24,8 @@
#include <gui/StreamSplitter.h>
#include <private/gui/ComposerService.h>
+#include <system/window.h>
+
#include <gtest/gtest.h>
namespace android {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index c18739a..de06292 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -383,6 +383,7 @@
uint32_t seq,
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t actionButton,
int32_t flags,
@@ -425,6 +426,7 @@
msg.body.motion.seq = seq;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
+ msg.body.motion.displayId = displayId;
msg.body.motion.action = action;
msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
@@ -494,7 +496,8 @@
}
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
- bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+ bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
+ int32_t* displayId) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
@@ -502,6 +505,7 @@
*outSeq = 0;
*outEvent = NULL;
+ *displayId = -1; // Invalid display.
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
@@ -516,7 +520,7 @@
if (result) {
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
- result = consumeBatch(factory, frameTime, outSeq, outEvent);
+ result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId);
if (*outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
@@ -560,7 +564,7 @@
// the previous batch right now and defer the new message until later.
mMsgDeferred = true;
status_t result = consumeSamples(factory,
- batch, batch.samples.size(), outSeq, outEvent);
+ batch, batch.samples.size(), outSeq, outEvent, displayId);
mBatches.removeAt(batchIndex);
if (result) {
return result;
@@ -594,6 +598,7 @@
initializeMotionEvent(motionEvent, &mMsg);
*outSeq = mMsg.body.motion.seq;
*outEvent = motionEvent;
+ *displayId = mMsg.body.motion.displayId;
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
mChannel->getName().string(), *outSeq);
@@ -611,14 +616,14 @@
}
status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
- nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+ nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
status_t result;
for (size_t i = mBatches.size(); i > 0; ) {
i--;
Batch& batch = mBatches.editItemAt(i);
if (frameTime < 0) {
result = consumeSamples(factory, batch, batch.samples.size(),
- outSeq, outEvent);
+ outSeq, outEvent, displayId);
mBatches.removeAt(i);
return result;
}
@@ -632,7 +637,7 @@
continue;
}
- result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
+ result = consumeSamples(factory, batch, split + 1, outSeq, outEvent, displayId);
const InputMessage* next;
if (batch.samples.isEmpty()) {
mBatches.removeAt(i);
@@ -650,7 +655,7 @@
}
status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
- Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
+ Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
MotionEvent* motionEvent = factory->createMotionEvent();
if (! motionEvent) return NO_MEMORY;
@@ -665,6 +670,7 @@
mSeqChains.push(seqChain);
addSample(motionEvent, &msg);
} else {
+ *displayId = msg.body.motion.displayId;
initializeMotionEvent(motionEvent, &msg);
}
chain = msg.body.motion.seq;
@@ -940,15 +946,14 @@
}
if (status) {
// An error occurred so at least one signal was not sent, reconstruct the chain.
- do {
+ for (;;) {
SeqChain seqChain;
seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
seqChain.chain = chainSeqs[chainIndex];
mSeqChains.push(seqChain);
- if (chainIndex != 0) {
- chainIndex--;
- }
- } while (chainIndex > 0);
+ if (!chainIndex) break;
+ chainIndex--;
+ }
return status;
}
}
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 8e69c9c..a136738 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -89,7 +89,8 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+ 0);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -132,6 +133,7 @@
const uint32_t seq = 15;
const int32_t deviceId = 1;
const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+ const int32_t displayId = 0;
const int32_t action = AMOTION_EVENT_ACTION_MOVE;
const int32_t actionButton = 0;
const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
@@ -164,7 +166,7 @@
pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
}
- status = mPublisher->publishMotionEvent(seq, deviceId, source, action, actionButton,
+ status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
downTime, eventTime, pointerCount,
pointerProperties, pointerCoords);
@@ -173,7 +175,8 @@
uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+ 0);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -256,7 +259,7 @@
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -272,7 +275,7 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 89be55a..12a6782 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -38,31 +38,33 @@
CHECK_OFFSET(InputMessage::Body::Key, eventTime, 8);
CHECK_OFFSET(InputMessage::Body::Key, deviceId, 16);
CHECK_OFFSET(InputMessage::Body::Key, source, 20);
- CHECK_OFFSET(InputMessage::Body::Key, action, 24);
- CHECK_OFFSET(InputMessage::Body::Key, flags, 28);
- CHECK_OFFSET(InputMessage::Body::Key, keyCode, 32);
- CHECK_OFFSET(InputMessage::Body::Key, scanCode, 36);
- CHECK_OFFSET(InputMessage::Body::Key, metaState, 40);
- CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 44);
- CHECK_OFFSET(InputMessage::Body::Key, downTime, 48);
+ CHECK_OFFSET(InputMessage::Body::Key, displayId, 24);
+ CHECK_OFFSET(InputMessage::Body::Key, action, 28);
+ CHECK_OFFSET(InputMessage::Body::Key, flags, 32);
+ CHECK_OFFSET(InputMessage::Body::Key, keyCode, 36);
+ CHECK_OFFSET(InputMessage::Body::Key, scanCode, 40);
+ CHECK_OFFSET(InputMessage::Body::Key, metaState, 44);
+ CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 48);
+ CHECK_OFFSET(InputMessage::Body::Key, downTime, 56);
CHECK_OFFSET(InputMessage::Body::Motion, seq, 0);
CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8);
CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16);
CHECK_OFFSET(InputMessage::Body::Motion, source, 20);
- CHECK_OFFSET(InputMessage::Body::Motion, action, 24);
- CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 28);
- CHECK_OFFSET(InputMessage::Body::Motion, flags, 32);
- CHECK_OFFSET(InputMessage::Body::Motion, metaState, 36);
- CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 40);
- CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 44);
- CHECK_OFFSET(InputMessage::Body::Motion, downTime, 48);
- CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 56);
- CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 60);
- CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 64);
- CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 68);
- CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 72);
- CHECK_OFFSET(InputMessage::Body::Motion, pointers, 80);
+ CHECK_OFFSET(InputMessage::Body::Motion, displayId, 24);
+ CHECK_OFFSET(InputMessage::Body::Motion, action, 28);
+ CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 32);
+ CHECK_OFFSET(InputMessage::Body::Motion, flags, 36);
+ CHECK_OFFSET(InputMessage::Body::Motion, metaState, 40);
+ CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 44);
+ CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 48);
+ CHECK_OFFSET(InputMessage::Body::Motion, downTime, 56);
+ CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 64);
+ CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68);
+ CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 72);
+ CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 76);
+ CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 80);
+ CHECK_OFFSET(InputMessage::Body::Motion, pointers, 88);
CHECK_OFFSET(InputMessage::Body::Finished, seq, 0);
CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
diff --git a/libs/math/Android.bp b/libs/math/Android.bp
index 3ef8b4a..693bace 100644
--- a/libs/math/Android.bp
+++ b/libs/math/Android.bp
@@ -15,6 +15,7 @@
cc_library_static {
name: "libmath",
host_supported: true,
+ vendor_available: true,
export_include_dirs: ["include"],
}
diff --git a/libs/math/include/math/TMatHelpers.h b/libs/math/include/math/TMatHelpers.h
index 5cb725d..1423ade 100644
--- a/libs/math/include/math/TMatHelpers.h
+++ b/libs/math/include/math/TMatHelpers.h
@@ -342,9 +342,9 @@
template <typename MATRIX>
String8 asString(const MATRIX& m) {
String8 s;
- for (size_t c = 0; c < MATRIX::col_size(); c++) {
+ for (size_t c = 0; c < MATRIX::COL_SIZE; c++) {
s.append("| ");
- for (size_t r = 0; r < MATRIX::row_size(); r++) {
+ for (size_t r = 0; r < MATRIX::ROW_SIZE; r++) {
s.appendFormat("%7.2f ", m[r][c]);
}
s.append("|\n");
diff --git a/libs/math/include/math/half.h b/libs/math/include/math/half.h
index 615b840..7682973 100644
--- a/libs/math/include/math/half.h
+++ b/libs/math/include/math/half.h
@@ -56,8 +56,8 @@
*/
class half {
struct fp16 {
- uint16_t bits = 0;
- fp16() noexcept = default;
+ uint16_t bits;
+ explicit constexpr fp16() noexcept : bits(0) { }
explicit constexpr fp16(uint16_t b) noexcept : bits(b) { }
void setS(unsigned int s) noexcept { bits = uint16_t((bits & 0x7FFF) | (s<<15)); }
void setE(unsigned int s) noexcept { bits = uint16_t((bits & 0xE3FF) | (s<<10)); }
@@ -68,11 +68,11 @@
};
struct fp32 {
union {
- uint32_t bits = 0;
+ uint32_t bits;
float fp;
};
- fp32() noexcept = default;
- explicit constexpr fp32(float f) : fp(f) { }
+ explicit constexpr fp32() noexcept : bits(0) { }
+ explicit constexpr fp32(float f) noexcept : fp(f) { }
void setS(unsigned int s) noexcept { bits = uint32_t((bits & 0x7FFFFFFF) | (s<<31)); }
void setE(unsigned int s) noexcept { bits = uint32_t((bits & 0x807FFFFF) | (s<<23)); }
void setM(unsigned int s) noexcept { bits = uint32_t((bits & 0xFF800000) | (s<< 0)); }
diff --git a/libs/math/tests/mat_test.cpp b/libs/math/tests/mat_test.cpp
index c365366..3217a1a 100644
--- a/libs/math/tests/mat_test.cpp
+++ b/libs/math/tests/mat_test.cpp
@@ -487,7 +487,7 @@
for (size_t i = 0; i < v1.size(); ++i) { \
EXPECT_FLOAT_EQ(v1[i], v2[i]); \
} \
- } else if (std::is_same<TypeParam,float>::value) { \
+ } else if (std::is_same<TypeParam,double>::value) { \
for (size_t i = 0; i < v1.size(); ++i) { \
EXPECT_DOUBLE_EQ(v1[i], v2[i]); \
} \
@@ -506,7 +506,7 @@
const decltype(T2) t2 = T2; \
if (std::is_same<TypeParam,float>::value) { \
ASSERT_FLOAT_EQ(t1, t2); \
- } else if (std::is_same<TypeParam,float>::value) { \
+ } else if (std::is_same<TypeParam,double>::value) { \
ASSERT_DOUBLE_EQ(t1, t2); \
} else { \
ASSERT_EQ(t1, t2); \
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
new file mode 100644
index 0000000..7375a2b
--- /dev/null
+++ b/libs/nativebase/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2017 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_headers {
+ name: "libnativebase_headers",
+ vendor_available: true,
+ host_supported: true,
+ export_include_dirs: ["include"],
+
+ target: {
+ linux_bionic: {
+ enabled: true,
+ },
+ windows: {
+ enabled: true,
+ },
+ }
+}
diff --git a/libs/nativebase/MODULE_LICENSE_APACHE2 b/libs/nativebase/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/nativebase/MODULE_LICENSE_APACHE2
diff --git a/libs/nativebase/NOTICE b/libs/nativebase/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/nativebase/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/libs/nativebase/include/nativebase/nativebase.h b/libs/nativebase/include/nativebase/nativebase.h
new file mode 100644
index 0000000..7ecdfbd
--- /dev/null
+++ b/libs/nativebase/include/nativebase/nativebase.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 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 <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <system/graphics-base.h>
+#include <cutils/native_handle.h>
+
+__BEGIN_DECLS
+
+#ifdef __cplusplus
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
+#else
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x))
+#endif
+
+#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
+ ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
+ (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
+ (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \
+ (ANDROID_NATIVE_UNSIGNED_CAST(d)))
+
+#define ANDROID_NATIVE_BUFFER_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
+
+
+typedef struct android_native_base_t
+{
+ /* a magic value defined by the actual EGL native type */
+ int magic;
+
+ /* the sizeof() of the actual EGL native type */
+ int version;
+
+ void* reserved[4];
+
+ /* reference-counting interface */
+ void (*incRef)(struct android_native_base_t* base);
+ void (*decRef)(struct android_native_base_t* base);
+} android_native_base_t;
+
+typedef struct android_native_rect_t
+{
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+} android_native_rect_t;
+
+typedef struct ANativeWindowBuffer
+{
+#ifdef __cplusplus
+ ANativeWindowBuffer() {
+ common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+ common.version = sizeof(ANativeWindowBuffer);
+ memset(common.reserved, 0, sizeof(common.reserved));
+ }
+
+ // Implement the methods that sp<ANativeWindowBuffer> expects so that it
+ // can be used to automatically refcount ANativeWindowBuffer's.
+ void incStrong(const void* /*id*/) const {
+ common.incRef(const_cast<android_native_base_t*>(&common));
+ }
+ void decStrong(const void* /*id*/) const {
+ common.decRef(const_cast<android_native_base_t*>(&common));
+ }
+#endif
+
+ struct android_native_base_t common;
+
+ int width;
+ int height;
+ int stride;
+ int format;
+ int usage_deprecated;
+ uintptr_t layerCount;
+
+ void* reserved[1];
+
+ const native_handle_t* handle;
+ uint64_t usage;
+
+ // we needed extra space for storing the 64-bits usage flags
+ // the number of slots to use from reserved_proc depends on the
+ // architecture.
+ void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
+} ANativeWindowBuffer_t;
+
+typedef struct ANativeWindowBuffer ANativeWindowBuffer;
+
+// Old typedef for backwards compatibility.
+typedef ANativeWindowBuffer_t android_native_buffer_t;
+
+__END_DECLS
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index f64bab1..c6994c3 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "ANativeWindow"
-#include <android/native_window.h>
-
#include <grallocusage/GrallocUsageConversion.h>
// from nativewindow/includes/system/window.h
// (not to be confused with the compatibility-only window.h from system/core/includes)
@@ -192,8 +190,7 @@
}
int ANativeWindow_setUsage(ANativeWindow* window, uint64_t usage) {
- usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
- return native_window_set_usage(window, (uint32_t)usage); // FIXME: we need a 64-bits version
+ return native_window_set_usage(window, usage);
}
int ANativeWindow_setBufferCount(ANativeWindow* window, size_t bufferCount) {
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index d759acb..e61fbd6 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -57,10 +57,25 @@
"libgrallocusage",
],
+ header_libs: [
+ "libnativebase_headers",
+ ],
+
// headers we include in our public headers
export_static_lib_headers: [
"libarect",
],
+
+ export_header_lib_headers: [
+ "libnativebase_headers",
+ ],
+}
+
+llndk_library {
+ name: "libnativewindow",
+ symbol_file: "libnativewindow.map.txt",
+ unversioned: true,
+ export_include_dirs: ["include"],
}
subdirs = ["tests"]
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 45110c4..3df97a1 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -60,25 +60,6 @@
// ---------------------------------------------------------------------------
-typedef const native_handle_t* buffer_handle_t;
-
-// ---------------------------------------------------------------------------
-
-typedef struct android_native_rect_t
-{
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
-} android_native_rect_t;
-
-// ---------------------------------------------------------------------------
-
-// Old typedef for backwards compatibility.
-typedef ANativeWindowBuffer_t android_native_buffer_t;
-
-// ---------------------------------------------------------------------------
-
/* attributes queriable with query() */
enum {
NATIVE_WINDOW_WIDTH = 0,
@@ -212,36 +193,37 @@
*/
enum {
// clang-format off
- NATIVE_WINDOW_SET_USAGE = 0,
- NATIVE_WINDOW_CONNECT = 1, /* deprecated */
- NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
- NATIVE_WINDOW_SET_CROP = 3, /* private */
- NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
- NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
- NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
- NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
- NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
- NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
- NATIVE_WINDOW_LOCK = 11, /* private */
- NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
- NATIVE_WINDOW_API_CONNECT = 13, /* private */
- NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
- NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
- NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */
- NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
- NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
- NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
- NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
- NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
- NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
- NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION= 23,
- NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
- NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
- NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
- NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
- NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
- NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
+ NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */
+ NATIVE_WINDOW_CONNECT = 1, /* deprecated */
+ NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
+ NATIVE_WINDOW_SET_CROP = 3, /* private */
+ NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
+ NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
+ NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
+ NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
+ NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
+ NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
+ NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
+ NATIVE_WINDOW_LOCK = 11, /* private */
+ NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
+ NATIVE_WINDOW_API_CONNECT = 13, /* private */
+ NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
+ NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
+ NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */
+ NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */
+ NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
+ NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
+ NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
+ NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
+ NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
+ NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23,
+ NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
+ NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
+ NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
+ NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
+ NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
+ NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
+ NATIVE_WINDOW_SET_USAGE64 = 30,
// clang-format on
};
@@ -549,24 +531,21 @@
/* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C).
* android_native_window_t is deprecated.
*/
-typedef struct ANativeWindow ANativeWindow;
typedef struct ANativeWindow android_native_window_t __deprecated;
/*
- * native_window_set_usage(..., usage)
+ * native_window_set_usage64(..., usage)
* Sets the intended usage flags for the next buffers
* acquired with (*lockBuffer)() and on.
- * By default (if this function is never called), a usage of
- * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
- * is assumed.
+ *
+ * Valid usage flags are defined in android/hardware_buffer.h
+ * All AHARDWAREBUFFER_USAGE_* flags can be specified as needed.
+ *
* Calling this function will usually cause following buffers to be
* reallocated.
*/
-
-static inline int native_window_set_usage(
- struct ANativeWindow* window, int usage)
-{
- return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+static inline int native_window_set_usage(struct ANativeWindow* window, uint64_t usage) {
+ return window->perform(window, NATIVE_WINDOW_SET_USAGE64, usage);
}
/* deprecated. Always returns 0. Don't call. */
@@ -609,45 +588,6 @@
}
/*
- * native_window_set_post_transform_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * Depending on the scaling mode, a buffer's crop region is scaled and/or
- * cropped to match the surface's size. This function sets the crop in
- * post-transformed pixel coordinates.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * If 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid, out of the
- * buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_post_transform_crop(
- struct ANativeWindow* window,
- android_native_rect_t const * crop)
-{
- return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop);
-}
-
-/*
- * native_window_set_active_rect(..., active_rect)
- *
- * This function is deprecated and will be removed soon. For now it simply
- * sets the post-transform crop for compatibility while multi-project commits
- * get checked.
- */
-static inline int native_window_set_active_rect(
- struct ANativeWindow* window,
- android_native_rect_t const * active_rect) __deprecated;
-
-static inline int native_window_set_active_rect(
- struct ANativeWindow* window,
- android_native_rect_t const * active_rect)
-{
- return native_window_set_post_transform_crop(window, active_rect);
-}
-
-/*
* native_window_set_buffer_count(..., count)
* Sets the number of buffers associated with this native window.
*/
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
index 95618c4..a7b340a 100644
--- a/libs/nativewindow/include/vndk/window.h
+++ b/libs/nativewindow/include/vndk/window.h
@@ -17,88 +17,14 @@
#ifndef ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H
#define ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/cdefs.h>
-#include <system/graphics-base.h>
-#include <cutils/native_handle.h>
+#include <nativebase/nativebase.h>
// vndk is a superset of the NDK
#include <android/native_window.h>
+
__BEGIN_DECLS
-/*****************************************************************************/
-
-#ifdef __cplusplus
-#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
-#else
-#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x))
-#endif
-
-#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
- ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
- (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
- (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \
- (ANDROID_NATIVE_UNSIGNED_CAST(d)))
-
-#define ANDROID_NATIVE_BUFFER_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
-
-
-/*****************************************************************************/
-
-typedef struct android_native_base_t
-{
- /* a magic value defined by the actual EGL native type */
- int magic;
-
- /* the sizeof() of the actual EGL native type */
- int version;
-
- void* reserved[4];
-
- /* reference-counting interface */
- void (*incRef)(struct android_native_base_t* base);
- void (*decRef)(struct android_native_base_t* base);
-} android_native_base_t;
-
-typedef struct ANativeWindowBuffer
-{
-#ifdef __cplusplus
- ANativeWindowBuffer() {
- common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
- common.version = sizeof(ANativeWindowBuffer);
- memset(common.reserved, 0, sizeof(common.reserved));
- }
-
- // Implement the methods that sp<ANativeWindowBuffer> expects so that it
- // can be used to automatically refcount ANativeWindowBuffer's.
- void incStrong(const void* /*id*/) const {
- common.incRef(const_cast<android_native_base_t*>(&common));
- }
- void decStrong(const void* /*id*/) const {
- common.decRef(const_cast<android_native_base_t*>(&common));
- }
-#endif
-
- struct android_native_base_t common;
-
- int width;
- int height;
- int stride;
- int format;
- int usage;
- uintptr_t layerCount;
-
- void* reserved[1];
-
- const native_handle_t* handle;
-
- void* reserved_proc[8];
-} ANativeWindowBuffer_t;
-
-typedef struct ANativeWindowBuffer ANativeWindowBuffer;
-
/*
* Convert this ANativeWindowBuffer into a AHardwareBuffer
*/
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index b1d1a72..58045be 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -4,22 +4,40 @@
AHardwareBuffer_allocate;
AHardwareBuffer_describe;
AHardwareBuffer_fromHardwareBuffer;
+ AHardwareBuffer_getNativeHandle; # vndk
AHardwareBuffer_lock;
AHardwareBuffer_recvHandleFromUnixSocket;
AHardwareBuffer_release;
AHardwareBuffer_sendHandleToUnixSocket;
AHardwareBuffer_toHardwareBuffer;
AHardwareBuffer_unlock;
+ ANativeWindowBuffer_getHardwareBuffer; # vndk
+ ANativeWindow_OemStorageGet; # vndk
+ ANativeWindow_OemStorageSet; # vndk
ANativeWindow_acquire;
+ ANativeWindow_cancelBuffer; # vndk
+ ANativeWindow_dequeueBuffer; # vndk
ANativeWindow_fromSurface;
ANativeWindow_fromSurfaceTexture;
ANativeWindow_getFormat;
ANativeWindow_getHeight;
ANativeWindow_getWidth;
ANativeWindow_lock;
+ ANativeWindow_query; # vndk
+ ANativeWindow_queryf; # vndk
+ ANativeWindow_queueBuffer; # vndk
ANativeWindow_release;
+ ANativeWindow_setAutoRefresh; # vndk
+ ANativeWindow_setBufferCount; # vndk
+ ANativeWindow_setBufferDataSpace; # vndk
+ ANativeWindow_setBuffersDimensions; # vndk
+ ANativeWindow_setBuffersFormat; # vndk
ANativeWindow_setBuffersGeometry;
+ ANativeWindow_setBuffersTimestamp; # vndk
ANativeWindow_setBuffersTransform;
+ ANativeWindow_setSharedBufferMode; # vndk
+ ANativeWindow_setSwapInterval; # vndk
+ ANativeWindow_setUsage; # vndk
ANativeWindow_unlockAndPost;
local:
*;
diff --git a/libs/sensor/ISensorEventConnection.cpp b/libs/sensor/ISensorEventConnection.cpp
index 8a3a623..1cd8e01 100644
--- a/libs/sensor/ISensorEventConnection.cpp
+++ b/libs/sensor/ISensorEventConnection.cpp
@@ -36,7 +36,8 @@
ENABLE_DISABLE,
SET_EVENT_RATE,
FLUSH_SENSOR,
- CONFIGURE_CHANNEL
+ CONFIGURE_CHANNEL,
+ DESTROY,
};
class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
@@ -96,11 +97,22 @@
remote()->transact(CONFIGURE_CHANNEL, data, &reply);
return reply.readInt32();
}
+
+ virtual void onLastStrongRef(const void* id) {
+ destroy();
+ BpInterface<ISensorEventConnection>::onLastStrongRef(id);
+ }
+
+protected:
+ virtual void destroy() {
+ Parcel data, reply;
+ remote()->transact(DESTROY, data, &reply);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
// translation unit (see clang warning -Wweak-vtables)
-BpSensorEventConnection::~BpSensorEventConnection() {}
+BpSensorEventConnection::~BpSensorEventConnection() { }
IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection");
@@ -150,6 +162,10 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case DESTROY: {
+ destroy();
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index 74186df..f20668d 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -119,10 +119,12 @@
return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
}
- virtual int setOperationParameter(
- int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) {
+ virtual int setOperationParameter(int32_t handle, int32_t type,
+ const Vector<float> &floats,
+ const Vector<int32_t> &ints) {
Parcel data, reply;
data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+ data.writeInt32(handle);
data.writeInt32(type);
data.writeUint32(static_cast<uint32_t>(floats.size()));
for (auto i : floats) {
@@ -203,10 +205,12 @@
}
case SET_OPERATION_PARAMETER: {
CHECK_INTERFACE(ISensorServer, data, reply);
+ int32_t handle;
int32_t type;
Vector<float> floats;
Vector<int32_t> ints;
+ handle = data.readInt32();
type = data.readInt32();
floats.resize(data.readUint32());
for (auto &i : floats) {
@@ -217,7 +221,7 @@
i = data.readInt32();
}
- int32_t ret = setOperationParameter(type, floats, ints);
+ int32_t ret = setOperationParameter(handle, type, floats, ints);
reply->writeInt32(ret);
return NO_ERROR;
}
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index ae7e5f3..2383516 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -30,7 +30,7 @@
mName(name), mHandle(0), mType(0),
mMinValue(0), mMaxValue(0), mResolution(0),
mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0),
- mFifoMaxEventCount(0), mRequiredAppOp(0),
+ mFifoMaxEventCount(0), mRequiredAppOp(-1),
mMaxDelay(0), mFlags(0) {
}
@@ -38,7 +38,8 @@
Sensor(*hwSensor, uuid_t(), halVersion) {
}
-Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) {
+Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) :
+ Sensor("") {
mName = hwSensor.name;
mVendor = hwSensor.vendor;
mVersion = hwSensor.version;
@@ -412,6 +413,10 @@
return (mFlags & SENSOR_FLAG_DYNAMIC_SENSOR) != 0;
}
+bool Sensor::isDataInjectionSupported() const {
+ return (mFlags & SENSOR_FLAG_DATA_INJECTION) != 0;
+}
+
bool Sensor::hasAdditionalInfo() const {
return (mFlags & SENSOR_FLAG_ADDITIONAL_INFO) != 0;
}
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 1ab9489..5fbaf1b 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -305,12 +305,13 @@
}
int SensorManager::setOperationParameter(
- int type, const Vector<float> &floats, const Vector<int32_t> &ints) {
+ int handle, int type,
+ const Vector<float> &floats, const Vector<int32_t> &ints) {
Mutex::Autolock _l(mLock);
if (assertStateLocked() != NO_ERROR) {
return NO_INIT;
}
- return mSensorServer->setOperationParameter(type, floats, ints);
+ return mSensorServer->setOperationParameter(handle, type, floats, ints);
}
// ----------------------------------------------------------------------------
diff --git a/libs/sensor/include/sensor/ISensorEventConnection.h b/libs/sensor/include/sensor/ISensorEventConnection.h
index 07cc7e8..b62e18c 100644
--- a/libs/sensor/include/sensor/ISensorEventConnection.h
+++ b/libs/sensor/include/sensor/ISensorEventConnection.h
@@ -42,6 +42,8 @@
virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
virtual status_t flush() = 0;
virtual int32_t configureChannel(int32_t handle, int32_t rateLevel) = 0;
+protected:
+ virtual void destroy() = 0; // synchronously release resource hold by remote object
};
// ----------------------------------------------------------------------------
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index 8d50062..edf3e0f 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -52,7 +52,7 @@
uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) = 0;
virtual int setOperationParameter(
- int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) = 0;
+ int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 043e635..6926f7f 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -90,6 +90,7 @@
uint32_t getFlags() const;
bool isWakeUpSensor() const;
bool isDynamicSensor() const;
+ bool isDataInjectionSupported() const;
bool hasAdditionalInfo() const;
int32_t getHighestDirectReportRateLevel() const;
bool isDirectChannelTypeSupported(int32_t sharedMemType) const;
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 5fc85d3..23f7a91 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -64,7 +64,7 @@
int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData);
void destroyDirectChannel(int channelNativeHandle);
int configureDirectChannel(int channelNativeHandle, int sensorHandle, int rateLevel);
- int setOperationParameter(int type, const Vector<float> &floats, const Vector<int32_t> &ints);
+ int setOperationParameter(int handle, int type, const Vector<float> &floats, const Vector<int32_t> &ints);
private:
// DeathRecipient interface
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 5edd664..6630d90 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -54,7 +54,6 @@
"GraphicBuffer.cpp",
"GraphicBufferAllocator.cpp",
"GraphicBufferMapper.cpp",
- "GraphicsEnv.cpp",
"HdrCapabilities.cpp",
"PixelFormat.cpp",
"Rect.cpp",
@@ -70,9 +69,8 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.configstore@1.0",
- "android.hardware.configstore-utils",
+ "android.hardware.configstore-utils",
"libbase",
- "libnativeloader",
"libcutils",
"libhardware",
"libhidlbase",
@@ -89,10 +87,22 @@
"libmath",
],
+ header_libs: [
+ "libnativebase_headers",
+ "libhardware_headers",
+ ],
+
+ export_include_dirs: ["include"],
+
export_static_lib_headers: [
"libarect",
"libmath",
],
+
+ export_header_lib_headers: [
+ "libnativebase_headers",
+ "libhardware_headers",
+ ],
}
subdirs = ["tests"]
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 882bd7c..d5676cc 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -15,6 +15,7 @@
*/
#include <ui/DebugUtils.h>
+#include <ui/PixelFormat.h>
#include <android-base/stringprintf.h>
#include <string>
@@ -58,24 +59,20 @@
case 0:
switch (dataspace & 0xffff) {
case HAL_DATASPACE_JFIF:
- return std::string("(deprecated) JFIF (BT601_625, SMPTE_170M Full range)");
+ return std::string("(deprecated) JFIF (BT601_625)");
case HAL_DATASPACE_BT601_625:
- return std::string("(deprecated) BT601_625 (BT601_625, SMPTE_170M Limited "
- "range)");
+ return std::string("(deprecated) BT601_625");
case HAL_DATASPACE_BT601_525:
- return std::string("(deprecated) BT601_525 (BT601_525, SMPTE_170M Limited "
- "range)");
+ return std::string("(deprecated) BT601_525");
case HAL_DATASPACE_SRGB_LINEAR:
- return std::string("(deprecated) SRGB Linear Full range");
-
case HAL_DATASPACE_SRGB:
return std::string("(deprecated) sRGB");
case HAL_DATASPACE_V0_BT709:
- return std::string("(deprecated) BT709 (BT709, SMPTE_170M Limited range)");
+ return std::string("(deprecated) BT709");
case HAL_DATASPACE_ARBITRARY:
return std::string("ARBITRARY");
@@ -92,6 +89,29 @@
}
std::string decodeTransfer(android_dataspace dataspace) {
+ const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
+ if (dataspaceSelect == 0) {
+ switch (dataspace & 0xffff) {
+ case HAL_DATASPACE_JFIF:
+ case HAL_DATASPACE_BT601_625:
+ case HAL_DATASPACE_BT601_525:
+ case HAL_DATASPACE_V0_BT709:
+ return std::string("SMPTE_170M");
+
+ case HAL_DATASPACE_SRGB_LINEAR:
+ case HAL_DATASPACE_ARBITRARY:
+ return std::string("Linear");
+
+ case HAL_DATASPACE_SRGB:
+ return std::string("sRGB");
+
+ case HAL_DATASPACE_UNKNOWN:
+ // Fallthrough
+ default:
+ return std::string("");
+ }
+ }
+
const uint32_t dataspaceTransfer = (dataspace & HAL_DATASPACE_TRANSFER_MASK);
switch (dataspaceTransfer) {
case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
@@ -126,6 +146,27 @@
}
std::string decodeRange(android_dataspace dataspace) {
+ const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
+ if (dataspaceSelect == 0) {
+ switch (dataspace & 0xffff) {
+ case HAL_DATASPACE_JFIF:
+ case HAL_DATASPACE_SRGB_LINEAR:
+ case HAL_DATASPACE_SRGB:
+ return std::string("Full range");
+
+ case HAL_DATASPACE_BT601_625:
+ case HAL_DATASPACE_BT601_525:
+ case HAL_DATASPACE_V0_BT709:
+ return std::string("Limited range)");
+
+ case HAL_DATASPACE_ARBITRARY:
+ case HAL_DATASPACE_UNKNOWN:
+ // Fallthrough
+ default:
+ return std::string("unspecified range");
+ }
+ }
+
const uint32_t dataspaceRange = (dataspace & HAL_DATASPACE_RANGE_MASK);
switch (dataspaceRange) {
case HAL_DATASPACE_RANGE_UNSPECIFIED:
@@ -145,6 +186,9 @@
}
std::string dataspaceDetails(android_dataspace dataspace) {
+ if (dataspace == 0) {
+ return "Default (0)";
+ }
return android::base::StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(),
decodeTransfer(dataspace).c_str(),
decodeRange(dataspace).c_str());
@@ -185,3 +229,36 @@
return android::base::StringPrintf("Unknown color mode %d", colorMode);
}
+
+// Converts a PixelFormat to a human-readable string. Max 11 chars.
+// (Could use a table of prefab String8 objects.)
+std::string decodePixelFormat(android::PixelFormat format) {
+ switch (format) {
+ case android::PIXEL_FORMAT_UNKNOWN:
+ return std::string("Unknown/None");
+ case android::PIXEL_FORMAT_CUSTOM:
+ return std::string("Custom");
+ case android::PIXEL_FORMAT_TRANSLUCENT:
+ return std::string("Translucent");
+ case android::PIXEL_FORMAT_TRANSPARENT:
+ return std::string("Transparent");
+ case android::PIXEL_FORMAT_OPAQUE:
+ return std::string("Opaque");
+ case android::PIXEL_FORMAT_RGBA_8888:
+ return std::string("RGBA_8888");
+ case android::PIXEL_FORMAT_RGBX_8888:
+ return std::string("RGBx_8888");
+ case android::PIXEL_FORMAT_RGBA_FP16:
+ return std::string("RGBA_FP16");
+ case android::PIXEL_FORMAT_RGBA_1010102:
+ return std::string("RGBA_1010102");
+ case android::PIXEL_FORMAT_RGB_888:
+ return std::string("RGB_888");
+ case android::PIXEL_FORMAT_RGB_565:
+ return std::string("RGB_565");
+ case android::PIXEL_FORMAT_BGRA_8888:
+ return std::string("BGRA_8888");
+ default:
+ return android::base::StringPrintf("Unknown %#08x", format);
+ }
+}
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 87dbaf4..0eb08e5 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "Gralloc2"
+#include <hidl/ServiceManagement.h>
#include <hwbinder/IPCThreadState.h>
#include <ui/Gralloc2.h>
@@ -31,6 +32,10 @@
static constexpr Error kTransactionError = Error::NO_RESOURCES;
+void Mapper::preload() {
+ android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
+}
+
Mapper::Mapper()
{
mMapper = IMapper::getService();
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index ee85c9b..6235bd6 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -51,6 +51,7 @@
height =
stride =
format =
+ usage_deprecated = 0;
usage = 0;
layerCount = 0;
handle = NULL;
@@ -59,14 +60,12 @@
// deprecated
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage, std::string requestorName)
- : GraphicBuffer(inWidth, inHeight, inFormat, 1, static_cast<uint64_t>(inUsage),
- requestorName)
+ : GraphicBuffer(inWidth, inHeight, inFormat, 1, static_cast<uint64_t>(inUsage), requestorName)
{
}
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage,
- std::string requestorName)
+ PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
: GraphicBuffer()
{
mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
@@ -139,7 +138,7 @@
static_cast<int>(inHeight) == height &&
inFormat == format &&
inLayerCount == layerCount &&
- static_cast<int>(inUsage) == usage)
+ inUsage == usage)
return NO_ERROR;
if (handle) {
@@ -147,8 +146,7 @@
allocator.free(handle);
handle = 0;
}
- return initWithSize(inWidth, inHeight, inFormat, inLayerCount,
- inUsage, "[Reallocation]");
+ return initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, "[Reallocation]");
}
bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight,
@@ -158,7 +156,7 @@
if (static_cast<int>(inHeight) != height) return true;
if (inFormat != format) return true;
if (inLayerCount != layerCount) return true;
- if ((static_cast<uint32_t>(usage) & inUsage) != inUsage) return true;
+ if ((usage & inUsage) != inUsage) return true;
return false;
}
@@ -176,7 +174,8 @@
height = static_cast<int>(inHeight);
format = inFormat;
layerCount = inLayerCount;
- usage = static_cast<int>(inUsage);
+ usage = inUsage;
+ usage_deprecated = int(usage);
stride = static_cast<int>(outStride);
}
return err;
@@ -191,7 +190,8 @@
ANativeWindowBuffer::height = static_cast<int>(height);
ANativeWindowBuffer::stride = static_cast<int>(stride);
ANativeWindowBuffer::format = format;
- ANativeWindowBuffer::usage = static_cast<int>(usage);
+ ANativeWindowBuffer::usage = usage;
+ ANativeWindowBuffer::usage_deprecated = int(usage);
ANativeWindowBuffer::layerCount = layerCount;
@@ -312,8 +312,7 @@
width, height);
return BAD_VALUE;
}
- status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect,
- ycbcr, fenceFd);
+ status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect, ycbcr, fenceFd);
return res;
}
@@ -324,7 +323,7 @@
}
size_t GraphicBuffer::getFlattenedSize() const {
- return static_cast<size_t>(12 + (handle ? handle->numInts : 0)) * sizeof(int);
+ return static_cast<size_t>(13 + (handle ? handle->numInts : 0)) * sizeof(int);
}
size_t GraphicBuffer::getFdCount() const {
@@ -339,25 +338,25 @@
if (count < fdCountNeeded) return NO_MEMORY;
int32_t* buf = static_cast<int32_t*>(buffer);
- buf[0] = 'GBFR';
+ buf[0] = 'GB01';
buf[1] = width;
buf[2] = height;
buf[3] = stride;
buf[4] = format;
buf[5] = static_cast<int32_t>(layerCount);
- buf[6] = usage;
+ buf[6] = int(usage); // low 32-bits
buf[7] = static_cast<int32_t>(mId >> 32);
buf[8] = static_cast<int32_t>(mId & 0xFFFFFFFFull);
buf[9] = static_cast<int32_t>(mGenerationNumber);
buf[10] = 0;
buf[11] = 0;
+ buf[12] = int(usage >> 32); // high 32-bits
if (handle) {
buf[10] = handle->numFds;
buf[11] = handle->numInts;
- memcpy(fds, handle->data,
- static_cast<size_t>(handle->numFds) * sizeof(int));
- memcpy(&buf[12], handle->data + handle->numFds,
+ memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int));
+ memcpy(buf + 13, handle->data + handle->numFds,
static_cast<size_t>(handle->numInts) * sizeof(int));
}
@@ -373,10 +372,25 @@
status_t GraphicBuffer::unflatten(
void const*& buffer, size_t& size, int const*& fds, size_t& count) {
- if (size < 12 * sizeof(int)) return NO_MEMORY;
+ if (size < 12 * sizeof(int)) {
+ android_errorWriteLog(0x534e4554, "114223584");
+ return NO_MEMORY;
+ }
int const* buf = static_cast<int const*>(buffer);
- if (buf[0] != 'GBFR') return BAD_TYPE;
+
+ // NOTE: it turns out that some media code generates a flattened GraphicBuffer manually!!!!!
+ // see H2BGraphicBufferProducer.cpp
+ uint32_t flattenWordCount = 0;
+ if (buf[0] == 'GB01') {
+ // new version with 64-bits usage bits
+ flattenWordCount = 13;
+ } else if (buf[0] == 'GBFR') {
+ // old version, when usage bits were 32-bits
+ flattenWordCount = 12;
+ } else {
+ return BAD_TYPE;
+ }
const size_t numFds = static_cast<size_t>(buf[10]);
const size_t numInts = static_cast<size_t>(buf[11]);
@@ -386,15 +400,16 @@
// chosen to be high enough to not cause issues and low enough to prevent
// overflow problems.
const size_t maxNumber = 4096;
- if (numFds >= maxNumber || numInts >= (maxNumber - 12)) {
- width = height = stride = format = layerCount = usage = 0;
+ if (numFds >= maxNumber || numInts >= (maxNumber - flattenWordCount)) {
+ width = height = stride = format = usage_deprecated = 0;
+ layerCount = 0;
+ usage = 0;
handle = NULL;
- ALOGE("unflatten: numFds or numInts is too large: %zd, %zd",
- numFds, numInts);
+ ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", numFds, numInts);
return BAD_VALUE;
}
- const size_t sizeNeeded = (12 + numInts) * sizeof(int);
+ const size_t sizeNeeded = (flattenWordCount + numInts) * sizeof(int);
if (size < sizeNeeded) return NO_MEMORY;
size_t fdCountNeeded = numFds;
@@ -411,20 +426,29 @@
stride = buf[3];
format = buf[4];
layerCount = static_cast<uintptr_t>(buf[5]);
- usage = buf[6];
+ usage_deprecated = buf[6];
+ if (flattenWordCount == 13) {
+ usage = (uint64_t(buf[12]) << 32) | uint32_t(buf[6]);
+ } else {
+ usage = uint64_t(usage_deprecated);
+ }
native_handle* h = native_handle_create(
static_cast<int>(numFds), static_cast<int>(numInts));
if (!h) {
- width = height = stride = format = layerCount = usage = 0;
+ width = height = stride = format = usage_deprecated = 0;
+ layerCount = 0;
+ usage = 0;
handle = NULL;
ALOGE("unflatten: native_handle_create failed");
return NO_MEMORY;
}
memcpy(h->data, fds, numFds * sizeof(int));
- memcpy(h->data + numFds, &buf[12], numInts * sizeof(int));
+ memcpy(h->data + numFds, buf + flattenWordCount, numInts * sizeof(int));
handle = h;
} else {
- width = height = stride = format = layerCount = usage = 0;
+ width = height = stride = format = usage_deprecated = 0;
+ layerCount = 0;
+ usage = 0;
handle = NULL;
}
@@ -439,10 +463,11 @@
buffer_handle_t importedHandle;
status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
if (err != NO_ERROR) {
- width = height = stride = format = layerCount = usage = 0;
+ width = height = stride = format = usage_deprecated = 0;
+ layerCount = 0;
+ usage = 0;
handle = NULL;
- ALOGE("unflatten: registerBuffer failed: %s (%d)",
- strerror(-err), err);
+ ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err);
return err;
}
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index b9fa640..d52c508 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -42,6 +42,10 @@
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
+void GraphicBufferMapper::preloadHal() {
+ Gralloc2::Mapper::preload();
+}
+
GraphicBufferMapper::GraphicBufferMapper()
: mMapper(std::make_unique<const Gralloc2::Mapper>())
{
diff --git a/include/ui/ANativeObjectBase.h b/libs/ui/include/ui/ANativeObjectBase.h
similarity index 71%
rename from include/ui/ANativeObjectBase.h
rename to libs/ui/include/ui/ANativeObjectBase.h
index 640e34b..e9d5d8d 100644
--- a/include/ui/ANativeObjectBase.h
+++ b/libs/ui/include/ui/ANativeObjectBase.h
@@ -19,26 +19,8 @@
#include <sys/types.h>
-#include <system/window.h>
+#include <nativebase/nativebase.h>
-// ---------------------------------------------------------------------------
-
-/* FIXME: this is legacy for pixmaps */
-typedef struct egl_native_pixmap_t
-{
- int32_t version; /* must be 32 */
- int32_t width;
- int32_t height;
- int32_t stride;
- uint8_t* data;
- uint8_t format;
- uint8_t rfu[3];
- union {
- uint32_t compressedFormat;
- int32_t vstride;
- };
- int32_t reserved;
-} egl_native_pixmap_t;
/*****************************************************************************/
@@ -52,7 +34,8 @@
* This helper class turns a ANativeXXX object type into a C++
* reference-counted object; with proper type conversions.
*/
-template <typename NATIVE_TYPE, typename TYPE, typename REF>
+template <typename NATIVE_TYPE, typename TYPE, typename REF,
+ typename NATIVE_BASE = android_native_base_t>
class ANativeObjectBase : public NATIVE_TYPE, public REF
{
public:
@@ -65,7 +48,7 @@
}
protected:
- typedef ANativeObjectBase<NATIVE_TYPE, TYPE, REF> BASE;
+ typedef ANativeObjectBase<NATIVE_TYPE, TYPE, REF, NATIVE_BASE> BASE;
ANativeObjectBase() : NATIVE_TYPE(), REF() {
NATIVE_TYPE::common.incRef = incRef;
NATIVE_TYPE::common.decRef = decRef;
@@ -76,17 +59,17 @@
static inline TYPE const* getSelf(NATIVE_TYPE const* self) {
return static_cast<TYPE const *>(self);
}
- static inline TYPE* getSelf(android_native_base_t* base) {
+ static inline TYPE* getSelf(NATIVE_BASE* base) {
return getSelf(reinterpret_cast<NATIVE_TYPE*>(base));
}
- static inline TYPE const * getSelf(android_native_base_t const* base) {
+ static inline TYPE const * getSelf(NATIVE_BASE const* base) {
return getSelf(reinterpret_cast<NATIVE_TYPE const*>(base));
}
- static void incRef(android_native_base_t* base) {
+ static void incRef(NATIVE_BASE* base) {
ANativeObjectBase* self = getSelf(base);
self->incStrong(self);
}
- static void decRef(android_native_base_t* base) {
+ static void decRef(NATIVE_BASE* base) {
ANativeObjectBase* self = getSelf(base);
self->decStrong(self);
}
diff --git a/include/ui/BufferQueueDefs.h b/libs/ui/include/ui/BufferQueueDefs.h
similarity index 100%
rename from include/ui/BufferQueueDefs.h
rename to libs/ui/include/ui/BufferQueueDefs.h
diff --git a/include/ui/ColorSpace.h b/libs/ui/include/ui/ColorSpace.h
similarity index 100%
rename from include/ui/ColorSpace.h
rename to libs/ui/include/ui/ColorSpace.h
diff --git a/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
similarity index 91%
rename from include/ui/DebugUtils.h
rename to libs/ui/include/ui/DebugUtils.h
index 8483808..30f4a59 100644
--- a/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -17,6 +17,7 @@
#pragma once
#include <system/graphics.h>
+#include <ui/PixelFormat.h>
#include <string>
@@ -25,3 +26,4 @@
std::string decodeRange(android_dataspace dataspace);
std::string dataspaceDetails(android_dataspace dataspace);
std::string decodeColorMode(android_color_mode colormode);
+std::string decodePixelFormat(android::PixelFormat format);
diff --git a/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
similarity index 100%
rename from include/ui/DisplayInfo.h
rename to libs/ui/include/ui/DisplayInfo.h
diff --git a/include/ui/DisplayStatInfo.h b/libs/ui/include/ui/DisplayStatInfo.h
similarity index 100%
rename from include/ui/DisplayStatInfo.h
rename to libs/ui/include/ui/DisplayStatInfo.h
diff --git a/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
similarity index 100%
rename from include/ui/Fence.h
rename to libs/ui/include/ui/Fence.h
diff --git a/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h
similarity index 100%
rename from include/ui/FenceTime.h
rename to libs/ui/include/ui/FenceTime.h
diff --git a/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
similarity index 100%
rename from include/ui/FloatRect.h
rename to libs/ui/include/ui/FloatRect.h
diff --git a/include/ui/FrameStats.h b/libs/ui/include/ui/FrameStats.h
similarity index 100%
rename from include/ui/FrameStats.h
rename to libs/ui/include/ui/FrameStats.h
diff --git a/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
similarity index 98%
rename from include/ui/Gralloc2.h
rename to libs/ui/include/ui/Gralloc2.h
index f826b92..8aee160 100644
--- a/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -21,7 +21,6 @@
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <system/window.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -39,6 +38,8 @@
// A wrapper to IMapper
class Mapper {
public:
+ static void preload();
+
Mapper();
Error createDescriptor(
diff --git a/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
similarity index 97%
rename from include/ui/GraphicBuffer.h
rename to libs/ui/include/ui/GraphicBuffer.h
index 4b82cff..95c2d22 100644
--- a/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -28,9 +28,9 @@
#include <utils/Flattenable.h>
#include <utils/RefBase.h>
-#include <hardware/gralloc.h>
+#include <nativebase/nativebase.h>
-struct ANativeWindowBuffer;
+#include <hardware/gralloc.h>
namespace android {
@@ -41,7 +41,7 @@
// ===========================================================================
class GraphicBuffer
- : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >,
+ : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
public Flattenable<GraphicBuffer>
{
friend class Flattenable<GraphicBuffer>;
@@ -141,7 +141,7 @@
uint32_t getWidth() const { return static_cast<uint32_t>(width); }
uint32_t getHeight() const { return static_cast<uint32_t>(height); }
uint32_t getStride() const { return static_cast<uint32_t>(stride); }
- uint32_t getUsage() const { return static_cast<uint32_t>(usage); }
+ uint64_t getUsage() const { return usage; }
PixelFormat getPixelFormat() const { return format; }
uint32_t getLayerCount() const { return static_cast<uint32_t>(layerCount); }
Rect getBounds() const { return Rect(width, height); }
diff --git a/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
similarity index 98%
rename from include/ui/GraphicBufferAllocator.h
rename to libs/ui/include/ui/GraphicBufferAllocator.h
index fe99de1..14a865e 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -25,8 +25,6 @@
#include <cutils/native_handle.h>
-#include <system/window.h>
-
#include <ui/PixelFormat.h>
#include <utils/Errors.h>
diff --git a/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
similarity index 98%
rename from include/ui/GraphicBufferMapper.h
rename to libs/ui/include/ui/GraphicBufferMapper.h
index e0702e9..06961b1 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -43,6 +43,7 @@
class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
{
public:
+ static void preloadHal();
static inline GraphicBufferMapper& get() { return getInstance(); }
// The imported outHandle must be freed with freeBuffer when no longer
diff --git a/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
similarity index 100%
rename from include/ui/HdrCapabilities.h
rename to libs/ui/include/ui/HdrCapabilities.h
diff --git a/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h
similarity index 100%
rename from include/ui/PixelFormat.h
rename to libs/ui/include/ui/PixelFormat.h
diff --git a/include/ui/Point.h b/libs/ui/include/ui/Point.h
similarity index 100%
rename from include/ui/Point.h
rename to libs/ui/include/ui/Point.h
diff --git a/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
similarity index 100%
rename from include/ui/Rect.h
rename to libs/ui/include/ui/Rect.h
diff --git a/include/ui/Region.h b/libs/ui/include/ui/Region.h
similarity index 100%
rename from include/ui/Region.h
rename to libs/ui/include/ui/Region.h
diff --git a/include/ui/UiConfig.h b/libs/ui/include/ui/UiConfig.h
similarity index 100%
rename from include/ui/UiConfig.h
rename to libs/ui/include/ui/UiConfig.h
diff --git a/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h
index 69cb648..f2e5034 100644
--- a/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h
+++ b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h
@@ -174,8 +174,6 @@
//
// There must be at least |MemorySize(record_count)| bytes of space already
// allocated at |mmap|. The ring does not take ownership.
- //
- // Use this function for dynamically sized rings.
static BroadcastRing Create(void* mmap, size_t mmap_size,
uint32_t record_count) {
BroadcastRing ring(mmap);
@@ -188,12 +186,11 @@
//
// There must be at least |MemorySize()| bytes of space already allocated at
// |mmap|. The ring does not take ownership.
- //
- // Use this function for statically sized rings.
static BroadcastRing Create(void* mmap, size_t mmap_size) {
- static_assert(Traits::kUseStaticRecordCount,
- "Wrong Create() function called for dynamic record count");
- return Create(mmap, mmap_size, Traits::kStaticRecordCount);
+ return Create(mmap, mmap_size,
+ Traits::kUseStaticRecordCount
+ ? Traits::kStaticRecordCount
+ : BroadcastRing::GetRecordCount(mmap_size));
}
// Imports an existing ring at |mmap|.
@@ -233,6 +230,30 @@
return MemorySize(Traits::kStaticRecordCount);
}
+ static uint32_t NextPowerOf2(uint32_t n) {
+ if (n == 0)
+ return 0;
+ n -= 1;
+ n |= n >> 16;
+ n |= n >> 8;
+ n |= n >> 4;
+ n |= n >> 2;
+ n |= n >> 1;
+ return n + 1;
+ }
+
+ // Gets the biggest power of 2 record count that can fit into this mmap.
+ //
+ // The header size has been taken into account.
+ static uint32_t GetRecordCount(size_t mmap_size) {
+ if (mmap_size <= sizeof(Header)) {
+ return 0;
+ }
+ uint32_t count =
+ static_cast<uint32_t>((mmap_size - sizeof(Header)) / sizeof(Record));
+ return IsPowerOfTwo(count) ? count : (NextPowerOf2(count) / 2);
+ }
+
// Writes a record to the ring.
//
// The oldest record is overwritten unless the ring is not already full.
@@ -348,6 +369,9 @@
return Get(sequence, record);
}
+ // Returns true if this instance has been created or imported.
+ bool is_valid() const { return !!data_.mmap; }
+
uint32_t record_count() const { return record_count_internal(); }
uint32_t record_size() const { return record_size_internal(); }
static constexpr uint32_t mmap_alignment() { return alignof(Mmap); }
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 452bad0..da0ea24 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -34,6 +34,11 @@
"liblog",
"libui",
"libutils",
+ "libnativewindow"
+]
+
+HeaderLibraries = [
+ "libnativebase_headers",
]
cc_library {
@@ -45,7 +50,11 @@
export_include_dirs: localIncludeFiles,
static_libs: staticLibraries,
shared_libs: sharedLibraries,
+ header_libs: HeaderLibraries,
name: "libbufferhub",
+ export_header_lib_headers: [
+ "libnativebase_headers",
+ ],
}
cc_test {
diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp
index fa61c4a..1daa5d6 100644
--- a/libs/vr/libbufferhub/bufferhub_tests.cpp
+++ b/libs/vr/libbufferhub/bufferhub_tests.cpp
@@ -62,6 +62,57 @@
EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
}
+TEST_F(LibBufferHubTest, TestStateTransitions) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ uint64_t context;
+ LocalHandle fence;
+
+ // The producer buffer starts in gained state.
+
+ // Acquire, release, and gain in gained state should fail.
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+ EXPECT_EQ(-EALREADY, p->Gain(&fence));
+
+ // Post in gained state should succeed.
+ EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+
+ // Post, release, and gain in posted state should fail.
+ EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+ EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+ EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+ // Acquire in posted state should succeed.
+ EXPECT_LE(0, c->Acquire(&fence, &context));
+
+ // Acquire, post, and gain in acquired state should fail.
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+ EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+ // Release in acquired state should succeed.
+ EXPECT_EQ(0, c->Release(LocalHandle()));
+
+ // Release, acquire, and post in released state should fail.
+ EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+
+ // Gain in released state should succeed.
+ EXPECT_EQ(0, p->Gain(&fence));
+
+ // Acquire, release, and gain in gained state should fail.
+ EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+ EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+ EXPECT_EQ(-EALREADY, p->Gain(&fence));
+}
+
TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
struct Metadata {
int64_t field1;
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index ffdc9e2..ca0e0e0 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -129,19 +129,102 @@
using LocalFence = FenceHandle<pdx::LocalHandle>;
using BorrowedFence = FenceHandle<pdx::BorrowedHandle>;
-struct QueueInfo {
+struct ProducerQueueConfig {
+ // Whether the buffer queue is operating in Async mode.
+ // From GVR's perspective of view, this means a buffer can be acquired
+ // asynchronously by the compositor.
+ // From Android Surface's perspective of view, this is equivalent to
+ // IGraphicBufferProducer's async mode. When in async mode, a producer
+ // will never block even if consumer is running slow.
+ bool is_async;
+
+ // Default buffer width that is set during ProducerQueue's creation.
+ uint32_t default_width;
+
+ // Default buffer height that is set during ProducerQueue's creation.
+ uint32_t default_height;
+
+ // Default buffer format that is set during ProducerQueue's creation.
+ uint32_t default_format;
+
+ // Size of the meta data associated with all the buffers allocated from the
+ // queue.
size_t meta_size_bytes;
+
+ private:
+ PDX_SERIALIZABLE_MEMBERS(ProducerQueueConfig, is_async, default_width,
+ default_height, default_format, meta_size_bytes);
+};
+
+class ProducerQueueConfigBuilder {
+ public:
+ // Build a ProducerQueueConfig object.
+ ProducerQueueConfig Build() {
+ return {is_async_, default_width_, default_height_, default_format_,
+ meta_size_bytes_};
+ }
+
+ ProducerQueueConfigBuilder& SetIsAsync(bool is_async) {
+ is_async_ = is_async;
+ return *this;
+ }
+
+ ProducerQueueConfigBuilder& SetDefaultWidth(uint32_t width) {
+ default_width_ = width;
+ return *this;
+ }
+
+ ProducerQueueConfigBuilder& SetDefaultHeight(uint32_t height) {
+ default_height_ = height;
+ return *this;
+ }
+
+ ProducerQueueConfigBuilder& SetDefaultFormat(uint32_t format) {
+ default_format_ = format;
+ return *this;
+ }
+
+ template <typename Meta>
+ ProducerQueueConfigBuilder& SetMetadata() {
+ meta_size_bytes_ = sizeof(Meta);
+ return *this;
+ }
+
+ ProducerQueueConfigBuilder& SetMetadataSize(size_t meta_size_bytes) {
+ meta_size_bytes_ = meta_size_bytes;
+ return *this;
+ }
+
+ private:
+ bool is_async_{false};
+ uint32_t default_width_{1};
+ uint32_t default_height_{1};
+ uint32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888
+ size_t meta_size_bytes_{0};
+};
+
+// Explicit specializations of ProducerQueueConfigBuilder::Build for void
+// metadata type.
+template <>
+inline ProducerQueueConfigBuilder&
+ProducerQueueConfigBuilder::SetMetadata<void>() {
+ meta_size_bytes_ = 0;
+ return *this;
+}
+
+struct QueueInfo {
+ ProducerQueueConfig producer_config;
int id;
private:
- PDX_SERIALIZABLE_MEMBERS(QueueInfo, meta_size_bytes, id);
+ PDX_SERIALIZABLE_MEMBERS(QueueInfo, producer_config, id);
};
struct UsagePolicy {
- uint64_t usage_set_mask;
- uint64_t usage_clear_mask;
- uint64_t usage_deny_set_mask;
- uint64_t usage_deny_clear_mask;
+ uint64_t usage_set_mask{0};
+ uint64_t usage_clear_mask{0};
+ uint64_t usage_deny_set_mask{0};
+ uint64_t usage_deny_clear_mask{0};
private:
PDX_SERIALIZABLE_MEMBERS(UsagePolicy, usage_set_mask, usage_clear_mask,
@@ -181,7 +264,7 @@
kOpCreateConsumerQueue,
kOpGetQueueInfo,
kOpProducerQueueAllocateBuffers,
- kOpProducerQueueDetachBuffer,
+ kOpProducerQueueRemoveBuffer,
kOpConsumerQueueImportBuffers,
};
@@ -219,7 +302,7 @@
// Buffer Queue Methods.
PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue,
- QueueInfo(size_t meta_size_bytes,
+ QueueInfo(const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy));
PDX_REMOTE_METHOD(CreateConsumerQueue, kOpCreateConsumerQueue,
LocalChannelHandle(Void));
@@ -229,7 +312,7 @@
std::vector<std::pair<LocalChannelHandle, size_t>>(
uint32_t width, uint32_t height, uint32_t layer_count,
uint32_t format, uint64_t usage, size_t buffer_count));
- PDX_REMOTE_METHOD(ProducerQueueDetachBuffer, kOpProducerQueueDetachBuffer,
+ PDX_REMOTE_METHOD(ProducerQueueRemoveBuffer, kOpProducerQueueRemoveBuffer,
void(size_t slot));
PDX_REMOTE_METHOD(ConsumerQueueImportBuffers, kOpConsumerQueueImportBuffers,
std::vector<std::pair<LocalChannelHandle, size_t>>(Void));
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
index b4ef2f5..140ffc5 100644
--- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
@@ -4,9 +4,9 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <log/log.h>
-#include <system/window.h>
#include <ui/ANativeObjectBase.h>
#include <utils/RefBase.h>
+#include <nativebase/nativebase.h>
#include <private/dvr/buffer_hub_client.h>
@@ -52,8 +52,6 @@
void operator=(NativeBuffer&) = delete;
};
-// NativeBufferProducer is an implementation of ANativeWindowBuffer backed by a
-// BufferProducer.
class NativeBufferProducer : public android::ANativeObjectBase<
ANativeWindowBuffer, NativeBufferProducer,
android::LightRefBase<NativeBufferProducer>> {
@@ -71,20 +69,25 @@
ANativeWindowBuffer::stride = buffer_->stride();
ANativeWindowBuffer::format = buffer_->format();
ANativeWindowBuffer::usage = buffer_->usage();
- handle = buffer_->native_handle();
+ ANativeWindowBuffer::handle = buffer_->native_handle();
+ if (display_) {
+ image_khr_ =
+ eglCreateImageKHR(display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ static_cast<ANativeWindowBuffer*>(this), nullptr);
+ } else {
+ image_khr_ = EGL_NO_IMAGE_KHR;
+ }
}
explicit NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer)
: NativeBufferProducer(buffer, nullptr, 0) {}
virtual ~NativeBufferProducer() {
- for (EGLImageKHR egl_image : egl_images_) {
- if (egl_image != EGL_NO_IMAGE_KHR)
- eglDestroyImageKHR(display_, egl_image);
- }
+ if (image_khr_ != EGL_NO_IMAGE_KHR)
+ eglDestroyImageKHR(display_, image_khr_);
}
- EGLImageKHR image_khr(int index) const { return egl_images_[index]; }
+ EGLImageKHR image_khr() const { return image_khr_; }
std::shared_ptr<BufferProducer> buffer() const { return buffer_; }
int release_fence() const { return release_fence_.Get(); }
uint32_t surface_buffer_index() const { return surface_buffer_index_; }
@@ -112,7 +115,7 @@
std::shared_ptr<BufferProducer> buffer_;
pdx::LocalHandle release_fence_;
- std::vector<EGLImageKHR> egl_images_;
+ EGLImageKHR image_khr_;
uint32_t surface_buffer_index_;
EGLDisplay display_;
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index a587f95..0b3b2f0 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -21,10 +21,6 @@
"include",
]
-headerLibraries = [
- "libdvr_headers",
-]
-
staticLibraries = [
"libbufferhub",
"libdvrcommon",
@@ -42,6 +38,11 @@
"libgui",
]
+headerLibraries = [
+ "libdvr_headers",
+ "libnativebase_headers",
+]
+
cc_library {
name: "libbufferhubqueue",
cflags: [
@@ -51,9 +52,9 @@
srcs: sourceFiles,
export_include_dirs: includeFiles,
export_static_lib_headers: staticLibraries,
- header_libs: headerLibraries,
static_libs: staticLibraries,
shared_libs: sharedLibraries,
+ header_libs: headerLibraries,
}
subdirs = ["tests"]
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 012a4e7..bfb9a55 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -10,7 +10,6 @@
#include <pdx/default_transport/client_channel.h>
#include <pdx/default_transport/client_channel_factory.h>
#include <pdx/file_handle.h>
-#include <private/dvr/bufferhub_rpc.h>
#define RETRY_EINTR(fnc_call) \
([&]() -> decltype(fnc_call) { \
@@ -23,34 +22,61 @@
using android::pdx::ErrorStatus;
using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
using android::pdx::Status;
namespace android {
namespace dvr {
+namespace {
+
+// Polls an fd for the given events.
+Status<int> PollEvents(int fd, short events) {
+ const int kTimeoutMs = 0;
+ pollfd pfd{fd, events, 0};
+ const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs));
+ if (count < 0) {
+ return ErrorStatus(errno);
+ } else if (count == 0) {
+ return ErrorStatus(ETIMEDOUT);
+ } else {
+ return {pfd.revents};
+ }
+}
+
+// Polls a buffer for the given events, taking care to do the proper
+// translation.
+Status<int> PollEvents(const std::shared_ptr<BufferHubBuffer>& buffer,
+ short events) {
+ auto poll_status = PollEvents(buffer->event_fd(), events);
+ if (!poll_status)
+ return poll_status;
+
+ return buffer->GetEventMask(poll_status.get());
+}
+
+std::pair<int32_t, int32_t> Unstuff(uint64_t value) {
+ return {static_cast<int32_t>(value >> 32),
+ static_cast<int32_t>(value & ((1ull << 32) - 1))};
+}
+
+uint64_t Stuff(int32_t a, int32_t b) {
+ const uint32_t ua = static_cast<uint32_t>(a);
+ const uint32_t ub = static_cast<uint32_t>(b);
+ return (static_cast<uint64_t>(ua) << 32) | static_cast<uint64_t>(ub);
+}
+
+} // anonymous namespace
+
BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle)
: Client{pdx::default_transport::ClientChannel::Create(
- std::move(channel_handle))},
- meta_size_(0),
- buffers_(BufferHubQueue::kMaxQueueCapacity),
- epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
- available_buffers_(BufferHubQueue::kMaxQueueCapacity),
- fences_(BufferHubQueue::kMaxQueueCapacity),
- capacity_(0),
- id_(-1) {
+ std::move(channel_handle))} {
Initialize();
}
BufferHubQueue::BufferHubQueue(const std::string& endpoint_path)
- : Client{pdx::default_transport::ClientChannelFactory::Create(
- endpoint_path)},
- meta_size_(0),
- buffers_(BufferHubQueue::kMaxQueueCapacity),
- epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
- available_buffers_(BufferHubQueue::kMaxQueueCapacity),
- fences_(BufferHubQueue::kMaxQueueCapacity),
- capacity_(0),
- id_(-1) {
+ : Client{
+ pdx::default_transport::ClientChannelFactory::Create(endpoint_path)} {
Initialize();
}
@@ -62,9 +88,9 @@
return;
}
- epoll_event event = {.events = EPOLLIN | EPOLLET,
- .data = {.u64 = static_cast<uint64_t>(
- BufferHubQueue::kEpollQueueEventIndex)}};
+ epoll_event event = {
+ .events = EPOLLIN | EPOLLET,
+ .data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}};
ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
if (ret < 0) {
ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s",
@@ -79,15 +105,18 @@
status.GetErrorMessage().c_str());
return ErrorStatus(status.error());
} else {
- SetupQueue(status.get().meta_size_bytes, status.get().id);
+ SetupQueue(status.get());
return {};
}
}
-void BufferHubQueue::SetupQueue(size_t meta_size_bytes, int id) {
- meta_size_ = meta_size_bytes;
- id_ = id;
- meta_buffer_tmp_.reset(meta_size_ > 0 ? new uint8_t[meta_size_] : nullptr);
+void BufferHubQueue::SetupQueue(const QueueInfo& queue_info) {
+ is_async_ = queue_info.producer_config.is_async;
+ default_width_ = queue_info.producer_config.default_width;
+ default_height_ = queue_info.producer_config.default_height;
+ default_format_ = queue_info.producer_config.default_format;
+ meta_size_ = queue_info.producer_config.meta_size_bytes;
+ id_ = queue_info.id;
}
std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
@@ -152,19 +181,24 @@
// one for each buffer, in the queue and one extra event for the queue
// client itself.
for (int i = 0; i < num_events; i++) {
- int64_t index = static_cast<int64_t>(events[i].data.u64);
+ int32_t event_fd;
+ int32_t index;
+ std::tie(event_fd, index) = Unstuff(events[i].data.u64);
ALOGD_IF(TRACE,
- "BufferHubQueue::WaitForBuffers: event %d: index=%" PRId64, i,
- index);
+ "BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d",
+ i, event_fd, index);
if (is_buffer_event_index(index)) {
- HandleBufferEvent(static_cast<size_t>(index), events[i].events);
+ HandleBufferEvent(static_cast<size_t>(index), event_fd,
+ events[i].events);
} else if (is_queue_event_index(index)) {
HandleQueueEvent(events[i].events);
} else {
- ALOGW("BufferHubQueue::WaitForBuffers: Unknown event index: %" PRId64,
- index);
+ ALOGW(
+ "BufferHubQueue::WaitForBuffers: Unknown event type event_fd=%d "
+ "index=%d",
+ event_fd, index);
}
}
} while (count() == 0 && capacity() > 0 && !hung_up());
@@ -172,52 +206,72 @@
return count() != 0;
}
-void BufferHubQueue::HandleBufferEvent(size_t slot, int poll_events) {
- auto buffer = buffers_[slot];
- if (!buffer) {
+Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd,
+ int poll_events) {
+ if (!buffers_[slot]) {
ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
- return;
+ return ErrorStatus(ENOENT);
}
- auto status = buffer->GetEventMask(poll_events);
+ auto status = buffers_[slot]->GetEventMask(poll_events);
if (!status) {
ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s",
status.GetErrorMessage().c_str());
- return;
+ return status.error_status();
}
const int events = status.get();
if (events & EPOLLIN) {
- const int ret = OnBufferReady(buffer, &fences_[slot]);
- if (ret == 0 || ret == -EALREADY || ret == -EBUSY) {
+ auto entry_status = OnBufferReady(buffers_[slot], slot);
+ if (entry_status.ok() || entry_status.error() == EALREADY) {
// Only enqueue the buffer if it moves to or is already in the state
- // requested in OnBufferReady(). If the buffer is busy this means that the
- // buffer moved from released to posted when a new consumer was created
- // before the ProducerQueue had a chance to regain it. This is a valid
- // transition that we have to handle because edge triggered poll events
- // latch the ready state even if it is later de-asserted -- don't enqueue
- // or print an error log in this case.
- if (ret != -EBUSY)
- Enqueue(buffer, slot);
+ // requested in OnBufferReady().
+ return Enqueue(entry_status.take());
+ } else if (entry_status.error() == EBUSY) {
+ // If the buffer is busy this means that the buffer moved from released to
+ // posted when a new consumer was created before the ProducerQueue had a
+ // chance to regain it. This is a valid transition that we have to handle
+ // because edge triggered poll events latch the ready state even if it is
+ // later de-asserted -- don't enqueue or print an error log in this case.
} else {
ALOGE(
"BufferHubQueue::HandleBufferEvent: Failed to set buffer ready, "
"queue_id=%d buffer_id=%d: %s",
- id(), buffer->id(), strerror(-ret));
+ id(), buffers_[slot]->id(), entry_status.GetErrorMessage().c_str());
}
} else if (events & EPOLLHUP) {
- // This might be caused by producer replacing an existing buffer slot, or
- // when BufferHubQueue is shutting down. For the first case, currently the
- // epoll FD is cleaned up when the replacement consumer client is imported,
- // we shouldn't detach again if |epollhub_pending_[slot]| is set.
+ // Check to see if the current buffer in the slot hung up. This is a bit of
+ // paranoia to deal with the epoll set getting out of sync with the buffer
+ // slots.
+ auto poll_status = PollEvents(buffers_[slot], POLLIN);
+ if (!poll_status && poll_status.error() != ETIMEDOUT) {
+ ALOGE("BufferHubQueue::HandleBufferEvent: Failed to poll buffer: %s",
+ poll_status.GetErrorMessage().c_str());
+ return poll_status.error_status();
+ }
+
+ const bool hangup_pending = status.ok() && (poll_status.get() & EPOLLHUP);
+
ALOGW(
- "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP at slot: %zu, "
- "buffer event fd: %d, EPOLLHUP pending: %d",
- slot, buffer->event_fd(), int{epollhup_pending_[slot]});
- if (epollhup_pending_[slot]) {
- epollhup_pending_[slot] = false;
+ "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu "
+ "event_fd=%d buffer_id=%d hangup_pending=%d poll_status=%x",
+ slot, buffers_[slot]->event_fd(), buffers_[slot]->id(), hangup_pending,
+ poll_status.get());
+
+ if (hangup_pending) {
+ return RemoveBuffer(slot);
} else {
- DetachBuffer(slot);
+ // Clean up the bookkeeping for the event fd. This is a bit of paranoia to
+ // deal with the epoll set getting out of sync with the buffer slots.
+ // Hitting this path should be very unusual.
+ const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, event_fd, nullptr);
+ if (ret < 0) {
+ ALOGE(
+ "BufferHubQueue::HandleBufferEvent: Failed to remove fd=%d from "
+ "epoll set: %s",
+ event_fd, strerror(-ret));
+ return ErrorStatus(-ret);
+ }
}
} else {
ALOGW(
@@ -225,14 +279,16 @@
"events=%d",
slot, events);
}
+
+ return {};
}
-void BufferHubQueue::HandleQueueEvent(int poll_event) {
+Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) {
auto status = GetEventMask(poll_event);
if (!status) {
ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
status.GetErrorMessage().c_str());
- return;
+ return status.error_status();
}
const int events = status.get();
@@ -250,115 +306,116 @@
} else {
ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%x", events);
}
+
+ return {};
}
-int BufferHubQueue::AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf,
- size_t slot) {
+Status<void> BufferHubQueue::AddBuffer(
+ const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
+ ALOGD_IF(TRACE, "BufferHubQueue::AddBuffer: buffer_id=%d slot=%zu",
+ buffer->id(), slot);
+
if (is_full()) {
- // TODO(jwcai) Move the check into Producer's AllocateBuffer and consumer's
- // import buffer.
ALOGE("BufferHubQueue::AddBuffer queue is at maximum capacity: %zu",
capacity_);
- return -E2BIG;
+ return ErrorStatus(E2BIG);
}
- if (buffers_[slot] != nullptr) {
- // Replace the buffer if the slot is preoccupied. This could happen when the
- // producer side replaced the slot with a newly allocated buffer. Detach the
+ if (buffers_[slot]) {
+ // Replace the buffer if the slot is occupied. This could happen when the
+ // producer side replaced the slot with a newly allocated buffer. Remove the
// buffer before setting up with the new one.
- DetachBuffer(slot);
- epollhup_pending_[slot] = true;
+ auto remove_status = RemoveBuffer(slot);
+ if (!remove_status)
+ return remove_status.error_status();
}
- epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u64 = slot}};
- const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buf->event_fd(), &event);
+ epoll_event event = {.events = EPOLLIN | EPOLLET,
+ .data = {.u64 = Stuff(buffer->event_fd(), slot)}};
+ const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buffer->event_fd(), &event);
if (ret < 0) {
ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
strerror(-ret));
- return ret;
+ return ErrorStatus(-ret);
}
- buffers_[slot] = buf;
+ buffers_[slot] = buffer;
capacity_++;
- return 0;
+ return {};
}
-int BufferHubQueue::DetachBuffer(size_t slot) {
- auto& buf = buffers_[slot];
- if (buf == nullptr) {
- ALOGE("BufferHubQueue::DetachBuffer: Invalid slot: %zu", slot);
- return -EINVAL;
+Status<void> BufferHubQueue::RemoveBuffer(size_t slot) {
+ ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot);
+
+ if (buffers_[slot]) {
+ const int ret =
+ epoll_fd_.Control(EPOLL_CTL_DEL, buffers_[slot]->event_fd(), nullptr);
+ if (ret < 0) {
+ ALOGE(
+ "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
+ "set: "
+ "%s",
+ strerror(-ret));
+ return ErrorStatus(-ret);
+ }
+
+ // Trigger OnBufferRemoved callback if registered.
+ if (on_buffer_removed_)
+ on_buffer_removed_(buffers_[slot]);
+
+ buffers_[slot] = nullptr;
+ capacity_--;
}
- const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, buf->event_fd(), nullptr);
- if (ret < 0) {
- ALOGE(
- "BufferHubQueue::DetachBuffer: Failed to detach buffer from epoll set: "
- "%s",
- strerror(-ret));
- return ret;
- }
-
- buffers_[slot] = nullptr;
- capacity_--;
- return 0;
+ return {};
}
-void BufferHubQueue::Enqueue(const std::shared_ptr<BufferHubBuffer>& buf,
- size_t slot) {
- if (count() == capacity_) {
+Status<void> BufferHubQueue::Enqueue(Entry entry) {
+ if (!is_full()) {
+ available_buffers_.Append(std::move(entry));
+
+ // Trigger OnBufferAvailable callback if registered.
+ if (on_buffer_available_)
+ on_buffer_available_();
+
+ return {};
+ } else {
ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!");
- return;
+ return ErrorStatus(E2BIG);
}
-
- // Set slot buffer back to vector.
- // TODO(jwcai) Here have to dynamically allocate BufferInfo::metadata due to
- // the limitation of the RingBuffer we are using. Would be better to refactor
- // that.
- BufferInfo buffer_info(slot, meta_size_);
- buffer_info.buffer = buf;
- // Swap metadata loaded during onBufferReady into vector.
- std::swap(buffer_info.metadata, meta_buffer_tmp_);
-
- available_buffers_.Append(std::move(buffer_info));
}
Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue(
int timeout, size_t* slot, void* meta, LocalHandle* fence) {
- ALOGD_IF(TRACE, "Dequeue: count=%zu, timeout=%d", count(), timeout);
+ ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
+ timeout);
if (!WaitForBuffers(timeout))
return ErrorStatus(ETIMEDOUT);
- std::shared_ptr<BufferHubBuffer> buf;
- BufferInfo& buffer_info = available_buffers_.Front();
+ auto& entry = available_buffers_.Front();
- *fence = std::move(fences_[buffer_info.slot]);
-
- // Report current pos as the output slot.
- std::swap(buffer_info.slot, *slot);
- // Swap buffer from vector to be returned later.
- std::swap(buffer_info.buffer, buf);
- // Swap metadata from vector into tmp so that we can write out to |meta|.
- std::swap(buffer_info.metadata, meta_buffer_tmp_);
-
- available_buffers_.PopFront();
-
- if (!buf) {
- ALOGE("BufferHubQueue::Dequeue: Buffer to be dequeued is nullptr");
- return ErrorStatus(ENOBUFS);
- }
-
- if (meta) {
- std::copy(meta_buffer_tmp_.get(), meta_buffer_tmp_.get() + meta_size_,
+ std::shared_ptr<BufferHubBuffer> buffer = std::move(entry.buffer);
+ *slot = entry.slot;
+ *fence = std::move(entry.fence);
+ if (meta && entry.metadata) {
+ std::copy(entry.metadata.get(), entry.metadata.get() + meta_size_,
reinterpret_cast<uint8_t*>(meta));
}
- return {std::move(buf)};
+ available_buffers_.PopFront();
+
+ return {std::move(buffer)};
}
-ProducerQueue::ProducerQueue(size_t meta_size)
- : ProducerQueue(meta_size, 0, 0, 0, 0) {}
+void BufferHubQueue::SetBufferAvailableCallback(
+ BufferAvailableCallback callback) {
+ on_buffer_available_ = callback;
+}
+
+void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) {
+ on_buffer_removed_ = callback;
+}
ProducerQueue::ProducerQueue(LocalChannelHandle handle)
: BASE(std::move(handle)) {
@@ -370,14 +427,11 @@
}
}
-ProducerQueue::ProducerQueue(size_t meta_size, uint64_t usage_set_mask,
- uint64_t usage_clear_mask,
- uint64_t usage_deny_set_mask,
- uint64_t usage_deny_clear_mask)
+ProducerQueue::ProducerQueue(const ProducerQueueConfig& config,
+ const UsagePolicy& usage)
: BASE(BufferHubRPC::kClientPath) {
- auto status = InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(
- meta_size, UsagePolicy{usage_set_mask, usage_clear_mask,
- usage_deny_set_mask, usage_deny_clear_mask});
+ auto status =
+ InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(config, usage);
if (!status) {
ALOGE("ProducerQueue::ProducerQueue: Failed to create producer queue: %s",
status.GetErrorMessage().c_str());
@@ -385,74 +439,106 @@
return;
}
- SetupQueue(status.get().meta_size_bytes, status.get().id);
+ SetupQueue(status.get());
}
-int ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
- uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t* out_slot) {
- if (out_slot == nullptr) {
- ALOGE("ProducerQueue::AllocateBuffer: Parameter out_slot cannot be null.");
- return -EINVAL;
+Status<std::vector<size_t>> ProducerQueue::AllocateBuffers(
+ uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t buffer_count) {
+ if (capacity() + buffer_count > kMaxQueueCapacity) {
+ ALOGE(
+ "ProducerQueue::AllocateBuffers: queue is at capacity: %zu, cannot "
+ "allocate %zu more buffer(s).",
+ capacity(), buffer_count);
+ return ErrorStatus(E2BIG);
}
- if (is_full()) {
- ALOGE("ProducerQueue::AllocateBuffer queue is at maximum capacity: %zu",
- capacity());
- return -E2BIG;
- }
-
- const size_t kBufferCount = 1U;
Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
- width, height, layer_count, format, usage, kBufferCount);
+ width, height, layer_count, format, usage, buffer_count);
if (!status) {
- ALOGE("ProducerQueue::AllocateBuffer failed to create producer buffer: %s",
+ ALOGE("ProducerQueue::AllocateBuffers: failed to allocate buffers: %s",
status.GetErrorMessage().c_str());
- return -status.error();
+ return status.error_status();
}
auto buffer_handle_slots = status.take();
- LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != kBufferCount,
+ LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != buffer_count,
"BufferHubRPC::ProducerQueueAllocateBuffers should "
- "return one and only one buffer handle.");
+ "return %zu buffer handle(s), but returned %zu instead.",
+ buffer_count, buffer_handle_slots.size());
- // We only allocate one buffer at a time.
- auto& buffer_handle = buffer_handle_slots[0].first;
- size_t buffer_slot = buffer_handle_slots[0].second;
- ALOGD_IF(TRACE,
- "ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
- buffer_handle.value());
+ std::vector<size_t> buffer_slots;
+ buffer_slots.reserve(buffer_count);
- *out_slot = buffer_slot;
- return AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
- buffer_slot);
-}
+ // Bookkeeping for each buffer.
+ for (auto& hs : buffer_handle_slots) {
+ auto& buffer_handle = hs.first;
+ size_t buffer_slot = hs.second;
-int ProducerQueue::AddBuffer(const std::shared_ptr<BufferProducer>& buf,
- size_t slot) {
- ALOGD_IF(TRACE, "ProducerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
- id(), buf->id(), slot);
- // For producer buffer, we need to enqueue the newly added buffer
- // immediately. Producer queue starts with all buffers in available state.
- const int ret = BufferHubQueue::AddBuffer(buf, slot);
- if (ret < 0)
- return ret;
-
- Enqueue(buf, slot);
- return 0;
-}
-
-int ProducerQueue::DetachBuffer(size_t slot) {
- auto status =
- InvokeRemoteMethod<BufferHubRPC::ProducerQueueDetachBuffer>(slot);
- if (!status) {
- ALOGE("ProducerQueue::DetachBuffer: Failed to detach producer buffer: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
+ // Note that import might (though very unlikely) fail. If so, buffer_handle
+ // will be closed and included in returned buffer_slots.
+ if (AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
+ buffer_slot)) {
+ ALOGD_IF(TRACE, "ProducerQueue::AllocateBuffers: new buffer at slot: %zu",
+ buffer_slot);
+ buffer_slots.push_back(buffer_slot);
+ }
}
- return BufferHubQueue::DetachBuffer(slot);
+ if (buffer_slots.size() == 0) {
+ // Error out if no buffer is allocated and improted.
+ ALOGE_IF(TRACE, "ProducerQueue::AllocateBuffers: no buffer allocated.");
+ ErrorStatus(ENOMEM);
+ }
+
+ return {std::move(buffer_slots)};
+}
+
+Status<size_t> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count,
+ uint32_t format, uint64_t usage) {
+ // We only allocate one buffer at a time.
+ constexpr size_t buffer_count = 1;
+ auto status =
+ AllocateBuffers(width, height, layer_count, format, usage, buffer_count);
+ if (!status) {
+ ALOGE("ProducerQueue::AllocateBuffer: Failed to allocate buffer: %s",
+ status.GetErrorMessage().c_str());
+ return status.error_status();
+ }
+
+ if (status.get().size() == 0) {
+ ALOGE_IF(TRACE, "ProducerQueue::AllocateBuffer: no buffer allocated.");
+ ErrorStatus(ENOMEM);
+ }
+
+ return {status.get()[0]};
+}
+
+Status<void> ProducerQueue::AddBuffer(
+ const std::shared_ptr<BufferProducer>& buffer, size_t slot) {
+ ALOGD_IF(TRACE, "ProducerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
+ id(), buffer->id(), slot);
+ // For producer buffer, we need to enqueue the newly added buffer
+ // immediately. Producer queue starts with all buffers in available state.
+ auto status = BufferHubQueue::AddBuffer(buffer, slot);
+ if (!status)
+ return status;
+
+ return Enqueue(buffer, slot);
+}
+
+Status<void> ProducerQueue::RemoveBuffer(size_t slot) {
+ auto status =
+ InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
+ if (!status) {
+ ALOGE("ProducerQueue::RemoveBuffer: Failed to remove producer buffer: %s",
+ status.GetErrorMessage().c_str());
+ return status.error_status();
+ }
+
+ return BufferHubQueue::RemoveBuffer(slot);
}
Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
@@ -471,12 +557,22 @@
return {std::static_pointer_cast<BufferProducer>(buffer_status.take())};
}
-int ProducerQueue::OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
- LocalHandle* release_fence) {
- ALOGD_IF(TRACE, "ProducerQueue::OnBufferReady: queue_id=%d buffer_id=%d",
- id(), buf->id());
- auto buffer = std::static_pointer_cast<BufferProducer>(buf);
- return buffer->Gain(release_fence);
+Status<BufferHubQueue::Entry> ProducerQueue::OnBufferReady(
+ const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
+ ALOGD_IF(TRACE,
+ "ProducerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu",
+ id(), buffer->id(), slot);
+
+ // Avoid taking a transient reference, buffer is valid for the duration of
+ // this method call.
+ auto* producer_buffer = static_cast<BufferProducer*>(buffer.get());
+ LocalHandle release_fence;
+
+ const int ret = producer_buffer->Gain(&release_fence);
+ if (ret < 0)
+ return ErrorStatus(-ret);
+ else
+ return {{buffer, nullptr, std::move(release_fence), slot}};
}
ConsumerQueue::ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import)
@@ -503,12 +599,12 @@
if (!status) {
ALOGE("ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
status.GetErrorMessage().c_str());
- return ErrorStatus(status.error());
+ return status.error_status();
}
int ret;
- int last_error = 0;
- int imported_buffers = 0;
+ Status<void> last_error;
+ size_t imported_buffers_count = 0;
auto buffer_handle_slots = status.take();
for (auto& buffer_handle_slot : buffer_handle_slots) {
@@ -517,6 +613,12 @@
std::unique_ptr<BufferConsumer> buffer_consumer =
BufferConsumer::Import(std::move(buffer_handle_slot.first));
+ if (!buffer_consumer) {
+ ALOGE("ConsumerQueue::ImportBuffers: Failed to import buffer: slot=%zu",
+ buffer_handle_slot.second);
+ last_error = ErrorStatus(EPIPE);
+ continue;
+ }
// Setup ignore state before adding buffer to the queue.
if (ignore_on_import_) {
@@ -530,53 +632,52 @@
"ConsumerQueue::ImportBuffers: Failed to set ignored state on "
"imported buffer buffer_id=%d: %s",
buffer_consumer->id(), strerror(-ret));
- last_error = ret;
+ last_error = ErrorStatus(-ret);
}
}
- ret = AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
- if (ret < 0) {
+ auto add_status =
+ AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
+ if (!add_status) {
ALOGE("ConsumerQueue::ImportBuffers: Failed to add buffer: %s",
- strerror(-ret));
- last_error = ret;
- continue;
+ add_status.GetErrorMessage().c_str());
+ last_error = add_status;
} else {
- imported_buffers++;
+ imported_buffers_count++;
}
}
- if (imported_buffers > 0)
- return {imported_buffers};
+ if (imported_buffers_count > 0)
+ return {imported_buffers_count};
else
- return ErrorStatus(-last_error);
+ return last_error.error_status();
}
-int ConsumerQueue::AddBuffer(const std::shared_ptr<BufferConsumer>& buf,
- size_t slot) {
+Status<void> ConsumerQueue::AddBuffer(
+ const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
- id(), buf->id(), slot);
- const int ret = BufferHubQueue::AddBuffer(buf, slot);
- if (ret < 0)
- return ret;
+ id(), buffer->id(), slot);
+ auto status = BufferHubQueue::AddBuffer(buffer, slot);
+ if (!status)
+ return status;
// Check to see if the buffer is already signaled. This is necessary to catch
// cases where buffers are already available; epoll edge triggered mode does
// not fire until and edge transition when adding new buffers to the epoll
- // set.
- const int kTimeoutMs = 0;
- pollfd pfd{buf->event_fd(), POLLIN, 0};
- const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs));
- if (count < 0) {
- const int error = errno;
+ // set. Note that we only poll the fd events because HandleBufferEvent() takes
+ // care of checking the translated buffer events.
+ auto poll_status = PollEvents(buffer->event_fd(), POLLIN);
+ if (!poll_status && poll_status.error() != ETIMEDOUT) {
ALOGE("ConsumerQueue::AddBuffer: Failed to poll consumer buffer: %s",
- strerror(errno));
- return -error;
+ poll_status.GetErrorMessage().c_str());
+ return poll_status.error_status();
}
- if (count == 1)
- HandleBufferEvent(slot, pfd.revents);
-
- return 0;
+ // Update accounting if the buffer is available.
+ if (poll_status)
+ return HandleBufferEvent(slot, buffer->event_fd(), poll_status.get());
+ else
+ return {};
}
Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
@@ -606,15 +707,30 @@
return {std::static_pointer_cast<BufferConsumer>(buffer_status.take())};
}
-int ConsumerQueue::OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
- LocalHandle* acquire_fence) {
- ALOGD_IF(TRACE, "ConsumerQueue::OnBufferReady: queue_id=%d buffer_id=%d",
- id(), buf->id());
- auto buffer = std::static_pointer_cast<BufferConsumer>(buf);
- return buffer->Acquire(acquire_fence, meta_buffer_tmp_.get(), meta_size_);
+Status<BufferHubQueue::Entry> ConsumerQueue::OnBufferReady(
+ const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
+ ALOGD_IF(TRACE,
+ "ConsumerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu",
+ id(), buffer->id(), slot);
+
+ // Avoid taking a transient reference, buffer is valid for the duration of
+ // this method call.
+ auto* consumer_buffer = static_cast<BufferConsumer*>(buffer.get());
+ std::unique_ptr<uint8_t[]> metadata(meta_size_ ? new uint8_t[meta_size_]
+ : nullptr);
+ LocalHandle acquire_fence;
+
+ const int ret =
+ consumer_buffer->Acquire(&acquire_fence, metadata.get(), meta_size_);
+ if (ret < 0)
+ return ErrorStatus(-ret);
+ else
+ return {{buffer, std::move(metadata), std::move(acquire_fence), slot}};
}
Status<void> ConsumerQueue::OnBufferAllocated() {
+ ALOGD_IF(TRACE, "ConsumerQueue::OnBufferAllocated: queue_id=%d", id());
+
auto status = ImportBuffers();
if (!status) {
ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s",
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 8582bbf..0f75a5c 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -3,6 +3,7 @@
#include <dvr/dvr_api.h>
#include <inttypes.h>
#include <log/log.h>
+#include <system/window.h>
namespace android {
namespace dvr {
@@ -10,7 +11,10 @@
/* static */
sp<BufferHubQueueProducer> BufferHubQueueProducer::Create() {
sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
- producer->queue_ = ProducerQueue::Create<DvrNativeBufferMetadata>();
+ auto config = ProducerQueueConfigBuilder()
+ .SetMetadata<DvrNativeBufferMetadata>()
+ .Build();
+ producer->queue_ = ProducerQueue::Create(config, UsagePolicy{});
return producer;
}
@@ -127,9 +131,9 @@
status_t BufferHubQueueProducer::dequeueBuffer(
int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage,
+ PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* /* out_timestamps */) {
- ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width,
+ ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%llu", width,
height, format, usage);
status_t ret;
@@ -158,6 +162,8 @@
for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) {
LocalHandle fence;
auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
+ if (!buffer_status)
+ return NO_MEMORY;
buffer_producer = buffer_status.take();
if (!buffer_producer)
@@ -526,7 +532,7 @@
void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */,
uint32_t /* height */,
PixelFormat /* format */,
- uint32_t /* usage */) {
+ uint64_t /* usage */) {
// TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
// of buffers permitted by the current BufferQueue configuration (aka
// |max_buffer_count_|).
@@ -606,14 +612,16 @@
uint32_t layer_count,
PixelFormat format,
uint64_t usage) {
- size_t slot;
-
- if (queue_->AllocateBuffer(width, height, layer_count, format, usage, &slot) <
- 0) {
- ALOGE("Failed to allocate new buffer in BufferHub.");
+ auto status =
+ queue_->AllocateBuffer(width, height, layer_count, format, usage);
+ if (!status) {
+ ALOGE(
+ "BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s",
+ status.GetErrorMessage().c_str());
return NO_MEMORY;
}
+ size_t slot = status.get();
auto buffer_producer = queue_->GetBuffer(slot);
LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr,
@@ -625,11 +633,11 @@
}
status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) {
- int ret = queue_->DetachBuffer(slot);
- if (ret < 0) {
- ALOGE("BufferHubQueueProducer::RemoveBuffer failed through RPC, ret=%s",
- strerror(-ret));
- return ret;
+ auto status = queue_->RemoveBuffer(slot);
+ if (!status) {
+ ALOGE("BufferHubQueueProducer::RemoveBuffer: Failed to remove buffer: %s",
+ status.GetErrorMessage().c_str());
+ return INVALID_OPERATION;
}
// Reset in memory objects related the the buffer.
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index ed67f79..d57c7af 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -5,6 +5,7 @@
#include <pdx/client.h>
#include <pdx/status.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/epoll_file_descriptor.h>
#include <private/dvr/ring_buffer.h>
@@ -21,45 +22,46 @@
// automatically re-requeued when released by the remote side.
class BufferHubQueue : public pdx::Client {
public:
- using LocalHandle = pdx::LocalHandle;
- using LocalChannelHandle = pdx::LocalChannelHandle;
- template <typename T>
- using Status = pdx::Status<T>;
+ using BufferAvailableCallback = std::function<void()>;
+ using BufferRemovedCallback =
+ std::function<void(const std::shared_ptr<BufferHubBuffer>&)>;
virtual ~BufferHubQueue() {}
- void Initialize();
- // Create a new consumer queue that is attached to the producer. Returns
+ // Creates a new consumer queue that is attached to the producer. Returns
// a new consumer queue client or nullptr on failure.
std::unique_ptr<ConsumerQueue> CreateConsumerQueue();
- // Create a new consumer queue that is attached to the producer. This queue
+ // Creates a new consumer queue that is attached to the producer. This queue
// sets each of its imported consumer buffers to the ignored state to avoid
// participation in lifecycle events.
std::unique_ptr<ConsumerQueue> CreateSilentConsumerQueue();
- // Return the default buffer width of this buffer queue.
- size_t default_width() const { return default_width_; }
+ // Returns whether the buffer queue is in async mode.
+ bool is_async() const { return is_async_; }
- // Return the default buffer height of this buffer queue.
- size_t default_height() const { return default_height_; }
+ // Returns the default buffer width of this buffer queue.
+ uint32_t default_width() const { return default_width_; }
- // Return the default buffer format of this buffer queue.
- int32_t default_format() const { return default_format_; }
+ // Returns the default buffer height of this buffer queue.
+ uint32_t default_height() const { return default_height_; }
- // Create a new consumer in handle form for immediate transport over RPC.
- Status<LocalChannelHandle> CreateConsumerQueueHandle();
+ // Returns the default buffer format of this buffer queue.
+ uint32_t default_format() const { return default_format_; }
- // Return the number of buffers avaiable for dequeue.
+ // Creates a new consumer in handle form for immediate transport over RPC.
+ pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle();
+
+ // Returns the number of buffers avaiable for dequeue.
size_t count() const { return available_buffers_.GetSize(); }
- // Return the total number of buffers that the queue is tracking.
+ // Returns the total number of buffers that the queue is tracking.
size_t capacity() const { return capacity_; }
- // Return the size of metadata structure associated with this BufferBubQueue.
+ // Returns the size of metadata structure associated with this queue.
size_t metadata_size() const { return meta_size_; }
- // Return whether the buffer queue is alrady full.
+ // Returns whether the buffer queue is full.
bool is_full() const { return available_buffers_.IsFull(); }
explicit operator bool() const { return epoll_fd_.IsValid(); }
@@ -68,7 +70,7 @@
return buffers_[slot];
}
- Status<int> GetEventMask(int events) {
+ pdx::Status<int> GetEventMask(int events) {
if (auto* client_channel = GetChannel()) {
return client_channel->GetEventMask(events);
} else {
@@ -86,81 +88,100 @@
// occurred.
bool HandleQueueEvents() { return WaitForBuffers(0); }
- // Enqueue a buffer marks buffer to be available (|Gain|'ed for producer
- // and |Acquire|'ed for consumer. This is only used for internal bookkeeping.
- void Enqueue(const std::shared_ptr<BufferHubBuffer>& buf, size_t slot);
+ // Set buffer event callbacks, which are std::function wrappers. The caller is
+ // responsible for ensuring the validity of these callbacks' callable targets.
+ void SetBufferAvailableCallback(BufferAvailableCallback callback);
+ void SetBufferRemovedCallback(BufferRemovedCallback callback);
- // |BufferHubQueue| will keep track of at most this value of buffers.
+ // The queue tracks at most this many buffers.
static constexpr size_t kMaxQueueCapacity =
android::BufferQueueDefs::NUM_BUFFER_SLOTS;
- // Special epoll data field indicating that the epoll event refers to the
- // queue.
- static constexpr int64_t kEpollQueueEventIndex = -1;
-
- // When pass |kNoTimeout| to |Dequeue|, it will block indefinitely without a
- // timeout.
static constexpr int kNoTimeOut = -1;
int id() const { return id_; }
bool hung_up() const { return hung_up_; }
protected:
- BufferHubQueue(LocalChannelHandle channel);
+ BufferHubQueue(pdx::LocalChannelHandle channel);
BufferHubQueue(const std::string& endpoint_path);
// Imports the queue parameters by querying BufferHub for the parameters for
// this channel.
- Status<void> ImportQueue();
+ pdx::Status<void> ImportQueue();
// Sets up the queue with the given parameters.
- void SetupQueue(size_t meta_size_bytes_, int id);
+ void SetupQueue(const QueueInfo& queue_info);
- // Called by ProducerQueue::AddBuffer and ConsumerQueue::AddBuffer only. to
- // register a buffer for epoll and internal bookkeeping.
- int AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf, size_t slot);
+ // Register a buffer for management by the queue. Used by subclasses to add a
+ // buffer to internal bookkeeping.
+ pdx::Status<void> AddBuffer(const std::shared_ptr<BufferHubBuffer>& buffer,
+ size_t slot);
- // Called by ProducerQueue::DetachBuffer and ConsumerQueue::DetachBuffer only.
+ // Called by ProducerQueue::RemoveBuffer and ConsumerQueue::RemoveBuffer only
// to deregister a buffer for epoll and internal bookkeeping.
- virtual int DetachBuffer(size_t slot);
+ virtual pdx::Status<void> RemoveBuffer(size_t slot);
// Dequeue a buffer from the free queue, blocking until one is available. The
// timeout argument specifies the number of milliseconds that |Dequeue()| will
- // block. Specifying a timeout of -1 causes |Dequeue()| to block indefinitely,
- // while specifying a timeout equal to zero cause |Dequeue()| to return
+ // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely,
+ // while specifying a timeout equal to zero cause Dequeue() to return
// immediately, even if no buffers are available.
- pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(int timeout,
- size_t* slot,
- void* meta,
- LocalHandle* fence);
+ pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(
+ int timeout, size_t* slot, void* meta, pdx::LocalHandle* fence);
- // Wait for buffers to be released and re-add them to the queue.
+ // Waits for buffers to become available and adds them to the available queue.
bool WaitForBuffers(int timeout);
- void HandleBufferEvent(size_t slot, int poll_events);
- void HandleQueueEvent(int poll_events);
- virtual int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
- LocalHandle* fence) = 0;
+ pdx::Status<void> HandleBufferEvent(size_t slot, int event_fd,
+ int poll_events);
+ pdx::Status<void> HandleQueueEvent(int poll_events);
+
+ // Entry in the ring buffer of available buffers that stores related
+ // per-buffer data.
+ struct Entry {
+ Entry() : slot(0) {}
+ Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot)
+ : buffer(buffer), slot(slot) {}
+ Entry(const std::shared_ptr<BufferHubBuffer>& buffer,
+ std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence,
+ size_t slot)
+ : buffer(buffer),
+ metadata(std::move(metadata)),
+ fence(std::move(fence)),
+ slot(slot) {}
+ Entry(Entry&&) = default;
+ Entry& operator=(Entry&&) = default;
+
+ std::shared_ptr<BufferHubBuffer> buffer;
+ std::unique_ptr<uint8_t[]> metadata;
+ pdx::LocalHandle fence;
+ size_t slot;
+ };
+
+ // Enqueues a buffer to the available list (Gained for producer or Acquireed
+ // for consumer).
+ pdx::Status<void> Enqueue(Entry entry);
+
+ virtual pdx::Status<Entry> OnBufferReady(
+ const std::shared_ptr<BufferHubBuffer>& buf, size_t slot) = 0;
// Called when a buffer is allocated remotely.
- virtual Status<void> OnBufferAllocated() { return {}; }
+ virtual pdx::Status<void> OnBufferAllocated() { return {}; }
- // Data members to handle arbitrary metadata passed through BufferHub. It is
- // fair to enforce that all buffers in the same queue share the same metadata
- // type. |meta_size_| is used to store the size of metadata on queue creation;
- // and |meta_buffer_tmp_| is allocated and resized to |meta_size_| on queue
- // creation to be later used as temporary space so that we can avoid
- // additional dynamic memory allocation in each |Enqueue| and |Dequeue| call.
- size_t meta_size_;
-
- // Here we intentionally choose |unique_ptr<uint8_t[]>| over vector<uint8_t>
- // to disallow dynamic resizing for stability reasons.
- std::unique_ptr<uint8_t[]> meta_buffer_tmp_;
+ // Size of the metadata that buffers in this queue cary.
+ size_t meta_size_{0};
private:
+ void Initialize();
+
+ // Special epoll data field indicating that the epoll event refers to the
+ // queue.
+ static constexpr int64_t kEpollQueueEventIndex = -1;
+
static constexpr size_t kMaxEvents = 128;
- // The |u64| data field of an epoll event is interpreted as int64_t:
+ // The u64 data field of an epoll event is interpreted as int64_t:
// When |index| >= 0 and |index| < kMaxQueueCapacity it refers to a specific
// element of |buffers_| as a direct index;
static bool is_buffer_event_index(int64_t index) {
@@ -168,102 +189,40 @@
index < static_cast<int64_t>(BufferHubQueue::kMaxQueueCapacity);
}
- // When |index| == kEpollQueueEventIndex, it refers to the queue itself.
+ // When |index| == kEpollQueueEventIndex it refers to the queue itself.
static bool is_queue_event_index(int64_t index) {
return index == BufferHubQueue::kEpollQueueEventIndex;
}
- struct BufferInfo {
- // A logical slot number that is assigned to a buffer at allocation time.
- // The slot number remains unchanged during the entire life cycle of the
- // buffer and should not be confused with the enqueue and dequeue order.
- size_t slot;
+ // Whether the buffer queue is operating in Async mode.
+ // From GVR's perspective of view, this means a buffer can be acquired
+ // asynchronously by the compositor.
+ // From Android Surface's perspective of view, this is equivalent to
+ // IGraphicBufferProducer's async mode. When in async mode, a producer
+ // will never block even if consumer is running slow.
+ bool is_async_{false};
- // A BufferHubBuffer client.
- std::shared_ptr<BufferHubBuffer> buffer;
-
- // Metadata associated with the buffer.
- std::unique_ptr<uint8_t[]> metadata;
-
- BufferInfo() : BufferInfo(-1, 0) {}
-
- BufferInfo(size_t slot, size_t metadata_size)
- : slot(slot),
- buffer(nullptr),
- metadata(metadata_size ? new uint8_t[metadata_size] : nullptr) {}
-
- BufferInfo(BufferInfo&& other)
- : slot(other.slot),
- buffer(std::move(other.buffer)),
- metadata(std::move(other.metadata)) {}
-
- BufferInfo& operator=(BufferInfo&& other) {
- slot = other.slot;
- buffer = std::move(other.buffer);
- metadata = std::move(other.metadata);
- return *this;
- }
-
- private:
- BufferInfo(const BufferInfo&) = delete;
- void operator=(BufferInfo&) = delete;
- };
-
- // Default buffer width that can be set to override the buffer width when a
- // width and height of 0 are specified in AllocateBuffer.
+ // Default buffer width that is set during ProducerQueue's creation.
size_t default_width_{1};
- // Default buffer height that can be set to override the buffer height when a
- // width and height of 0 are specified in AllocateBuffer.
+ // Default buffer height that is set during ProducerQueue's creation.
size_t default_height_{1};
- // Default buffer format that can be set to override the buffer format when it
- // isn't specified in AllocateBuffer.
- int32_t default_format_{PIXEL_FORMAT_RGBA_8888};
+ // Default buffer format that is set during ProducerQueue's creation.
+ int32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888
- // Buffer queue:
- // |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|.
- std::vector<std::shared_ptr<BufferHubBuffer>> buffers_;
+ // Tracks the buffers belonging to this queue. Buffers are stored according to
+ // "slot" in this vector. Each slot is a logical id of the buffer within this
+ // queue regardless of its queue position or presence in the ring buffer.
+ std::vector<std::shared_ptr<BufferHubBuffer>> buffers_{kMaxQueueCapacity};
- // |epollhup_pending_| tracks whether a slot of |buffers_| get detached before
- // its corresponding EPOLLHUP event got handled. This could happen as the
- // following sequence:
- // 1. Producer queue's client side allocates a new buffer (at slot 1).
- // 2. Producer queue's client side replaces an existing buffer (at slot 0).
- // This is implemented by first detaching the buffer and then allocating a
- // new buffer.
- // 3. During the same epoll_wait, Consumer queue's client side gets EPOLLIN
- // event on the queue which indicates a new buffer is available and the
- // EPOLLHUP event for slot 0. Consumer handles these two events in order.
- // 4. Consumer client calls BufferHubRPC::ConsumerQueueImportBuffers and both
- // slot 0 and (the new) slot 1 buffer will be imported. During the import
- // of the buffer at slot 1, consumer client detaches the old buffer so that
- // the new buffer can be registered. At the same time
- // |epollhup_pending_[slot]| is marked to indicate that buffer at this slot
- // was detached prior to EPOLLHUP event.
- // 5. Consumer client continues to handle the EPOLLHUP. Since
- // |epollhup_pending_[slot]| is marked as true, it can safely ignore the
- // event without detaching the newly allocated buffer at slot 1.
- //
- // In normal situations where the previously described sequence doesn't
- // happen, an EPOLLHUP event should trigger a regular buffer detach.
- std::vector<bool> epollhup_pending_;
+ // Buffers and related data that are available for dequeue.
+ RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
- // |available_buffers_| uses |dvr::RingBuffer| to implementation queue
- // sematics. When |Dequeue|, we pop the front element from
- // |available_buffers_|, and that buffer's reference count will decrease by
- // one, while another reference in |buffers_| keeps the last reference to
- // prevent the buffer from being deleted.
- RingBuffer<BufferInfo> available_buffers_;
+ // Keeps track with how many buffers have been added into the queue.
+ size_t capacity_{0};
- // Fences (acquire fence for consumer and release fence for consumer) , one
- // for each buffer slot.
- std::vector<LocalHandle> fences_;
-
- // Keep track with how many buffers have been added into the queue.
- size_t capacity_;
-
- // Epoll fd used to wait for BufferHub events.
+ // Epoll fd used to manage buffer events.
EpollFileDescriptor epoll_fd_;
// Flag indicating that the other side hung up. For ProducerQueues this
@@ -273,7 +232,11 @@
bool hung_up_{false};
// Global id for the queue that is consistent across processes.
- int id_;
+ int id_{-1};
+
+ // Buffer event callbacks
+ BufferAvailableCallback on_buffer_available_;
+ BufferRemovedCallback on_buffer_removed_;
BufferHubQueue(const BufferHubQueue&) = delete;
void operator=(BufferHubQueue&) = delete;
@@ -281,14 +244,6 @@
class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> {
public:
- template <typename Meta>
- static std::unique_ptr<ProducerQueue> Create() {
- return BASE::Create(sizeof(Meta));
- }
- static std::unique_ptr<ProducerQueue> Create(size_t meta_size_bytes) {
- return BASE::Create(meta_size_bytes);
- }
-
// Usage bits in |usage_set_mask| will be automatically masked on. Usage bits
// in |usage_clear_mask| will be automatically masked off. Note that
// |usage_set_mask| and |usage_clear_mask| may conflict with each other, but
@@ -300,59 +255,59 @@
// this will be rejected. Note that |usage_deny_set_mask| and
// |usage_deny_clear_mask| shall not conflict with each other. Such
// configuration will be treated as invalid input on creation.
- template <typename Meta>
- static std::unique_ptr<ProducerQueue> Create(uint32_t usage_set_mask,
- uint32_t usage_clear_mask,
- uint32_t usage_deny_set_mask,
- uint32_t usage_deny_clear_mask) {
- return BASE::Create(sizeof(Meta), usage_set_mask, usage_clear_mask,
- usage_deny_set_mask, usage_deny_clear_mask);
- }
- static std::unique_ptr<ProducerQueue> Create(size_t meta_size_bytes,
- uint32_t usage_set_mask,
- uint32_t usage_clear_mask,
- uint32_t usage_deny_set_mask,
- uint32_t usage_deny_clear_mask) {
- return BASE::Create(meta_size_bytes, usage_set_mask, usage_clear_mask,
- usage_deny_set_mask, usage_deny_clear_mask);
+ static std::unique_ptr<ProducerQueue> Create(
+ const ProducerQueueConfig& config, const UsagePolicy& usage) {
+ return BASE::Create(config, usage);
}
- // Import a |ProducerQueue| from a channel handle.
- static std::unique_ptr<ProducerQueue> Import(LocalChannelHandle handle) {
+ // Import a ProducerQueue from a channel handle.
+ static std::unique_ptr<ProducerQueue> Import(pdx::LocalChannelHandle handle) {
return BASE::Create(std::move(handle));
}
// Get a buffer producer. Note that the method doesn't check whether the
// buffer slot has a valid buffer that has been allocated already. When no
- // buffer has been imported before it returns |nullptr|; otherwise it returns
- // a shared pointer to a |BufferProducer|.
+ // buffer has been imported before it returns nullptr; otherwise it returns
+ // a shared pointer to a BufferProducer.
std::shared_ptr<BufferProducer> GetBuffer(size_t slot) const {
return std::static_pointer_cast<BufferProducer>(
BufferHubQueue::GetBuffer(slot));
}
+ // Batch allocate buffers. Once allocated, producer buffers are automatically
+ // enqueue'd into the ProducerQueue and available to use (i.e. in GAINED
+ // state). Upon success, returns a list of slots for each buffer allocated.
+ pdx::Status<std::vector<size_t>> AllocateBuffers(
+ uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t buffer_count);
+
// Allocate producer buffer to populate the queue. Once allocated, a producer
// buffer is automatically enqueue'd into the ProducerQueue and available to
- // use (i.e. in |Gain|'ed mode).
- // Returns Zero on success and negative error code when buffer allocation
- // fails.
- int AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage, size_t* out_slot);
+ // use (i.e. in GAINED state). Upon success, returns the slot number for the
+ // buffer allocated.
+ pdx::Status<size_t> AllocateBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage);
// Add a producer buffer to populate the queue. Once added, a producer buffer
- // is available to use (i.e. in |Gain|'ed mode).
- int AddBuffer(const std::shared_ptr<BufferProducer>& buf, size_t slot);
+ // is available to use (i.e. in GAINED state).
+ pdx::Status<void> AddBuffer(const std::shared_ptr<BufferProducer>& buffer,
+ size_t slot);
- // Detach producer buffer from the queue.
- // Returns Zero on success and negative error code when buffer detach
- // fails.
- int DetachBuffer(size_t slot) override;
+ // Remove producer buffer from the queue.
+ pdx::Status<void> RemoveBuffer(size_t slot) override;
// Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
// and caller should call Post() once it's done writing to release the buffer
// to the consumer side.
pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
- int timeout, size_t* slot, LocalHandle* release_fence);
+ int timeout, size_t* slot, pdx::LocalHandle* release_fence);
+
+ // Enqueues a producer buffer in the queue.
+ pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer,
+ size_t slot) {
+ return BufferHubQueue::Enqueue({buffer, slot});
+ }
private:
friend BASE;
@@ -360,29 +315,13 @@
// Constructors are automatically exposed through ProducerQueue::Create(...)
// static template methods inherited from ClientBase, which take the same
// arguments as the constructors.
- explicit ProducerQueue(size_t meta_size);
- ProducerQueue(LocalChannelHandle handle);
- ProducerQueue(size_t meta_size, uint64_t usage_set_mask,
- uint64_t usage_clear_mask, uint64_t usage_deny_set_mask,
- uint64_t usage_deny_clear_mask);
+ explicit ProducerQueue(pdx::LocalChannelHandle handle);
+ ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
- int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
- LocalHandle* release_fence) override;
+ pdx::Status<Entry> OnBufferReady(
+ const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override;
};
-// Explicit specializations of ProducerQueue::Create for void metadata type.
-template <>
-inline std::unique_ptr<ProducerQueue> ProducerQueue::Create<void>() {
- return ProducerQueue::Create(0);
-}
-template <>
-inline std::unique_ptr<ProducerQueue> ProducerQueue::Create<void>(
- uint32_t usage_set_mask, uint32_t usage_clear_mask,
- uint32_t usage_deny_set_mask, uint32_t usage_deny_clear_mask) {
- return ProducerQueue::Create(0, usage_set_mask, usage_clear_mask,
- usage_deny_set_mask, usage_deny_clear_mask);
-}
-
class ConsumerQueue : public BufferHubQueue {
public:
// Get a buffer consumer. Note that the method doesn't check whether the
@@ -399,7 +338,7 @@
// used to avoid participation in the buffer lifecycle by a consumer queue
// that is only used to spawn other consumer queues, such as in an
// intermediate service.
- static std::unique_ptr<ConsumerQueue> Import(LocalChannelHandle handle,
+ static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle,
bool ignore_on_import = false) {
return std::unique_ptr<ConsumerQueue>(
new ConsumerQueue(std::move(handle), ignore_on_import));
@@ -407,7 +346,7 @@
// Import newly created buffers from the service side.
// Returns number of buffers successfully imported or an error.
- Status<size_t> ImportBuffers();
+ pdx::Status<size_t> ImportBuffers();
// Dequeue a consumer buffer to read. The returned buffer in |Acquired|'ed
// mode, and caller should call Releasse() once it's done writing to release
@@ -417,33 +356,34 @@
// when the buffer is orignally created.
template <typename Meta>
pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
- int timeout, size_t* slot, Meta* meta, LocalHandle* acquire_fence) {
+ int timeout, size_t* slot, Meta* meta, pdx::LocalHandle* acquire_fence) {
return Dequeue(timeout, slot, meta, sizeof(*meta), acquire_fence);
}
pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
- int timeout, size_t* slot, LocalHandle* acquire_fence) {
+ int timeout, size_t* slot, pdx::LocalHandle* acquire_fence) {
return Dequeue(timeout, slot, nullptr, 0, acquire_fence);
}
pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
int timeout, size_t* slot, void* meta, size_t meta_size,
- LocalHandle* acquire_fence);
+ pdx::LocalHandle* acquire_fence);
private:
friend BufferHubQueue;
- ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import = false);
+ ConsumerQueue(pdx::LocalChannelHandle handle, bool ignore_on_import = false);
// Add a consumer buffer to populate the queue. Once added, a consumer buffer
// is NOT available to use until the producer side |Post| it. |WaitForBuffers|
// will catch the |Post| and |Acquire| the buffer to make it available for
// consumer.
- int AddBuffer(const std::shared_ptr<BufferConsumer>& buf, size_t slot);
+ pdx::Status<void> AddBuffer(const std::shared_ptr<BufferConsumer>& buffer,
+ size_t slot);
- int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
- LocalHandle* acquire_fence) override;
+ pdx::Status<Entry> OnBufferReady(
+ const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override;
- Status<void> OnBufferAllocated() override;
+ pdx::Status<void> OnBufferAllocated() override;
// Flag indicating that imported (consumer) buffers should be ignored when
// imported to avoid participating in the buffer ownership flow.
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
index 7890176..638a56c 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
@@ -42,7 +42,7 @@
// See |IGraphicBufferProducer::dequeueBuffer|
status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
- uint32_t height, PixelFormat format, uint32_t usage,
+ uint32_t height, PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps) override;
// See |IGraphicBufferProducer::detachBuffer|
@@ -80,7 +80,7 @@
// See |IGraphicBufferProducer::allocateBuffers|
void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
- uint32_t usage) override;
+ uint64_t usage) override;
// See |IGraphicBufferProducer::allowAllocation|
status_t allowAllocation(bool allow) override;
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index fe0b12a..e0a4052 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -6,6 +6,9 @@
#include <vector>
+// Enable/disable debug logging.
+#define TRACE 0
+
namespace android {
namespace dvr {
@@ -13,22 +16,17 @@
namespace {
-constexpr int kBufferWidth = 100;
-constexpr int kBufferHeight = 1;
-constexpr int kBufferLayerCount = 1;
-constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+constexpr uint32_t kBufferWidth = 100;
+constexpr uint32_t kBufferHeight = 1;
+constexpr uint32_t kBufferLayerCount = 1;
+constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
class BufferHubQueueTest : public ::testing::Test {
public:
- template <typename Meta>
- bool CreateProducerQueue(uint64_t usage_set_mask = 0,
- uint64_t usage_clear_mask = 0,
- uint64_t usage_deny_set_mask = 0,
- uint64_t usage_deny_clear_mask = 0) {
- producer_queue_ =
- ProducerQueue::Create<Meta>(usage_set_mask, usage_clear_mask,
- usage_deny_set_mask, usage_deny_clear_mask);
+ bool CreateProducerQueue(const ProducerQueueConfig& config,
+ const UsagePolicy& usage) {
+ producer_queue_ = ProducerQueue::Create(config, usage);
return producer_queue_ != nullptr;
}
@@ -41,26 +39,25 @@
}
}
- template <typename Meta>
- bool CreateQueues(int usage_set_mask = 0, int usage_clear_mask = 0,
- int usage_deny_set_mask = 0,
- int usage_deny_clear_mask = 0) {
- return CreateProducerQueue<Meta>(usage_set_mask, usage_clear_mask,
- usage_deny_set_mask,
- usage_deny_clear_mask) &&
- CreateConsumerQueue();
+ bool CreateQueues(const ProducerQueueConfig& config,
+ const UsagePolicy& usage) {
+ return CreateProducerQueue(config, usage) && CreateConsumerQueue();
}
- void AllocateBuffer() {
+ void AllocateBuffer(size_t* slot_out = nullptr) {
// Create producer buffer.
- size_t slot;
- int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
- kBufferLayerCount, kBufferFormat,
- kBufferUsage, &slot);
- ASSERT_EQ(ret, 0);
+ auto status = producer_queue_->AllocateBuffer(
+ kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+ kBufferUsage);
+
+ ASSERT_TRUE(status.ok());
+ size_t slot = status.take();
+ if (slot_out)
+ *slot_out = slot;
}
protected:
+ ProducerQueueConfigBuilder config_builder_;
std::unique_ptr<ProducerQueue> producer_queue_;
std::unique_ptr<ConsumerQueue> consumer_queue_;
};
@@ -68,7 +65,8 @@
TEST_F(BufferHubQueueTest, TestDequeue) {
const size_t nb_dequeue_times = 16;
- ASSERT_TRUE(CreateQueues<size_t>());
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<size_t>().Build(),
+ UsagePolicy{}));
// Allocate only one buffer.
AllocateBuffer();
@@ -94,13 +92,14 @@
}
TEST_F(BufferHubQueueTest, TestProducerConsumer) {
- const size_t nb_buffer = 16;
+ const size_t kBufferCount = 16;
size_t slot;
uint64_t seq;
- ASSERT_TRUE(CreateQueues<uint64_t>());
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
+ UsagePolicy{}));
- for (size_t i = 0; i < nb_buffer; i++) {
+ for (size_t i = 0; i < kBufferCount; i++) {
AllocateBuffer();
// Producer queue has all the available buffers on initialize.
@@ -120,14 +119,23 @@
ASSERT_EQ(consumer_queue_->capacity(), i + 1);
}
- for (size_t i = 0; i < nb_buffer; i++) {
+ // Use /dev/zero as a stand-in for a fence. As long as BufferHub does not need
+ // to merge fences, which only happens when multiple consumers release the
+ // same buffer with release fences, the file object should simply pass
+ // through.
+ LocalHandle post_fence("/dev/zero", O_RDONLY);
+ struct stat post_fence_stat;
+ ASSERT_EQ(0, fstat(post_fence.Get(), &post_fence_stat));
+
+ for (size_t i = 0; i < kBufferCount; i++) {
LocalHandle fence;
- // First time, there is no buffer available to dequeue.
+
+ // First time there is no buffer available to dequeue.
auto consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
ASSERT_FALSE(consumer_status.ok());
ASSERT_EQ(ETIMEDOUT, consumer_status.error());
- // Make sure Producer buffer is Post()'ed so that it's ready to Accquire
+ // Make sure Producer buffer is POSTED so that it's ready to Accquire
// in the consumer's Dequeue() function.
auto producer_status = producer_queue_->Dequeue(0, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
@@ -135,20 +143,137 @@
ASSERT_NE(nullptr, producer);
uint64_t seq_in = static_cast<uint64_t>(i);
- ASSERT_EQ(producer->Post({}, &seq_in, sizeof(seq_in)), 0);
+ ASSERT_EQ(producer->Post(post_fence, &seq_in, sizeof(seq_in)), 0);
- // Second time, the just |Post()|'ed buffer should be dequeued.
+ // Second time the just the POSTED buffer should be dequeued.
uint64_t seq_out = 0;
consumer_status = consumer_queue_->Dequeue(0, &slot, &seq_out, &fence);
ASSERT_TRUE(consumer_status.ok());
+ EXPECT_TRUE(fence.IsValid());
+
+ struct stat acquire_fence_stat;
+ ASSERT_EQ(0, fstat(fence.Get(), &acquire_fence_stat));
+
+ // The file descriptors should refer to the same file object. Testing the
+ // device id and inode is a proxy for testing that the fds refer to the same
+ // file object.
+ EXPECT_NE(post_fence.Get(), fence.Get());
+ EXPECT_EQ(post_fence_stat.st_dev, acquire_fence_stat.st_dev);
+ EXPECT_EQ(post_fence_stat.st_ino, acquire_fence_stat.st_ino);
+
auto consumer = consumer_status.take();
ASSERT_NE(nullptr, consumer);
ASSERT_EQ(seq_in, seq_out);
}
}
+TEST_F(BufferHubQueueTest, TestRemoveBuffer) {
+ ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
+
+ // Allocate buffers.
+ const size_t kBufferCount = 4u;
+ for (size_t i = 0; i < kBufferCount; i++) {
+ AllocateBuffer();
+ }
+ ASSERT_EQ(kBufferCount, producer_queue_->count());
+ ASSERT_EQ(kBufferCount, producer_queue_->capacity());
+
+ consumer_queue_ = producer_queue_->CreateConsumerQueue();
+ ASSERT_NE(nullptr, consumer_queue_);
+
+ // Check that buffers are correctly imported on construction.
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+ EXPECT_EQ(0u, consumer_queue_->count());
+
+ // Dequeue all the buffers and keep track of them in an array. This prevents
+ // the producer queue ring buffer ref counts from interfering with the tests.
+ struct Entry {
+ std::shared_ptr<BufferProducer> buffer;
+ LocalHandle fence;
+ size_t slot;
+ };
+ std::array<Entry, kBufferCount> buffers;
+
+ for (size_t i = 0; i < kBufferCount; i++) {
+ Entry* entry = &buffers[i];
+ auto producer_status =
+ producer_queue_->Dequeue(0, &entry->slot, &entry->fence);
+ ASSERT_TRUE(producer_status.ok());
+ entry->buffer = producer_status.take();
+ ASSERT_NE(nullptr, entry->buffer);
+ EXPECT_EQ(i, entry->slot);
+ }
+
+ // Remove a buffer and make sure both queues reflect the change.
+ ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[0].slot));
+ EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity());
+
+ // As long as the removed buffer is still alive the consumer queue won't know
+ // its gone.
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+ EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+
+ // Release the removed buffer.
+ buffers[0].buffer = nullptr;
+
+ // Now the consumer queue should know it's gone.
+ EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+ EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity());
+
+ // Allocate a new buffer. This should take the first empty slot.
+ size_t slot;
+ AllocateBuffer(&slot);
+ ALOGE_IF(TRACE, "ALLOCATE %zu", slot);
+ EXPECT_EQ(buffers[0].slot, slot);
+ EXPECT_EQ(kBufferCount, producer_queue_->capacity());
+
+ // The consumer queue should pick up the new buffer.
+ EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity());
+ EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+
+ // Remove and allocate a buffer.
+ ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[1].slot));
+ EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity());
+ buffers[1].buffer = nullptr;
+
+ AllocateBuffer(&slot);
+ ALOGE_IF(TRACE, "ALLOCATE %zu", slot);
+ EXPECT_EQ(buffers[1].slot, slot);
+ EXPECT_EQ(kBufferCount, producer_queue_->capacity());
+
+ // The consumer queue should pick up the new buffer but the count shouldn't
+ // change.
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+ EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+
+ // Remove and allocate a buffer, but don't free the buffer right away.
+ ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[2].slot));
+ EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity());
+
+ AllocateBuffer(&slot);
+ ALOGE_IF(TRACE, "ALLOCATE %zu", slot);
+ EXPECT_EQ(buffers[2].slot, slot);
+ EXPECT_EQ(kBufferCount, producer_queue_->capacity());
+
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+ EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+
+ // Release the producer buffer to trigger a POLLHUP event for an already
+ // removed buffer.
+ buffers[2].buffer = nullptr;
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+ EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+ EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+}
+
TEST_F(BufferHubQueueTest, TestMultipleConsumers) {
- ASSERT_TRUE(CreateProducerQueue<void>());
+ // ProducerConfigureBuilder doesn't set Metadata{size}, which means there
+ // is no metadata associated with this BufferQueue's buffer.
+ ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
// Allocate buffers.
const size_t kBufferCount = 4u;
@@ -226,7 +351,9 @@
};
TEST_F(BufferHubQueueTest, TestMetadata) {
- ASSERT_TRUE(CreateQueues<TestMetadata>());
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<TestMetadata>().Build(),
+ UsagePolicy{}));
+
AllocateBuffer();
std::vector<TestMetadata> ms = {
@@ -252,7 +379,9 @@
}
TEST_F(BufferHubQueueTest, TestMetadataMismatch) {
- ASSERT_TRUE(CreateQueues<int64_t>());
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+ UsagePolicy{}));
+
AllocateBuffer();
int64_t mi = 3;
@@ -271,7 +400,8 @@
}
TEST_F(BufferHubQueueTest, TestEnqueue) {
- ASSERT_TRUE(CreateQueues<int64_t>());
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+ UsagePolicy{}));
AllocateBuffer();
size_t slot;
@@ -288,7 +418,8 @@
}
TEST_F(BufferHubQueueTest, TestAllocateBuffer) {
- ASSERT_TRUE(CreateQueues<int64_t>());
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+ UsagePolicy{}));
size_t s1;
AllocateBuffer();
@@ -343,16 +474,17 @@
TEST_F(BufferHubQueueTest, TestUsageSetMask) {
const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
- ASSERT_TRUE(CreateQueues<int64_t>(set_mask, 0, 0, 0));
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+ UsagePolicy{set_mask, 0, 0, 0}));
// When allocation, leave out |set_mask| from usage bits on purpose.
- size_t slot;
- int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
- kBufferFormat, kBufferLayerCount,
- kBufferUsage & ~set_mask, &slot);
- ASSERT_EQ(0, ret);
+ auto status = producer_queue_->AllocateBuffer(
+ kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+ kBufferUsage & ~set_mask);
+ ASSERT_TRUE(status.ok());
LocalHandle fence;
+ size_t slot;
auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
@@ -361,16 +493,17 @@
TEST_F(BufferHubQueueTest, TestUsageClearMask) {
const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
- ASSERT_TRUE(CreateQueues<int64_t>(0, clear_mask, 0, 0));
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+ UsagePolicy{0, clear_mask, 0, 0}));
// When allocation, add |clear_mask| into usage bits on purpose.
- size_t slot;
- int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
- kBufferLayerCount, kBufferFormat,
- kBufferUsage | clear_mask, &slot);
- ASSERT_EQ(0, ret);
+ auto status = producer_queue_->AllocateBuffer(
+ kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+ kBufferUsage | clear_mask);
+ ASSERT_TRUE(status.ok());
LocalHandle fence;
+ size_t slot;
auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
@@ -379,40 +512,62 @@
TEST_F(BufferHubQueueTest, TestUsageDenySetMask) {
const uint32_t deny_set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
- ASSERT_TRUE(CreateQueues<int64_t>(0, 0, deny_set_mask, 0));
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+ UsagePolicy{0, 0, deny_set_mask, 0}));
// Now that |deny_set_mask| is illegal, allocation without those bits should
// be able to succeed.
- size_t slot;
- int ret = producer_queue_->AllocateBuffer(
+ auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~deny_set_mask, &slot);
- ASSERT_EQ(ret, 0);
+ kBufferUsage & ~deny_set_mask);
+ ASSERT_TRUE(status.ok());
// While allocation with those bits should fail.
- ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
- kBufferLayerCount, kBufferFormat,
- kBufferUsage | deny_set_mask, &slot);
- ASSERT_EQ(ret, -EINVAL);
+ status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
+ kBufferLayerCount, kBufferFormat,
+ kBufferUsage | deny_set_mask);
+ ASSERT_FALSE(status.ok());
+ ASSERT_EQ(EINVAL, status.error());
}
TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) {
const uint32_t deny_clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
- ASSERT_TRUE(CreateQueues<int64_t>(0, 0, 0, deny_clear_mask));
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+ UsagePolicy{0, 0, 0, deny_clear_mask}));
// Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are
// mandatory), allocation with those bits should be able to succeed.
- size_t slot;
- int ret = producer_queue_->AllocateBuffer(
+ auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage | deny_clear_mask, &slot);
- ASSERT_EQ(ret, 0);
+ kBufferUsage | deny_clear_mask);
+ ASSERT_TRUE(status.ok());
// While allocation without those bits should fail.
- ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
- kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~deny_clear_mask, &slot);
- ASSERT_EQ(ret, -EINVAL);
+ status = producer_queue_->AllocateBuffer(
+ kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+ kBufferUsage & ~deny_clear_mask);
+ ASSERT_FALSE(status.ok());
+ ASSERT_EQ(EINVAL, status.error());
+}
+
+TEST_F(BufferHubQueueTest, TestQueueInfo) {
+ static const bool kIsAsync = true;
+ ASSERT_TRUE(CreateQueues(config_builder_.SetIsAsync(kIsAsync)
+ .SetDefaultWidth(kBufferWidth)
+ .SetDefaultHeight(kBufferHeight)
+ .SetDefaultFormat(kBufferFormat)
+ .Build(),
+ UsagePolicy{}));
+
+ EXPECT_EQ(producer_queue_->default_width(), kBufferWidth);
+ EXPECT_EQ(producer_queue_->default_height(), kBufferHeight);
+ EXPECT_EQ(producer_queue_->default_format(), kBufferFormat);
+ EXPECT_EQ(producer_queue_->is_async(), kIsAsync);
+
+ EXPECT_EQ(consumer_queue_->default_width(), kBufferWidth);
+ EXPECT_EQ(consumer_queue_->default_height(), kBufferHeight);
+ EXPECT_EQ(consumer_queue_->default_format(), kBufferFormat);
+ EXPECT_EQ(consumer_queue_->is_async(), kIsAsync);
}
} // namespace
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index 2b6239f..c7692d0 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -192,7 +192,7 @@
EXPECT_EQ(NO_ERROR,
mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value));
EXPECT_LE(0, value);
- EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, static_cast<size_t>(value));
+ EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, value);
EXPECT_EQ(NO_ERROR,
mProducer->query(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value));
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index d90521a..e3ab7fa 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -17,6 +17,7 @@
"display_manager_client.cpp",
"display_protocol.cpp",
"vsync_client.cpp",
+ "shared_buffer_helpers.cpp",
]
localIncludeFiles = [
@@ -39,12 +40,13 @@
"libdvrcommon",
"libbufferhubqueue",
"libbufferhub",
- "libvrsensor",
+ "libbroadcastring",
"libpdx_default_transport",
]
headerLibraries = [
"vulkan_headers",
+ "libdvr_headers",
]
cc_library {
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 935ca2e..442c82d 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -104,9 +104,16 @@
return {};
}
-Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue() {
+Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
+ uint32_t width, uint32_t height, uint32_t format, size_t metadata_size) {
ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue.");
- auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(0);
+ auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(
+ ProducerQueueConfigBuilder()
+ .SetDefaultWidth(width)
+ .SetDefaultHeight(height)
+ .SetDefaultFormat(format)
+ .SetMetadataSize(metadata_size)
+ .Build());
if (!status) {
ALOGE("Surface::CreateQueue: Failed to create queue: %s",
status.GetErrorMessage().c_str());
@@ -124,32 +131,24 @@
Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t capacity) {
+ uint64_t usage, size_t capacity, size_t metadata_size) {
ALOGD_IF(TRACE,
"Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u "
"usage=%" PRIx64 " capacity=%zu",
width, height, layer_count, format, usage, capacity);
- auto status = CreateQueue();
+ auto status = CreateQueue(width, height, format, metadata_size);
if (!status)
return status.error_status();
auto producer_queue = status.take();
ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity);
- for (size_t i = 0; i < capacity; i++) {
- size_t slot;
- const int ret = producer_queue->AllocateBuffer(width, height, layer_count,
- format, usage, &slot);
- if (ret < 0) {
- ALOGE(
- "Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
- producer_queue->id(), strerror(-ret));
- return ErrorStatus(ENOMEM);
- }
- ALOGD_IF(
- TRACE,
- "Surface::CreateQueue: Allocated buffer at slot=%zu of capacity=%zu",
- slot, capacity);
+ auto allocate_status = producer_queue->AllocateBuffers(
+ width, height, layer_count, format, usage, capacity);
+ if (!allocate_status) {
+ ALOGE("Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
+ producer_queue->id(), allocate_status.GetErrorMessage().c_str());
+ return allocate_status.error_status();
}
return {std::move(producer_queue)};
@@ -167,6 +166,19 @@
return InvokeRemoteMethod<DisplayProtocol::GetMetrics>();
}
+Status<std::string> DisplayClient::GetConfigurationData(
+ ConfigFileType config_type) {
+ auto status =
+ InvokeRemoteMethod<DisplayProtocol::GetConfigurationData>(config_type);
+ if (!status && status.error() != ENOENT) {
+ ALOGE(
+ "DisplayClient::GetConfigurationData: Unable to get"
+ "configuration data. Error: %s",
+ status.GetErrorMessage().c_str());
+ }
+ return status;
+}
+
Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface(
const SurfaceAttributes& attributes) {
int error;
@@ -176,14 +188,15 @@
return ErrorStatus(error);
}
-Status<std::unique_ptr<IonBuffer>> DisplayClient::GetNamedBuffer(
- const std::string& name) {
- auto status = InvokeRemoteMethod<DisplayProtocol::GetNamedBuffer>(name);
+pdx::Status<std::unique_ptr<IonBuffer>> DisplayClient::SetupGlobalBuffer(
+ DvrGlobalBufferKey key, size_t size, uint64_t usage) {
+ auto status =
+ InvokeRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(key, size, usage);
if (!status) {
ALOGE(
- "DisplayClient::GetNamedBuffer: Failed to get named buffer: name=%s; "
- "error=%s",
- name.c_str(), status.GetErrorMessage().c_str());
+ "DisplayClient::SetupGlobalBuffer: Failed to create the global buffer "
+ "%s",
+ status.GetErrorMessage().c_str());
return status.error_status();
}
@@ -192,9 +205,44 @@
const int ret = native_buffer_handle.Import(ion_buffer.get());
if (ret < 0) {
ALOGE(
- "DisplayClient::GetNamedBuffer: Failed to import named buffer: "
- "name=%s; error=%s",
- name.c_str(), strerror(-ret));
+ "DisplayClient::GetGlobalBuffer: Failed to import global buffer: "
+ "key=%d; error=%s",
+ key, strerror(-ret));
+ return ErrorStatus(-ret);
+ }
+
+ return {std::move(ion_buffer)};
+}
+
+pdx::Status<void> DisplayClient::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
+ auto status = InvokeRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(key);
+ if (!status) {
+ ALOGE("DisplayClient::DeleteGlobalBuffer Failed: %s",
+ status.GetErrorMessage().c_str());
+ }
+
+ return status;
+}
+
+Status<std::unique_ptr<IonBuffer>> DisplayClient::GetGlobalBuffer(
+ DvrGlobalBufferKey key) {
+ auto status = InvokeRemoteMethod<DisplayProtocol::GetGlobalBuffer>(key);
+ if (!status) {
+ ALOGE(
+ "DisplayClient::GetGlobalBuffer: Failed to get named buffer: key=%d; "
+ "error=%s",
+ key, status.GetErrorMessage().c_str());
+ return status.error_status();
+ }
+
+ auto ion_buffer = std::make_unique<IonBuffer>();
+ auto native_buffer_handle = status.take();
+ const int ret = native_buffer_handle.Import(ion_buffer.get());
+ if (ret < 0) {
+ ALOGE(
+ "DisplayClient::GetGlobalBuffer: Failed to import global buffer: "
+ "key=%d; error=%s",
+ key, strerror(-ret));
return ErrorStatus(-ret);
}
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index 82dacf7..974c231 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -32,32 +32,6 @@
return status;
}
-pdx::Status<std::unique_ptr<IonBuffer>> DisplayManagerClient::SetupNamedBuffer(
- const std::string& name, size_t size, uint64_t usage) {
- auto status = InvokeRemoteMethod<DisplayManagerProtocol::SetupNamedBuffer>(
- name, size, usage);
- if (!status) {
- ALOGE(
- "DisplayManagerClient::SetupPoseBuffer: Failed to create the named "
- "buffer %s",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- auto ion_buffer = std::make_unique<IonBuffer>();
- auto native_buffer_handle = status.take();
- const int ret = native_buffer_handle.Import(ion_buffer.get());
- if (ret < 0) {
- ALOGE(
- "DisplayClient::GetNamedBuffer: Failed to import named buffer: "
- "name=%s; error=%s",
- name.c_str(), strerror(-ret));
- return ErrorStatus(-ret);
- }
-
- return {std::move(ion_buffer)};
-}
-
pdx::Status<std::unique_ptr<ConsumerQueue>>
DisplayManagerClient::GetSurfaceQueue(int surface_id, int queue_id) {
auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>(
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index 7a7f670..caf3182 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -1,6 +1,7 @@
#ifndef ANDROID_DVR_DISPLAY_CLIENT_H_
#define ANDROID_DVR_DISPLAY_CLIENT_H_
+#include <dvr/dvr_api.h>
#include <hardware/hwcomposer.h>
#include <pdx/client.h>
#include <pdx/file_handle.h>
@@ -36,7 +37,10 @@
pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes);
// Creates an empty queue.
- pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue();
+ pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ size_t metadata_size);
// Creates a queue and populates it with |capacity| buffers of the specified
// parameters.
@@ -45,7 +49,8 @@
uint32_t layer_count,
uint32_t format,
uint64_t usage,
- size_t capacity);
+ size_t capacity,
+ size_t metadata_size);
private:
friend BASE;
@@ -67,8 +72,12 @@
class DisplayClient : public pdx::ClientBase<DisplayClient> {
public:
pdx::Status<Metrics> GetDisplayMetrics();
- pdx::Status<std::unique_ptr<IonBuffer>> GetNamedBuffer(
- const std::string& name);
+ pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type);
+ pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer(
+ DvrGlobalBufferKey key, size_t size, uint64_t usage);
+ pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
+ pdx::Status<std::unique_ptr<IonBuffer>> GetGlobalBuffer(
+ DvrGlobalBufferKey key);
pdx::Status<std::unique_ptr<Surface>> CreateSurface(
const SurfaceAttributes& attributes);
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
index fea8415..45aef51 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
@@ -21,8 +21,6 @@
~DisplayManagerClient() override;
pdx::Status<std::vector<SurfaceState>> GetSurfaceState();
- pdx::Status<std::unique_ptr<IonBuffer>> SetupNamedBuffer(
- const std::string& name, size_t size, uint64_t usage);
pdx::Status<std::unique_ptr<ConsumerQueue>> GetSurfaceQueue(int surface_id,
int queue_id);
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index f34d61f..eff50ba 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -8,6 +8,8 @@
#include <dvr/dvr_display_types.h>
+#include <dvr/dvr_api.h>
+#include <pdx/rpc/buffer_wrapper.h>
#include <pdx/rpc/remote_method.h>
#include <pdx/rpc/serializable.h>
#include <pdx/rpc/variant.h>
@@ -184,6 +186,12 @@
PDX_SERIALIZABLE_MEMBERS(SurfaceInfo, surface_id, visible, z_order);
};
+enum class ConfigFileType : uint32_t {
+ kLensMetrics,
+ kDeviceMetrics,
+ kDeviceConfiguration
+};
+
struct DisplayProtocol {
// Service path.
static constexpr char kClientPath[] = "system/vr/display/client";
@@ -191,7 +199,10 @@
// Op codes.
enum {
kOpGetMetrics = 0,
- kOpGetNamedBuffer,
+ kOpGetConfigurationData,
+ kOpSetupGlobalBuffer,
+ kOpDeleteGlobalBuffer,
+ kOpGetGlobalBuffer,
kOpIsVrAppRunning,
kOpCreateSurface,
kOpGetSurfaceInfo,
@@ -205,14 +216,22 @@
// Methods.
PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void));
- PDX_REMOTE_METHOD(GetNamedBuffer, kOpGetNamedBuffer,
- LocalNativeBufferHandle(std::string name));
+ PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData,
+ std::string(ConfigFileType config_type));
+ PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer,
+ LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size,
+ uint64_t usage));
+ PDX_REMOTE_METHOD(DeleteGlobalBuffer, kOpDeleteGlobalBuffer,
+ void(DvrGlobalBufferKey key));
+ PDX_REMOTE_METHOD(GetGlobalBuffer, kOpGetGlobalBuffer,
+ LocalNativeBufferHandle(DvrGlobalBufferKey key));
PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, bool(Void));
PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface,
SurfaceInfo(const SurfaceAttributes& attributes));
PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void));
- PDX_REMOTE_METHOD(CreateQueue, kOpCreateQueue,
- LocalChannelHandle(size_t meta_size_bytes));
+ PDX_REMOTE_METHOD(
+ CreateQueue, kOpCreateQueue,
+ LocalChannelHandle(const ProducerQueueConfig& producer_config));
PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes,
void(const SurfaceAttributes& attributes));
};
@@ -225,7 +244,6 @@
enum {
kOpGetSurfaceState = 0,
kOpGetSurfaceQueue,
- kOpSetupNamedBuffer,
};
// Aliases.
@@ -237,9 +255,6 @@
std::vector<SurfaceState>(Void));
PDX_REMOTE_METHOD(GetSurfaceQueue, kOpGetSurfaceQueue,
LocalChannelHandle(int surface_id, int queue_id));
- PDX_REMOTE_METHOD(SetupNamedBuffer, kOpSetupNamedBuffer,
- LocalNativeBufferHandle(const std::string& name,
- size_t size, uint64_t usage));
};
struct VSyncSchedInfo {
diff --git a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
new file mode 100644
index 0000000..20541a6
--- /dev/null
+++ b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
@@ -0,0 +1,146 @@
+#ifndef ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
+#define ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
+
+#include <assert.h>
+#include <tuple>
+
+#include <libbroadcastring/broadcast_ring.h>
+#include <private/dvr/display_client.h>
+
+namespace android {
+namespace dvr {
+
+// The buffer usage type for mapped shared buffers.
+enum class CPUUsageMode { READ_OFTEN, READ_RARELY, WRITE_OFTEN, WRITE_RARELY };
+
+// Holds the memory for the mapped shared buffer. Unlocks and releases the
+// underlying IonBuffer in destructor.
+class CPUMappedBuffer {
+ public:
+ // This constructor will create a display client and get the buffer from it.
+ CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode);
+
+ // If you already have the IonBuffer, use this. It will take ownership.
+ CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode);
+
+ // Use this if you do not want to take ownership.
+ CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode);
+
+ ~CPUMappedBuffer();
+
+ // Getters.
+ size_t Size() const { return size_; }
+ void* Address() const { return address_; }
+ bool IsMapped() const { return Address() != nullptr; }
+
+ // Attempt mapping this buffer to the CPU addressable space.
+ // This will create a display client and see if the buffer exists.
+ // If the buffer has not been setup yet, you will need to try again later.
+ void TryMapping();
+
+ protected:
+ // The memory area if we managed to map it.
+ size_t size_ = 0;
+ void* address_ = nullptr;
+
+ // If we are polling the display client, the buffer key here.
+ DvrGlobalBufferKey buffer_key_;
+
+ // If we just own the IonBuffer outright, it's here.
+ std::unique_ptr<IonBuffer> owned_buffer_ = nullptr;
+
+ // The last time we connected to the display service.
+ int64_t last_display_service_connection_ns_ = 0;
+
+ // If we do not own the IonBuffer, it's here
+ IonBuffer* buffer_ = nullptr;
+
+ // The usage mode.
+ CPUUsageMode usage_mode_ = CPUUsageMode::READ_OFTEN;
+};
+
+// Represents a broadcast ring inside a mapped shared memory buffer.
+// If has the same set of constructors as CPUMappedBuffer.
+// The template argument is the concrete BroadcastRing class that this buffer
+// holds.
+template <class RingType>
+class CPUMappedBroadcastRing : public CPUMappedBuffer {
+ public:
+ CPUMappedBroadcastRing(DvrGlobalBufferKey key, CPUUsageMode mode)
+ : CPUMappedBuffer(key, mode) {}
+
+ CPUMappedBroadcastRing(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode)
+ : CPUMappedBuffer(std::move(buffer), mode) {}
+
+ CPUMappedBroadcastRing(IonBuffer* buffer, CPUUsageMode mode)
+ : CPUMappedBuffer(buffer, mode) {}
+
+ // Helper function for publishing records in the ring.
+ void Publish(const typename RingType::Record& record) {
+ assert((usage_mode_ == CPUUsageMode::WRITE_OFTEN) ||
+ (usage_mode_ == CPUUsageMode::WRITE_RARELY));
+
+ auto ring = Ring();
+ if (ring) {
+ ring->Put(record);
+ }
+ }
+
+ // Helper function for getting records from the ring.
+ // Returns true if we were able to retrieve the latest.
+ bool GetNewest(typename RingType::Record* record) {
+ assert((usage_mode_ == CPUUsageMode::READ_OFTEN) ||
+ (usage_mode_ == CPUUsageMode::READ_RARELY));
+
+ auto ring = Ring();
+ if (ring) {
+ return ring->GetNewest(&sequence_, record);
+ }
+
+ return false;
+ }
+
+ // Try obtaining the ring. If the named buffer has not been created yet, it
+ // will return nullptr.
+ RingType* Ring() {
+ // No ring created yet?
+ if (ring_ == nullptr) {
+ // Not mapped the memory yet?
+ if (IsMapped() == false) {
+ TryMapping();
+ }
+
+ // If have the memory mapped, allocate the ring.
+ if (IsMapped()) {
+ switch (usage_mode_) {
+ case CPUUsageMode::READ_OFTEN:
+ case CPUUsageMode::READ_RARELY: {
+ RingType ring;
+ bool import_ok;
+ std::tie(ring, import_ok) = RingType::Import(address_, size_);
+ if (import_ok) {
+ ring_ = std::make_unique<RingType>(ring);
+ }
+ } break;
+ case CPUUsageMode::WRITE_OFTEN:
+ case CPUUsageMode::WRITE_RARELY:
+ ring_ =
+ std::make_unique<RingType>(RingType::Create(address_, size_));
+ break;
+ }
+ }
+ }
+
+ return ring_.get();
+ }
+
+ protected:
+ std::unique_ptr<RingType> ring_ = nullptr;
+
+ uint32_t sequence_ = 0;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
diff --git a/libs/vr/libdisplay/shared_buffer_helpers.cpp b/libs/vr/libdisplay/shared_buffer_helpers.cpp
new file mode 100644
index 0000000..6ebf487
--- /dev/null
+++ b/libs/vr/libdisplay/shared_buffer_helpers.cpp
@@ -0,0 +1,98 @@
+#include <private/dvr/clock_ns.h>
+#include <private/dvr/shared_buffer_helpers.h>
+
+namespace android {
+namespace dvr {
+namespace {
+
+// We will not poll the display service for buffers more frequently than this.
+constexpr size_t kDisplayServiceTriesPerSecond = 2;
+} // namespace
+
+CPUMappedBuffer::CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode)
+ : buffer_key_(key), usage_mode_(mode) {
+ TryMapping();
+}
+
+CPUMappedBuffer::CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer,
+ CPUUsageMode mode)
+ : owned_buffer_(std::move(buffer)),
+ buffer_(owned_buffer_.get()),
+ usage_mode_(mode) {
+ TryMapping();
+}
+
+CPUMappedBuffer::CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode)
+ : buffer_(buffer), usage_mode_(mode) {
+ TryMapping();
+}
+
+CPUMappedBuffer::~CPUMappedBuffer() {
+ if (IsMapped()) {
+ buffer_->Unlock();
+ }
+}
+
+void CPUMappedBuffer::TryMapping() {
+ // Do we have an IonBuffer for this shared memory object?
+ if (buffer_ == nullptr) {
+ // Has it been too long since we last connected to the display service?
+ const auto current_time_ns = GetSystemClockNs();
+ if ((current_time_ns - last_display_service_connection_ns_) <
+ (1e9 / kDisplayServiceTriesPerSecond)) {
+ // Early exit.
+ return;
+ }
+ last_display_service_connection_ns_ = current_time_ns;
+
+ // Create a display client and get the buffer.
+ auto display_client = display::DisplayClient::Create();
+ if (display_client) {
+ auto get_result = display_client->GetGlobalBuffer(buffer_key_);
+ if (get_result.ok()) {
+ owned_buffer_ = get_result.take();
+ buffer_ = owned_buffer_.get();
+ } else {
+ // The buffer has not been created yet. This is OK, we will keep
+ // retrying.
+ }
+ } else {
+ ALOGE("Unable to create display client for shared buffer access");
+ }
+ }
+
+ if (buffer_) {
+ auto usage = buffer_->usage() & ~GRALLOC_USAGE_SW_READ_MASK &
+ ~GRALLOC_USAGE_SW_WRITE_MASK;
+
+ // Figure out the usage bits.
+ switch (usage_mode_) {
+ case CPUUsageMode::READ_OFTEN:
+ usage |= GRALLOC_USAGE_SW_READ_OFTEN;
+ break;
+ case CPUUsageMode::READ_RARELY:
+ usage |= GRALLOC_USAGE_SW_READ_RARELY;
+ break;
+ case CPUUsageMode::WRITE_OFTEN:
+ usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+ break;
+ case CPUUsageMode::WRITE_RARELY:
+ usage |= GRALLOC_USAGE_SW_WRITE_RARELY;
+ break;
+ }
+
+ int width = static_cast<int>(buffer_->width());
+ int height = 1;
+ const auto ret = buffer_->Lock(usage, 0, 0, width, height, &address_);
+
+ if (ret < 0 || !address_) {
+ ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, address_);
+ buffer_->Unlock();
+ } else {
+ size_ = width;
+ }
+ }
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index fa78b1c..7fe9825 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -21,27 +21,32 @@
cflags = [
"-DLOG_TAG=\"libdvr\"",
+ "-DTRACE=0",
]
srcs = [
"dvr_api.cpp",
"dvr_buffer.cpp",
"dvr_buffer_queue.cpp",
+ "dvr_configuration_data.cpp",
"dvr_display_manager.cpp",
"dvr_hardware_composer_client.cpp",
+ "dvr_performance.cpp",
"dvr_surface.cpp",
"dvr_vsync.cpp",
]
static_libs = [
+ "libbroadcastring",
"libbufferhub",
"libbufferhubqueue",
- "libdisplay",
"libvrsensor",
+ "libdisplay",
"libvirtualtouchpadclient",
"libvr_hwc-impl",
"libvr_hwc-binder",
"libgrallocusage",
+ "libperformance",
"libpdx_default_transport",
]
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index 2c95583..7d4e2d1 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -3,10 +3,14 @@
#include <errno.h>
#include <utils/Log.h>
+#include <algorithm>
+
// Headers from libdvr
#include <dvr/dvr_buffer.h>
#include <dvr/dvr_buffer_queue.h>
+#include <dvr/dvr_configuration_data.h>
#include <dvr/dvr_display_manager.h>
+#include <dvr/dvr_performance.h>
#include <dvr/dvr_surface.h>
#include <dvr/dvr_vsync.h>
@@ -22,15 +26,20 @@
ALOGI("dvrGetApi: api=%p struct_size=%zu version=%d", api, struct_size,
version);
if (version == 1) {
- if (struct_size != sizeof(DvrApi_v1)) {
- ALOGE("dvrGetApi: Size mismatch: expected %zu; actual %zu",
- sizeof(DvrApi_v1), struct_size);
- return -EINVAL;
- }
+ // New entry points are added at the end. If the caller's struct and
+ // this library have different sizes, we define the entry points in common.
+ // The caller is expected to handle unset entry points if necessary.
+ size_t clamped_struct_size = std::min(struct_size, sizeof(DvrApi_v1));
DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
// Defines an API entry for V1 (no version suffix).
-#define DVR_V1_API_ENTRY(name) dvr_api->name = dvr##name
+#define DVR_V1_API_ENTRY(name) \
+ do { \
+ if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
+ clamped_struct_size) { \
+ dvr_api->name = dvr##name; \
+ } \
+ } while (0)
#include "include/dvr/dvr_api_entries.h"
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index 82469b8..4d9b215 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -1,6 +1,7 @@
#include "include/dvr/dvr_buffer.h"
#include <android/hardware_buffer.h>
+#include <dvr/dvr_shared_buffers.h>
#include <private/dvr/buffer_hub_client.h>
#include <ui/GraphicBuffer.h>
@@ -176,6 +177,11 @@
hardware_buffer);
}
+// Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
+int dvrBufferGlobalLayoutVersionGet() {
+ return android::dvr::kSharedBufferLayoutVersion;
+}
+
const struct native_handle* dvrWriteBufferGetNativeHandle(
DvrWriteBuffer* write_buffer) {
if (!write_buffer || !write_buffer->write_buffer)
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index f668510..018abbb 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -2,60 +2,176 @@
#include "include/dvr/dvr_buffer_queue.h"
#include <android/native_window.h>
-#include <gui/Surface.h>
-#include <private/dvr/buffer_hub_queue_client.h>
#include <private/dvr/buffer_hub_queue_producer.h>
#include "dvr_internal.h"
-
-#define CHECK_PARAM(param) \
- LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
- __FUNCTION__)
+#include "dvr_buffer_queue_internal.h"
using namespace android;
-
-namespace android {
-namespace dvr {
-
-DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
- const std::shared_ptr<dvr::ProducerQueue>& producer_queue) {
- return new DvrWriteBufferQueue{std::move(producer_queue)};
-}
-
-DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
- const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) {
- return new DvrReadBufferQueue{std::move(consumer_queue)};
-}
-
-dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
- DvrWriteBufferQueue* write_queue) {
- return write_queue->producer_queue.get();
-}
-
-} // namespace dvr
-} // namespace android
+using android::dvr::BufferConsumer;
+using android::dvr::BufferHubBuffer;
+using android::dvr::BufferHubQueueProducer;
+using android::dvr::BufferProducer;
+using android::dvr::ConsumerQueue;
+using android::dvr::ProducerQueue;
extern "C" {
-void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
- if (write_queue != nullptr && write_queue->native_window != nullptr)
- ANativeWindow_release(write_queue->native_window);
+DvrWriteBufferQueue::DvrWriteBufferQueue(
+ const std::shared_ptr<ProducerQueue>& producer_queue)
+ : producer_queue_(producer_queue),
+ width_(producer_queue->default_width()),
+ height_(producer_queue->default_height()),
+ format_(producer_queue->default_format()) {}
+int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
+ if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
+ ALOGE(
+ "DvrWriteBufferQueue::GetNativeWindow: The size of buffer metadata "
+ "(%zu) of the write queue does not match of size of "
+ "DvrNativeBufferMetadata (%zu).",
+ producer_queue_->metadata_size(), sizeof(DvrNativeBufferMetadata));
+ return -EINVAL;
+ }
+
+ if (native_window_ == nullptr) {
+ // Lazy creation of |native_window|, as not everyone is using
+ // DvrWriteBufferQueue as an external surface.
+ sp<IGraphicBufferProducer> gbp =
+ BufferHubQueueProducer::Create(producer_queue_);
+ native_window_ = new Surface(gbp, true);
+ }
+
+ *out_window = static_cast<ANativeWindow*>(native_window_.get());
+ return 0;
+}
+
+int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
+ std::unique_ptr<ConsumerQueue> consumer_queue =
+ producer_queue_->CreateConsumerQueue();
+ if (consumer_queue == nullptr) {
+ ALOGE(
+ "DvrWriteBufferQueue::CreateReadQueue: Failed to create consumer queue "
+ "from producer queue: queue_id=%d.", producer_queue_->id());
+ return -ENOMEM;
+ }
+
+ *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
+ return 0;
+}
+
+int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
+ int* out_fence_fd) {
+ size_t slot;
+ pdx::LocalHandle fence;
+ std::shared_ptr<BufferProducer> buffer_producer;
+
+ // Need to retry N+1 times, where N is total number of buffers in the queue.
+ // As in the worst case, we will dequeue all N buffers and reallocate them, on
+ // the {N+1}th dequeue, we are guaranteed to get a buffer with new dimension.
+ size_t max_retries = 1 + producer_queue_->capacity();
+ size_t retry = 0;
+
+ for (; retry < max_retries; retry++) {
+ auto buffer_status = producer_queue_->Dequeue(timeout, &slot, &fence);
+ if (!buffer_status) {
+ ALOGE_IF(buffer_status.error() != ETIMEDOUT,
+ "DvrWriteBufferQueue::Dequeue: Failed to dequeue buffer: %s",
+ buffer_status.GetErrorMessage().c_str());
+ return -buffer_status.error();
+ }
+
+ buffer_producer = buffer_status.take();
+ if (!buffer_producer)
+ return -ENOMEM;
+
+ if (width_ == buffer_producer->width() &&
+ height_ == buffer_producer->height() &&
+ format_ == buffer_producer->format()) {
+ // Producer queue returns a buffer matches the current request.
+ break;
+ }
+
+ // Needs reallocation. Note that if there are already multiple available
+ // buffers in the queue, the next one returned from |queue_->Dequeue| may
+ // still have the old buffer dimension or format. Retry up to N+1 times or
+ // until we dequeued a buffer with new configuration.
+ ALOGD_IF(TRACE,
+ "DvrWriteBufferQueue::Dequeue: requested buffer at slot: %zu "
+ "(w=%u, h=%u, fmt=%u) is different from the buffer returned "
+ "(w=%u, h=%u, fmt=%u). Need re-allocation.",
+ slot, width_, height_, format_, buffer_producer->width(),
+ buffer_producer->height(), buffer_producer->format());
+
+ // Currently, we are not storing |layer_count| and |usage| in queue
+ // configuration. Copy those setup from the last buffer dequeued before we
+ // remove it.
+ uint32_t old_layer_count = buffer_producer->layer_count();
+ uint64_t old_usage = buffer_producer->usage();
+
+ // Allocate a new producer buffer with new buffer configs. Note that if
+ // there are already multiple available buffers in the queue, the next one
+ // returned from |queue_->Dequeue| may still have the old buffer dimension
+ // or format. Retry up to BufferHubQueue::kMaxQueueCapacity times or until
+ // we dequeued a buffer with new configuration.
+ auto remove_status = producer_queue_->RemoveBuffer(slot);
+ if (!remove_status) {
+ ALOGE("DvrWriteBufferQueue::Dequeue: Failed to remove buffer: %s",
+ remove_status.GetErrorMessage().c_str());
+ return -remove_status.error();
+ }
+
+ auto allocate_status = producer_queue_->AllocateBuffer(
+ width_, height_, old_layer_count, format_, old_usage);
+ if (!allocate_status) {
+ ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s",
+ allocate_status.GetErrorMessage().c_str());
+ return -allocate_status.error();
+ }
+ }
+
+ if (retry >= max_retries) {
+ ALOGE(
+ "DvrWriteBufferQueue::Dequeue: Failed to re-allocate buffer after "
+ "resizing.");
+ return -ENOMEM;
+ }
+
+ write_buffer->write_buffer = std::move(buffer_producer);
+ *out_fence_fd = fence.Release();
+ return 0;
+}
+
+int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) {
+ if (width == 0 || height == 0) {
+ ALOGE(
+ "DvrWriteBufferQueue::ResizeBuffer: invalid buffer dimension: w=%u, "
+ "h=%u.",
+ width, height);
+ return -EINVAL;
+ }
+
+ width_ = width;
+ height_ = height;
+ return 0;
+}
+
+void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
delete write_queue;
}
ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
- if (!write_queue || !write_queue->producer_queue)
+ if (!write_queue)
return -EINVAL;
- return write_queue->producer_queue->capacity();
+ return write_queue->capacity();
}
int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
if (!write_queue)
return -EINVAL;
- return write_queue->producer_queue->id();
+ return write_queue->id();
}
int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
@@ -63,131 +179,68 @@
if (!write_queue || !out_window)
return -EINVAL;
- if (write_queue->producer_queue->metadata_size() !=
- sizeof(DvrNativeBufferMetadata)) {
- ALOGE(
- "The size of buffer metadata (%zu) of the write queue does not match "
- "of size of DvrNativeBufferMetadata (%zu).",
- write_queue->producer_queue->metadata_size(),
- sizeof(DvrNativeBufferMetadata));
- return -EINVAL;
- }
-
- // Lazy creation of |native_window|.
- if (write_queue->native_window == nullptr) {
- sp<IGraphicBufferProducer> gbp =
- dvr::BufferHubQueueProducer::Create(write_queue->producer_queue);
- sp<Surface> surface = new Surface(gbp, true);
- write_queue->native_window = static_cast<ANativeWindow*>(surface.get());
- ANativeWindow_acquire(write_queue->native_window);
- }
-
- *out_window = write_queue->native_window;
- return 0;
+ return write_queue->GetNativeWindow(out_window);
}
int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
DvrReadBufferQueue** out_read_queue) {
- if (!write_queue || !write_queue->producer_queue || !out_read_queue)
+ if (!write_queue || !out_read_queue)
return -EINVAL;
- auto read_queue = std::make_unique<DvrReadBufferQueue>();
- read_queue->consumer_queue =
- write_queue->producer_queue->CreateConsumerQueue();
- if (read_queue->consumer_queue == nullptr) {
- ALOGE(
- "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue "
- "from DvrWriteBufferQueue[%p].",
- write_queue);
- return -ENOMEM;
- }
-
- *out_read_queue = read_queue.release();
- return 0;
+ return write_queue->CreateReadQueue(out_read_queue);
}
int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
DvrWriteBuffer* write_buffer,
int* out_fence_fd) {
- if (!write_queue || !write_queue->producer_queue || !write_buffer ||
- !out_fence_fd) {
+ if (!write_queue || !write_buffer || !out_fence_fd)
return -EINVAL;
- }
- size_t slot;
- pdx::LocalHandle release_fence;
- auto buffer_status =
- write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence);
- if (!buffer_status) {
- ALOGE_IF(buffer_status.error() != ETIMEDOUT,
- "dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s",
- buffer_status.GetErrorMessage().c_str());
- return -buffer_status.error();
- }
+ return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
+}
- write_buffer->write_buffer = buffer_status.take();
- *out_fence_fd = release_fence.Release();
- return 0;
+int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
+ uint32_t width, uint32_t height) {
+ if (!write_queue)
+ return -EINVAL;
+
+ return write_queue->ResizeBuffer(width, height);
}
// ReadBufferQueue
-void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
- delete read_queue;
-}
-ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
- if (!read_queue)
- return -EINVAL;
+DvrReadBufferQueue::DvrReadBufferQueue(
+ const std::shared_ptr<ConsumerQueue>& consumer_queue)
+ : consumer_queue_(consumer_queue) {}
- return read_queue->consumer_queue->capacity();
-}
-
-int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
- if (!read_queue)
- return -EINVAL;
-
- return read_queue->consumer_queue->id();
-}
-
-int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
- DvrReadBufferQueue** out_read_queue) {
- if (!read_queue || !read_queue->consumer_queue || !out_read_queue)
- return -EINVAL;
-
- auto new_read_queue = std::make_unique<DvrReadBufferQueue>();
- new_read_queue->consumer_queue =
- read_queue->consumer_queue->CreateConsumerQueue();
- if (new_read_queue->consumer_queue == nullptr) {
+int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
+ std::unique_ptr<ConsumerQueue> consumer_queue =
+ consumer_queue_->CreateConsumerQueue();
+ if (consumer_queue == nullptr) {
ALOGE(
- "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue "
- "from DvrReadBufferQueue[%p].",
- read_queue);
+ "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue "
+ "from producer queue: queue_id=%d.", consumer_queue_->id());
return -ENOMEM;
}
- *out_read_queue = new_read_queue.release();
+ *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
return 0;
}
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
- DvrReadBuffer* read_buffer, int* out_fence_fd,
- void* out_meta, size_t meta_size_bytes) {
- if (!read_queue || !read_queue->consumer_queue || !read_buffer ||
- !out_fence_fd || !out_meta) {
- return -EINVAL;
- }
-
- if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) {
+int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,
+ int* out_fence_fd, void* out_meta,
+ size_t meta_size_bytes) {
+ if (meta_size_bytes != consumer_queue_->metadata_size()) {
ALOGE(
- "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), "
+ "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), "
"but actual (%zu).",
- read_queue->consumer_queue->metadata_size(), meta_size_bytes);
+ consumer_queue_->metadata_size(), meta_size_bytes);
return -EINVAL;
}
size_t slot;
pdx::LocalHandle acquire_fence;
- auto buffer_status = read_queue->consumer_queue->Dequeue(
+ auto buffer_status = consumer_queue_->Dequeue(
timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
if (!buffer_status) {
ALOGE_IF(buffer_status.error() != ETIMEDOUT,
@@ -201,4 +254,107 @@
return 0;
}
+void DvrReadBufferQueue::SetBufferAvailableCallback(
+ DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
+ if (callback == nullptr) {
+ consumer_queue_->SetBufferAvailableCallback(nullptr);
+ } else {
+ consumer_queue_->SetBufferAvailableCallback(
+ [callback, context]() { callback(context); });
+ }
+}
+
+void DvrReadBufferQueue::SetBufferRemovedCallback(
+ DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
+ if (callback == nullptr) {
+ consumer_queue_->SetBufferRemovedCallback(nullptr);
+ } else {
+ consumer_queue_->SetBufferRemovedCallback(
+ [callback, context](const std::shared_ptr<BufferHubBuffer>& buffer) {
+ DvrReadBuffer read_buffer{
+ std::static_pointer_cast<BufferConsumer>(buffer)};
+ callback(&read_buffer, context);
+ });
+ }
+}
+
+int DvrReadBufferQueue::HandleEvents() {
+ // TODO(jwcai) Probably should change HandleQueueEvents to return Status.
+ consumer_queue_->HandleQueueEvents();
+ return 0;
+}
+
+void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
+ delete read_queue;
+}
+
+ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
+ if (!read_queue)
+ return -EINVAL;
+
+ return read_queue->capacity();
+}
+
+int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
+ if (!read_queue)
+ return -EINVAL;
+
+ return read_queue->id();
+}
+
+int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue) {
+ if (!read_queue)
+ return -EINVAL;
+
+ return read_queue->event_fd();
+}
+
+int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueue** out_read_queue) {
+ if (!read_queue || !out_read_queue)
+ return -EINVAL;
+
+ return read_queue->CreateReadQueue(out_read_queue);
+}
+
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer* read_buffer, int* out_fence_fd,
+ void* out_meta, size_t meta_size_bytes) {
+ if (!read_queue || !read_buffer || !out_fence_fd)
+ return -EINVAL;
+
+ if (meta_size_bytes != 0 && !out_meta)
+ return -EINVAL;
+
+ return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
+ meta_size_bytes);
+}
+
+int dvrReadBufferQueueSetBufferAvailableCallback(
+ DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
+ if (!read_queue)
+ return -EINVAL;
+
+ read_queue->SetBufferAvailableCallback(callback, context);
+ return 0;
+}
+
+int dvrReadBufferQueueSetBufferRemovedCallback(
+ DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
+ if (!read_queue)
+ return -EINVAL;
+
+ read_queue->SetBufferRemovedCallback(callback, context);
+ return 0;
+}
+
+int dvrReadBufferQueueHandleEvents(DvrReadBufferQueue* read_queue) {
+ if (!read_queue)
+ return -EINVAL;
+
+ return read_queue->HandleEvents();
+}
+
} // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h
new file mode 100644
index 0000000..ffbe7a5
--- /dev/null
+++ b/libs/vr/libdvr/dvr_buffer_queue_internal.h
@@ -0,0 +1,68 @@
+#ifndef ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
+#define ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
+
+#include <gui/Surface.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <sys/cdefs.h>
+
+#include <memory>
+
+struct ANativeWindow;
+
+struct DvrWriteBufferQueue {
+ using ProducerQueue = android::dvr::ProducerQueue;
+
+ // Create a concrete object for DvrWriteBufferQueue.
+ //
+ // @param producer_queue The BufferHub's ProducerQueue that is used to back
+ // this DvrWriteBufferQueue, must not be NULL.
+ explicit DvrWriteBufferQueue(
+ const std::shared_ptr<ProducerQueue>& producer_queue);
+
+ int id() const { return producer_queue_->id(); }
+ uint32_t width() const { return width_; };
+ uint32_t height() const { return height_; };
+ uint32_t format() const { return format_; };
+ size_t capacity() const { return producer_queue_->capacity(); }
+ const std::shared_ptr<ProducerQueue>& producer_queue() const {
+ return producer_queue_;
+ }
+
+ int GetNativeWindow(ANativeWindow** out_window);
+ int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
+ int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd);
+ int ResizeBuffer(uint32_t width, uint32_t height);
+
+ private:
+ std::shared_ptr<ProducerQueue> producer_queue_;
+
+ uint32_t width_;
+ uint32_t height_;
+ uint32_t format_;
+ android::sp<android::Surface> native_window_;
+};
+
+struct DvrReadBufferQueue {
+ using ConsumerQueue = android::dvr::ConsumerQueue;
+
+ explicit DvrReadBufferQueue(
+ const std::shared_ptr<ConsumerQueue>& consumer_queue);
+
+ int id() const { return consumer_queue_->id(); }
+ int event_fd() const { return consumer_queue_->queue_fd(); }
+ size_t capacity() const { return consumer_queue_->capacity(); }
+
+ int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
+ int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd,
+ void* out_meta, size_t meta_size_bytes);
+ void SetBufferAvailableCallback(
+ DvrReadBufferQueueBufferAvailableCallback callback, void* context);
+ void SetBufferRemovedCallback(
+ DvrReadBufferQueueBufferRemovedCallback callback, void* context);
+ int HandleEvents();
+
+ private:
+ std::shared_ptr<ConsumerQueue> consumer_queue_;
+};
+
+#endif // ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_configuration_data.cpp b/libs/vr/libdvr/dvr_configuration_data.cpp
new file mode 100644
index 0000000..df0d54e
--- /dev/null
+++ b/libs/vr/libdvr/dvr_configuration_data.cpp
@@ -0,0 +1,40 @@
+#include "include/dvr/dvr_configuration_data.h"
+
+#include <private/dvr/display_client.h>
+
+using android::dvr::display::ConfigFileType;
+using android::dvr::display::DisplayClient;
+
+extern "C" {
+
+int dvrConfigurationDataGet(int config_type, uint8_t** data,
+ size_t* data_size) {
+ if (!data || !data_size) {
+ return -EINVAL;
+ }
+
+ auto client = DisplayClient::Create();
+ if (!client) {
+ ALOGE("dvrGetGlobalBuffer: Failed to create display client!");
+ return -ECOMM;
+ }
+
+ ConfigFileType config_file_type = static_cast<ConfigFileType>(config_type);
+ auto config_data_status =
+ client->GetConfigurationData(config_file_type);
+
+ if (!config_data_status) {
+ return -config_data_status.error();
+ }
+
+ *data_size = config_data_status.get().size();
+ *data = new uint8_t[*data_size];
+ std::copy_n(config_data_status.get().begin(), *data_size, *data);
+ return 0;
+}
+
+void dvrConfigurationDataDestroy(uint8_t* data) {
+ delete[] data;
+}
+
+} // extern "C"
diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp
index 87636ec..852f9a4 100644
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ b/libs/vr/libdvr/dvr_display_manager.cpp
@@ -2,20 +2,19 @@
#include <dvr/dvr_buffer.h>
#include <pdx/rpc/variant.h>
-#include <private/android/AHardwareBufferHelpers.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/display_client.h>
#include <private/dvr/display_manager_client.h>
#include "dvr_internal.h"
+#include "dvr_buffer_queue_internal.h"
-using android::AHardwareBuffer_convertToGrallocUsageBits;
using android::dvr::BufferConsumer;
using android::dvr::display::DisplayManagerClient;
using android::dvr::display::SurfaceAttributes;
using android::dvr::display::SurfaceAttribute;
using android::dvr::display::SurfaceState;
-using android::dvr::CreateDvrReadBufferQueueFromConsumerQueue;
using android::pdx::rpc::EmptyVariant;
namespace {
@@ -111,26 +110,6 @@
void dvrDisplayManagerDestroy(DvrDisplayManager* client) { delete client; }
-int dvrDisplayManagerSetupNamedBuffer(DvrDisplayManager* client,
- const char* name, size_t size,
- uint64_t usage, DvrBuffer** buffer_out) {
- if (!client || !name || !buffer_out)
- return -EINVAL;
-
- uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
-
- auto buffer_status =
- client->client->SetupNamedBuffer(name, size, gralloc_usage);
- if (!buffer_status) {
- ALOGE("dvrDisplayManagerSetupPoseBuffer: Failed to setup named buffer: %s",
- buffer_status.GetErrorMessage().c_str());
- return -buffer_status.error();
- }
-
- *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take());
- return 0;
-}
-
int dvrDisplayManagerGetEventFd(DvrDisplayManager* client) {
if (!client)
return -EINVAL;
@@ -177,7 +156,7 @@
return -status.error();
}
- *queue_out = CreateDvrReadBufferQueueFromConsumerQueue(status.take());
+ *queue_out = new DvrReadBufferQueue(status.take());
return 0;
}
diff --git a/libs/vr/libdvr/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
index d3ae299..4e87cf6 100644
--- a/libs/vr/libdvr/dvr_hardware_composer_client.cpp
+++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
@@ -6,7 +6,9 @@
#include <binder/IServiceManager.h>
#include <private/android/AHardwareBufferHelpers.h>
+#include <functional>
#include <memory>
+#include <mutex>
struct DvrHwcFrame {
android::dvr::ComposerView::Frame frame;
@@ -16,10 +18,15 @@
class HwcCallback : public android::dvr::BnVrComposerCallback {
public:
- explicit HwcCallback(DvrHwcOnFrameCallback callback,
- void* client_state);
+ using CallbackFunction = std::function<int(DvrHwcFrame*)>;
+
+ explicit HwcCallback(const CallbackFunction& callback);
~HwcCallback() override;
+ // Reset the callback. This needs to be done early to avoid use after free
+ // accesses from binder thread callbacks.
+ void Shutdown();
+
std::unique_ptr<DvrHwcFrame> DequeueFrame();
private:
@@ -28,26 +35,41 @@
const android::dvr::ParcelableComposerFrame& frame,
android::dvr::ParcelableUniqueFd* fence) override;
- DvrHwcOnFrameCallback callback_;
- void* client_state_;
+ // Protects the |callback_| from uses from multiple threads. During shutdown
+ // there may be in-flight frame update events. In those cases the callback
+ // access needs to be protected otherwise binder threads may access an invalid
+ // callback.
+ std::mutex mutex_;
+ CallbackFunction callback_;
HwcCallback(const HwcCallback&) = delete;
void operator=(const HwcCallback&) = delete;
};
-HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback, void* client_state)
- : callback_(callback), client_state_(client_state) {}
+HwcCallback::HwcCallback(const CallbackFunction& callback)
+ : callback_(callback) {}
HwcCallback::~HwcCallback() {}
+void HwcCallback::Shutdown() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ callback_ = nullptr;
+}
+
android::binder::Status HwcCallback::onNewFrame(
const android::dvr::ParcelableComposerFrame& frame,
android::dvr::ParcelableUniqueFd* fence) {
+ std::lock_guard<std::mutex> guard(mutex_);
+
+ if (!callback_) {
+ fence->set_fence(android::base::unique_fd());
+ return android::binder::Status::ok();
+ }
+
std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
dvr_frame->frame = frame.frame();
- fence->set_fence(android::base::unique_fd(callback_(client_state_,
- dvr_frame.release())));
+ fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
return android::binder::Status::ok();
}
@@ -67,7 +89,8 @@
if (!client->composer.get())
return nullptr;
- client->callback = new HwcCallback(callback, data);
+ client->callback = new HwcCallback(std::bind(callback, data,
+ std::placeholders::_1));
android::binder::Status status = client->composer->registerObserver(
client->callback);
if (!status.isOk())
@@ -77,6 +100,13 @@
}
void dvrHwcClientDestroy(DvrHwcClient* client) {
+ client->composer->clearObserver();
+
+ // NOTE: Deleting DvrHwcClient* isn't enough since DvrHwcClient::callback is a
+ // shared pointer that could be referenced from a binder thread. But the
+ // client callback isn't valid past this calls so that needs to be reset.
+ client->callback->Shutdown();
+
delete client;
}
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
index 89bef09..28b6c28 100644
--- a/libs/vr/libdvr/dvr_internal.h
+++ b/libs/vr/libdvr/dvr_internal.h
@@ -10,8 +10,6 @@
typedef struct DvrBuffer DvrBuffer;
typedef struct DvrReadBuffer DvrReadBuffer;
typedef struct DvrWriteBuffer DvrWriteBuffer;
-typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
-typedef struct DvrReadBufferQueue DvrReadBufferQueue;
} // extern "C"
@@ -20,9 +18,7 @@
class BufferProducer;
class BufferConsumer;
-class ConsumerQueue;
class IonBuffer;
-class ProducerQueue;
DvrBuffer* CreateDvrBufferFromIonBuffer(
const std::shared_ptr<IonBuffer>& ion_buffer);
@@ -32,13 +28,6 @@
DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
const std::shared_ptr<BufferProducer>& buffer_producer);
-DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
- const std::shared_ptr<ConsumerQueue>& consumer_queue);
-DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
- const std::shared_ptr<ProducerQueue>& producer_queue);
-ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
- DvrWriteBufferQueue* write_queue);
-
} // namespace dvr
} // namespace android
@@ -56,15 +45,6 @@
std::shared_ptr<android::dvr::IonBuffer> buffer;
};
-struct DvrWriteBufferQueue {
- std::shared_ptr<android::dvr::ProducerQueue> producer_queue;
- ANativeWindow* native_window{nullptr};
-};
-
-struct DvrReadBufferQueue {
- std::shared_ptr<android::dvr::ConsumerQueue> consumer_queue;
-};
-
} // extern "C"
#endif // ANDROID_DVR_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_performance.cpp b/libs/vr/libdvr/dvr_performance.cpp
new file mode 100644
index 0000000..599101f
--- /dev/null
+++ b/libs/vr/libdvr/dvr_performance.cpp
@@ -0,0 +1,18 @@
+#include "include/dvr/dvr_performance.h"
+
+#include <private/dvr/performance_client.h>
+
+using android::dvr::PerformanceClient;
+
+extern "C" {
+
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ int error;
+ if (auto client = PerformanceClient::Create(&error))
+ return client->SetSchedulerPolicy(task_id, scheduler_policy);
+ else
+ return error;
+}
+
+} // extern "C"
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
index 67e2ae8..a3a47f1 100644
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -2,19 +2,33 @@
#include <inttypes.h>
+#include <pdx/rpc/variant.h>
+#include <private/android/AHardwareBufferHelpers.h>
#include <private/dvr/display_client.h>
+#include "dvr_buffer_queue_internal.h"
#include "dvr_internal.h"
+using android::AHardwareBuffer_convertToGrallocUsageBits;
using android::dvr::display::DisplayClient;
using android::dvr::display::Surface;
using android::dvr::display::SurfaceAttributes;
using android::dvr::display::SurfaceAttributeValue;
using android::dvr::CreateDvrReadBufferFromBufferConsumer;
-using android::dvr::CreateDvrWriteBufferQueueFromProducerQueue;
+using android::pdx::rpc::EmptyVariant;
namespace {
+// Sets the Variant |destination| to the target std::array type and copies the C
+// array into it. Unsupported std::array configurations will fail to compile.
+template <typename T, std::size_t N>
+void ArrayCopy(SurfaceAttributeValue* destination, const T (&source)[N]) {
+ using ArrayType = std::array<T, N>;
+ *destination = ArrayType{};
+ std::copy(std::begin(source), std::end(source),
+ std::get<ArrayType>(*destination).begin());
+}
+
bool ConvertSurfaceAttributes(const DvrSurfaceAttribute* attributes,
size_t attribute_count,
SurfaceAttributes* surface_attributes,
@@ -29,25 +43,31 @@
value = attributes[i].value.int64_value;
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_BOOL:
- value = attributes[i].value.bool_value;
+ // bool_value is defined in an extern "C" block, which makes it look
+ // like an int to C++. Use a cast to assign the correct type to the
+ // Variant type SurfaceAttributeValue.
+ value = static_cast<bool>(attributes[i].value.bool_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT:
value = attributes[i].value.float_value;
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2:
- value = attributes[i].value.float2_value;
+ ArrayCopy(&value, attributes[i].value.float2_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3:
- value = attributes[i].value.float3_value;
+ ArrayCopy(&value, attributes[i].value.float3_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4:
- value = attributes[i].value.float4_value;
+ ArrayCopy(&value, attributes[i].value.float4_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8:
- value = attributes[i].value.float8_value;
+ ArrayCopy(&value, attributes[i].value.float8_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16:
- value = attributes[i].value.float16_value;
+ ArrayCopy(&value, attributes[i].value.float16_value);
+ break;
+ case DVR_SURFACE_ATTRIBUTE_TYPE_NONE:
+ value = EmptyVariant{};
break;
default:
*error_index = i;
@@ -134,7 +154,7 @@
int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width,
uint32_t height, uint32_t format,
uint32_t layer_count, uint64_t usage,
- size_t capacity,
+ size_t capacity, size_t metadata_size,
DvrWriteBufferQueue** out_writer) {
if (surface == nullptr || out_writer == nullptr) {
ALOGE(
@@ -144,39 +164,115 @@
return -EINVAL;
}
- auto status = surface->surface->CreateQueue(width, height, layer_count,
- format, usage, capacity);
+ auto status = surface->surface->CreateQueue(
+ width, height, layer_count, format, usage, capacity, metadata_size);
if (!status) {
ALOGE("dvrSurfaceCreateWriteBufferQueue: Failed to create queue: %s",
status.GetErrorMessage().c_str());
return -status.error();
}
- *out_writer = CreateDvrWriteBufferQueueFromProducerQueue(status.take());
+ *out_writer = new DvrWriteBufferQueue(status.take());
return 0;
}
-int dvrGetNamedBuffer(const char* name, DvrBuffer** out_buffer) {
- auto client = DisplayClient::Create();
- if (!client) {
- ALOGE("dvrGetNamedBuffer: Failed to create display client!");
- return -ECOMM;
- }
-
- if (out_buffer == nullptr || name == nullptr) {
- ALOGE("dvrGetNamedBuffer: Invalid inputs: name=%p, out_buffer=%p.", name,
- out_buffer);
+int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage,
+ DvrBuffer** buffer_out) {
+ if (!buffer_out)
return -EINVAL;
+
+ int error;
+ auto client = DisplayClient::Create(&error);
+ if (!client) {
+ ALOGE("dvrSetupGlobalBuffer: Failed to create display client: %s",
+ strerror(-error));
+ return error;
}
- auto status = client->GetNamedBuffer(name);
+ uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
+
+ auto buffer_status = client->SetupGlobalBuffer(key, size, gralloc_usage);
+ if (!buffer_status) {
+ ALOGE("dvrSetupGlobalBuffer: Failed to setup global buffer: %s",
+ buffer_status.GetErrorMessage().c_str());
+ return -buffer_status.error();
+ }
+
+ *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take());
+ return 0;
+}
+
+int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key) {
+ int error;
+ auto client = DisplayClient::Create(&error);
+ if (!client) {
+ ALOGE("dvrDeleteGlobalBuffer: Failed to create display client: %s",
+ strerror(-error));
+ return error;
+ }
+
+ auto buffer_status = client->DeleteGlobalBuffer(key);
+ if (!buffer_status) {
+ ALOGE("dvrDeleteGlobalBuffer: Failed to delete named buffer: %s",
+ buffer_status.GetErrorMessage().c_str());
+ return -buffer_status.error();
+ }
+
+ return 0;
+}
+
+int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) {
+ if (!out_buffer)
+ return -EINVAL;
+
+ int error;
+ auto client = DisplayClient::Create(&error);
+ if (!client) {
+ ALOGE("dvrGetGlobalBuffer: Failed to create display client: %s",
+ strerror(-error));
+ return error;
+ }
+
+ auto status = client->GetGlobalBuffer(key);
if (!status) {
- ALOGE("dvrGetNamedBuffer: Failed to find named buffer name=%s: %s", name,
- status.GetErrorMessage().c_str());
return -status.error();
}
*out_buffer = CreateDvrBufferFromIonBuffer(status.take());
return 0;
}
+int dvrGetNativeDisplayMetrics(size_t sizeof_metrics,
+ DvrNativeDisplayMetrics* metrics) {
+ ALOGE_IF(sizeof_metrics != sizeof(DvrNativeDisplayMetrics),
+ "dvrGetNativeDisplayMetrics: metrics struct mismatch, your dvr api "
+ "header is out of date.");
+
+ auto client = DisplayClient::Create();
+ if (!client) {
+ ALOGE("dvrGetNativeDisplayMetrics: Failed to create display client!");
+ return -ECOMM;
+ }
+
+ if (metrics == nullptr) {
+ ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null");
+ return -EINVAL;
+ }
+
+ auto status = client->GetDisplayMetrics();
+
+ if (!status) {
+ return -status.error();
+ }
+
+ if (sizeof_metrics >= 20) {
+ metrics->display_width = status.get().display_width;
+ metrics->display_height = status.get().display_height;
+ metrics->display_x_dpi = status.get().display_x_dpi;
+ metrics->display_y_dpi = status.get().display_y_dpi;
+ metrics->vsync_period_ns = status.get().vsync_period_ns;
+ }
+
+ return 0;
+}
+
} // extern "C"
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 8a203e0..d0dbd8d 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -4,12 +4,16 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
-#include <sys/cdefs.h>
#include <unistd.h>
+#include <cstdio>
-#include <dvr/dvr_hardware_composer_defs.h>
+#include <dvr/dvr_display_types.h>
+#include <dvr/dvr_hardware_composer_types.h>
+#include <dvr/dvr_pose.h>
-__BEGIN_DECLS
+#ifdef __cplusplus
+extern "C" {
+#endif
typedef struct ANativeWindow ANativeWindow;
@@ -18,7 +22,7 @@
typedef uint64_t DvrSurfaceUpdateFlags;
typedef struct DvrDisplayManager DvrDisplayManager;
typedef struct DvrSurfaceState DvrSurfaceState;
-typedef struct DvrPose DvrPose;
+typedef struct DvrPoseClient DvrPoseClient;
typedef struct DvrVSyncClient DvrVSyncClient;
typedef struct DvrVirtualTouchpad DvrVirtualTouchpad;
@@ -33,19 +37,44 @@
typedef struct DvrSurface DvrSurface;
typedef uint64_t DvrSurfaceAttributeType;
typedef int32_t DvrSurfaceAttributeKey;
+typedef int32_t DvrGlobalBufferKey;
typedef struct DvrSurfaceAttributeValue DvrSurfaceAttributeValue;
typedef struct DvrSurfaceAttribute DvrSurfaceAttribute;
+// Note: To avoid breaking others during active development, only modify this
+// struct by appending elements to the end.
+// If you do feel we should to re-arrange or remove elements, please make a
+// note of it, and wait until we're about to finalize for an API release to do
+// so.
+typedef struct DvrNativeDisplayMetrics {
+ uint32_t display_width;
+ uint32_t display_height;
+ uint32_t display_x_dpi;
+ uint32_t display_y_dpi;
+ uint32_t vsync_period_ns;
+} DvrNativeDisplayMetrics;
+
+// native_handle contains the fds for the underlying ION allocations inside
+// the gralloc buffer. This is needed temporarily while GPU vendors work on
+// better support for AHardwareBuffer via glBindSharedBuffer APIs. See
+// b/37207909. For now we can declare the native_handle struct where it is
+// used for GPU late latching. See cutils/native_handle.h for the struct layout.
struct native_handle;
+// Device metrics data type enums.
+enum {
+ // Request the device lens metrics protobuf. This matches cardboard protos.
+ DVR_CONFIGURATION_DATA_LENS_METRICS = 0,
+ // Request the device metrics protobuf.
+ DVR_CONFIGURATION_DATA_DEVICE_METRICS = 1,
+ // Request the per device configuration data file.
+ DVR_CONFIGURATION_DATA_DEVICE_CONFIG = 2,
+};
+
// dvr_display_manager.h
typedef int (*DvrDisplayManagerCreatePtr)(DvrDisplayManager** client_out);
typedef void (*DvrDisplayManagerDestroyPtr)(DvrDisplayManager* client);
-typedef int (*DvrDisplayManagerSetupNamedBufferPtr)(DvrDisplayManager* client,
- const char* name,
- size_t size, uint64_t usage,
- DvrBuffer** buffer_out);
typedef int (*DvrDisplayManagerGetEventFdPtr)(DvrDisplayManager* client);
typedef int (*DvrDisplayManagerTranslateEpollEventMaskPtr)(
DvrDisplayManager* client, int in_events, int* out_events);
@@ -54,6 +83,9 @@
typedef int (*DvrDisplayManagerGetReadBufferQueuePtr)(
DvrDisplayManager* client, int surface_id, int queue_id,
DvrReadBufferQueue** queue_out);
+typedef int (*DvrConfigurationDataGetPtr)(int config_type, uint8_t** data,
+ size_t* data_size);
+typedef void (*DvrConfigurationDataDestroyPtr)(uint8_t* data);
typedef int (*DvrSurfaceStateCreatePtr)(DvrSurfaceState** surface_state);
typedef void (*DvrSurfaceStateDestroyPtr)(DvrSurfaceState* surface_state);
typedef int (*DvrSurfaceStateGetSurfaceCountPtr)(DvrSurfaceState* surface_state,
@@ -122,6 +154,7 @@
typedef void (*DvrBufferDestroyPtr)(DvrBuffer* buffer);
typedef int (*DvrBufferGetAHardwareBufferPtr)(
DvrBuffer* buffer, AHardwareBuffer** hardware_buffer);
+typedef int (*DvrBufferGlobalLayoutVersionGetPtr)();
typedef const struct native_handle* (*DvrBufferGetNativeHandlePtr)(
DvrBuffer* buffer);
@@ -138,10 +171,13 @@
int timeout,
DvrWriteBuffer* out_buffer,
int* out_fence_fd);
+typedef int (*DvrWriteBufferQueueResizeBufferPtr)(
+ DvrWriteBufferQueue* write_queue, uint32_t width, uint32_t height);
typedef void (*DvrReadBufferQueueDestroyPtr)(DvrReadBufferQueue* read_queue);
typedef ssize_t (*DvrReadBufferQueueGetCapacityPtr)(
DvrReadBufferQueue* read_queue);
typedef int (*DvrReadBufferQueueGetIdPtr)(DvrReadBufferQueue* read_queue);
+typedef int (*DvrReadBufferQueueGetEventFdPtr)(DvrReadBufferQueue* read_queue);
typedef int (*DvrReadBufferQueueCreateReadQueuePtr)(
DvrReadBufferQueue* read_queue, DvrReadBufferQueue** out_read_queue);
typedef int (*DvrReadBufferQueueDequeuePtr)(DvrReadBufferQueue* read_queue,
@@ -149,9 +185,24 @@
DvrReadBuffer* out_buffer,
int* out_fence_fd, void* out_meta,
size_t meta_size_bytes);
+typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
+typedef int (*DvrReadBufferQueueSetBufferAvailableCallbackPtr)(
+ DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueueBufferAvailableCallback callback, void* context);
+typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer,
+ void* context);
+typedef int (*DvrReadBufferQueueSetBufferRemovedCallbackPtr)(
+ DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueueBufferRemovedCallback callback, void* context);
+typedef int (*DvrReadBufferQueueHandleEventsPtr)(
+ DvrReadBufferQueue* read_queue);
// dvr_surface.h
-typedef int (*DvrGetNamedBufferPtr)(const char* name, DvrBuffer** out_buffer);
+typedef int (*DvrSetupGlobalBufferPtr)(DvrGlobalBufferKey key, size_t size,
+ uint64_t usage, DvrBuffer** buffer_out);
+typedef int (*DvrDeleteGlobalBufferPtr)(DvrGlobalBufferKey key);
+typedef int (*DvrGetGlobalBufferPtr)(DvrGlobalBufferKey key,
+ DvrBuffer** out_buffer);
typedef int (*DvrSurfaceCreatePtr)(const DvrSurfaceAttribute* attributes,
size_t attribute_count,
DvrSurface** surface_out);
@@ -162,10 +213,12 @@
size_t attribute_count);
typedef int (*DvrSurfaceCreateWriteBufferQueuePtr)(
DvrSurface* surface, uint32_t width, uint32_t height, uint32_t format,
- uint32_t layer_count, uint64_t usage, size_t capacity,
+ uint32_t layer_count, uint64_t usage, size_t capacity, size_t metadata_size,
DvrWriteBufferQueue** queue_out);
+typedef int (*DvrGetNativeDisplayMetricsPtr)(size_t sizeof_metrics,
+ DvrNativeDisplayMetrics* metrics);
-// vsync_client_api.h
+// dvr_vsync.h
typedef int (*DvrVSyncClientCreatePtr)(DvrVSyncClient** client_out);
typedef void (*DvrVSyncClientDestroyPtr)(DvrVSyncClient* client);
typedef int (*DvrVSyncClientGetSchedInfoPtr)(DvrVSyncClient* client,
@@ -173,18 +226,27 @@
int64_t* next_timestamp_ns,
uint32_t* next_vsync_count);
-// pose_client.h
-typedef DvrPose* (*DvrPoseCreatePtr)(void);
-typedef void (*DvrPoseDestroyPtr)(DvrPose* client);
-typedef int (*DvrPoseGetPtr)(DvrPose* client, uint32_t vsync_count,
- DvrPoseAsync* out_pose);
-typedef uint32_t (*DvrPoseGetVsyncCountPtr)(DvrPose* client);
-typedef int (*DvrPoseGetControllerPtr)(DvrPose* client, int32_t controller_id,
- uint32_t vsync_count,
- DvrPoseAsync* out_pose);
+// libs/vr/libvrsensor/include/dvr/pose_client.h
+typedef DvrPoseClient* (*DvrPoseClientCreatePtr)();
+typedef void (*DvrPoseClientDestroyPtr)(DvrPoseClient* client);
+typedef int (*DvrPoseClientGetPtr)(DvrPoseClient* client, uint32_t vsync_count,
+ DvrPoseAsync* out_pose);
+typedef uint32_t (*DvrPoseClientGetVsyncCountPtr)(DvrPoseClient* client);
+typedef int (*DvrPoseClientGetControllerPtr)(DvrPoseClient* client,
+ int32_t controller_id,
+ uint32_t vsync_count,
+ DvrPoseAsync* out_pose);
+typedef int (*DvrPoseClientSensorsEnablePtr)(DvrPoseClient* client,
+ bool enabled);
-// virtual_touchpad_client.h
-typedef DvrVirtualTouchpad* (*DvrVirtualTouchpadCreatePtr)(void);
+// services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
+
+// Touchpad IDs for *Touch*() and *ButtonState*() calls.
+enum {
+ DVR_VIRTUAL_TOUCHPAD_PRIMARY = 0,
+ DVR_VIRTUAL_TOUCHPAD_VIRTUAL = 1,
+};
+typedef DvrVirtualTouchpad* (*DvrVirtualTouchpadCreatePtr)();
typedef void (*DvrVirtualTouchpadDestroyPtr)(DvrVirtualTouchpad* client);
typedef int (*DvrVirtualTouchpadAttachPtr)(DvrVirtualTouchpad* client);
typedef int (*DvrVirtualTouchpadDetachPtr)(DvrVirtualTouchpad* client);
@@ -193,6 +255,8 @@
float pressure);
typedef int (*DvrVirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client,
int touchpad, int buttons);
+typedef int (*DvrVirtualTouchpadScrollPtr)(DvrVirtualTouchpad* client,
+ int touchpad, float x, float y);
// dvr_hardware_composer_client.h
typedef struct DvrHwcClient DvrHwcClient;
@@ -260,6 +324,10 @@
size_t layer_index,
size_t index);
+// dvr_performance.h
+typedef int (*DvrPerformanceSetSchedulerPolicyPtr)(
+ pid_t task_id, const char* scheduler_policy);
+
// The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
// will populate. A DvrWriteBufferQueue must be created with this metadata iff
// ANativeWindow access is needed. Please do not remove, modify, or reorder
@@ -298,7 +366,6 @@
// Defines an API entry for V1 (no version suffix).
#define DVR_V1_API_ENTRY(name) Dvr##name##Ptr name
-// Include file with API entries.
#include "dvr_api_entries.h"
// Undefine macro definitions to play nice with Google3 style rules.
@@ -307,6 +374,8 @@
int dvrGetApi(void* api, size_t struct_size, int version);
-__END_DECLS
+#ifdef __cplusplus
+} // extern "C"
+#endif
#endif // ANDROID_DVR_API_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index 09568fd..72e0f67 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -8,14 +8,16 @@
#error Do not include this header directly.
#endif
+// Do not delete this line: BEGIN CODEGEN OUTPUT
// Display manager client
DVR_V1_API_ENTRY(DisplayManagerCreate);
DVR_V1_API_ENTRY(DisplayManagerDestroy);
-DVR_V1_API_ENTRY(DisplayManagerSetupNamedBuffer);
DVR_V1_API_ENTRY(DisplayManagerGetEventFd);
DVR_V1_API_ENTRY(DisplayManagerTranslateEpollEventMask);
DVR_V1_API_ENTRY(DisplayManagerGetSurfaceState);
DVR_V1_API_ENTRY(DisplayManagerGetReadBufferQueue);
+DVR_V1_API_ENTRY(ConfigurationDataGet);
+DVR_V1_API_ENTRY(ConfigurationDataDestroy);
DVR_V1_API_ENTRY(SurfaceStateCreate);
DVR_V1_API_ENTRY(SurfaceStateDestroy);
DVR_V1_API_ENTRY(SurfaceStateGetSurfaceCount);
@@ -57,6 +59,7 @@
DVR_V1_API_ENTRY(BufferDestroy);
DVR_V1_API_ENTRY(BufferGetAHardwareBuffer);
DVR_V1_API_ENTRY(BufferGetNativeHandle);
+DVR_V1_API_ENTRY(BufferGlobalLayoutVersionGet);
// Write buffer queue
DVR_V1_API_ENTRY(WriteBufferQueueDestroy);
@@ -65,6 +68,7 @@
DVR_V1_API_ENTRY(WriteBufferQueueGetExternalSurface);
DVR_V1_API_ENTRY(WriteBufferQueueCreateReadQueue);
DVR_V1_API_ENTRY(WriteBufferQueueDequeue);
+DVR_V1_API_ENTRY(WriteBufferQueueResizeBuffer);
// Read buffer queue
DVR_V1_API_ENTRY(ReadBufferQueueDestroy);
@@ -72,6 +76,9 @@
DVR_V1_API_ENTRY(ReadBufferQueueGetId);
DVR_V1_API_ENTRY(ReadBufferQueueCreateReadQueue);
DVR_V1_API_ENTRY(ReadBufferQueueDequeue);
+DVR_V1_API_ENTRY(ReadBufferQueueSetBufferAvailableCallback);
+DVR_V1_API_ENTRY(ReadBufferQueueSetBufferRemovedCallback);
+DVR_V1_API_ENTRY(ReadBufferQueueHandleEvents);
// V-Sync client
DVR_V1_API_ENTRY(VSyncClientCreate);
@@ -84,14 +91,16 @@
DVR_V1_API_ENTRY(SurfaceGetId);
DVR_V1_API_ENTRY(SurfaceSetAttributes);
DVR_V1_API_ENTRY(SurfaceCreateWriteBufferQueue);
-DVR_V1_API_ENTRY(GetNamedBuffer);
+DVR_V1_API_ENTRY(SetupGlobalBuffer);
+DVR_V1_API_ENTRY(DeleteGlobalBuffer);
+DVR_V1_API_ENTRY(GetGlobalBuffer);
// Pose client
-DVR_V1_API_ENTRY(PoseCreate);
-DVR_V1_API_ENTRY(PoseDestroy);
-DVR_V1_API_ENTRY(PoseGet);
-DVR_V1_API_ENTRY(PoseGetVsyncCount);
-DVR_V1_API_ENTRY(PoseGetController);
+DVR_V1_API_ENTRY(PoseClientCreate);
+DVR_V1_API_ENTRY(PoseClientDestroy);
+DVR_V1_API_ENTRY(PoseClientGet);
+DVR_V1_API_ENTRY(PoseClientGetVsyncCount);
+DVR_V1_API_ENTRY(PoseClientGetController);
// Virtual touchpad client
DVR_V1_API_ENTRY(VirtualTouchpadCreate);
@@ -133,3 +142,21 @@
DVR_V1_API_ENTRY(HwcFrameGetLayerVisibleRegion);
DVR_V1_API_ENTRY(HwcFrameGetLayerNumDamagedRegions);
DVR_V1_API_ENTRY(HwcFrameGetLayerDamagedRegion);
+
+// New entries added at the end to allow the DVR platform library API
+// to be updated before updating VrCore.
+
+// Virtual touchpad client
+DVR_V1_API_ENTRY(VirtualTouchpadScroll);
+
+// Read the native display metrics from the hardware composer
+DVR_V1_API_ENTRY(GetNativeDisplayMetrics);
+
+// Performance
+DVR_V1_API_ENTRY(PerformanceSetSchedulerPolicy);
+
+// Pose client
+DVR_V1_API_ENTRY(PoseClientSensorsEnable);
+
+// Read buffer queue
+DVR_V1_API_ENTRY(ReadBufferQueueGetEventFd);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer.h b/libs/vr/libdvr/include/dvr/dvr_buffer.h
index af55698..935a7b2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h
@@ -95,6 +95,9 @@
int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer,
AHardwareBuffer** hardware_buffer);
+// Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
+int dvrBufferGlobalLayoutVersionGet();
+
// TODO(eieio): Switch to return int and take an out parameter for the native
// handle.
const struct native_handle* dvrBufferGetNativeHandle(DvrBuffer* buffer);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index dd669dc..e2127f8 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -12,33 +12,191 @@
typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
typedef struct DvrReadBufferQueue DvrReadBufferQueue;
-// WriteBufferQueue
+// Destroy a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue);
+
+// Get the total number of buffers in a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @return The capacity on success; or negative error code.
ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue);
+
+// Get the system unique queue id of a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @return Queue id on success; or negative error code.
int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue);
-// Returns ANativeWindow. Can be casted to a Java Surface using
-// ANativeWindow_toSurface NDK API. Note that this method does not acquire an
-// additional reference to the ANativeWindow returned, don't call
-// ANativeWindow_release on it.
+// Gets an ANativeWindow backed by the DvrWriteBufferQueue
+//
+// Can be casted to a Java Surface using ANativeWindow_toSurface NDK API. Note
+// that the native window is lazily created at the first time |GetNativeWindow|
+// is called, and the created ANativeWindow will be cached so that multiple
+// calls to this method will return the same object. Also note that this method
+// does not acquire an additional reference to the ANativeWindow returned, don't
+// call ANativeWindow_release on it.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param out_window The pointer of an ANativeWindow will be filled here if
+// the method call succeeds.
+// @return Zero on success; or -EINVAL if this DvrWriteBufferQueue does not
+// support being used as an android Surface.
int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
ANativeWindow** out_window);
+// Create a read buffer queue from an existing write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param out_read_queue The pointer of a DvrReadBufferQueue will be filled here
+// if the method call succeeds.
+// @return Zero on success, or negative error code.
int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
DvrReadBufferQueue** out_read_queue);
+
+// Dequeue a buffer to write into.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param timeout Specifies the number of milliseconds that the method will
+// block. Specifying a timeout of -1 causes it to block indefinitely,
+// while specifying a timeout equal to zero cause it to return immediately,
+// even if no buffers are available.
+// @param out_buffer A targeting DvrWriteBuffer object to hold the output of the
+// dequeue operation. Must be created by |dvrWriteBufferCreateEmpty|.
+// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
+// signals the release of underlying buffer. The producer should wait until
+// this fence clears before writing data into it.
+// @return Zero on success, or negative error code.
int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
DvrWriteBuffer* out_buffer, int* out_fence_fd);
-// ReadeBufferQueue
+// Overrides buffer dimension with new width and height.
+//
+// After the call successfully returns, each |dvrWriteBufferQueueDequeue| call
+// will return buffer with newly assigned |width| and |height|. When necessary,
+// old buffer will be removed from the buffer queue and replaced with new buffer
+// matching the new buffer size.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param width Desired width, cannot be Zero.
+// @param height Desired height, cannot be Zero.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
+ uint32_t width, uint32_t height);
+
+// Destroy a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue);
+
+// Get the total number of buffers in a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return The capacity on success; or negative error code.
ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue);
+
+// Get the system unique queue id of a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return Queue id on success; or negative error code.
int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue);
+
+// Get the event fd that signals when queue updates occur.
+//
+// Use ReadBufferQueueHandleEvents to trigger registered event callbacks.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return Fd on success; or negative error code.
+int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue);
+
+// Create a read buffer queue from an existing read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param out_read_queue The pointer of a DvrReadBufferQueue will be filled here
+// if the method call succeeds.
+// @return Zero on success, or negative error code.
int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
DvrReadBufferQueue** out_read_queue);
+
+// Dequeue a buffer to read from.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param timeout Specifies the number of milliseconds that the method will
+// block. Specifying a timeout of -1 causes it to block indefinitely,
+// while specifying a timeout equal to zero cause it to return immediately,
+// even if no buffers are available.
+// @param out_buffer A targeting DvrReadBuffer object to hold the output of the
+// dequeue operation. Must be created by |dvrReadBufferCreateEmpty|.
+// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
+// signals the release of underlying buffer. The consumer should wait until
+// this fence clears before reading data from it.
+// @param out_meta The memory area where a metadata object will be filled.
+// Can be nullptr iff |meta_size_bytes| is zero (i.e., there is no
+// metadata).
+// @param meta_size_bytes Size of the metadata object caller expects. If it
+// doesn't match the size of actually metadata transported by the buffer
+// queue, the method returns -EINVAL.
+// @return Zero on success, or negative error code.
int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
DvrReadBuffer* out_buffer, int* out_fence_fd,
void* out_meta, size_t meta_size_bytes);
+// Callback function which will be called when a buffer is avaiable.
+//
+// Note that there is no guarantee of thread safety and on which thread the
+// callback will be fired.
+//
+// @param context User provided opaque pointer.
+typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
+
+// Set buffer avaiable callback.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param callback The callback function. Set this to NULL if caller no longer
+// needs to listen to new buffer available events.
+// @param context User provided opaque pointer, will be passed back during
+// callback. The caller is responsible for ensuring the validity of the
+// context through the life cycle of the DvrReadBufferQueue.
+// @return Zero on success, or negative error code.
+int dvrReadBufferQueueSetBufferAvailableCallback(
+ DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueueBufferAvailableCallback callback, void* context);
+
+// Callback function which will be called when a buffer is about to be removed.
+//
+// Note that there is no guarantee of thread safety and on which thread the
+// callback will be fired.
+//
+// @param buffer The buffer being removed. Once the callbacks returns, this
+// buffer will be dereferenced from the buffer queue. If user has ever
+// cached other DvrReadBuffer/AHardwareBuffer/EglImageKHR objects derived
+// from this buffer, it's the user's responsibility to clean them up.
+// Note that the ownership of the read buffer is not passed to this
+// callback, so it should call dvrReadBufferDestroy on the buffer.
+// @param context User provided opaque pointer.
+typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer,
+ void* context);
+
+// Set buffer removed callback.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param callback The callback function. Set this to NULL if caller no longer
+// needs to listen to buffer removed events.
+// @param context User provided opaque pointer, will be passed back during
+// callback. The caller is responsible for ensuring the validity of the
+// context through the life cycle of the DvrReadBufferQueue.
+// @return Zero on success, or negative error code.
+int dvrReadBufferQueueSetBufferRemovedCallback(
+ DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueueBufferRemovedCallback callback, void* context);
+
+// Handle all pending events on the read queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return Zero on success, or negative error code.
+int dvrReadBufferQueueHandleEvents(DvrReadBufferQueue* read_queue);
+
__END_DECLS
#endif // ANDROID_DVR_BUFFER_QUEUE_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_config.h b/libs/vr/libdvr/include/dvr/dvr_config.h
new file mode 100644
index 0000000..3d2c066
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_config.h
@@ -0,0 +1,34 @@
+#ifndef ANDROID_DVR_CONFIG_H
+#define ANDROID_DVR_CONFIG_H
+
+// This header is shared by VrCore and Android and must be kept in sync.
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+// This is a shared memory buffer for passing config data from VrCore to
+// libvrflinger in SurfaceFlinger.
+struct __attribute__((packed, aligned(16))) DvrConfig {
+ // Offset before vsync to submit frames to hardware composer.
+ int32_t frame_post_offset_ns{4000000};
+
+ // If the number of pending fences goes over this count at the point when we
+ // are about to submit a new frame to HWC, we will drop the frame. This
+ // should be a signal that the display driver has begun queuing frames. Note
+ // that with smart displays (with RAM), the fence is signaled earlier than
+ // the next vsync, at the point when the DMA to the display completes.
+ // Currently we use a smart display and the EDS timing coincides with zero
+ // pending fences, so this is 0.
+ int32_t allowed_pending_fence_count{0};
+
+ // New fields should always be added to the end for backwards compat.
+
+ // Reserved padding to 16 bytes.
+ uint8_t pad[8];
+};
+
+__END_DECLS
+
+#endif // ANDROID_DVR_CONFIG_H
diff --git a/libs/vr/libdvr/include/dvr/dvr_configuration_data.h b/libs/vr/libdvr/include/dvr/dvr_configuration_data.h
new file mode 100644
index 0000000..22a509f
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_configuration_data.h
@@ -0,0 +1,24 @@
+#ifndef DVR_CONFIGURATION_DATA_H_
+#define DVR_CONFIGURATION_DATA_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+#include <dvr/dvr_display_types.h>
+#include <dvr/dvr_surface.h>
+
+__BEGIN_DECLS
+
+// Loads device configuration data of DVR_CONFIGURATION_DATA_*.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrConfigurationDataGet(int config_type,
+ uint8_t** data, size_t* data_size);
+
+// Destroy the configuration data returned from dvrGetConfigurationData.
+void dvrConfigurationDataDestroy(uint8_t* data);
+
+__END_DECLS
+
+#endif // DVR_CONFIGURATION_DATA_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_display_manager.h b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
index d5aef8b..f910d61 100644
--- a/libs/vr/libdvr/include/dvr/dvr_display_manager.h
+++ b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
@@ -1,5 +1,5 @@
-#ifndef DVR_DISPLAY_MANAGER_CLIENT_H_
-#define DVR_DISPLAY_MANAGER_CLIENT_H_
+#ifndef ANDROID_DVR_DISPLAY_MANAGER_H_
+#define ANDROID_DVR_DISPLAY_MANAGER_H_
#include <stdbool.h>
#include <stddef.h>
@@ -25,13 +25,6 @@
// Destroys the display manager client object.
void dvrDisplayManagerDestroy(DvrDisplayManager* client);
-// Sets up a named buffer for shared memory data transfer between display
-// clients and the display manager.
-// @return 0 on success. Otherwise returns a negative error value.
-int dvrDisplayManagerSetupNamedBuffer(DvrDisplayManager* client,
- const char* name, size_t size,
- uint64_t usage, DvrBuffer** buffer_out);
-
// Returns an fd used to signal when surface updates occur. Note that depending
// on the underlying transport, only a subset of the real event bits may be
// supported. Use dvrDisplayManagerClientTranslateEpollEventMask to get the real
@@ -76,7 +69,7 @@
size_t* count_out);
// Returns the update flags for the surface at |surface_index| in the state
-// object. The flags may be used to determine what changes, if any, occured to
+// object. The flags may be used to determine what changes, if any, occurred to
// the surface since the last state update.
// @return 0 on success. Otherwise returns a negative error value.
int dvrSurfaceStateGetUpdateFlags(DvrSurfaceState* surface_state,
@@ -137,4 +130,4 @@
__END_DECLS
-#endif // DVR_DISPLAY_MANAGER_CLIENT_H_
+#endif // ANDROID_DVR_DISPLAY_MANAGER_H_
diff --git a/libs/vr/libdisplay/include/dvr/dvr_display_types.h b/libs/vr/libdvr/include/dvr/dvr_display_types.h
similarity index 100%
rename from libs/vr/libdisplay/include/dvr/dvr_display_types.h
rename to libs/vr/libdvr/include/dvr/dvr_display_types.h
diff --git a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
index 7ee7f9e..0ba76e2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
@@ -1,7 +1,7 @@
#ifndef ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
#define ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
-#include <dvr/dvr_hardware_composer_defs.h>
+#include <dvr/dvr_hardware_composer_types.h>
#include <stdbool.h>
#ifdef __cplusplus
@@ -24,37 +24,73 @@
DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback,
void* client_state);
+// Called to free the DvrHwcClient pointer.
void dvrHwcClientDestroy(DvrHwcClient* client);
// Called to free the frame information.
+// @param frame Pointer for the valid frame used for the query.
void dvrHwcFrameDestroy(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @return Identifier for the display associated by the frame.
DvrHwcDisplay dvrHwcFrameGetDisplayId(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @return width of the physical display associated with |frame|. This does not
+// take into account any orientation changes.
int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @return height of the physical display associated with |frame|. This does not
+// take into account any orientation changes.
int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
// @return True if the display has been removed. In this case the current frame
// does not contain any valid layers to display. It is a signal to clean up any
// display related state.
bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
// @return Number of layers in the frame.
size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @return The ID of the currently active display configuration.
uint32_t dvrHwcFrameGetActiveConfig(DvrHwcFrame* frame);
+
+// @param frame Pointer for the valid frame used for the query.
+// @return The ID of the current color mode. See HAL_COLOR_MODE_* for valid
+// values.
uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame);
+
+// @param frame Pointer for the valid frame used for the query.
+// @param out_matrix Output parameter for a float[16] array which will be filled
+// with the color transform matrix.
+// @param out_hint Output parameter which will contain the color transform hint.
+// See HAL_COLOR_TRANSFORM_* for valid values.
void dvrHwcFrameGetColorTransform(DvrHwcFrame* frame, float* out_matrix,
int32_t* out_hint);
+
+// @param frame Pointer for the valid frame used for the query.
+// @return The current power mode for the display. See HWC2_POWER_MODE_* for
+// valid values.
uint32_t dvrHwcFrameGetPowerMode(DvrHwcFrame* frame);
+
+// @param frame Pointer for the valid frame used for the query.
+// @return The current state of vsync. See HWC2_VSYNC_* for valid values.
uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return A unique ID for the layer.
DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index);
// Return the graphic buffer associated with the layer at |layer_index| in
// |frame|.
//
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
// @return Graphic buffer. Caller owns the buffer and is responsible for freeing
// it. (see AHardwareBuffer_release())
AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
@@ -62,42 +98,98 @@
// Returns the fence FD for the layer at index |layer_index| in |frame|.
//
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
// @return Fence FD. Caller owns the FD and is responsible for closing it.
int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return describing the portion of the display covered by the layer. Will
+// not exceed the display dimensions.
DvrHwcRecti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame,
size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return describing the portion of the layer that will fill the display
+// frame. Will not exceed the layer dimensions.
DvrHwcRectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The blend mode of the layer.
DvrHwcBlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame,
size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The alpha value to be applied to the whole layer. Will be in the
+// [0.0, 1.0] range.
float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The type of the layer assigned by the window manager.
uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The application id the layer belongs to.
uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The z-order for the layer.
uint32_t dvrHwcFrameGetLayerZOrder(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @param out_x Output parameter for the x coordinate of the cursor location.
+// @param out_y Output parameter for the y coordinate of the cursor location.
void dvrHwcFrameGetLayerCursor(DvrHwcFrame* frame, size_t layer_index,
int32_t* out_x, int32_t* out_y);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The transformation that needs to be applied to the layer before
+// presenting it. See DVR_HWC_TRANSFORM_* for valid values.
uint32_t dvrHwcFrameGetLayerTransform(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The dataspace which represents how the pixel values should be
+// interpreted. See HAL_DATASPACE_* for valid values.
uint32_t dvrHwcFrameGetLayerDataspace(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The color of the layer if layer composition is SOLID_COLOR.
uint32_t dvrHwcFrameGetLayerColor(DvrHwcFrame* frame, size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The number of visible regions.
uint32_t dvrHwcFrameGetLayerNumVisibleRegions(DvrHwcFrame* frame,
size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @param index The index of the visible region for the layer.
+// @return The rectangle describing the visible region.
DvrHwcRecti dvrHwcFrameGetLayerVisibleRegion(DvrHwcFrame* frame,
size_t layer_index, size_t index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The number of damanged regions.
uint32_t dvrHwcFrameGetLayerNumDamagedRegions(DvrHwcFrame* frame,
size_t layer_index);
+
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @param index The index of the damanged region for the layer.
+// @return The rectangle describing the damaged region.
DvrHwcRecti dvrHwcFrameGetLayerDamagedRegion(DvrHwcFrame* frame,
size_t layer_index, size_t index);
#ifdef __cplusplus
diff --git a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h
similarity index 82%
rename from libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
rename to libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h
index 36c30f9..1d5eda6 100644
--- a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h
@@ -26,6 +26,15 @@
DVR_HWC_COMPOSITION_SIDEBAND = 5,
};
+enum DvrHwcTransform {
+ DVR_HWC_TRANSFORM_NONE = 0,
+ DVR_HWC_TRANSFORM_FLIP_H = 1,
+ DVR_HWC_TRANSFORM_FLIP_V = 2,
+ DVR_HWC_TRANSFORM_ROT_90 = 4,
+ DVR_HWC_TRANSFORM_ROT_180 = 3,
+ DVR_HWC_TRANSFORM_ROT_270 = 7,
+};
+
typedef uint64_t DvrHwcDisplay;
typedef uint64_t DvrHwcLayer;
diff --git a/libs/vr/libdvr/include/dvr/dvr_performance.h b/libs/vr/libdvr/include/dvr/dvr_performance.h
new file mode 100644
index 0000000..5df35ad
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_performance.h
@@ -0,0 +1,26 @@
+#ifndef ANDROID_DVR_PERFORMANCE_H_
+#define ANDROID_DVR_PERFORMANCE_H_
+
+#include <stddef.h>
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+__END_DECLS
+
+#endif // ANDROID_DVR_PERFORMANCE_H_
+
diff --git a/libs/vr/libdvr/include/dvr/dvr_pose.h b/libs/vr/libdvr/include/dvr/dvr_pose.h
new file mode 100644
index 0000000..b3df028
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_pose.h
@@ -0,0 +1,100 @@
+#ifndef ANDROID_DVR_PUBLIC_POSE_H_
+#define ANDROID_DVR_PUBLIC_POSE_H_
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#ifdef __ARM_NEON
+#include <arm_neon.h>
+#else
+#ifndef __FLOAT32X4T_86
+#define __FLOAT32X4T_86
+typedef float float32x4_t __attribute__((__vector_size__(16)));
+#endif
+#endif
+
+// Represents an estimated pose, accessed asynchronously through a shared ring
+// buffer. No assumptions should be made about the data in padding space.
+// The size of this struct is 128 bytes.
+typedef struct __attribute__((packed, aligned(16))) DvrPoseAsync {
+ // Left eye head-from-start orientation quaternion x,y,z,w.
+ float32x4_t orientation;
+ // Left eye head-from-start position x,y,z,pad in meters.
+ float32x4_t position;
+ // Right eye head-from-start orientation quaternion x,y,z,w.
+ float32x4_t right_orientation;
+ // Right eye head-from-start position x,y,z,pad in meters.
+ float32x4_t right_position;
+ // Start-space angular velocity x,y,z,pad in radians per second.
+ float32x4_t angular_velocity;
+ // Start-space positional velocity x,y,z,pad in meters per second.
+ float32x4_t velocity;
+ // Timestamp of when this pose is predicted for, typically halfway through
+ // scanout.
+ int64_t timestamp_ns;
+ // Bitmask of DVR_POSE_FLAG_* constants that apply to this pose.
+ //
+ // If DVR_POSE_FLAG_INVALID is set, the pose is indeterminate.
+ uint64_t flags;
+ // Reserved padding to 128 bytes.
+ uint8_t pad[16];
+} DvrPoseAsync;
+
+enum {
+ DVR_POSE_FLAG_INVALID = (1ULL << 0), // This pose is invalid.
+ DVR_POSE_FLAG_INITIALIZING = (1ULL << 1), // The pose delivered during
+ // initialization and it may not be
+ // correct.
+ DVR_POSE_FLAG_3DOF =
+ (1ULL << 2), // This pose is derived from 3Dof sensors. If
+ // this is not set, pose is derived using
+ // 3Dof and 6Dof sensors.
+ DVR_POSE_FLAG_FLOOR_HEIGHT_INVALID =
+ (1ULL << 3), // If set the floor height is invalid.
+
+ // Bits that indicate the tracking system state.
+ DVR_POSE_FLAG_SERVICE_EXCEPTION = (1ULL << 32),
+ DVR_POSE_FLAG_FISHEYE_OVER_EXPOSED = (1ULL << 33),
+ DVR_POSE_FLAG_FISHEYE_UNDER_EXPOSED = (1ULL << 34),
+ DVR_POSE_FLAG_COLOR_OVER_EXPOSED = (1ULL << 35),
+ DVR_POSE_FLAG_COLOR_UNDER_EXPOSED = (1ULL << 36),
+ DVR_POSE_FLAG_TOO_FEW_FEATURES_TRACKED = (1ULL << 37)
+};
+
+// Represents a sensor pose sample.
+typedef struct __attribute__((packed, aligned(16))) DvrPose {
+ // Head-from-start orientation quaternion x,y,z,w.
+ float32x4_t orientation;
+
+ // The angular velocity where the x,y,z is the rotation axis and the
+ // magnitude is the radians / second in the same coordinate frame as
+ // orientation.
+ float32x4_t angular_velocity;
+
+ // Head-from-start position x,y,z,pad in meters.
+ float32x4_t position;
+
+ // In meters / second in the same coordinate frame as position.
+ float32x4_t velocity;
+
+ // In meters / second ^ 2 in the same coordinate frame as position.
+ float32x4_t acceleration;
+
+ // Timestamp for the measurement in nanoseconds.
+ int64_t timestamp_ns;
+
+ // The combination of flags above.
+ uint64_t flags;
+
+ // The current floor height. May be updated at a lower cadence than pose.
+ float floor_height;
+
+ // Padding to 112 bytes so the size is a multiple of 16.
+ uint8_t padding[12];
+} DvrPose;
+
+__END_DECLS
+
+#endif // ANDROID_DVR_PUBLIC_POSE_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h b/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
new file mode 100644
index 0000000..63c7385
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
@@ -0,0 +1,102 @@
+#ifndef ANDROID_DVR_SHARED_BUFFERS_H_
+#define ANDROID_DVR_SHARED_BUFFERS_H_
+
+#include <dvr/dvr_config.h>
+#include <dvr/dvr_pose.h>
+#include <dvr/dvr_vsync.h>
+#include <libbroadcastring/broadcast_ring.h>
+
+// This header is shared by VrCore and Android and must be kept in sync.
+namespace android {
+namespace dvr {
+
+// Increment when the layout for the buffers change.
+enum : uint32_t { kSharedBufferLayoutVersion = 2 };
+
+// Note: These buffers will be mapped from various system processes as well
+// as VrCore and the application processes in a r/w manner.
+//
+// Therefore it is possible for the application to mess with the contents of
+// these buffers.
+//
+// While using them, assume garbage memory: Your logic must not crash or lead
+// to execution of unsafe code as a function of the contents of these buffers.
+
+// Sanity check for basic type sizes.
+static_assert(sizeof(DvrPoseAsync) == 128, "Unexpected size for DvrPoseAsync");
+static_assert(sizeof(DvrPose) == 112, "Unexpected size for DvrPose");
+static_assert(sizeof(DvrVsync) == 32, "Unexpected size for DvrVsync");
+static_assert(sizeof(DvrConfig) == 16, "Unexpected size for DvrConfig");
+
+// A helper class that provides compile time sized traits for the BroadcastRing.
+template <class DvrType, size_t StaticCount>
+class DvrRingBufferTraits {
+ public:
+ using Record = DvrType;
+ static constexpr bool kUseStaticRecordSize = false;
+ static constexpr uint32_t kStaticRecordCount = StaticCount;
+ static constexpr int kMaxReservedRecords = 1;
+ static constexpr int kMinAvailableRecords = 1;
+};
+
+// Traits classes.
+using DvrPoseTraits = DvrRingBufferTraits<DvrPose, 0>;
+using DvrVsyncTraits = DvrRingBufferTraits<DvrVsync, 2>;
+using DvrConfigTraits = DvrRingBufferTraits<DvrConfig, 2>;
+
+// The broadcast ring classes that will expose the data.
+using DvrPoseRing = BroadcastRing<DvrPose, DvrPoseTraits>;
+using DvrVsyncRing = BroadcastRing<DvrVsync, DvrVsyncTraits>;
+using DvrConfigRing = BroadcastRing<DvrConfig, DvrConfigTraits>;
+
+// This is a shared memory buffer for passing pose data estimated at vsyncs.
+//
+// This will be primarily used for late latching and EDS where we bind this
+// buffer in a shader and extract the right vsync-predicted pose.
+struct __attribute__((packed, aligned(16))) DvrVsyncPoseBuffer {
+ enum : int {
+ // The number vsync predicted poses to keep in the ring buffer.
+ // Must be a power of 2.
+ kSize = 8,
+ kIndexMask = kSize - 1,
+
+ // The number of vsyncs (from the current vsync) we predict in vsync buffer.
+ // The other poses are left alone.
+ kMinFutureCount = 4
+ };
+
+ // The vsync predicted poses.
+ // The pose for the vsync n is:
+ // vsync_poses[n % kSize]
+ //
+ // This buffer is unsynchronized: It is possible to get torn reads as the
+ // sensor service updates the predictions as new sensor measurements come
+ // in. In particular, it is possible to get the position and an updated
+ // orientation while reading.
+ DvrPoseAsync vsync_poses[kSize];
+
+ // The latest sensor pose for GPU usage.
+ DvrPose current_pose;
+
+ // Current vsync_count (where sensord is writing poses from).
+ uint32_t vsync_count;
+
+ // For 16 byte alignment.
+ uint8_t padding[12];
+};
+
+static_assert(sizeof(DvrVsyncPoseBuffer) == 1152,
+ "Unexpected size for DvrVsyncPoseBuffer");
+
+// The keys for the dvr global buffers.
+enum DvrGlobalBuffers : int32_t {
+ kVsyncPoseBuffer = 1,
+ kVsyncBuffer = 2,
+ kSensorPoseBuffer = 3,
+ kVrFlingerConfigBufferKey = 4
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_SHARED_BUFFERS_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_surface.h b/libs/vr/libdvr/include/dvr/dvr_surface.h
index 361488e..74a68a1 100644
--- a/libs/vr/libdvr/include/dvr/dvr_surface.h
+++ b/libs/vr/libdvr/include/dvr/dvr_surface.h
@@ -6,16 +6,13 @@
#include <stdint.h>
#include <sys/cdefs.h>
+#include <dvr/dvr_api.h>
#include <dvr/dvr_buffer.h>
#include <dvr/dvr_buffer_queue.h>
#include <dvr/dvr_display_types.h>
__BEGIN_DECLS
-typedef struct DvrBuffer DvrBuffer;
-typedef struct DvrSurface DvrSurface;
-typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
-
// Attribute types. The values are one-hot encoded to support singluar types or
// masks of supported types.
enum {
@@ -79,12 +76,37 @@
int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width,
uint32_t height, uint32_t format,
uint32_t layer_count, uint64_t usage,
- size_t capacity,
+ size_t capacity, size_t metadata_size,
DvrWriteBufferQueue** queue_out);
-// Get a named buffer from the display service.
+// Sets up a named buffer for shared memory data transfer between display
+// clients and the system. Protected API that may only be called with sufficient
+// privilege.
// @return 0 on success. Otherwise returns a negative error value.
-int dvrGetNamedBuffer(const char* name, DvrBuffer** out_buffer);
+int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage,
+ DvrBuffer** buffer_out);
+
+// Deletes a named buffer. WARNING: This is dangerous because any existing
+// clients of this buffer will not be notified and will remain attached to
+// the old buffer. This is useful for tests, but probably not for production
+// code.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key);
+
+// Get a global buffer from the display service.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer);
+
+// Read the native device display metrics as reported by the hardware composer.
+// This is useful as otherwise the device metrics are only reported as
+// relative to the current device orientation.
+// @param sizeof_metrics the size of the passed in metrics struct. This is used
+// to ensure we don't break each other during active development.
+// @param metrics on success holds the retrieved device metrics.
+// @return 0 on success. Otherwise returns a negative error value (typically
+// this means the display service is not available).
+int dvrGetNativeDisplayMetrics(size_t metrics_struct_size,
+ DvrNativeDisplayMetrics* metrics);
__END_DECLS
diff --git a/libs/vr/libdvr/include/dvr/dvr_vsync.h b/libs/vr/libdvr/include/dvr/dvr_vsync.h
index 1eea3d9..87fdf31 100644
--- a/libs/vr/libdvr/include/dvr/dvr_vsync.h
+++ b/libs/vr/libdvr/include/dvr/dvr_vsync.h
@@ -8,6 +8,27 @@
typedef struct DvrVSyncClient DvrVSyncClient;
+// Represents a vsync sample. The size of this struct is 32 bytes.
+typedef struct __attribute__((packed, aligned(16))) DvrVsync {
+ // The timestamp for the last vsync in nanoseconds.
+ uint64_t vsync_timestamp_ns;
+
+ // The index of the last vsync.
+ uint32_t vsync_count;
+
+ // Scan out for the left eye = vsync_timestamp_ns + vsync_left_eye_offset_ns.
+ int32_t vsync_left_eye_offset_ns;
+
+ // Scan out for the right eye = vsync_timestamp_ns + vsync_right_eye_offset_ns
+ int32_t vsync_right_eye_offset_ns;
+
+ // The period of a vsync in nanoseconds.
+ uint32_t vsync_period_ns;
+
+ // Padding to 32 bytes so the size is a multiple of 16.
+ uint8_t padding[8];
+} DvrVsync;
+
// Creates a new client to the system vsync service.
int dvrVSyncClientCreate(DvrVSyncClient** client_out);
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index ef746e2..ab2ee75 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -32,6 +32,7 @@
"libdvrcommon",
"libdisplay",
"libpdx_default_transport",
+ "libbroadcastring",
]
cc_test {
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 474e968..16da1d9 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -7,27 +7,41 @@
#include <gtest/gtest.h>
#include "../dvr_internal.h"
+#include "../dvr_buffer_queue_internal.h"
namespace android {
namespace dvr {
namespace {
-static constexpr int kBufferWidth = 100;
-static constexpr int kBufferHeight = 1;
-static constexpr int kLayerCount = 1;
-static constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr uint32_t kBufferWidth = 100;
+static constexpr uint32_t kBufferHeight = 1;
+static constexpr uint32_t kLayerCount = 1;
+static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
static constexpr size_t kQueueCapacity = 3;
typedef uint64_t TestMeta;
class DvrBufferQueueTest : public ::testing::Test {
+ public:
+ static void BufferAvailableCallback(void* context) {
+ DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context);
+ thiz->HandleBufferAvailable();
+ }
+
+ static void BufferRemovedCallback(DvrReadBuffer* buffer, void* context) {
+ DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context);
+ thiz->HandleBufferRemoved(buffer);
+ }
+
protected:
void SetUp() override {
- write_queue_ = CreateDvrWriteBufferQueueFromProducerQueue(
- ProducerQueue::Create<TestMeta>(0, 0, 0, 0));
- ASSERT_NE(nullptr, write_queue_);
+ config_builder_ = ProducerQueueConfigBuilder()
+ .SetDefaultWidth(kBufferWidth)
+ .SetDefaultHeight(kBufferHeight)
+ .SetDefaultFormat(kBufferFormat)
+ .SetMetadata<TestMeta>();
}
void TearDown() override {
@@ -37,26 +51,47 @@
}
}
- void AllocateBuffers(size_t buffer_count) {
- size_t out_slot;
- for (size_t i = 0; i < buffer_count; i++) {
- int ret = GetProducerQueueFromDvrWriteBufferQueue(write_queue_)
- ->AllocateBuffer(kBufferWidth, kBufferHeight, kLayerCount,
- kBufferFormat, kBufferUsage, &out_slot);
- ASSERT_EQ(0, ret);
- }
+ void CreateWriteBufferQueue() {
+ write_queue_ = new DvrWriteBufferQueue(
+ ProducerQueue::Create(config_builder_.Build(), UsagePolicy{}));
+ ASSERT_NE(nullptr, write_queue_);
}
+ void AllocateBuffers(size_t buffer_count) {
+ auto status = write_queue_->producer_queue()->AllocateBuffers(
+ kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
+ buffer_count);
+ ASSERT_TRUE(status.ok());
+ }
+
+ void HandleBufferAvailable() {
+ buffer_available_count_ += 1;
+ ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_);
+ }
+
+ void HandleBufferRemoved(DvrReadBuffer* buffer) {
+ buffer_removed_count_ += 1;
+ ALOGD_IF(TRACE, "Buffer removed, buffer=%p, count=%d", buffer,
+ buffer_removed_count_);
+ }
+
+ ProducerQueueConfigBuilder config_builder_;
DvrWriteBufferQueue* write_queue_{nullptr};
+ int buffer_available_count_{0};
+ int buffer_removed_count_{0};
};
-TEST_F(DvrBufferQueueTest, TestWrite_QueueDestroy) {
+TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
dvrWriteBufferQueueDestroy(write_queue_);
write_queue_ = nullptr;
}
TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
- AllocateBuffers(kQueueCapacity);
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
@@ -64,6 +99,8 @@
}
TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
DvrReadBufferQueue* read_queue = nullptr;
int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
@@ -74,6 +111,8 @@
}
TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
DvrReadBufferQueue* read_queue1 = nullptr;
DvrReadBufferQueue* read_queue2 = nullptr;
int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
@@ -91,7 +130,8 @@
}
TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) {
- AllocateBuffers(3);
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(3));
DvrReadBuffer* read_buffer = nullptr;
DvrWriteBuffer* write_buffer = nullptr;
@@ -124,6 +164,9 @@
}
TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
static constexpr int kTimeout = 0;
DvrReadBufferQueue* read_queue = nullptr;
DvrReadBuffer* rb = nullptr;
@@ -135,14 +178,15 @@
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
+ dvrReadBufferQueueSetBufferAvailableCallback(read_queue,
+ &BufferAvailableCallback, this);
+
dvrWriteBufferCreateEmpty(&wb);
ASSERT_NE(nullptr, wb);
dvrReadBufferCreateEmpty(&rb);
ASSERT_NE(nullptr, rb);
- AllocateBuffers(kQueueCapacity);
-
// Gain buffer for writing.
ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb, &fence_fd);
ASSERT_EQ(0, ret);
@@ -163,6 +207,9 @@
ret = dvrReadBufferQueueDequeue(read_queue, kTimeout, rb, &fence_fd,
&acquired_seq, sizeof(acquired_seq));
ASSERT_EQ(0, ret);
+
+ // Dequeue is successfully, BufferAvailableCallback should be fired once.
+ ASSERT_EQ(1, buffer_available_count_);
ASSERT_TRUE(dvrReadBufferIsValid(rb));
ASSERT_EQ(seq, acquired_seq);
ALOGD_IF(TRACE,
@@ -187,6 +234,8 @@
}
TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
ANativeWindow* window = nullptr;
// The |write_queue_| doesn't have proper metadata (must be
@@ -196,10 +245,12 @@
ASSERT_EQ(nullptr, window);
// A write queue with DvrNativeBufferMetadata should work fine.
+ auto config = ProducerQueueConfigBuilder()
+ .SetMetadata<DvrNativeBufferMetadata>()
+ .Build();
std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
write_queue(
- CreateDvrWriteBufferQueueFromProducerQueue(
- ProducerQueue::Create<DvrNativeBufferMetadata>(0, 0, 0, 0)),
+ new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})),
dvrWriteBufferQueueDestroy);
ASSERT_NE(nullptr, write_queue.get());
@@ -211,6 +262,208 @@
ASSERT_TRUE(Surface::isValid(surface));
}
+// Create buffer queue of three buffers and dequeue three buffers out of it.
+// Before each dequeue operation, we resize the buffer queue and expect the
+// queue always return buffer with desired dimension.
+TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
+ static constexpr int kTimeout = 0;
+ int fence_fd = -1;
+
+ DvrReadBufferQueue* read_queue = nullptr;
+ DvrWriteBuffer* wb1 = nullptr;
+ DvrWriteBuffer* wb2 = nullptr;
+ DvrWriteBuffer* wb3 = nullptr;
+ AHardwareBuffer* ahb1 = nullptr;
+ AHardwareBuffer* ahb2 = nullptr;
+ AHardwareBuffer* ahb3 = nullptr;
+ AHardwareBuffer_Desc buffer_desc;
+
+ int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, read_queue);
+
+ dvrReadBufferQueueSetBufferRemovedCallback(read_queue, &BufferRemovedCallback,
+ this);
+
+ dvrWriteBufferCreateEmpty(&wb1);
+ ASSERT_NE(nullptr, wb1);
+ dvrWriteBufferCreateEmpty(&wb2);
+ ASSERT_NE(nullptr, wb2);
+ dvrWriteBufferCreateEmpty(&wb3);
+ ASSERT_NE(nullptr, wb3);
+
+ // Handle all pending events on the read queue.
+ ret = dvrReadBufferQueueHandleEvents(read_queue);
+ ASSERT_EQ(0, ret);
+
+ size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+ ALOGD_IF(TRACE, "TestResizeBuffer, capacity=%zu", capacity);
+ ASSERT_EQ(kQueueCapacity, capacity);
+
+ // Resize before dequeuing.
+ constexpr uint32_t w1 = 10;
+ ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
+ ASSERT_EQ(0, ret);
+
+ // Gain first buffer for writing. All buffers will be resized.
+ ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb1, &fence_fd);
+ ASSERT_EQ(0, ret);
+ ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
+ ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
+ pdx::LocalHandle release_fence1(fence_fd);
+
+ // Check the buffer dimension.
+ ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
+ ASSERT_EQ(0, ret);
+ AHardwareBuffer_describe(ahb1, &buffer_desc);
+ ASSERT_EQ(w1, buffer_desc.width);
+ ASSERT_EQ(kBufferHeight, buffer_desc.height);
+ AHardwareBuffer_release(ahb1);
+
+ // For the first resize, all buffers are reallocated.
+ int expected_buffer_removed_count = kQueueCapacity;
+ ret = dvrReadBufferQueueHandleEvents(read_queue);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
+
+ // Resize the queue. We are testing with blob format, keep height to be 1.
+ constexpr uint32_t w2 = 20;
+ ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
+ ASSERT_EQ(0, ret);
+
+ // The next buffer we dequeued should have new width.
+ ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb2, &fence_fd);
+ ASSERT_EQ(0, ret);
+ ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
+ ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
+ fence_fd);
+ pdx::LocalHandle release_fence2(fence_fd);
+
+ // Check the buffer dimension, should be new width
+ ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
+ ASSERT_EQ(0, ret);
+ AHardwareBuffer_describe(ahb2, &buffer_desc);
+ ASSERT_EQ(w2, buffer_desc.width);
+ AHardwareBuffer_release(ahb2);
+
+ // For the second resize, all but one buffers are reallocated.
+ expected_buffer_removed_count += (kQueueCapacity - 1);
+ ret = dvrReadBufferQueueHandleEvents(read_queue);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
+
+ // Resize the queue for the third time.
+ constexpr uint32_t w3 = 30;
+ ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
+ ASSERT_EQ(0, ret);
+
+ // The next buffer we dequeued should have new width.
+ ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb3, &fence_fd);
+ ASSERT_EQ(0, ret);
+ ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
+ ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
+ fence_fd);
+ pdx::LocalHandle release_fence3(fence_fd);
+
+ // Check the buffer dimension, should be new width
+ ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
+ ASSERT_EQ(0, ret);
+ AHardwareBuffer_describe(ahb3, &buffer_desc);
+ ASSERT_EQ(w3, buffer_desc.width);
+ AHardwareBuffer_release(ahb3);
+
+ // For the third resize, all but two buffers are reallocated.
+ expected_buffer_removed_count += (kQueueCapacity - 2);
+ ret = dvrReadBufferQueueHandleEvents(read_queue);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
+
+ dvrReadBufferQueueDestroy(read_queue);
+}
+
+TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) {
+ // Overrides default queue parameters: Empty metadata.
+ config_builder_.SetMetadata<void>();
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+
+ DvrReadBuffer* rb = nullptr;
+ DvrWriteBuffer* wb = nullptr;
+ dvrReadBufferCreateEmpty(&rb);
+ dvrWriteBufferCreateEmpty(&wb);
+
+ DvrReadBufferQueue* read_queue = nullptr;
+ EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+ const int kTimeoutMs = 0;
+ int fence_fd = -1;
+ EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
+
+ EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, nullptr, 0));
+ EXPECT_EQ(0, dvrWriteBufferClear(wb));
+ dvrWriteBufferDestroy(wb);
+ wb = nullptr;
+
+ // When acquire buffer, it's legit to pass nullptr as out_meta iff metadata
+ // size is Zero.
+ EXPECT_EQ(0, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
+ nullptr, 0));
+ EXPECT_TRUE(dvrReadBufferIsValid(rb));
+}
+
+TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+
+ DvrReadBuffer* rb = nullptr;
+ DvrWriteBuffer* wb = nullptr;
+ dvrReadBufferCreateEmpty(&rb);
+ dvrWriteBufferCreateEmpty(&wb);
+
+ DvrReadBufferQueue* read_queue = nullptr;
+ EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+ const int kTimeoutMs = 0;
+ int fence_fd = -1;
+ EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
+
+ TestMeta seq = 42U;
+ EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, &seq, sizeof(seq)));
+ EXPECT_EQ(0, dvrWriteBufferClear(wb));
+ dvrWriteBufferDestroy(wb);
+ wb = nullptr;
+
+ // Dequeue with wrong metadata will cause EINVAL.
+ int8_t wrong_metadata;
+ EXPECT_EQ(-EINVAL,
+ dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
+ &wrong_metadata, sizeof(wrong_metadata)));
+ EXPECT_FALSE(dvrReadBufferIsValid(rb));
+
+ // Dequeue with empty metadata will cause EINVAL.
+ EXPECT_EQ(-EINVAL, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb,
+ &fence_fd, nullptr, 0));
+ EXPECT_FALSE(dvrReadBufferIsValid(rb));
+}
+
+TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
+ DvrReadBufferQueue* read_queue = nullptr;
+ int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, read_queue);
+
+ int event_fd = dvrReadBufferQueueGetEventFd(read_queue);
+ ASSERT_GT(event_fd, 0);
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
index a2414d6..f83b26e 100644
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
@@ -1,14 +1,18 @@
+#include <android-base/properties.h>
#include <base/logging.h>
#include <gtest/gtest.h>
+#include <log/log.h>
#include <poll.h>
#include <android/hardware_buffer.h>
#include <algorithm>
+#include <array>
#include <set>
#include <thread>
#include <vector>
+#include <dvr/dvr_configuration_data.h>
#include <dvr/dvr_deleter.h>
#include <dvr/dvr_display_manager.h>
#include <dvr/dvr_surface.h>
@@ -23,7 +27,30 @@
namespace {
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, bool value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, nullptr_t) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
+ attribute.value.int32_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int64_t value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64;
+ attribute.value.int64_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, bool value) {
DvrSurfaceAttribute attribute;
attribute.key = key;
attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
@@ -31,11 +58,56 @@
return attribute;
}
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, float value) {
DvrSurfaceAttribute attribute;
attribute.key = key;
- attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
- attribute.value.bool_value = value;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT;
+ attribute.value.float_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 2>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2;
+ std::copy(value.begin(), value.end(), attribute.value.float2_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 3>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3;
+ std::copy(value.begin(), value.end(), attribute.value.float3_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 4>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4;
+ std::copy(value.begin(), value.end(), attribute.value.float4_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 8>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8;
+ std::copy(value.begin(), value.end(), attribute.value.float8_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 16>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16;
+ std::copy(value.begin(), value.end(), attribute.value.float16_value);
return attribute;
}
@@ -43,8 +115,8 @@
int32_t z_order = 0) {
DvrSurface* surface = nullptr;
DvrSurfaceAttribute attributes[] = {
- GetAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
- GetAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
const int ret = dvrSurfaceCreate(
attributes, std::extent<decltype(attributes)>::value, &surface);
@@ -56,11 +128,12 @@
Status<UniqueDvrWriteBufferQueue> CreateSurfaceQueue(
const UniqueDvrSurface& surface, uint32_t width, uint32_t height,
- uint32_t format, uint32_t layer_count, uint64_t usage, size_t capacity) {
+ uint32_t format, uint32_t layer_count, uint64_t usage, size_t capacity,
+ size_t metadata_size) {
DvrWriteBufferQueue* queue;
- const int ret =
- dvrSurfaceCreateWriteBufferQueue(surface.get(), width, height, format,
- layer_count, usage, capacity, &queue);
+ const int ret = dvrSurfaceCreateWriteBufferQueue(
+ surface.get(), width, height, format, layer_count, usage, capacity,
+ metadata_size, &queue);
if (ret < 0)
return ErrorStatus(-ret);
else
@@ -98,13 +171,14 @@
return {};
}
- Status<void> WaitForUpdate() {
+ enum : int { kTimeoutMs = 10000 }; // 10s
+
+ Status<void> WaitForUpdate(int timeout_ms = kTimeoutMs) {
if (display_manager_event_fd_ < 0)
return ErrorStatus(-display_manager_event_fd_);
- const int kTimeoutMs = 10000; // 10s
pollfd pfd = {display_manager_event_fd_, POLLIN, 0};
- const int count = poll(&pfd, 1, kTimeoutMs);
+ const int count = poll(&pfd, 1, timeout_ms);
if (count < 0)
return ErrorStatus(errno);
else if (count == 0)
@@ -200,6 +274,23 @@
return {std::move(queue_ids)};
}
+ Status<std::vector<uint8_t>> GetConfigData(int config_type) {
+ uint8_t* data = nullptr;
+ size_t data_size = 0;
+ int error = dvrConfigurationDataGet(config_type, &data, &data_size);
+ if (error < 0) {
+ return ErrorStatus(-error);
+ }
+
+ if (!data || data_size == 0) {
+ return ErrorStatus(EINVAL);
+ }
+ std::vector<uint8_t> data_result(data, data + data_size);
+ dvrConfigurationDataDestroy(data);
+ std::string s(data, data + data_size);
+ return {std::move(data_result)};
+ }
+
private:
UniqueDvrDisplayManager display_manager_;
UniqueDvrSurfaceState surface_state_;
@@ -451,20 +542,218 @@
auto attributes = attribute_status.take();
EXPECT_GE(attributes.size(), 2u);
- const std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
- DVR_SURFACE_ATTRIBUTE_VISIBLE};
+ std::set<int32_t> actual_keys;
+ std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
// Collect all the keys in attributes that match the expected keys.
- std::set<int32_t> actual_keys;
- std::for_each(attributes.begin(), attributes.end(),
- [&expected_keys, &actual_keys](const auto& attribute) {
- if (expected_keys.find(attribute.key) != expected_keys.end())
- actual_keys.emplace(attribute.key);
- });
+ auto compare_keys = [](const auto& attributes, const auto& expected_keys) {
+ std::set<int32_t> keys;
+ for (const auto& attribute : attributes) {
+ if (expected_keys.find(attribute.key) != expected_keys.end())
+ keys.emplace(attribute.key);
+ }
+ return keys;
+ };
// If the sets match then attributes contained at least the expected keys,
// even if other keys were also present.
+ actual_keys = compare_keys(attributes, expected_keys);
EXPECT_EQ(expected_keys, actual_keys);
+
+ std::vector<DvrSurfaceAttribute> attributes_to_set = {
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, 0)};
+
+ // Test invalid args.
+ EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(nullptr, attributes_to_set.data(),
+ attributes_to_set.size()));
+ EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(surface.get(), nullptr,
+ attributes_to_set.size()));
+
+ // Test attribute change events.
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+
+ // Verify the attributes changed flag is set.
+ auto check_flags = [](const auto& value) {
+ return value & DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED;
+ };
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+
+ // Test setting and then deleting an attribute.
+ const DvrSurfaceAttributeKey kUserKey = 1;
+ attributes_to_set = {MakeAttribute(kUserKey, 1024)};
+
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+ kUserKey};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+
+ // Delete the attribute.
+ attributes_to_set = {MakeAttribute(kUserKey, nullptr)};
+
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+ kUserKey};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_NE(expected_keys, actual_keys);
+
+ // Test deleting a reserved attribute.
+ attributes_to_set = {MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, nullptr)};
+
+ EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+
+ // Failed attribute operations should not trigger update events.
+ const int kTimeoutMs = 100; // 0.1s
+ EXPECT_STATUS_ERROR_VALUE(ETIMEDOUT, manager_->WaitForUpdate(kTimeoutMs));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+}
+
+TEST_F(DvrDisplayManagerTest, SurfaceAttributeTypes) {
+ // Create an application surface.
+ auto surface_status = CreateApplicationSurface();
+ ASSERT_STATUS_OK(surface_status);
+ UniqueDvrSurface surface = surface_status.take();
+ ASSERT_NE(nullptr, surface.get());
+
+ enum : std::int32_t {
+ kInt32Key = 1,
+ kInt64Key,
+ kBoolKey,
+ kFloatKey,
+ kFloat2Key,
+ kFloat3Key,
+ kFloat4Key,
+ kFloat8Key,
+ kFloat16Key,
+ };
+
+ const std::vector<DvrSurfaceAttribute> attributes_to_set = {
+ MakeAttribute(kInt32Key, int32_t{0}),
+ MakeAttribute(kInt64Key, int64_t{0}),
+ MakeAttribute(kBoolKey, false),
+ MakeAttribute(kFloatKey, 0.0f),
+ MakeAttribute(kFloat2Key, std::array<float, 2>{{1.0f, 2.0f}}),
+ MakeAttribute(kFloat3Key, std::array<float, 3>{{3.0f, 4.0f, 5.0f}}),
+ MakeAttribute(kFloat4Key, std::array<float, 4>{{6.0f, 7.0f, 8.0f, 9.0f}}),
+ MakeAttribute(kFloat8Key,
+ std::array<float, 8>{{10.0f, 11.0f, 12.0f, 13.0f, 14.0f,
+ 15.0f, 16.0f, 17.0f}}),
+ MakeAttribute(kFloat16Key, std::array<float, 16>{
+ {18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f,
+ 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f,
+ 30.0f, 31.0f, 32.0f, 33.0f}})};
+
+ EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ auto attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ auto attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), attributes_to_set.size());
+
+ auto HasAttribute = [](const auto& attributes,
+ DvrSurfaceAttributeKey key) -> bool {
+ for (const auto& attribute : attributes) {
+ if (attribute.key == key)
+ return true;
+ }
+ return false;
+ };
+ auto AttributeType =
+ [](const auto& attributes,
+ DvrSurfaceAttributeKey key) -> DvrSurfaceAttributeType {
+ for (const auto& attribute : attributes) {
+ if (attribute.key == key)
+ return attribute.value.type;
+ }
+ return DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+ };
+
+ ASSERT_TRUE(HasAttribute(attributes, kInt32Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+ AttributeType(attributes, kInt32Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kInt64Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT64,
+ AttributeType(attributes, kInt64Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kBoolKey));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+ AttributeType(attributes, kBoolKey));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloatKey));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT,
+ AttributeType(attributes, kFloatKey));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat2Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2,
+ AttributeType(attributes, kFloat2Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat3Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3,
+ AttributeType(attributes, kFloat3Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat4Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4,
+ AttributeType(attributes, kFloat4Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat8Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8,
+ AttributeType(attributes, kFloat8Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat16Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16,
+ AttributeType(attributes, kFloat16Key));
}
TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) {
@@ -480,13 +769,14 @@
ASSERT_STATUS_OK(manager_->WaitForUpdate());
ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
- // Verify there are no queues for the surface recorded in the state snapshot.
+ // Verify there are no queues for the surface recorded in the state
+ // snapshot.
EXPECT_STATUS_EQ(std::vector<int>{}, manager_->GetQueueIds(0));
// Create a new queue in the surface.
auto write_queue_status = CreateSurfaceQueue(
surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 1,
- AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1);
+ AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0);
ASSERT_STATUS_OK(write_queue_status);
UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
ASSERT_NE(nullptr, write_queue.get());
@@ -549,7 +839,7 @@
const uint32_t kLayerCount = 3;
auto write_queue_status = CreateSurfaceQueue(
surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, kLayerCount,
- AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1);
+ AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0);
ASSERT_STATUS_OK(write_queue_status);
UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
ASSERT_NE(nullptr, write_queue.get());
@@ -573,6 +863,24 @@
dvrWriteBufferDestroy(buffer);
}
+TEST_F(DvrDisplayManagerTest, ConfigurationData) {
+ // TODO(hendrikw): Move this out of the display manager tests.
+ auto data1 = manager_->GetConfigData(-1);
+ ASSERT_STATUS_ERROR(data1);
+
+ const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics";
+
+ // This should be run on devices with and without built in metrics.
+ bool has_metric = !base::GetProperty(kDvrLensMetricsProperty, "").empty();
+ auto data2 = manager_->GetConfigData(DVR_CONFIGURATION_DATA_LENS_METRICS);
+ if (has_metric) {
+ ASSERT_STATUS_OK(data2);
+ ASSERT_NE(0u, data2.get().size());
+ } else {
+ ASSERT_STATUS_ERROR(data2);
+ }
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
index e65f6d5..c21deb0 100644
--- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
@@ -1,6 +1,7 @@
#include <android/hardware_buffer.h>
#include <dvr/dvr_buffer.h>
-#include <dvr/dvr_display_manager.h>
+#include <dvr/dvr_config.h>
+#include <dvr/dvr_shared_buffers.h>
#include <dvr/dvr_surface.h>
#include <system/graphics.h>
@@ -12,33 +13,15 @@
namespace {
-class DvrNamedBufferTest : public ::testing::Test {
- protected:
- void SetUp() override {
- const int ret = dvrDisplayManagerCreate(&client_);
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, client_);
- }
-
- void TearDown() override {
- dvrDisplayManagerDestroy(client_);
- client_ = nullptr;
- }
-
- DvrDisplayManager* client_ = nullptr;
-};
-
-TEST_F(DvrNamedBufferTest, TestNamedBuffersSameName) {
- const char* buffer_name = "same_name";
+TEST(DvrGlobalBufferTest, TestGlobalBuffersSameName) {
+ const DvrGlobalBufferKey buffer_key = 101;
DvrBuffer* buffer1 = nullptr;
- int ret1 =
- dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, 0, &buffer1);
+ int ret1 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer1);
ASSERT_EQ(0, ret1);
ASSERT_NE(nullptr, buffer1);
DvrBuffer* buffer2 = nullptr;
- int ret2 =
- dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, 0, &buffer2);
+ int ret2 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer2);
ASSERT_EQ(0, ret1);
ASSERT_NE(nullptr, buffer2);
@@ -71,7 +54,7 @@
dvrBufferDestroy(buffer2);
DvrBuffer* buffer3 = nullptr;
- int e3 = dvrGetNamedBuffer(buffer_name, &buffer3);
+ int e3 = dvrGetGlobalBuffer(buffer_key, &buffer3);
ASSERT_NE(nullptr, buffer3);
ASSERT_EQ(0, e3);
@@ -95,38 +78,36 @@
AHardwareBuffer_release(hardware_buffer3);
}
-TEST_F(DvrNamedBufferTest, TestMultipleNamedBuffers) {
- const char* buffer_name1 = "test1";
- const char* buffer_name2 = "test2";
+TEST(DvrGlobalBufferTest, TestMultipleGlobalBuffers) {
+ const DvrGlobalBufferKey buffer_key1 = 102;
+ const DvrGlobalBufferKey buffer_key2 = 103;
DvrBuffer* setup_buffer1 = nullptr;
- int ret1 = dvrDisplayManagerSetupNamedBuffer(client_, buffer_name1, 10, 0,
- &setup_buffer1);
+ int ret1 = dvrSetupGlobalBuffer(buffer_key1, 10, 0, &setup_buffer1);
ASSERT_EQ(0, ret1);
ASSERT_NE(nullptr, setup_buffer1);
dvrBufferDestroy(setup_buffer1);
DvrBuffer* setup_buffer2 = nullptr;
- int ret2 = dvrDisplayManagerSetupNamedBuffer(client_, buffer_name2, 10, 0,
- &setup_buffer2);
+ int ret2 = dvrSetupGlobalBuffer(buffer_key2, 10, 0, &setup_buffer2);
ASSERT_EQ(0, ret2);
ASSERT_NE(nullptr, setup_buffer2);
dvrBufferDestroy(setup_buffer2);
DvrBuffer* buffer1 = nullptr;
- int e1 = dvrGetNamedBuffer(buffer_name1, &buffer1);
+ int e1 = dvrGetGlobalBuffer(buffer_key1, &buffer1);
ASSERT_NE(nullptr, buffer1);
ASSERT_EQ(0, e1);
dvrBufferDestroy(buffer1);
DvrBuffer* buffer2 = nullptr;
- int e2 = dvrGetNamedBuffer(buffer_name2, &buffer2);
+ int e2 = dvrGetGlobalBuffer(buffer_key2, &buffer2);
ASSERT_NE(nullptr, buffer2);
ASSERT_EQ(0, e2);
dvrBufferDestroy(buffer2);
}
-TEST_F(DvrNamedBufferTest, TestNamedBufferUsage) {
- const char* buffer_name = "buffer_usage";
+TEST(DvrGlobalBufferTest, TestGlobalBufferUsage) {
+ const DvrGlobalBufferKey buffer_key = 100;
// Set usage to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE. We use this because
// internally AHARDWAREBUFFER_USAGE_VIDEO_ENCODE is converted to
@@ -136,8 +117,7 @@
const uint64_t usage = AHARDWAREBUFFER_USAGE_VIDEO_ENCODE;
DvrBuffer* setup_buffer = nullptr;
- int e1 = dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, usage,
- &setup_buffer);
+ int e1 = dvrSetupGlobalBuffer(buffer_key, 10, usage, &setup_buffer);
ASSERT_NE(nullptr, setup_buffer);
ASSERT_EQ(0, e1);
@@ -154,6 +134,151 @@
AHardwareBuffer_release(hardware_buffer);
}
+TEST(DvrGlobalBufferTest, TestGlobalBufferCarriesData) {
+ const DvrGlobalBufferKey buffer_name = 110;
+
+ uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+ constexpr size_t size = 1024 * sizeof(uint64_t);
+ constexpr uint64_t value = 0x123456787654321;
+
+ {
+ // Allocate some data and set it to something.
+ DvrBuffer* setup_buffer = nullptr;
+ int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
+ ASSERT_NE(nullptr, setup_buffer);
+ ASSERT_EQ(0, e1);
+
+ AHardwareBuffer* hardware_buffer = nullptr;
+ int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
+ ASSERT_EQ(0, e2);
+ ASSERT_NE(nullptr, hardware_buffer);
+
+ void* buffer;
+ int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
+ ASSERT_EQ(0, e3);
+ ASSERT_NE(nullptr, buffer);
+ // Verify that the buffer pointer is at least 16 byte aligned.
+ ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+
+ uint64_t* data = static_cast<uint64_t*>(buffer);
+ constexpr size_t num_values = size / sizeof(uint64_t);
+ for (size_t i = 0; i < num_values; ++i) {
+ data[i] = value;
+ }
+
+ int32_t fence = -1;
+ int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
+ ASSERT_EQ(0, e4);
+
+ dvrBufferDestroy(setup_buffer);
+ AHardwareBuffer_release(hardware_buffer);
+ }
+
+ {
+ // Get the buffer and check that all the data is still present.
+ DvrBuffer* setup_buffer = nullptr;
+ int e1 = dvrGetGlobalBuffer(buffer_name, &setup_buffer);
+ ASSERT_NE(nullptr, setup_buffer);
+ ASSERT_EQ(0, e1);
+
+ AHardwareBuffer* hardware_buffer = nullptr;
+ int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
+ ASSERT_EQ(0, e2);
+ ASSERT_NE(nullptr, hardware_buffer);
+
+ void* buffer;
+ int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
+ ASSERT_EQ(0, e3);
+ ASSERT_NE(nullptr, buffer);
+ // Verify that the buffer pointer is at least 16 byte aligned.
+ ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+
+ uint64_t* data = static_cast<uint64_t*>(buffer);
+ constexpr size_t num_values = size / sizeof(uint64_t);
+ bool is_equal = true;
+ for (size_t i = 0; i < num_values; ++i) {
+ is_equal &= (data[i] == value);
+ }
+ ASSERT_TRUE(is_equal);
+
+ int32_t fence = -1;
+ int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
+ ASSERT_EQ(0, e4);
+
+ dvrBufferDestroy(setup_buffer);
+ AHardwareBuffer_release(hardware_buffer);
+ }
+}
+
+TEST(DvrGlobalBufferTest, TestGlobalBufferZeroed) {
+ const DvrGlobalBufferKey buffer_name = 120;
+
+ // Allocate 1MB and check that it is all zeros.
+ uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+ constexpr size_t size = 1024 * 1024;
+ DvrBuffer* setup_buffer = nullptr;
+ int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
+ ASSERT_NE(nullptr, setup_buffer);
+ ASSERT_EQ(0, e1);
+
+ AHardwareBuffer* hardware_buffer = nullptr;
+ int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
+ ASSERT_EQ(0, e2);
+ ASSERT_NE(nullptr, hardware_buffer);
+
+ void* buffer;
+ int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
+ ASSERT_EQ(0, e3);
+ ASSERT_NE(nullptr, buffer);
+ // Verify that the buffer pointer is at least 16 byte aligned.
+ ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+
+ uint64_t* data = static_cast<uint64_t*>(buffer);
+ constexpr size_t num_values = size / sizeof(uint64_t);
+ uint64_t zero = 0;
+ for (size_t i = 0; i < num_values; ++i) {
+ zero |= data[i];
+ }
+ ASSERT_EQ(0, zero);
+
+ int32_t fence = -1;
+ int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
+ ASSERT_EQ(0, e4);
+
+ dvrBufferDestroy(setup_buffer);
+ AHardwareBuffer_release(hardware_buffer);
+}
+
+TEST(DvrGlobalBufferTest, TestVrflingerConfigBuffer) {
+ const DvrGlobalBufferKey buffer_name =
+ DvrGlobalBuffers::kVrFlingerConfigBufferKey;
+
+ // First delete any existing buffer so we can test the failure case.
+ dvrDeleteGlobalBuffer(buffer_name);
+
+ const uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY;
+
+ size_t correct_size = DvrConfigRing::MemorySize();
+ size_t wrong_size = DvrConfigRing::MemorySize(0);
+
+ // Setup an invalid config buffer (too small) and assert that it fails.
+ DvrBuffer* setup_buffer = nullptr;
+ int e1 = dvrSetupGlobalBuffer(buffer_name, wrong_size, usage, &setup_buffer);
+ ASSERT_EQ(nullptr, setup_buffer);
+ ASSERT_GT(0, e1);
+
+ // Setup a correct config buffer.
+ int e2 =
+ dvrSetupGlobalBuffer(buffer_name, correct_size, usage, &setup_buffer);
+ ASSERT_NE(nullptr, setup_buffer);
+ ASSERT_EQ(0, e2);
+
+ dvrBufferDestroy(setup_buffer);
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index 527cdbd..62aeb79 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -28,7 +28,7 @@
"libhardware",
]
-staticLibraries = ["libpdx_default_transport"]
+staticLibraries = ["libpdx_default_transport", "libbroadcastring"]
headerLibraries = [
"libeigen",
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index cb44a51..80b1769 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -26,14 +26,35 @@
template <std::size_t I, typename... Types>
using TypeTagForIndex = TypeTag<TypeForIndex<I, Types...>>;
+// Similar to std::is_constructible except that it evaluates to false for bool
+// construction from pointer types: this helps prevent subtle to bugs caused by
+// assigning values that decay to pointers to Variants with bool elements.
+//
+// Here is an example of the problematic situation this trait avoids:
+//
+// Variant<int, bool> v;
+// const int array[3] = {1, 2, 3};
+// v = array; // This is allowed by regular std::is_constructible.
+//
+template <typename...>
+struct IsConstructible;
+template <typename T, typename U>
+struct IsConstructible<T, U>
+ : std::integral_constant<bool,
+ std::is_constructible<T, U>::value &&
+ !(std::is_same<std::decay_t<T>, bool>::value &&
+ std::is_pointer<std::decay_t<U>>::value)> {};
+template <typename T, typename... Args>
+struct IsConstructible<T, Args...> : std::is_constructible<T, Args...> {};
+
// Enable if T(Args...) is well formed.
template <typename R, typename T, typename... Args>
using EnableIfConstructible =
- typename std::enable_if<std::is_constructible<T, Args...>::value, R>::type;
+ typename std::enable_if<IsConstructible<T, Args...>::value, R>::type;
// Enable if T(Args...) is not well formed.
template <typename R, typename T, typename... Args>
using EnableIfNotConstructible =
- typename std::enable_if<!std::is_constructible<T, Args...>::value, R>::type;
+ typename std::enable_if<!IsConstructible<T, Args...>::value, R>::type;
// Determines whether T is an element of Types...;
template <typename... Types>
@@ -65,12 +86,11 @@
struct ConstructibleCount;
template <typename From, typename To>
struct ConstructibleCount<From, To>
- : std::integral_constant<std::size_t,
- std::is_constructible<To, From>::value> {};
+ : std::integral_constant<std::size_t, IsConstructible<To, From>::value> {};
template <typename From, typename First, typename... Rest>
struct ConstructibleCount<From, First, Rest...>
: std::integral_constant<std::size_t,
- std::is_constructible<First, From>::value +
+ IsConstructible<First, From>::value +
ConstructibleCount<From, Rest...>::value> {};
// Enable if T is an element of Types...
@@ -126,6 +146,18 @@
: first_(std::forward<T>(value)) {
*index_out = index;
}
+ Union(const Union& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) Type(other.first_);
+ }
+ Union(Union&& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) Type(std::move(other.first_));
+ }
+ Union(const Union&) = delete;
+ Union(Union&&) = delete;
+ void operator=(const Union&) = delete;
+ void operator=(Union&&) = delete;
Type& get(TypeTag<Type>) { return first_; }
const Type& get(TypeTag<Type>) const { return first_; }
@@ -217,6 +249,22 @@
template <typename T, typename U>
Union(std::int32_t index, std::int32_t* index_out, TypeTag<T>, U&& value)
: rest_(index + 1, index_out, TypeTag<T>{}, std::forward<U>(value)) {}
+ Union(const Union& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) First(other.first_);
+ else
+ new (&rest_) Union<Rest...>(other.rest_, index - 1);
+ }
+ Union(Union&& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) First(std::move(other.first_));
+ else
+ new (&rest_) Union<Rest...>(std::move(other.rest_), index - 1);
+ }
+ Union(const Union&) = delete;
+ Union(Union&&) = delete;
+ void operator=(const Union&) = delete;
+ void operator=(Union&&) = delete;
struct FirstType {};
struct RestType {};
@@ -351,6 +399,10 @@
} // namespace detail
+// Variant is a type safe union that can store values of any of its element
+// types. A Variant is different than std::tuple in that it only stores one type
+// at a time or a special empty type. Variants are always default constructible
+// to empty, even when none of the element types are default constructible.
template <typename... Types>
class Variant {
private:
@@ -393,6 +445,11 @@
explicit Variant(EmptyVariant) {}
~Variant() { Destruct(); }
+ Variant(const Variant& other)
+ : index_{other.index_}, value_{other.value_, other.index_} {}
+ Variant(Variant&& other)
+ : index_{other.index_}, value_{std::move(other.value_), other.index_} {}
+
// Copy and move construction from Variant types. Each element of OtherTypes
// must be convertible to an element of Types.
template <typename... OtherTypes>
@@ -404,6 +461,15 @@
other.Visit([this](auto&& value) { Construct(std::move(value)); });
}
+ Variant& operator=(const Variant& other) {
+ other.Visit([this](const auto& value) { *this = value; });
+ return *this;
+ }
+ Variant& operator=(Variant&& other) {
+ other.Visit([this](auto&& value) { *this = std::move(value); });
+ return *this;
+ }
+
// Construction from non-Variant types.
template <typename T, typename = EnableIfAssignable<void, T>>
explicit Variant(T&& value)
@@ -429,7 +495,7 @@
// Handles assignment from the empty type. This overload supports assignment
// in visitors using generic lambdas.
Variant& operator=(EmptyVariant) {
- Assign(EmptyVariant{});
+ Destruct();
return *this;
}
@@ -541,7 +607,10 @@
void Construct(EmptyVariant) {}
// Destroys the active element of the Variant.
- void Destruct() { value_.Destruct(index_); }
+ void Destruct() {
+ value_.Destruct(index_);
+ index_ = kEmptyIndex;
+ }
// Assigns the Variant when non-empty and the current type matches the target
// type, otherwise destroys the current value and constructs a element of the
@@ -562,8 +631,6 @@
Construct(std::forward<T>(value));
}
}
- // Handles assignment from an empty Variant.
- void Assign(EmptyVariant) { Destruct(); }
};
// Utility type to extract/convert values from a variant. This class simplifies
diff --git a/libs/vr/libpdx/private/pdx/utility.h b/libs/vr/libpdx/private/pdx/utility.h
index 305c3b8..08fcaea 100644
--- a/libs/vr/libpdx/private/pdx/utility.h
+++ b/libs/vr/libpdx/private/pdx/utility.h
@@ -2,6 +2,7 @@
#define ANDROID_PDX_UTILITY_H_
#include <cstdint>
+#include <cstdlib>
#include <iterator>
#include <pdx/rpc/sequence.h>
@@ -23,6 +24,7 @@
if (other.size())
memcpy(data_, other.data(), other.size());
}
+ ~ByteBuffer() { std::free(data_); }
ByteBuffer& operator=(const ByteBuffer& other) {
resize(other.size());
@@ -69,7 +71,7 @@
size |= size >> 8;
size |= size >> 16;
size++;
- void* new_data = data_ ? realloc(data_, size) : malloc(size);
+ void* new_data = data_ ? std::realloc(data_, size) : std::malloc(size);
// TODO(avakulenko): Check for allocation failures.
data_ = static_cast<uint8_t*>(new_data);
capacity_ = size;
diff --git a/libs/vr/libpdx/variant_tests.cpp b/libs/vr/libpdx/variant_tests.cpp
index 325f33f..e3520f5 100644
--- a/libs/vr/libpdx/variant_tests.cpp
+++ b/libs/vr/libpdx/variant_tests.cpp
@@ -1,3 +1,4 @@
+#include <array>
#include <cstdint>
#include <functional>
#include <memory>
@@ -584,6 +585,25 @@
EXPECT_EQ(0u, InstrumentType<int>::move_assignment_count());
EXPECT_EQ(1u, InstrumentType<int>::copy_assignment_count());
}
+
+ {
+ InstrumentType<int>::clear();
+
+ // Construct from temporary, temporary ctor/dtor.
+ Variant<int, InstrumentType<int>> v(InstrumentType<int>(25));
+
+ // Assign EmptyVariant.
+ v = EmptyVariant{};
+
+ EXPECT_EQ(2u, InstrumentType<int>::constructor_count());
+ EXPECT_EQ(2u, InstrumentType<int>::destructor_count());
+ EXPECT_EQ(0u, InstrumentType<int>::move_assignment_count());
+ EXPECT_EQ(0u, InstrumentType<int>::copy_assignment_count());
+ }
+ EXPECT_EQ(2u, InstrumentType<int>::constructor_count());
+ EXPECT_EQ(2u, InstrumentType<int>::destructor_count());
+ EXPECT_EQ(0u, InstrumentType<int>::move_assignment_count());
+ EXPECT_EQ(0u, InstrumentType<int>::copy_assignment_count());
}
TEST(Variant, MoveConstructor) {
@@ -758,7 +778,7 @@
Variant<std::string> b;
std::swap(a, b);
- EXPECT_TRUE(!a.empty());
+ EXPECT_TRUE(a.empty());
EXPECT_TRUE(!b.empty());
ASSERT_TRUE(b.is<std::string>());
EXPECT_EQ("1", std::get<std::string>(b));
@@ -770,7 +790,7 @@
std::swap(a, b);
EXPECT_TRUE(!a.empty());
- EXPECT_TRUE(!b.empty());
+ EXPECT_TRUE(b.empty());
ASSERT_TRUE(a.is<std::string>());
EXPECT_EQ("1", std::get<std::string>(a));
}
@@ -1078,6 +1098,29 @@
EXPECT_FALSE((detail::HasType<char&, int, float, bool>::value));
}
+TEST(Variant, IsConstructible) {
+ using ArrayType = const float[3];
+ struct ImplicitBool {
+ operator bool() const { return true; }
+ };
+ struct ExplicitBool {
+ explicit operator bool() const { return true; }
+ };
+ struct NonBool {};
+ struct TwoArgs {
+ TwoArgs(int, bool) {}
+ };
+
+ EXPECT_FALSE((detail::IsConstructible<bool, ArrayType>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, int>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, ImplicitBool>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, ExplicitBool>::value));
+ EXPECT_FALSE((detail::IsConstructible<bool, NonBool>::value));
+ EXPECT_TRUE((detail::IsConstructible<TwoArgs, int, bool>::value));
+ EXPECT_FALSE((detail::IsConstructible<TwoArgs, int, std::string>::value));
+ EXPECT_FALSE((detail::IsConstructible<TwoArgs, int>::value));
+}
+
TEST(Variant, Set) {
EXPECT_TRUE((detail::Set<int, bool, float>::template IsSubset<int, bool,
float>::value));
diff --git a/libs/vr/libpdx_uds/channel_event_set.cpp b/libs/vr/libpdx_uds/channel_event_set.cpp
index ac4dea9..ebe7cea 100644
--- a/libs/vr/libpdx_uds/channel_event_set.cpp
+++ b/libs/vr/libpdx_uds/channel_event_set.cpp
@@ -100,6 +100,9 @@
ALOGE("ChannelEventReceiver::GetPendingEvents: Failed to get events: %s",
status.GetErrorMessage().c_str());
return status;
+ } else if (count == 0) {
+ status.SetError(ETIMEDOUT);
+ return status;
}
const int mask_out = event.data.u32;
diff --git a/libs/vr/libperformance/include/dvr/performance_client_api.h b/libs/vr/libperformance/include/dvr/performance_client_api.h
index 2216e38..9d617cb 100644
--- a/libs/vr/libperformance/include/dvr/performance_client_api.h
+++ b/libs/vr/libperformance/include/dvr/performance_client_api.h
@@ -8,6 +8,20 @@
extern "C" {
#endif
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
/// Sets the CPU partition for a task.
///
/// Sets the CPU partition for a task to the partition described by a CPU
diff --git a/libs/vr/libperformance/include/private/dvr/performance_client.h b/libs/vr/libperformance/include/private/dvr/performance_client.h
index a61c6b2..3bd90dc 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_client.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_client.h
@@ -14,6 +14,10 @@
class PerformanceClient : public pdx::ClientBase<PerformanceClient> {
public:
+ int SetSchedulerPolicy(pid_t task_id, const std::string& scheduler_policy);
+ int SetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+ // TODO(eieio): Consider deprecating this API.
int SetCpuPartition(pid_t task_id, const std::string& partition);
int SetCpuPartition(pid_t task_id, const char* partition);
int SetSchedulerClass(pid_t task_id, const std::string& scheduler_class);
diff --git a/libs/vr/libperformance/include/private/dvr/performance_rpc.h b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
index 73bdaa7..d57bbe8 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_rpc.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
@@ -21,14 +21,17 @@
kOpSetCpuPartition = 0,
kOpSetSchedulerClass,
kOpGetCpuPartition,
+ kOpSetSchedulerPolicy,
};
// Methods.
PDX_REMOTE_METHOD(SetCpuPartition, kOpSetCpuPartition,
- int(pid_t, const std::string&));
+ void(pid_t, const std::string&));
PDX_REMOTE_METHOD(SetSchedulerClass, kOpSetSchedulerClass,
- int(pid_t, const std::string&));
+ void(pid_t, const std::string&));
PDX_REMOTE_METHOD(GetCpuPartition, kOpGetCpuPartition, std::string(pid_t));
+ PDX_REMOTE_METHOD(SetSchedulerPolicy, kOpSetSchedulerPolicy,
+ void(pid_t, const std::string&));
};
} // namespace dvr
diff --git a/libs/vr/libperformance/performance_client.cpp b/libs/vr/libperformance/performance_client.cpp
index 2124162..bf3726e 100644
--- a/libs/vr/libperformance/performance_client.cpp
+++ b/libs/vr/libperformance/performance_client.cpp
@@ -37,6 +37,26 @@
task_id, WrapString(partition)));
}
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+ const std::string& scheduler_policy) {
+ if (task_id == 0)
+ task_id = gettid();
+
+ return ReturnStatusOrError(
+ InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(task_id,
+ scheduler_policy));
+}
+
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ if (task_id == 0)
+ task_id = gettid();
+
+ return ReturnStatusOrError(
+ InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+ task_id, WrapString(scheduler_policy)));
+}
+
int PerformanceClient::SetSchedulerClass(pid_t task_id,
const std::string& scheduler_class) {
if (task_id == 0)
@@ -101,6 +121,15 @@
return error;
}
+extern "C" int dvrSetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ int error;
+ if (auto client = android::dvr::PerformanceClient::Create(&error))
+ return client->SetSchedulerPolicy(task_id, scheduler_policy);
+ else
+ return error;
+}
+
extern "C" int dvrSetSchedulerClass(pid_t task_id,
const char* scheduler_class) {
int error;
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index de26a74..0fb2d84 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -34,8 +34,10 @@
"libdvrcommon",
"libperformance",
"libvrsensor",
+ "libbroadcastring",
"libpdx_default_transport",
"libvr_manager",
+ "libbroadcastring",
]
sharedLibraries = [
@@ -61,6 +63,10 @@
"libfmq",
]
+headerLibraries = [
+ "libdvr_headers"
+]
+
cc_library_static {
srcs: sourceFiles,
export_include_dirs: includeFiles,
@@ -74,5 +80,6 @@
],
shared_libs: sharedLibraries,
whole_static_libs: staticLibraries,
+ header_libs: headerLibraries,
name: "libvrflinger",
}
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
index 7932a9c..fda9585 100644
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ b/libs/vr/libvrflinger/acquired_buffer.cpp
@@ -55,9 +55,9 @@
if (acquire_fence_) {
const int ret = sync_wait(acquire_fence_.Get(), 0);
ALOGD_IF(TRACE || (ret < 0 && errno != ETIME),
- "AcquiredBuffer::IsAvailable: acquire_fence_=%d sync_wait()=%d "
- "errno=%d.",
- acquire_fence_.Get(), ret, ret < 0 ? errno : 0);
+ "AcquiredBuffer::IsAvailable: buffer_id=%d acquire_fence=%d "
+ "sync_wait()=%d errno=%d.",
+ buffer_->id(), acquire_fence_.Get(), ret, ret < 0 ? errno : 0);
if (ret == 0) {
// The fence is completed, so to avoid further calls to sync_wait we close
// it here.
@@ -78,6 +78,8 @@
}
int AcquiredBuffer::Release(LocalHandle release_fence) {
+ ALOGD_IF(TRACE, "AcquiredBuffer::Release: buffer_id=%d release_fence=%d",
+ buffer_ ? buffer_->id() : -1, release_fence.Get());
if (buffer_) {
// Close the release fence since we can't transfer it with an async release.
release_fence.Close();
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index dd4fcc5..e0dc9f2 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -67,13 +67,13 @@
int Release(pdx::LocalHandle release_fence);
private:
- AcquiredBuffer(const AcquiredBuffer&) = delete;
- void operator=(const AcquiredBuffer&) = delete;
-
std::shared_ptr<BufferConsumer> buffer_;
// Mutable so that the fence can be closed when it is determined to be
// signaled during IsAvailable().
mutable pdx::LocalHandle acquire_fence_;
+
+ AcquiredBuffer(const AcquiredBuffer&) = delete;
+ void operator=(const AcquiredBuffer&) = delete;
};
} // namespace dvr
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index a0b3efe..40396b9 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -78,11 +78,6 @@
*this, &DisplayManagerService::OnGetSurfaceQueue, message);
return {};
- case DisplayManagerProtocol::SetupNamedBuffer::Opcode:
- DispatchRemoteMethod<DisplayManagerProtocol::SetupNamedBuffer>(
- *this, &DisplayManagerService::OnSetupNamedBuffer, message);
- return {};
-
default:
return Service::DefaultHandleMessage(message);
}
@@ -129,23 +124,6 @@
return status;
}
-pdx::Status<BorrowedNativeBufferHandle>
-DisplayManagerService::OnSetupNamedBuffer(pdx::Message& message,
- const std::string& name, size_t size,
- uint64_t usage) {
- const int user_id = message.GetEffectiveUserId();
- const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
-
- if (!trusted) {
- ALOGE(
- "DisplayService::SetupNamedBuffer: Named buffers may only be created "
- "by trusted UIDs: user_id=%d",
- user_id);
- return ErrorStatus(EPERM);
- }
- return display_service_->SetupNamedBuffer(name, size, usage);
-}
-
void DisplayManagerService::OnDisplaySurfaceChange() {
if (display_manager_)
display_manager_->SetNotificationsPending(true);
diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h
index 0857eb5..3133fe1 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -56,9 +56,6 @@
pdx::Status<pdx::LocalChannelHandle> OnGetSurfaceQueue(pdx::Message& message,
int surface_id,
int queue_id);
- pdx::Status<BorrowedNativeBufferHandle> OnSetupNamedBuffer(
- pdx::Message& message, const std::string& name, size_t size,
- uint64_t usage);
// Called by the display service to indicate changes to display surfaces that
// the display manager should evaluate.
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 47efa76..733edc6 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -1,13 +1,21 @@
#include "display_service.h"
#include <unistd.h>
+
+#include <algorithm>
+#include <sstream>
+#include <string>
#include <vector>
+#include <android-base/file.h>
+#include <android-base/properties.h>
#include <dvr/dvr_display_types.h>
#include <pdx/default_transport/service_endpoint.h>
#include <pdx/rpc/remote_method.h>
+#include <private/android_filesystem_config.h>
#include <private/dvr/display_protocol.h>
#include <private/dvr/numeric.h>
+#include <private/dvr/trusted_uids.h>
#include <private/dvr/types.h>
using android::dvr::display::DisplayProtocol;
@@ -18,6 +26,14 @@
using android::pdx::default_transport::Endpoint;
using android::pdx::rpc::DispatchRemoteMethod;
+namespace {
+
+const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics";
+const char kDvrDeviceMetricsProperty[] = "ro.dvr.device_metrics";
+const char kDvrDeviceConfigProperty[] = "ro.dvr.device_configuration";
+
+} // namespace
+
namespace android {
namespace dvr {
@@ -35,7 +51,65 @@
}
std::string DisplayService::DumpState(size_t /*max_length*/) {
- return hardware_composer_.Dump();
+ std::ostringstream stream;
+
+ auto surfaces = GetDisplaySurfaces();
+ std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
+ return a->surface_id() < b->surface_id();
+ });
+
+ stream << "Application Surfaces:" << std::endl;
+
+ size_t count = 0;
+ for (const auto& surface : surfaces) {
+ if (surface->surface_type() == SurfaceType::Application) {
+ stream << "Surface " << count++ << ":";
+ stream << " surface_id=" << surface->surface_id()
+ << " process_id=" << surface->process_id()
+ << " user_id=" << surface->user_id()
+ << " visible=" << surface->visible()
+ << " z_order=" << surface->z_order();
+
+ stream << " queue_ids=";
+ auto queue_ids = surface->GetQueueIds();
+ std::sort(queue_ids.begin(), queue_ids.end());
+ for (int32_t id : queue_ids) {
+ if (id != queue_ids[0])
+ stream << ",";
+ stream << id;
+ }
+ stream << std::endl;
+ }
+ }
+ stream << std::endl;
+
+ stream << "Direct Surfaces:" << std::endl;
+
+ count = 0;
+ for (const auto& surface : surfaces) {
+ if (surface->surface_type() == SurfaceType::Direct) {
+ stream << "Surface " << count++ << ":";
+ stream << " surface_id=" << surface->surface_id()
+ << " process_id=" << surface->process_id()
+ << " user_id=" << surface->user_id()
+ << " visible=" << surface->visible()
+ << " z_order=" << surface->z_order();
+
+ stream << " queue_ids=";
+ auto queue_ids = surface->GetQueueIds();
+ std::sort(queue_ids.begin(), queue_ids.end());
+ for (int32_t id : queue_ids) {
+ if (id != queue_ids[0])
+ stream << ",";
+ stream << id;
+ }
+ stream << std::endl;
+ }
+ }
+ stream << std::endl;
+
+ stream << hardware_composer_.Dump();
+ return stream.str();
}
void DisplayService::OnChannelClose(pdx::Message& message,
@@ -44,8 +118,6 @@
surface->OnSetAttributes(message,
{{display::SurfaceAttribute::Visible,
display::SurfaceAttributeValue{false}}});
- SurfaceUpdated(surface->surface_type(),
- display::SurfaceUpdateFlags::VisibilityChanged);
}
}
@@ -60,14 +132,29 @@
*this, &DisplayService::OnGetMetrics, message);
return {};
+ case DisplayProtocol::GetConfigurationData::Opcode:
+ DispatchRemoteMethod<DisplayProtocol::GetConfigurationData>(
+ *this, &DisplayService::OnGetConfigurationData, message);
+ return {};
+
case DisplayProtocol::CreateSurface::Opcode:
DispatchRemoteMethod<DisplayProtocol::CreateSurface>(
*this, &DisplayService::OnCreateSurface, message);
return {};
- case DisplayProtocol::GetNamedBuffer::Opcode:
- DispatchRemoteMethod<DisplayProtocol::GetNamedBuffer>(
- *this, &DisplayService::OnGetNamedBuffer, message);
+ case DisplayProtocol::SetupGlobalBuffer::Opcode:
+ DispatchRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(
+ *this, &DisplayService::OnSetupGlobalBuffer, message);
+ return {};
+
+ case DisplayProtocol::DeleteGlobalBuffer::Opcode:
+ DispatchRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(
+ *this, &DisplayService::OnDeleteGlobalBuffer, message);
+ return {};
+
+ case DisplayProtocol::GetGlobalBuffer::Opcode:
+ DispatchRemoteMethod<DisplayProtocol::GetGlobalBuffer>(
+ *this, &DisplayService::OnGetGlobalBuffer, message);
return {};
case DisplayProtocol::IsVrAppRunning::Opcode:
@@ -102,6 +189,35 @@
{}}};
}
+pdx::Status<std::string> DisplayService::OnGetConfigurationData(
+ pdx::Message& /*message*/, display::ConfigFileType config_type) {
+ std::string property_name;
+ switch (config_type) {
+ case display::ConfigFileType::kLensMetrics:
+ property_name = kDvrLensMetricsProperty;
+ break;
+ case display::ConfigFileType::kDeviceMetrics:
+ property_name = kDvrDeviceMetricsProperty;
+ break;
+ case display::ConfigFileType::kDeviceConfiguration:
+ property_name = kDvrDeviceConfigProperty;
+ break;
+ default:
+ return ErrorStatus(EINVAL);
+ }
+ std::string file_path = base::GetProperty(property_name, "");
+ if (file_path.empty()) {
+ return ErrorStatus(ENOENT);
+ }
+
+ std::string data;
+ if (!base::ReadFileToString(file_path, &data)) {
+ return ErrorStatus(errno);
+ }
+
+ return std::move(data);
+}
+
// Creates a new DisplaySurface and associates it with this channel. This may
// only be done once per channel.
Status<display::SurfaceInfo> DisplayService::OnCreateSurface(
@@ -155,12 +271,42 @@
}
}
-pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetNamedBuffer(
- pdx::Message& /* message */, const std::string& name) {
- ALOGD_IF(TRACE, "displayService::OnGetNamedBuffer: name=%s", name.c_str());
- auto named_buffer = named_buffers_.find(name);
- if (named_buffer != named_buffers_.end())
- return {BorrowedNativeBufferHandle(*named_buffer->second, 0)};
+pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnSetupGlobalBuffer(
+ pdx::Message& message, DvrGlobalBufferKey key, size_t size,
+ uint64_t usage) {
+ const int user_id = message.GetEffectiveUserId();
+ const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
+
+ if (!trusted) {
+ ALOGE(
+ "DisplayService::OnSetupGlobalBuffer: Permission denied for user_id=%d",
+ user_id);
+ return ErrorStatus(EPERM);
+ }
+ return SetupGlobalBuffer(key, size, usage);
+}
+
+pdx::Status<void> DisplayService::OnDeleteGlobalBuffer(pdx::Message& message,
+ DvrGlobalBufferKey key) {
+ const int user_id = message.GetEffectiveUserId();
+ const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
+
+ if (!trusted) {
+ ALOGE(
+ "DisplayService::OnDeleteGlobalBuffer: Permission denied for "
+ "user_id=%d",
+ user_id);
+ return ErrorStatus(EPERM);
+ }
+ return DeleteGlobalBuffer(key);
+}
+
+pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetGlobalBuffer(
+ pdx::Message& /* message */, DvrGlobalBufferKey key) {
+ ALOGD_IF(TRACE, "DisplayService::OnGetGlobalBuffer: key=%d", key);
+ auto global_buffer = global_buffers_.find(key);
+ if (global_buffer != global_buffers_.end())
+ return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
else
return pdx::ErrorStatus(EINVAL);
}
@@ -221,18 +367,35 @@
hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
}
-pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupNamedBuffer(
- const std::string& name, size_t size, uint64_t usage) {
- auto named_buffer = named_buffers_.find(name);
- if (named_buffer == named_buffers_.end()) {
+pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupGlobalBuffer(
+ DvrGlobalBufferKey key, size_t size, uint64_t usage) {
+ auto global_buffer = global_buffers_.find(key);
+ if (global_buffer == global_buffers_.end()) {
auto ion_buffer = std::make_unique<IonBuffer>(static_cast<int>(size), 1,
HAL_PIXEL_FORMAT_BLOB, usage);
- named_buffer =
- named_buffers_.insert(std::make_pair(name, std::move(ion_buffer)))
+
+ // Some buffers are used internally. If they were configured with an
+ // invalid size or format, this will fail.
+ int result = hardware_composer_.OnNewGlobalBuffer(key, *ion_buffer.get());
+ if (result < 0)
+ return ErrorStatus(result);
+ global_buffer =
+ global_buffers_.insert(std::make_pair(key, std::move(ion_buffer)))
.first;
}
- return {BorrowedNativeBufferHandle(*named_buffer->second, 0)};
+ return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
+}
+
+pdx::Status<void> DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
+ auto global_buffer = global_buffers_.find(key);
+ if (global_buffer != global_buffers_.end()) {
+ // Some buffers are used internally.
+ hardware_composer_.OnDeletedGlobalBuffer(key);
+ global_buffers_.erase(global_buffer);
+ }
+
+ return {0};
}
void DisplayService::OnHardwareComposerRefresh() {
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index bb4eeef..6efe264 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -1,6 +1,7 @@
#ifndef ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SERVICE_H_
#define ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SERVICE_H_
+#include <dvr/dvr_api.h>
#include <pdx/service.h>
#include <pdx/status.h>
#include <private/dvr/buffer_hub_client.h>
@@ -40,8 +41,10 @@
// any change to client/manager attributes that affect visibility or z order.
void UpdateActiveDisplaySurfaces();
- pdx::Status<BorrowedNativeBufferHandle> SetupNamedBuffer(
- const std::string& name, size_t size, uint64_t usage);
+ pdx::Status<BorrowedNativeBufferHandle> SetupGlobalBuffer(
+ DvrGlobalBufferKey key, size_t size, uint64_t usage);
+
+ pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
template <class A>
void ForEachDisplaySurface(SurfaceType surface_type, A action) const {
@@ -82,11 +85,18 @@
DisplayService(android::Hwc2::Composer* hidl,
RequestDisplayCallback request_display_callback);
- pdx::Status<BorrowedNativeBufferHandle> OnGetNamedBuffer(
- pdx::Message& message, const std::string& name);
+ pdx::Status<BorrowedNativeBufferHandle> OnGetGlobalBuffer(
+ pdx::Message& message, DvrGlobalBufferKey key);
pdx::Status<display::Metrics> OnGetMetrics(pdx::Message& message);
+ pdx::Status<std::string> OnGetConfigurationData(
+ pdx::Message& message, display::ConfigFileType config_type);
pdx::Status<display::SurfaceInfo> OnCreateSurface(
pdx::Message& message, const display::SurfaceAttributes& attributes);
+ pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
+ pdx::Message& message, DvrGlobalBufferKey key, size_t size,
+ uint64_t usage);
+ pdx::Status<void> OnDeleteGlobalBuffer(pdx::Message& message,
+ DvrGlobalBufferKey key);
// Temporary query for current VR status. Will be removed later.
pdx::Status<bool> IsVrAppRunning(pdx::Message& message);
@@ -113,7 +123,8 @@
EpollEventDispatcher dispatcher_;
DisplayConfigurationUpdateNotifier update_notifier_;
- std::unordered_map<std::string, std::unique_ptr<IonBuffer>> named_buffers_;
+ std::unordered_map<DvrGlobalBufferKey, std::unique_ptr<IonBuffer>>
+ global_buffers_;
DisplayService(const DisplayService&) = delete;
void operator=(const DisplayService&) = delete;
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index fb2751b..0d6a732 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -68,7 +68,7 @@
display::SurfaceUpdateFlags update_flags;
for (const auto& attribute : attributes) {
- const auto& key = attribute.first;
+ const auto key = attribute.first;
const auto* variant = &attribute.second;
bool invalid_value = false;
bool visibility_changed = false;
@@ -95,14 +95,23 @@
break;
}
+ // Only update the attribute map with valid values. This check also has the
+ // effect of preventing special attributes handled above from being deleted
+ // by an empty value.
if (invalid_value) {
ALOGW(
"DisplaySurface::OnClientSetAttributes: Failed to set display "
"surface attribute '%d' because of incompatible type: %d",
key, variant->index());
} else {
- // Only update the attribute map with valid values.
- attributes_[attribute.first] = attribute.second;
+ // An empty value indicates the attribute should be deleted.
+ if (variant->empty()) {
+ auto search = attributes_.find(key);
+ if (search != attributes_.end())
+ attributes_.erase(search);
+ } else {
+ attributes_[key] = *variant;
+ }
// All attribute changes generate a notification, even if the value
// doesn't change. Visibility attributes set a flag only if the value
@@ -127,7 +136,8 @@
}
void DisplaySurface::ClearUpdate() {
- ALOGD_IF(TRACE, "DisplaySurface::ClearUpdate: surface_id=%d", surface_id());
+ ALOGD_IF(TRACE > 1, "DisplaySurface::ClearUpdate: surface_id=%d",
+ surface_id());
update_flags_ = display::SurfaceUpdateFlags::None;
}
@@ -184,6 +194,7 @@
"ApplicationDisplaySurface::GetQueue: surface_id=%d queue_id=%d",
surface_id(), queue_id);
+ std::lock_guard<std::mutex> autolock(lock_);
auto search = consumer_queues_.find(queue_id);
if (search != consumer_queues_.end())
return search->second;
@@ -192,6 +203,7 @@
}
std::vector<int32_t> ApplicationDisplaySurface::GetQueueIds() const {
+ std::lock_guard<std::mutex> autolock(lock_);
std::vector<int32_t> queue_ids;
for (const auto& entry : consumer_queues_)
queue_ids.push_back(entry.first);
@@ -199,15 +211,15 @@
}
Status<LocalChannelHandle> ApplicationDisplaySurface::OnCreateQueue(
- Message& /*message*/, size_t meta_size_bytes) {
+ Message& /*message*/, const ProducerQueueConfig& config) {
ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue");
ALOGD_IF(TRACE,
"ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, "
"meta_size_bytes=%zu",
- surface_id(), meta_size_bytes);
+ surface_id(), config.meta_size_bytes);
std::lock_guard<std::mutex> autolock(lock_);
- auto producer = ProducerQueue::Create(meta_size_bytes);
+ auto producer = ProducerQueue::Create(config, UsagePolicy{});
if (!producer) {
ALOGE(
"ApplicationDisplaySurface::OnCreateQueue: Failed to create producer "
@@ -238,11 +250,12 @@
"ApplicationDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
consumer_queue->id(), events);
+ std::lock_guard<std::mutex> autolock(lock_);
+
// Always give the queue a chance to handle its internal bookkeeping.
consumer_queue->HandleQueueEvents();
// Check for hangup and remove a queue that is no longer needed.
- std::lock_guard<std::mutex> autolock(lock_);
if (consumer_queue->hung_up()) {
ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnQueueEvent: Removing queue.");
UnregisterQueue(consumer_queue);
@@ -258,17 +271,28 @@
}
}
+std::vector<int32_t> DirectDisplaySurface::GetQueueIds() const {
+ std::lock_guard<std::mutex> autolock(lock_);
+ std::vector<int32_t> queue_ids;
+ if (direct_queue_)
+ queue_ids.push_back(direct_queue_->id());
+ return queue_ids;
+}
+
Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
- Message& /*message*/, size_t meta_size_bytes) {
+ Message& /*message*/, const ProducerQueueConfig& config) {
ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
ALOGD_IF(
TRACE,
"DirectDisplaySurface::OnCreateQueue: surface_id=%d meta_size_bytes=%zu",
- surface_id(), meta_size_bytes);
+ surface_id(), config.meta_size_bytes);
std::lock_guard<std::mutex> autolock(lock_);
if (!direct_queue_) {
- auto producer = ProducerQueue::Create(meta_size_bytes);
+ // Inject the hw composer usage flag to enable the display to read the
+ // buffers.
+ auto producer = ProducerQueue::Create(
+ config, UsagePolicy{GraphicBuffer::USAGE_HW_COMPOSER, 0, 0, 0});
if (!producer) {
ALOGE(
"DirectDisplaySurface::OnCreateQueue: Failed to create producer "
@@ -297,11 +321,12 @@
ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
consumer_queue->id(), events);
+ std::lock_guard<std::mutex> autolock(lock_);
+
// Always give the queue a chance to handle its internal bookkeeping.
consumer_queue->HandleQueueEvents();
// Check for hangup and remove a queue that is no longer needed.
- std::lock_guard<std::mutex> autolock(lock_);
if (consumer_queue->hung_up()) {
ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: Removing queue.");
UnregisterQueue(consumer_queue);
@@ -323,7 +348,7 @@
auto buffer_status = direct_queue_->Dequeue(0, &slot, &acquire_fence);
if (!buffer_status) {
ALOGD_IF(
- TRACE && buffer_status.error() == ETIMEDOUT,
+ TRACE > 1 && buffer_status.error() == ETIMEDOUT,
"DirectDisplaySurface::DequeueBuffersLocked: All buffers dequeued.");
ALOGE_IF(buffer_status.error() != ETIMEDOUT,
"DirectDisplaySurface::DequeueBuffersLocked: Failed to dequeue "
@@ -367,8 +392,8 @@
}
AcquiredBuffer buffer = std::move(acquired_buffers_.Front());
acquired_buffers_.PopFront();
- ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer: %p",
- buffer.buffer().get());
+ ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer_id=%d",
+ buffer.buffer()->id());
return buffer;
}
@@ -396,8 +421,8 @@
break;
}
ALOGD_IF(TRACE,
- "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer: %p",
- buffer.buffer().get());
+ "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer_id=%d",
+ buffer.buffer()->id());
return buffer;
}
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index c456b10..5cbee57 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -66,7 +66,7 @@
}
virtual pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
- pdx::Message& message, size_t meta_size_bytes) = 0;
+ pdx::Message& message, const ProducerQueueConfig& config) = 0;
// Registers a consumer queue with the event dispatcher in DisplayService. The
// OnQueueEvent callback below is called to handle queue events.
@@ -129,10 +129,11 @@
private:
pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
- pdx::Message& message, size_t meta_size_bytes) override;
+ pdx::Message& message, const ProducerQueueConfig& config) override;
void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
int events) override;
+ // Accessed by both message dispatch thread and epoll event thread.
std::unordered_map<int32_t, std::shared_ptr<ConsumerQueue>> consumer_queues_;
};
@@ -144,6 +145,7 @@
: DisplaySurface(service, SurfaceType::Direct, surface_id, process_id,
user_id, attributes),
acquired_buffers_(kMaxPostedBuffers) {}
+ std::vector<int32_t> GetQueueIds() const override;
bool IsBufferAvailable();
bool IsBufferPosted();
AcquiredBuffer AcquireCurrentBuffer();
@@ -154,7 +156,7 @@
private:
pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
- pdx::Message& message, size_t meta_size_bytes) override;
+ pdx::Message& message, const ProducerQueueConfig& config) override;
void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
int events) override;
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
index 06b69bb..962c745 100644
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
+++ b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
@@ -101,12 +101,12 @@
if (num_events < 0 && errno != EINTR)
break;
- ALOGD_IF(TRACE, "EpollEventDispatcher::EventThread: num_events=%d",
+ ALOGD_IF(TRACE > 1, "EpollEventDispatcher::EventThread: num_events=%d",
num_events);
for (int i = 0; i < num_events; i++) {
ALOGD_IF(
- TRACE,
+ TRACE > 1,
"EpollEventDispatcher::EventThread: event %d: handler=%p events=0x%x",
i, events[i].data.ptr, events[i].events);
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 34474d9..def9b7d 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -19,12 +19,14 @@
#include <chrono>
#include <functional>
#include <map>
+#include <sstream>
+#include <string>
+#include <tuple>
#include <dvr/dvr_display_types.h>
#include <dvr/performance_client_api.h>
#include <private/dvr/clock_ns.h>
#include <private/dvr/ion_buffer.h>
-#include <private/dvr/pose_client_internal.h>
using android::pdx::LocalHandle;
using android::pdx::rpc::EmptyVariant;
@@ -37,17 +39,6 @@
namespace {
-// If the number of pending fences goes over this count at the point when we
-// are about to submit a new frame to HWC, we will drop the frame. This should
-// be a signal that the display driver has begun queuing frames. Note that with
-// smart displays (with RAM), the fence is signaled earlier than the next vsync,
-// at the point when the DMA to the display completes. Currently we use a smart
-// display and the EDS timing coincides with zero pending fences, so this is 0.
-constexpr int kAllowedPendingFenceCount = 0;
-
-// Offset before vsync to submit frames to hardware composer.
-constexpr int64_t kFramePostOffsetNs = 4000000; // 4ms
-
const char kBacklightBrightnessSysFile[] =
"/sys/class/leds/lcd-backlight/brightness";
@@ -221,10 +212,6 @@
void HardwareComposer::OnPostThreadResumed() {
hwc2_hidl_->resetCommands();
- // Connect to pose service.
- pose_client_ = dvrPoseCreate();
- ALOGE_IF(!pose_client_, "HardwareComposer: Failed to create pose client");
-
// HIDL HWC seems to have an internal race condition. If we submit a frame too
// soon after turning on VSync we don't get any VSync signals. Give poor HWC
// implementations a chance to enable VSync before we continue.
@@ -253,11 +240,6 @@
}
active_layer_count_ = 0;
- if (pose_client_) {
- dvrPoseDestroy(pose_client_);
- pose_client_ = nullptr;
- }
-
EnableVsync(false);
hwc2_hidl_->resetCommands();
@@ -367,7 +349,36 @@
return HWC::Error::None;
}
-std::string HardwareComposer::Dump() { return hwc2_hidl_->dumpDebugInfo(); }
+std::string HardwareComposer::Dump() {
+ std::unique_lock<std::mutex> lock(post_thread_mutex_);
+ std::ostringstream stream;
+
+ stream << "Display metrics: " << display_metrics_.width << "x"
+ << display_metrics_.height << " " << (display_metrics_.dpi.x / 1000.0)
+ << "x" << (display_metrics_.dpi.y / 1000.0) << " dpi @ "
+ << (1000000000.0 / display_metrics_.vsync_period_ns) << " Hz"
+ << std::endl;
+
+ stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
+ stream << "Active layers: " << active_layer_count_ << std::endl;
+ stream << std::endl;
+
+ for (size_t i = 0; i < active_layer_count_; i++) {
+ stream << "Layer " << i << ":";
+ stream << " type=" << layers_[i].GetCompositionType().to_string();
+ stream << " surface_id=" << layers_[i].GetSurfaceId();
+ stream << " buffer_id=" << layers_[i].GetBufferId();
+ stream << std::endl;
+ }
+ stream << std::endl;
+
+ if (post_thread_resumed_) {
+ stream << "Hardware Composer Debug Info:" << std::endl;
+ stream << hwc2_hidl_->dumpDebugInfo();
+ }
+
+ return stream.str();
+}
void HardwareComposer::PostLayers() {
ATRACE_NAME("HardwareComposer::PostLayers");
@@ -397,8 +408,8 @@
}
const bool is_frame_pending = IsFramePendingInDriver();
- const bool is_fence_pending =
- retire_fence_fds_.size() > kAllowedPendingFenceCount;
+ const bool is_fence_pending = retire_fence_fds_.size() >
+ post_thread_config_.allowed_pending_fence_count;
if (is_fence_pending || is_frame_pending) {
ATRACE_INT("frame_skip_count", ++frame_skip_count_);
@@ -418,10 +429,12 @@
ATRACE_INT("frame_skip_count", 0);
}
-#if TRACE
- for (size_t i = 0; i < active_layer_count_; i++)
- ALOGI("HardwareComposer::PostLayers: layer=%zu composition=%s", i,
+#if TRACE > 1
+ for (size_t i = 0; i < active_layer_count_; i++) {
+ ALOGI("HardwareComposer::PostLayers: layer=%zu buffer_id=%d composition=%s",
+ i, layers_[i].GetBufferId(),
layers_[i].GetCompositionType().to_string().c_str());
+ }
#endif
error = Present(HWC_DISPLAY_PRIMARY);
@@ -460,19 +473,76 @@
pending_surfaces_ = std::move(surfaces);
}
- // Set idle state based on whether there are any surfaces to handle.
- UpdatePostThreadState(PostThreadState::Idle, display_idle);
-
- // XXX: TEMPORARY
- // Request control of the display based on whether there are any surfaces to
- // handle. This callback sets the post thread active state once the transition
- // is complete in SurfaceFlinger.
- // TODO(eieio): Unify the control signal used to move SurfaceFlinger into VR
- // mode. Currently this is hooked up to persistent VR mode, but perhaps this
- // makes more sense to control it from VrCore, which could in turn base its
- // decision on persistent VR mode.
if (request_display_callback_)
request_display_callback_(!display_idle);
+
+ // Set idle state based on whether there are any surfaces to handle.
+ UpdatePostThreadState(PostThreadState::Idle, display_idle);
+}
+
+int HardwareComposer::OnNewGlobalBuffer(DvrGlobalBufferKey key,
+ IonBuffer& ion_buffer) {
+ if (key == DvrGlobalBuffers::kVsyncBuffer) {
+ vsync_ring_ = std::make_unique<CPUMappedBroadcastRing<DvrVsyncRing>>(
+ &ion_buffer, CPUUsageMode::WRITE_OFTEN);
+
+ if (vsync_ring_->IsMapped() == false) {
+ return -EPERM;
+ }
+ }
+
+ if (key == DvrGlobalBuffers::kVrFlingerConfigBufferKey) {
+ return MapConfigBuffer(ion_buffer);
+ }
+
+ return 0;
+}
+
+void HardwareComposer::OnDeletedGlobalBuffer(DvrGlobalBufferKey key) {
+ if (key == DvrGlobalBuffers::kVrFlingerConfigBufferKey) {
+ ConfigBufferDeleted();
+ }
+}
+
+int HardwareComposer::MapConfigBuffer(IonBuffer& ion_buffer) {
+ std::lock_guard<std::mutex> lock(shared_config_mutex_);
+ shared_config_ring_ = DvrConfigRing();
+
+ if (ion_buffer.width() < DvrConfigRing::MemorySize()) {
+ ALOGE("HardwareComposer::MapConfigBuffer: invalid buffer size.");
+ return -EINVAL;
+ }
+
+ void* buffer_base = 0;
+ int result = ion_buffer.Lock(ion_buffer.usage(), 0, 0, ion_buffer.width(),
+ ion_buffer.height(), &buffer_base);
+ if (result != 0) {
+ ALOGE(
+ "HardwareComposer::MapConfigBuffer: Failed to map vrflinger config "
+ "buffer.");
+ return -EPERM;
+ }
+
+ shared_config_ring_ = DvrConfigRing::Create(buffer_base, ion_buffer.width());
+ ion_buffer.Unlock();
+
+ return 0;
+}
+
+void HardwareComposer::ConfigBufferDeleted() {
+ std::lock_guard<std::mutex> lock(shared_config_mutex_);
+ shared_config_ring_ = DvrConfigRing();
+}
+
+void HardwareComposer::UpdateConfigBuffer() {
+ std::lock_guard<std::mutex> lock(shared_config_mutex_);
+ if (!shared_config_ring_.is_valid())
+ return;
+ // Copy from latest record in shared_config_ring_ to local copy.
+ DvrConfig record;
+ if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) {
+ post_thread_config_ = record;
+ }
}
int HardwareComposer::PostThreadPollInterruptible(
@@ -744,12 +814,16 @@
while (1) {
ATRACE_NAME("HardwareComposer::PostThread");
+ // Check for updated config once per vsync.
+ UpdateConfigBuffer();
+
while (post_thread_quiescent_) {
std::unique_lock<std::mutex> lock(post_thread_mutex_);
ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
- // Tear down resources.
- OnPostThreadPaused();
+ // Tear down resources if necessary.
+ if (was_running)
+ OnPostThreadPaused();
was_running = false;
post_thread_resumed_ = false;
@@ -801,16 +875,20 @@
++vsync_count_;
- if (pose_client_) {
- // Signal the pose service with vsync info.
- // Display timestamp is in the middle of scanout.
- privateDvrPoseNotifyVsync(pose_client_, vsync_count_,
- vsync_timestamp + photon_offset_ns,
- ns_per_frame, right_eye_photon_offset_ns);
- }
-
const bool layer_config_changed = UpdateLayerConfig();
+ // Publish the vsync event.
+ if (vsync_ring_) {
+ DvrVsync vsync;
+ vsync.vsync_count = vsync_count_;
+ vsync.vsync_timestamp_ns = vsync_timestamp;
+ vsync.vsync_left_eye_offset_ns = photon_offset_ns;
+ vsync.vsync_right_eye_offset_ns = right_eye_photon_offset_ns;
+ vsync.vsync_period_ns = ns_per_frame;
+
+ vsync_ring_->Publish(vsync);
+ }
+
// Signal all of the vsync clients. Because absolute time is used for the
// wakeup time below, this can take a little time if necessary.
if (vsync_callback_)
@@ -823,9 +901,10 @@
const int64_t display_time_est_ns = vsync_timestamp + ns_per_frame;
const int64_t now_ns = GetSystemClockNs();
- const int64_t sleep_time_ns =
- display_time_est_ns - now_ns - kFramePostOffsetNs;
- const int64_t wakeup_time_ns = display_time_est_ns - kFramePostOffsetNs;
+ const int64_t sleep_time_ns = display_time_est_ns - now_ns -
+ post_thread_config_.frame_post_offset_ns;
+ const int64_t wakeup_time_ns =
+ display_time_est_ns - post_thread_config_.frame_post_offset_ns;
ATRACE_INT64("sleep_time_ns", sleep_time_ns);
if (sleep_time_ns > 0) {
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 8ba72ab..a0c50e1 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -5,6 +5,7 @@
#include "DisplayHardware/ComposerHal.h"
#include "hwc_types.h"
+#include <dvr/dvr_shared_buffers.h>
#include <hardware/gralloc.h>
#include <log/log.h>
@@ -16,10 +17,12 @@
#include <tuple>
#include <vector>
-#include <dvr/pose_client.h>
+#include <dvr/dvr_config.h>
+#include <dvr/dvr_vsync.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/variant.h>
#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/shared_buffer_helpers.h>
#include "acquired_buffer.h"
#include "display_surface.h"
@@ -124,11 +127,20 @@
int surface_id = -1;
pdx::rpc::IfAnyOf<SourceSurface>::Call(
&source_, [&surface_id](const SourceSurface& surface_source) {
- surface_id = surface_source.surface->surface_id();
+ surface_id = surface_source.GetSurfaceId();
});
return surface_id;
}
+ int GetBufferId() const {
+ int buffer_id = -1;
+ pdx::rpc::IfAnyOf<SourceSurface>::Call(
+ &source_, [&buffer_id](const SourceSurface& surface_source) {
+ buffer_id = surface_source.GetBufferId();
+ });
+ return buffer_id;
+ }
+
private:
void CommonLayerSetup();
@@ -189,7 +201,15 @@
}
// Returns the surface id of the surface.
- int GetSurfaceId() { return surface->surface_id(); }
+ int GetSurfaceId() const { return surface->surface_id(); }
+
+ // Returns the buffer id for the current buffer.
+ int GetBufferId() const {
+ if (acquired_buffer.IsAvailable())
+ return acquired_buffer.buffer()->id();
+ else
+ return -1;
+ }
};
// State when the layer is connected to a buffer. Provides the same interface
@@ -210,6 +230,7 @@
IonBuffer* GetBuffer() { return buffer.get(); }
int GetSurfaceId() const { return -1; }
+ int GetBufferId() const { return -1; }
};
// The underlying hardware composer layer is supplied buffers either from a
@@ -284,6 +305,9 @@
void SetDisplaySurfaces(
std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces);
+ int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer);
+ void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
+
void OnHardwareComposerRefresh();
private:
@@ -365,6 +389,13 @@
// Called on the post thread when the post thread is paused or quits.
void OnPostThreadPaused();
+ // Map the given shared memory buffer to our broadcast ring to track updates
+ // to the config parameters.
+ int MapConfigBuffer(IonBuffer& ion_buffer);
+ void ConfigBufferDeleted();
+ // Poll for config udpates.
+ void UpdateConfigBuffer();
+
bool initialized_;
// Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own
@@ -435,9 +466,15 @@
// us to detect when the display driver begins queuing frames.
std::vector<pdx::LocalHandle> retire_fence_fds_;
- // Pose client for frame count notifications. Pose client predicts poses
- // out to display frame boundaries, so we need to tell it about vsyncs.
- DvrPose* pose_client_ = nullptr;
+ // If we are publishing vsync data, we will put it here.
+ std::unique_ptr<CPUMappedBroadcastRing<DvrVsyncRing>> vsync_ring_;
+
+ // Broadcast ring for receiving config data from the DisplayManager.
+ DvrConfigRing shared_config_ring_;
+ uint32_t shared_config_ring_sequence_{0};
+ // Config buffer for reading from the post thread.
+ DvrConfig post_thread_config_;
+ std::mutex shared_config_mutex_;
static constexpr int kPostThreadInterrupted = 1;
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 145852e..f41da87 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -32,6 +32,9 @@
// Called on a binder thread.
void OnHardwareComposerRefresh();
+ // dump all vr flinger state.
+ std::string Dump();
+
private:
VrFlinger();
bool Init(Hwc2::Composer* hidl,
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index b2dc1d8..3a0ca4a 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -139,6 +139,11 @@
display_service_->OnHardwareComposerRefresh();
}
+std::string VrFlinger::Dump() {
+ // TODO(karthikrs): Add more state information here.
+ return display_service_->DumpState(0/*unused*/);
+}
+
void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
bool enabled) {
ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off");
@@ -146,6 +151,5 @@
// Persistent VR mode is not enough.
// request_display_callback_(enabled);
}
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index 2a83933..3098b43 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -200,12 +200,12 @@
}
void VSyncChannel::Ack() {
- ALOGD_IF(TRACE, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
+ ALOGD_IF(TRACE > 1, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
service_.ModifyChannelEvents(cid_, POLLPRI, 0);
}
void VSyncChannel::Signal() {
- ALOGD_IF(TRACE, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
+ ALOGD_IF(TRACE > 1, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
service_.ModifyChannelEvents(cid_, 0, POLLPRI);
}
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index abad78b..d022adf 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -23,9 +23,11 @@
]
staticLibraries = [
+ "libdisplay",
"libbufferhub",
"libbufferhubqueue",
"libdvrcommon",
+ "libbroadcastring",
"libpdx_default_transport",
]
@@ -43,6 +45,7 @@
export_include_dirs: includeFiles,
static_libs: staticLibraries,
shared_libs: sharedLibraries,
+ header_libs: ["libdvr_headers"],
name: "libvrsensor",
}
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
index ed75f84..d684ddc 100644
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ b/libs/vr/libvrsensor/include/dvr/pose_client.h
@@ -14,63 +14,13 @@
#include <stdbool.h>
#include <stdint.h>
+#include <dvr/dvr_pose.h>
+
#ifdef __cplusplus
extern "C" {
#endif
-typedef struct DvrPose DvrPose;
-
-// Represents the current state provided by the pose service, containing a
-// rotation and translation.
-typedef struct __attribute__((packed, aligned(8))) DvrPoseState {
- // A quaternion representing the rotation of the HMD in Start Space.
- struct __attribute__((packed)) {
- float x, y, z, w;
- } head_from_start_rotation;
- // The position of the HMD in Start Space.
- struct __attribute__((packed)) {
- float x, y, z;
- } head_from_start_translation;
- // Time in nanoseconds for the current pose.
- uint64_t timestamp_ns;
- // The rotational velocity of the HMD.
- struct __attribute__((packed)) {
- float x, y, z;
- } sensor_from_start_rotation_velocity;
-} DvrPoseState;
-
-enum {
- DVR_POSE_FLAG_VALID = (1UL << 0), // This pose is valid.
- DVR_POSE_FLAG_HEAD = (1UL << 1), // This pose is the head.
- DVR_POSE_FLAG_CONTROLLER = (1UL << 2), // This pose is a controller.
-};
-
-// Represents an estimated pose, accessed asynchronously through a shared ring
-// buffer. No assumptions should be made about the data in padding space.
-// The size of this struct is 128 bytes.
-typedef struct __attribute__((packed, aligned(16))) DvrPoseAsync {
- // Left eye head-from-start orientation quaternion x,y,z,w.
- float32x4_t orientation;
- // Left eye head-from-start translation x,y,z,pad in meters.
- float32x4_t translation;
- // Right eye head-from-start orientation quaternion x,y,z,w.
- float32x4_t right_orientation;
- // Right eye head-from-start translation x,y,z,pad in meters.
- float32x4_t right_translation;
- // Start-space angular velocity x,y,z,pad in radians per second.
- float32x4_t angular_velocity;
- // Start-space positional velocity x,y,z,pad in meters per second.
- float32x4_t velocity;
- // Timestamp of when this pose is predicted for, typically halfway through
- // scanout.
- int64_t timestamp_ns;
- // Bitmask of DVR_POSE_FLAG_* constants that apply to this pose.
- //
- // If DVR_POSE_FLAG_VALID is not set, the pose is indeterminate.
- uint64_t flags;
- // Reserved padding to 128 bytes.
- uint8_t pad[16];
-} DvrPoseAsync;
+typedef struct DvrPoseClient DvrPoseClient;
// Returned by the async pose ring buffer access API.
typedef struct DvrPoseRingBufferInfo {
@@ -105,6 +55,8 @@
DVR_POSE_MODE_MOCK_ROTATE_MEDIUM,
DVR_POSE_MODE_MOCK_ROTATE_FAST,
DVR_POSE_MODE_MOCK_CIRCLE_STRAFE,
+ DVR_POSE_MODE_FLOAT,
+ DVR_POSE_MODE_MOCK_MOTION_SICKNESS,
// Always last.
DVR_POSE_MODE_COUNT,
@@ -118,12 +70,12 @@
// Creates a new pose client.
//
// @return Pointer to the created pose client, nullptr on failure.
-DvrPose* dvrPoseCreate();
+DvrPoseClient* dvrPoseClientCreate();
// Destroys a pose client.
//
// @param client Pointer to the pose client to be destroyed.
-void dvrPoseDestroy(DvrPose* client);
+void dvrPoseClientDestroy(DvrPoseClient* client);
// Gets the pose for the given vsync count.
//
@@ -132,10 +84,11 @@
// Typically this is the count returned by dvrGetNextVsyncCount.
// @param out_pose Struct to store pose state.
// @return Zero on success, negative error code on failure.
-int dvrPoseGet(DvrPose* client, uint32_t vsync_count, DvrPoseAsync* out_pose);
+int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count,
+ DvrPoseAsync* out_pose);
// Gets the current vsync count.
-uint32_t dvrPoseGetVsyncCount(DvrPose* client);
+uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client);
// Gets the pose for the given controller at the given vsync count.
//
@@ -145,15 +98,15 @@
// Typically this is the count returned by dvrGetNextVsyncCount.
// @param out_pose Struct to store pose state.
// @return Zero on success, negative error code on failure.
-int dvrPoseGetController(DvrPose* client, int32_t controller_id,
- uint32_t vsync_count, DvrPoseAsync* out_pose);
+int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id,
+ uint32_t vsync_count, DvrPoseAsync* out_pose);
// Enables/disables logging for the controller fusion.
//
// @param client Pointer to the pose client.
// @param enable True starts logging, False stops.
// @return Zero on success, negative error code on failure.
-int dvrPoseLogController(DvrPose* client, bool enable);
+int dvrPoseClientLogController(DvrPoseClient* client, bool enable);
// DEPRECATED
// Polls current pose state.
@@ -161,30 +114,30 @@
// @param client Pointer to the pose client.
// @param state Struct to store polled state.
// @return Zero on success, negative error code on failure.
-int dvrPosePoll(DvrPose* client, DvrPoseState* state);
+int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state);
// Freezes the pose to the provided state.
//
// Future poll operations will return this state until a different state is
-// frozen or dvrPoseSetMode() is called with a different mode. The timestamp is
+// frozen or dvrPoseClientModeSet() is called with a different mode. The timestamp is
// not frozen.
//
// @param client Pointer to the pose client.
// @param frozen_state State pose to be frozen to.
// @return Zero on success, negative error code on failure.
-int dvrPoseFreeze(DvrPose* client, const DvrPoseState* frozen_state);
+int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state);
// Sets the pose service mode.
//
// @param mode The requested pose mode.
// @return Zero on success, negative error code on failure.
-int dvrPoseSetMode(DvrPose* client, DvrPoseMode mode);
+int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode);
// Gets the pose service mode.
//
// @param mode Return value for the current pose mode.
// @return Zero on success, negative error code on failure.
-int dvrPoseGetMode(DvrPose* client, DvrPoseMode* mode);
+int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode);
// Get access to the shared memory pose ring buffer.
// A future pose at vsync <current> + <offset> is accessed at index:
@@ -195,8 +148,14 @@
// |out_fd| will be set to the gralloc buffer file descriptor, which is
// required for binding this buffer for GPU use.
// Returns 0 on success.
-int dvrPoseGetRingBuffer(DvrPose* client, DvrPoseRingBufferInfo* out_info);
+int dvrPoseClientGetRingBuffer(DvrPoseClient* client,
+ DvrPoseRingBufferInfo* out_info);
+// Sets enabled state for sensors pose processing.
+//
+// @param enabled Whether sensors are enabled or disabled.
+// @return Zero on success
+int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled);
#ifdef __cplusplus
} // extern "C"
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
index 0616d46..e4455f1 100644
--- a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
+++ b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
@@ -11,14 +11,12 @@
#define DVR_POSE_SERVICE_CLIENT (DVR_POSE_SERVICE_BASE "/client")
enum {
- DVR_POSE_POLL = 0,
- DVR_POSE_FREEZE,
+ DVR_POSE_FREEZE = 0,
DVR_POSE_SET_MODE,
- DVR_POSE_GET_RING_BUFFER,
- DVR_POSE_NOTIFY_VSYNC,
DVR_POSE_GET_MODE,
DVR_POSE_GET_CONTROLLER_RING_BUFFER,
DVR_POSE_LOG_CONTROLLER,
+ DVR_POSE_SENSORS_ENABLE,
};
#ifdef __cplusplus
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
deleted file mode 100644
index 66c4c7c..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
-#define ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
-
-#include <stdint.h>
-
-#include <dvr/pose_client.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/sensor_constants.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Sensord head pose ring buffer.
-typedef struct __attribute__((packed, aligned(16))) DvrPoseRingBuffer {
- // Ring buffer always at the beginning of the structure, as consumers may
- // not have access to this parent structure definition.
- DvrPoseAsync ring[kPoseAsyncBufferTotalCount];
- // Current vsync_count (where sensord is writing poses from).
- uint32_t vsync_count;
-} DvrPoseMetadata;
-
-// Called by displayd to give vsync count info to the pose service.
-// |display_timestamp| Display timestamp is in the middle of scanout.
-// |display_period_ns| Nanos between vsyncs.
-// |right_eye_photon_offset_ns| Nanos to shift the prediction timestamp for
-// the right eye head pose (relative to the left eye prediction).
-int privateDvrPoseNotifyVsync(DvrPose* client, uint32_t vsync_count,
- int64_t display_timestamp,
- int64_t display_period_ns,
- int64_t right_eye_photon_offset_ns);
-
-// Get file descriptor for access to the shared memory pose buffer. This can be
-// used with GL extensions that support shared memory buffer objects. The caller
-// takes ownership of the returned fd and must close it or pass on ownership.
-int privateDvrPoseGetRingBufferFd(DvrPose* client,
- android::pdx::LocalHandle* fd);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor_constants.h b/libs/vr/libvrsensor/include/private/dvr/sensor_constants.h
deleted file mode 100644
index 8fa87b3..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/sensor_constants.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef ANDROID_DVR_SENSOR_CONSTANTS_H_
-#define ANDROID_DVR_SENSOR_CONSTANTS_H_
-
-namespace android {
-namespace dvr {
-
-// Number of elements in the async pose buffer.
-// Must be power of two.
-// Macro so that shader code can easily include this value.
-#define kPoseAsyncBufferTotalCount 8
-
-// Mask for accessing the current ring buffer array element:
-// index = vsync_count & kPoseAsyncBufferIndexMask
-constexpr uint32_t kPoseAsyncBufferIndexMask = kPoseAsyncBufferTotalCount - 1;
-
-// Number of pose frames including the current frame that are kept updated with
-// pose forecast data. The other poses are left their last known estimates.
-constexpr uint32_t kPoseAsyncBufferMinFutureCount = 4;
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_SENSOR_CONSTANTS_H_
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
index 9eae3aa..4ddf1f3 100644
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ b/libs/vr/libvrsensor/pose_client.cpp
@@ -1,4 +1,5 @@
#define LOG_TAG "PoseClient"
+#include <dvr/dvr_shared_buffers.h>
#include <dvr/pose_client.h>
#include <stdint.h>
@@ -8,9 +9,9 @@
#include <pdx/default_transport/client_channel_factory.h>
#include <pdx/file_handle.h>
#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/display_client.h>
#include <private/dvr/pose-ipc.h>
-#include <private/dvr/pose_client_internal.h>
-#include <private/dvr/sensor_constants.h>
+#include <private/dvr/shared_buffer_helpers.h>
using android::pdx::LocalHandle;
using android::pdx::LocalChannelHandle;
@@ -21,6 +22,11 @@
namespace android {
namespace dvr {
+namespace {
+
+typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing;
+
+} // namespace
// PoseClient is a remote interface to the pose service in sensord.
class PoseClient : public pdx::ClientBase<PoseClient> {
@@ -28,39 +34,49 @@
~PoseClient() override {}
// Casts C handle into an instance of this class.
- static PoseClient* FromC(DvrPose* client) {
+ static PoseClient* FromC(DvrPoseClient* client) {
return reinterpret_cast<PoseClient*>(client);
}
// Polls the pose service for the current state and stores it in *state.
// Returns zero on success, a negative error code otherwise.
- int Poll(DvrPoseState* state) {
- Transaction trans{*this};
- Status<int> status =
- trans.Send<int>(DVR_POSE_POLL, nullptr, 0, state, sizeof(*state));
- ALOGE_IF(!status, "Pose poll() failed because: %s\n",
- status.GetErrorMessage().c_str());
- return ReturnStatusOrError(status);
+ int Poll(DvrPose* state) {
+ // Allocate the helper class to access the sensor pose buffer.
+ if (sensor_pose_buffer_ == nullptr) {
+ sensor_pose_buffer_ = std::make_unique<SensorPoseRing>(
+ DvrGlobalBuffers::kSensorPoseBuffer, CPUUsageMode::READ_RARELY);
+ }
+
+ if (state) {
+ if (sensor_pose_buffer_->GetNewest(state)) {
+ return 0;
+ } else {
+ return -EAGAIN;
+ }
+ }
+
+ return -EINVAL;
}
int GetPose(uint32_t vsync_count, DvrPoseAsync* out_pose) {
- if (!mapped_pose_buffer_) {
- int ret = GetRingBuffer(nullptr);
- if (ret < 0)
- return ret;
+ const auto vsync_buffer = GetVsyncBuffer();
+ if (vsync_buffer) {
+ *out_pose =
+ vsync_buffer
+ ->vsync_poses[vsync_count & DvrVsyncPoseBuffer::kIndexMask];
+ return 0;
+ } else {
+ return -EAGAIN;
}
- *out_pose =
- mapped_pose_buffer_->ring[vsync_count & kPoseAsyncBufferIndexMask];
- return 0;
}
uint32_t GetVsyncCount() {
- if (!mapped_pose_buffer_) {
- int ret = GetRingBuffer(nullptr);
- if (ret < 0)
- return 0;
+ const auto vsync_buffer = GetVsyncBuffer();
+ if (vsync_buffer) {
+ return vsync_buffer->vsync_count;
}
- return mapped_pose_buffer_->vsync_count;
+
+ return 0;
}
int GetControllerPose(int32_t controller_id, uint32_t vsync_count,
@@ -75,7 +91,7 @@
}
*out_pose =
controllers_[controller_id]
- .mapped_pose_buffer[vsync_count & kPoseAsyncBufferIndexMask];
+ .mapped_pose_buffer[vsync_count & DvrVsyncPoseBuffer::kIndexMask];
return 0;
}
@@ -92,7 +108,7 @@
// this state until a different state is frozen or SetMode() is called with a
// different mode.
// Returns zero on success, a negative error code otherwise.
- int Freeze(const DvrPoseState& frozen_state) {
+ int Freeze(const DvrPose& frozen_state) {
Transaction trans{*this};
Status<int> status = trans.Send<int>(DVR_POSE_FREEZE, &frozen_state,
sizeof(frozen_state), nullptr, 0);
@@ -124,48 +140,29 @@
return ReturnStatusOrError(status);
}
- int GetRingBuffer(DvrPoseRingBufferInfo* out_info) {
- if (pose_buffer_.get()) {
- if (out_info) {
- GetPoseRingBufferInfo(out_info);
- }
- return 0;
- }
-
+ // Enables or disables all pose processing from sensors
+ int EnableSensors(bool enabled) {
Transaction trans{*this};
- Status<LocalChannelHandle> status =
- trans.Send<LocalChannelHandle>(DVR_POSE_GET_RING_BUFFER);
- if (!status) {
- ALOGE("Pose GetRingBuffer() failed because: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
+ Status<int> status = trans.Send<int>(DVR_POSE_SENSORS_ENABLE, &enabled,
+ sizeof(enabled), nullptr, 0);
+ ALOGE_IF(!status, "Pose EnableSensors() failed because: %s\n",
+ status.GetErrorMessage().c_str());
+ return ReturnStatusOrError(status);
+ }
+
+ int GetRingBuffer(DvrPoseRingBufferInfo* out_info) {
+ // First time mapping the buffer?
+ const auto vsync_buffer = GetVsyncBuffer();
+ if (vsync_buffer) {
+ if (out_info) {
+ out_info->min_future_count = DvrVsyncPoseBuffer::kMinFutureCount;
+ out_info->total_count = DvrVsyncPoseBuffer::kSize;
+ out_info->buffer = vsync_buffer->vsync_poses;
+ }
+ return -EINVAL;
}
- auto buffer = BufferConsumer::Import(status.take());
- if (!buffer) {
- ALOGE("Pose failed to import ring buffer");
- return -EIO;
- }
- void* addr = nullptr;
- int ret = buffer->GetBlobReadOnlyPointer(sizeof(DvrPoseRingBuffer), &addr);
- if (ret < 0 || !addr) {
- ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr);
- return -EIO;
- }
- pose_buffer_.swap(buffer);
- mapped_pose_buffer_ = static_cast<const DvrPoseRingBuffer*>(addr);
- ALOGI("Mapped pose data translation %f,%f,%f quat %f,%f,%f,%f",
- mapped_pose_buffer_->ring[0].translation[0],
- mapped_pose_buffer_->ring[0].translation[1],
- mapped_pose_buffer_->ring[0].translation[2],
- mapped_pose_buffer_->ring[0].orientation[0],
- mapped_pose_buffer_->ring[0].orientation[1],
- mapped_pose_buffer_->ring[0].orientation[2],
- mapped_pose_buffer_->ring[0].orientation[3]);
- if (out_info) {
- GetPoseRingBufferInfo(out_info);
- }
- return 0;
+ return -EAGAIN;
}
int GetControllerRingBuffer(int32_t controller_id) {
@@ -190,7 +187,7 @@
ALOGE("Pose failed to import ring buffer");
return -EIO;
}
- constexpr size_t size = kPoseAsyncBufferTotalCount * sizeof(DvrPoseAsync);
+ constexpr size_t size = DvrVsyncPoseBuffer::kSize * sizeof(DvrPoseAsync);
void* addr = nullptr;
int ret = buffer->GetBlobReadOnlyPointer(size, &addr);
if (ret < 0 || !addr) {
@@ -201,9 +198,9 @@
client_state.mapped_pose_buffer = static_cast<const DvrPoseAsync*>(addr);
ALOGI(
"Mapped controller %d pose data translation %f,%f,%f quat %f,%f,%f,%f",
- controller_id, client_state.mapped_pose_buffer[0].translation[0],
- client_state.mapped_pose_buffer[0].translation[1],
- client_state.mapped_pose_buffer[0].translation[2],
+ controller_id, client_state.mapped_pose_buffer[0].position[0],
+ client_state.mapped_pose_buffer[0].position[1],
+ client_state.mapped_pose_buffer[0].position[2],
client_state.mapped_pose_buffer[0].orientation[0],
client_state.mapped_pose_buffer[0].orientation[1],
client_state.mapped_pose_buffer[0].orientation[2],
@@ -211,32 +208,6 @@
return 0;
}
- int NotifyVsync(uint32_t vsync_count, int64_t display_timestamp,
- int64_t display_period_ns,
- int64_t right_eye_photon_offset_ns) {
- const struct iovec data[] = {
- {.iov_base = &vsync_count, .iov_len = sizeof(vsync_count)},
- {.iov_base = &display_timestamp, .iov_len = sizeof(display_timestamp)},
- {.iov_base = &display_period_ns, .iov_len = sizeof(display_period_ns)},
- {.iov_base = &right_eye_photon_offset_ns,
- .iov_len = sizeof(right_eye_photon_offset_ns)},
- };
- Transaction trans{*this};
- Status<int> status =
- trans.SendVector<int>(DVR_POSE_NOTIFY_VSYNC, data, nullptr);
- ALOGE_IF(!status, "Pose NotifyVsync() failed because: %s\n",
- status.GetErrorMessage().c_str());
- return ReturnStatusOrError(status);
- }
-
- int GetRingBufferFd(LocalHandle* fd) {
- int ret = GetRingBuffer(nullptr);
- if (ret < 0)
- return ret;
- *fd = pose_buffer_->GetBlobFd();
- return 0;
- }
-
private:
friend BASE;
@@ -252,14 +223,32 @@
PoseClient(const PoseClient&) = delete;
PoseClient& operator=(const PoseClient&) = delete;
- void GetPoseRingBufferInfo(DvrPoseRingBufferInfo* out_info) const {
- out_info->min_future_count = kPoseAsyncBufferMinFutureCount;
- out_info->total_count = kPoseAsyncBufferTotalCount;
- out_info->buffer = mapped_pose_buffer_->ring;
+ const DvrVsyncPoseBuffer* GetVsyncBuffer() {
+ if (mapped_vsync_pose_buffer_ == nullptr) {
+ if (vsync_pose_buffer_ == nullptr) {
+ // The constructor tries mapping it so we do not need TryMapping after.
+ vsync_pose_buffer_ = std::make_unique<CPUMappedBuffer>(
+ DvrGlobalBuffers::kVsyncPoseBuffer, CPUUsageMode::READ_OFTEN);
+ } else if (vsync_pose_buffer_->IsMapped() == false) {
+ vsync_pose_buffer_->TryMapping();
+ }
+
+ if (vsync_pose_buffer_->IsMapped()) {
+ mapped_vsync_pose_buffer_ =
+ static_cast<DvrVsyncPoseBuffer*>(vsync_pose_buffer_->Address());
+ }
+ }
+
+ return mapped_vsync_pose_buffer_;
}
- std::unique_ptr<BufferConsumer> pose_buffer_;
- const DvrPoseRingBuffer* mapped_pose_buffer_ = nullptr;
+ // The vsync pose buffer if already mapped.
+ std::unique_ptr<CPUMappedBuffer> vsync_pose_buffer_;
+
+ // The direct sensor pose buffer.
+ std::unique_ptr<SensorPoseRing> sensor_pose_buffer_;
+
+ const DvrVsyncPoseBuffer* mapped_vsync_pose_buffer_ = nullptr;
struct ControllerClientState {
std::unique_ptr<BufferConsumer> pose_buffer;
@@ -273,66 +262,55 @@
using android::dvr::PoseClient;
-struct DvrPose {};
-
extern "C" {
-DvrPose* dvrPoseCreate() {
- PoseClient* client = PoseClient::Create().release();
- return reinterpret_cast<DvrPose*>(client);
+DvrPoseClient* dvrPoseClientCreate() {
+ auto* client = PoseClient::Create().release();
+ return reinterpret_cast<DvrPoseClient*>(client);
}
-void dvrPoseDestroy(DvrPose* client) { delete PoseClient::FromC(client); }
+void dvrPoseClientDestroy(DvrPoseClient* client) {
+ delete PoseClient::FromC(client);
+}
-int dvrPoseGet(DvrPose* client, uint32_t vsync_count, DvrPoseAsync* out_pose) {
+int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count,
+ DvrPoseAsync* out_pose) {
return PoseClient::FromC(client)->GetPose(vsync_count, out_pose);
}
-uint32_t dvrPoseGetVsyncCount(DvrPose* client) {
+uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client) {
return PoseClient::FromC(client)->GetVsyncCount();
}
-int dvrPoseGetController(DvrPose* client, int32_t controller_id,
- uint32_t vsync_count, DvrPoseAsync* out_pose) {
+int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id,
+ uint32_t vsync_count, DvrPoseAsync* out_pose) {
return PoseClient::FromC(client)->GetControllerPose(controller_id,
vsync_count, out_pose);
}
-int dvrPoseLogController(DvrPose* client, bool enable) {
+int dvrPoseClientLogController(DvrPoseClient* client, bool enable) {
return PoseClient::FromC(client)->LogController(enable);
}
-int dvrPosePoll(DvrPose* client, DvrPoseState* state) {
+int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state) {
return PoseClient::FromC(client)->Poll(state);
}
-int dvrPoseFreeze(DvrPose* client, const DvrPoseState* frozen_state) {
+int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state) {
return PoseClient::FromC(client)->Freeze(*frozen_state);
}
-int dvrPoseSetMode(DvrPose* client, DvrPoseMode mode) {
+int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode) {
return PoseClient::FromC(client)->SetMode(mode);
}
-int dvrPoseGetMode(DvrPose* client, DvrPoseMode* mode) {
+int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode) {
return PoseClient::FromC(client)->GetMode(mode);
}
-int dvrPoseGetRingBuffer(DvrPose* client, DvrPoseRingBufferInfo* out_info) {
- return PoseClient::FromC(client)->GetRingBuffer(out_info);
-}
-int privateDvrPoseNotifyVsync(DvrPose* client, uint32_t vsync_count,
- int64_t display_timestamp,
- int64_t display_period_ns,
- int64_t right_eye_photon_offset_ns) {
- return PoseClient::FromC(client)->NotifyVsync(vsync_count, display_timestamp,
- display_period_ns,
- right_eye_photon_offset_ns);
-}
-
-int privateDvrPoseGetRingBufferFd(DvrPose* client, LocalHandle* fd) {
- return PoseClient::FromC(client)->GetRingBufferFd(fd);
+int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled) {
+ return PoseClient::FromC(client)->EnableSensors(enabled);
}
} // extern "C"
diff --git a/opengl/Android.bp b/opengl/Android.bp
index c520bda..aec5a95 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -52,6 +52,12 @@
license: "include/KHR/NOTICE",
}
+cc_library_headers {
+ name: "gl_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
+
subdirs = [
"*",
]
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index d0996f0..bb28600 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -625,6 +625,11 @@
#define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000
#endif
+#ifndef EGL_KHR_no_config_context
+#define EGL_KHR_no_config_context 1
+#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0)
+#endif /* EGL_KHR_no_config_context */
+
#ifndef EGL_ANDROID_get_frame_timestamps
#define EGL_ANDROID_get_frame_timestamps 1
#define EGL_TIMESTAMPS_ANDROID 0x3430
@@ -667,6 +672,21 @@
#define EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340
#endif /* EGL_EXT_gl_colorspace_bt2020_pq */
+#ifndef EGL_EXT_gl_colorspace_display_p3
+#define EGL_EXT_gl_colorspace_display_p3 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363
+#endif /* EGL_EXT_gl_colorspace_display_p3 */
+
+#ifndef EGL_EXT_gl_colorspace_display_p3_linear
+#define EGL_EXT_gl_colorspace_display_p3_linear 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362
+#endif /* EGL_EXT_gl_colorspace_display_p3_linear */
+
+#ifndef EGL_EXT_gl_colorspace_scrgb
+#define EGL_EXT_gl_colorspace_scrgb 1
+#define EGL_GL_COLORSPACE_SCRGB_EXT 0x3351
+#endif /* EGL_EXT_gl_colorspace_scrgb */
+
#ifndef EGL_EXT_gl_colorspace_scrgb_linear
#define EGL_EXT_gl_colorspace_scrgb_linear 1
#define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 4b08749..c7635e2 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -26,7 +26,7 @@
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
-LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui
+LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui libnativewindow
LOCAL_SRC_FILES_arm += fixed_asm.S iterators.S
LOCAL_CFLAGS_arm += -fstrict-aliasing
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 04f6d6d..b79051c 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -56,6 +56,24 @@
EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
EGLint left, EGLint top, EGLint width, EGLint height);
+
+typedef struct egl_native_pixmap_t
+{
+ int32_t version; /* must be 32 */
+ int32_t width;
+ int32_t height;
+ int32_t stride;
+ uint8_t* data;
+ uint8_t format;
+ uint8_t rfu[3];
+ union {
+ uint32_t compressedFormat;
+ int32_t vstride;
+ };
+ int32_t reserved;
+} egl_native_pixmap_t;
+
+
// ----------------------------------------------------------------------------
namespace android {
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index d6bdc81..b4cc211 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -64,6 +64,16 @@
"liblog",
"libdl",
],
+ static_libs: [
+ "libarect",
+ ],
+ header_libs: [
+ "gl_headers",
+ "libsystem_headers",
+ "libhardware_headers",
+ "libnativebase_headers",
+ ],
+ export_header_lib_headers: ["gl_headers"],
// we need to access the private Bionic header <bionic_tls.h>
include_dirs: ["bionic/libc/private"],
@@ -75,16 +85,22 @@
cc_defaults {
name: "egl_libs_defaults",
defaults: ["gl_libs_defaults"],
+ vendor_available: true,
cflags: [
"-DLOG_TAG=\"libEGL\"",
],
shared_libs: [
// ***** DO NOT ADD NEW DEPENDENCIES HERE *****
// In particular, DO NOT add libutils nor anything "above" libui
- "libui",
+ "libgraphicsenv",
"libnativewindow",
"libbacktrace",
],
+ target: {
+ vendor: {
+ exclude_shared_libs: ["libgraphicsenv"],
+ },
+ },
}
cc_library_static {
@@ -111,7 +127,14 @@
"EGL/Loader.cpp",
"EGL/BlobCache.cpp",
],
- shared_libs: ["libvndksupport"],
+ shared_libs: [
+ "libvndksupport",
+ "android.hardware.configstore@1.0",
+ "android.hardware.configstore-utils",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ ],
static_libs: ["libEGL_getProcAddress"],
ldflags: ["-Wl,--exclude-libs=ALL"],
export_include_dirs: ["EGL/include"],
@@ -129,6 +152,7 @@
cc_defaults {
name: "gles_libs_defaults",
defaults: ["gl_libs_defaults"],
+ vendor_available: true,
arch: {
arm: {
instruction_set: "arm",
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 823b502..32f8caa 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -28,7 +28,9 @@
#include <cutils/properties.h>
#include <log/log.h>
-#include <ui/GraphicsEnv.h>
+#ifndef __ANDROID_VNDK__
+#include <graphicsenv/GraphicsEnv.h>
+#endif
#include <vndksupport/linker.h>
#include "egl_trace.h"
@@ -477,10 +479,12 @@
ATRACE_CALL();
void* dso = nullptr;
+#ifndef __ANDROID_VNDK__
android_namespace_t* ns = android_getDriverNamespace();
if (ns) {
dso = load_updated_driver(kind, ns);
}
+#endif
if (!dso) {
dso = load_system_driver(kind);
if (!dso)
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index ba3a5f9..0214b0e 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -79,6 +79,7 @@
extern char const * const gBuiltinExtensionString;
extern char const * const gExtensionString;
+// clang-format off
char const * const gBuiltinExtensionString =
"EGL_KHR_get_all_proc_addresses "
"EGL_ANDROID_presentation_time "
@@ -123,6 +124,7 @@
"EGL_IMG_context_priority "
"EGL_KHR_no_config_context "
;
+// clang-format on
// extensions not exposed to applications but used by the ANDROID system
// "EGL_ANDROID_blob_cache " // strongly recommended
@@ -452,16 +454,216 @@
// EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear
// formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where
// the modification isn't possible, the original dataSpace is returned.
-static android_dataspace modifyBufferDataspace( android_dataspace dataSpace,
- EGLint colorspace) {
+static android_dataspace modifyBufferDataspace(android_dataspace dataSpace,
+ EGLint colorspace) {
if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
return HAL_DATASPACE_SRGB_LINEAR;
} else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
return HAL_DATASPACE_SRGB;
+ } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) {
+ return HAL_DATASPACE_DISPLAY_P3;
+ } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) {
+ return HAL_DATASPACE_DISPLAY_P3_LINEAR;
+ } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) {
+ return HAL_DATASPACE_V0_SCRGB;
+ } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
+ return HAL_DATASPACE_V0_SCRGB_LINEAR;
}
return dataSpace;
}
+// Return true if we stripped any EGL_GL_COLORSPACE_KHR attributes.
+static EGLBoolean stripColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+ EGLint format,
+ std::vector<EGLint>& stripped_attrib_list) {
+ std::vector<EGLint> allowedColorSpaces;
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ // driver okay with linear & sRGB for 8888, but can't handle
+ // Display-P3 or other spaces.
+ allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+ allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
+ break;
+
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ default:
+ // driver does not want to see colorspace attributes for 1010102 or fp16.
+ // Future: if driver supports XXXX extension, we can pass down that colorspace
+ break;
+ }
+
+ bool stripped = false;
+ if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
+ for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
+ if (attr[0] == EGL_GL_COLORSPACE_KHR) {
+ EGLint colorSpace = attr[1];
+ bool found = false;
+ // Verify that color space is allowed
+ for (auto it : allowedColorSpaces) {
+ if (colorSpace == it) {
+ found = true;
+ }
+ }
+ if (!found) {
+ stripped = true;
+ } else {
+ stripped_attrib_list.push_back(attr[0]);
+ stripped_attrib_list.push_back(attr[1]);
+ }
+ } else {
+ stripped_attrib_list.push_back(attr[0]);
+ stripped_attrib_list.push_back(attr[1]);
+ }
+ }
+ }
+ if (stripped) {
+ stripped_attrib_list.push_back(EGL_NONE);
+ stripped_attrib_list.push_back(EGL_NONE);
+ }
+ return stripped;
+}
+
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType window,
+ const EGLint* attrib_list, EGLint& colorSpace,
+ android_dataspace& dataSpace) {
+ colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
+ dataSpace = HAL_DATASPACE_UNKNOWN;
+
+ if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
+ for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
+ if (*attr == EGL_GL_COLORSPACE_KHR) {
+ colorSpace = attr[1];
+ bool found = false;
+ bool verify = true;
+ // Verify that color space is allowed
+ if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
+ colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) {
+ // SRGB and LINEAR are always supported when EGL_KHR_gl_colorspace
+ // is available, so no need to verify.
+ found = true;
+ verify = false;
+ } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_linear &&
+ dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) {
+ found = true;
+ } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_pq &&
+ dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) {
+ found = true;
+ } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_EXT &&
+ dp->haveExtension("EGL_EXT_gl_colorspace_scrgb")) {
+ found = true;
+ } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT &&
+ dp->haveExtension("EGL_EXT_gl_colorspace_scrgb_linear")) {
+ found = true;
+ } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT &&
+ dp->haveExtension("EGL_EXT_gl_colorspace_display_p3_linear")) {
+ found = true;
+ } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT &&
+ dp->haveExtension("EGL_EXT_gl_colorspace_display_p3")) {
+ found = true;
+ }
+ if (!found) {
+ return false;
+ }
+ if (verify && window) {
+ bool wide_color_support = true;
+ // Ordinarily we'd put a call to native_window_get_wide_color_support
+ // at the beginning of the function so that we'll have the
+ // result when needed elsewhere in the function.
+ // However, because eglCreateWindowSurface is called by SurfaceFlinger and
+ // SurfaceFlinger is required to answer the call below we would
+ // end up in a deadlock situation. By moving the call to only happen
+ // if the application has specifically asked for wide-color we avoid
+ // the deadlock with SurfaceFlinger since it will not ask for a
+ // wide-color surface.
+ int err = native_window_get_wide_color_support(window, &wide_color_support);
+
+ if (err) {
+ ALOGE("getColorSpaceAttribute: invalid window (win=%p) "
+ "failed (%#x) (already connected to another API?)",
+ window, err);
+ return false;
+ }
+ if (!wide_color_support) {
+ // Application has asked for a wide-color colorspace but
+ // wide-color support isn't available on the display the window is on.
+ return false;
+ }
+ }
+ // Only change the dataSpace from default if the application
+ // has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute.
+ dataSpace = modifyBufferDataspace(dataSpace, colorSpace);
+ }
+ }
+ }
+ return true;
+}
+
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+ EGLint& colorSpace, android_dataspace& dataSpace) {
+ return getColorSpaceAttribute(dp, NULL, attrib_list, colorSpace, dataSpace);
+}
+
+void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) {
+ // Set the native window's buffers format to match what this config requests.
+ // Whether to use sRGB gamma is not part of the EGLconfig, but is part
+ // of our native format. So if sRGB gamma is requested, we have to
+ // modify the EGLconfig's format before setting the native window's
+ // format.
+
+ EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, &componentType);
+
+ EGLint a = 0;
+ EGLint r, g, b;
+ r = g = b = 0;
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+ EGLint colorDepth = r + g + b;
+
+ // Today, the driver only understands sRGB and linear on 888X
+ // formats. Strip other colorspaces from the attribute list and
+ // only use them to set the dataspace via
+ // native_window_set_buffers_dataspace
+ // if pixel format is RGBX 8888
+ // TBD: Can test for future extensions that indicate that driver
+ // handles requested color space and we can let it through.
+ // allow SRGB and LINEAR. All others need to be stripped.
+ // else if 565, 4444
+ // TBD: Can we assume these are supported if 8888 is?
+ // else if FP16 or 1010102
+ // strip colorspace from attribs.
+ // endif
+ if (a == 0) {
+ if (colorDepth <= 16) {
+ format = HAL_PIXEL_FORMAT_RGB_565;
+ } else {
+ if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+ if (colorDepth > 24) {
+ format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBX_8888;
+ }
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ }
+ }
+ } else {
+ if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+ if (colorDepth > 24) {
+ format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_8888;
+ }
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ }
+ }
+}
+
EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
NativeWindowType window,
const EGLint *attrib_list)
@@ -491,60 +693,22 @@
return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
}
- // Set the native window's buffers format to match what this config requests.
- // Whether to use sRGB gamma is not part of the EGLconfig, but is part
- // of our native format. So if sRGB gamma is requested, we have to
- // modify the EGLconfig's format before setting the native window's
- // format.
-
- EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_COLOR_COMPONENT_TYPE_EXT,
- &componentType);
-
EGLint format;
- android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;
- EGLint a = 0;
- EGLint r, g, b;
- r = g = b = 0;
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE, &r);
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g);
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE, &b);
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a);
- EGLint colorDepth = r + g + b;
+ getNativePixelFormat(iDpy, cnx, config, format);
- if (a == 0) {
- if (colorDepth <= 16) {
- format = HAL_PIXEL_FORMAT_RGB_565;
- } else {
- if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
- if (colorDepth > 24) {
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
- } else {
- format = HAL_PIXEL_FORMAT_RGBX_8888;
- }
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_FP16;
- }
- }
- } else {
- if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
- if (colorDepth > 24) {
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_8888;
- }
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_FP16;
- }
+ // now select correct colorspace and dataspace based on user's attribute list
+ EGLint colorSpace;
+ android_dataspace dataSpace;
+ if (!getColorSpaceAttribute(dp, window, attrib_list, colorSpace, dataSpace)) {
+ ALOGE("error invalid colorspace: %d", colorSpace);
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
- // now select a corresponding sRGB format if needed
- if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
- for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
- if (*attr == EGL_GL_COLORSPACE_KHR) {
- dataSpace = modifyBufferDataspace(dataSpace, *(attr+1));
- }
- }
+ std::vector<EGLint> strippedAttribList;
+ if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+ // Had to modify the attribute list due to use of color space.
+ // Use modified list from here on.
+ attrib_list = strippedAttribList.data();
}
if (format != 0) {
@@ -575,8 +739,8 @@
EGLSurface surface = cnx->egl.eglCreateWindowSurface(
iDpy, config, window, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dp.get(), config, window,
- surface, cnx);
+ egl_surface_t* s =
+ new egl_surface_t(dp.get(), config, window, surface, colorSpace, cnx);
return s;
}
@@ -595,12 +759,19 @@
egl_connection_t* cnx = NULL;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ EGLint colorSpace;
+ android_dataspace dataSpace;
if (dp) {
+ // now select a corresponding sRGB format if needed
+ if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+ ALOGE("error invalid colorspace: %d", colorSpace);
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
dp->disp.dpy, config, pixmap, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
- surface, cnx);
+ egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx);
return s;
}
}
@@ -615,11 +786,32 @@
egl_connection_t* cnx = NULL;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
+ EGLDisplay iDpy = dp->disp.dpy;
+ EGLint format;
+ getNativePixelFormat(iDpy, cnx, config, format);
+
+ // now select correct colorspace and dataspace based on user's attribute list
+ EGLint colorSpace;
+ android_dataspace dataSpace;
+ if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+ ALOGE("error invalid colorspace: %d", colorSpace);
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
+ // Pbuffers are not displayed so we don't need to store the
+ // colorspace. We do need to filter out color spaces the
+ // driver doesn't know how to process.
+ std::vector<EGLint> strippedAttribList;
+ if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+ // Had to modify the attribute list due to use of color space.
+ // Use modified list from here on.
+ attrib_list = strippedAttribList.data();
+ }
+
EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
dp->disp.dpy, config, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
- surface, cnx);
+ egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx);
return s;
}
}
@@ -658,6 +850,10 @@
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
egl_surface_t const * const s = get_surface(surface);
+ if (attribute == EGL_GL_COLORSPACE_KHR) {
+ *value = s->getColorSpace();
+ return EGL_TRUE;
+ }
return s->cnx->egl.eglQuerySurface(
dp->disp.dpy, s->surface, attribute, value);
}
@@ -1729,13 +1925,22 @@
egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_NO_SURFACE;
+ EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
+ android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;
+ // TODO: Probably need to update EGL_KHR_stream_producer_eglsurface to
+ // indicate support for EGL_GL_COLORSPACE_KHR.
+ // now select a corresponding sRGB format if needed
+ if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+ ALOGE("error invalid colorspace: %d", colorSpace);
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) {
EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR(
dp->disp.dpy, config, stream, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
- surface, cnx);
+ egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx);
return s;
}
}
@@ -1886,8 +2091,15 @@
EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) {
clearError();
+ // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus
+ // this function cannot be implemented when this libEGL is built for
+ // vendors.
+#ifndef __ANDROID_VNDK__
if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
+#else
+ return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
+#endif
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index dc1a4af..579e422 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -26,6 +26,7 @@
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <thread>
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index b696920..4e5833a 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -30,6 +30,12 @@
#include "Loader.h"
#include <cutils/properties.h>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -192,6 +198,18 @@
mClientApiString = sClientApiString;
mExtensionString = gBuiltinExtensionString;
+
+ bool wideColorBoardConfig =
+ getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
+ false);
+
+ // Add wide-color extensions if device can support wide-color
+ if (wideColorBoardConfig) {
+ mExtensionString.append(
+ "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear "
+ "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 ");
+ }
+
char const* start = gExtensionString;
do {
// length of the extension name
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 6238780..837cfa9 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -55,12 +55,15 @@
// ----------------------------------------------------------------------------
-egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config,
- EGLNativeWindowType win, EGLSurface surface,
- egl_connection_t const* cnx) :
- egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx),
- connected(true)
-{
+egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win,
+ EGLSurface surface, EGLint colorSpace, egl_connection_t const* cnx)
+ : egl_object_t(dpy),
+ surface(surface),
+ config(config),
+ win(win),
+ cnx(cnx),
+ connected(true),
+ colorSpace(colorSpace) {
if (win) {
win->incStrong(this);
}
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 8988905..7c3075c 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -131,12 +131,12 @@
public:
typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
- egl_surface_t(egl_display_t* dpy, EGLConfig config,
- EGLNativeWindowType win, EGLSurface surface,
- egl_connection_t const* cnx);
+ egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, EGLSurface surface,
+ EGLint colorSpace, egl_connection_t const* cnx);
ANativeWindow* getNativeWindow() { return win; }
ANativeWindow* getNativeWindow() const { return win; }
+ EGLint getColorSpace() const { return colorSpace; }
// Try to keep the order of these fields and size unchanged. It's not public API, but
// it's not hard to imagine native games accessing them.
@@ -149,6 +149,7 @@
private:
bool connected;
void disconnect();
+ EGLint colorSpace;
};
class egl_context_t: public egl_object_t {
diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp
new file mode 100644
index 0000000..bf7aeb1
--- /dev/null
+++ b/opengl/tests/Android.bp
@@ -0,0 +1,4 @@
+subdirs = [
+ "hwc",
+ "lib",
+]
diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk
index 3ae3b4e..92d223c 100644
--- a/opengl/tests/Android.mk
+++ b/opengl/tests/Android.mk
@@ -12,7 +12,6 @@
gl_perf \
gl_yuvtex \
gralloc \
- hwc \
include \
lib \
linetex \
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 24b1315..62e6bd3 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -28,18 +28,17 @@
#include <gui/IGraphicBufferConsumer.h>
#include <gui/BufferQueue.h>
-#define PIXEL_FORMAT_FLOAT "EGL_EXT_pixel_format_float"
-
-bool hasEglPixelFormatFloat() {
- EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+bool hasEglExtension(EGLDisplay dpy, const char* extensionName) {
const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
- size_t cropExtLen = strlen(PIXEL_FORMAT_FLOAT);
+ size_t cropExtLen = strlen(extensionName);
size_t extsLen = strlen(exts);
- bool equal = !strcmp(PIXEL_FORMAT_FLOAT, exts);
- bool atStart = !strncmp(PIXEL_FORMAT_FLOAT " ", exts, cropExtLen + 1);
+ bool equal = !strcmp(extensionName, exts);
+ android::String8 extString(extensionName);
+ android::String8 space(" ");
+ bool atStart = !strncmp(extString + space, exts, cropExtLen + 1);
bool atEnd = (cropExtLen + 1) < extsLen &&
- !strcmp(" " PIXEL_FORMAT_FLOAT, exts + extsLen - (cropExtLen + 1));
- bool inMiddle = strstr(exts, " " PIXEL_FORMAT_FLOAT " ");
+ !strcmp(space + extString, exts + extsLen - (cropExtLen + 1));
+ bool inMiddle = strstr(exts, space + extString + space);
return equal || atStart || atEnd || inMiddle;
}
@@ -194,6 +193,176 @@
EXPECT_GE(components[3], 8);
}
+TEST_F(EGLTest, EGLDisplayP3) {
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLBoolean success;
+
+ if (!hasWideColorDisplay) {
+ // skip this test if device does not have wide-color display
+ return;
+ }
+
+ // Test that display-p3 extensions exist
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3"));
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear"));
+
+ // Use 8-bit to keep forcus on Display-P3 aspect
+ EGLint attrs[] = {
+ // clang-format off
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
+ EGL_NONE, EGL_NONE
+ // clang-format on
+ };
+ success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(1, numConfigs);
+
+ EGLint components[4];
+ EGLint value;
+ eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value);
+
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ EXPECT_EQ(components[0], 8);
+ EXPECT_EQ(components[1], 8);
+ EXPECT_EQ(components[2], 8);
+ EXPECT_EQ(components[3], 8);
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+ EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+ EGL_NONE, EGL_NONE
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, value);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
+TEST_F(EGLTest, EGLDisplayP31010102) {
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLBoolean success;
+
+ if (!hasWideColorDisplay) {
+ // skip this test if device does not have wide-color display
+ return;
+ }
+
+ // Test that display-p3 extensions exist
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3"));
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear"));
+
+ // Use 8-bit to keep forcus on Display-P3 aspect
+ EGLint attrs[] = {
+ // clang-format off
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+ EGL_RED_SIZE, 10,
+ EGL_GREEN_SIZE, 10,
+ EGL_BLUE_SIZE, 10,
+ EGL_ALPHA_SIZE, 2,
+ EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
+ EGL_NONE, EGL_NONE
+ // clang-format on
+ };
+ success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(1, numConfigs);
+
+ EGLint components[4];
+ EGLint value;
+ eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value);
+
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ EXPECT_EQ(components[0], 10);
+ EXPECT_EQ(components[1], 10);
+ EXPECT_EQ(components[2], 10);
+ EXPECT_EQ(components[3], 2);
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ // Create a EGLSurface
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+ EGLint winAttrs[] = {
+ // clang-format off
+ EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+ EGL_NONE, EGL_NONE
+ // clang-format on
+ };
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, value);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
TEST_F(EGLTest, EGLConfigFP16) {
EGLint numConfigs;
EGLConfig config;
@@ -204,23 +373,20 @@
return;
}
- ASSERT_TRUE(hasEglPixelFormatFloat());
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_pixel_format_float"));
- EGLint attrs[] = {EGL_SURFACE_TYPE,
- EGL_WINDOW_BIT,
- EGL_RENDERABLE_TYPE,
- EGL_OPENGL_ES2_BIT,
- EGL_RED_SIZE,
- 16,
- EGL_GREEN_SIZE,
- 16,
- EGL_BLUE_SIZE,
- 16,
- EGL_ALPHA_SIZE,
- 16,
- EGL_COLOR_COMPONENT_TYPE_EXT,
- EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
- EGL_NONE};
+ EGLint attrs[] = {
+ // clang-format off
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 16,
+ EGL_GREEN_SIZE, 16,
+ EGL_BLUE_SIZE, 16,
+ EGL_ALPHA_SIZE, 16,
+ EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
+ EGL_NONE, EGL_NONE
+ // clang-format on
+ };
success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(1, numConfigs);
@@ -251,6 +417,108 @@
void onSidebandStreamChanged() override {}
};
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ consumer->consumerConnect(new DummyConsumer, false);
+ sp<Surface> mSTC = new Surface(producer);
+ sp<ANativeWindow> mANW = mSTC;
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
+TEST_F(EGLTest, EGL_KHR_no_config_context) {
+ if (!hasWideColorDisplay) {
+ // skip this test if device does not have wide-color display
+ return;
+ }
+
+ ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_KHR_no_config_context"));
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
+ std::vector<EGLint> contextAttributes;
+ contextAttributes.reserve(4);
+ contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+ contextAttributes.push_back(2);
+ contextAttributes.push_back(EGL_NONE);
+ contextAttributes.push_back(EGL_NONE);
+
+ EGLContext eglContext = eglCreateContext(mEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT,
+ contextAttributes.data());
+ EXPECT_NE(EGL_NO_CONTEXT, eglContext);
+ EXPECT_EQ(EGL_SUCCESS, eglGetError());
+
+ if (eglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEglDisplay, eglContext);
+ }
+}
+
+// Emulate what a native application would do to create a
+// 10:10:10:2 surface.
+TEST_F(EGLTest, EGLConfig1010102) {
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLBoolean success;
+
+ if (!hasWideColorDisplay) {
+ // skip this test if device does not have wide-color display
+ return;
+ }
+
+ EGLint attrs[] = {
+ // clang-format off
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+ EGL_RED_SIZE, 10,
+ EGL_GREEN_SIZE, 10,
+ EGL_BLUE_SIZE, 10,
+ EGL_ALPHA_SIZE, 2,
+ EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
+ EGL_NONE, EGL_NONE
+ // clang-format on
+ };
+ success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(1, numConfigs);
+
+ EGLint components[4];
+ EGLint value;
+ eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value);
+
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ EXPECT_EQ(components[0], 10);
+ EXPECT_EQ(components[1], 10);
+ EXPECT_EQ(components[2], 10);
+ EXPECT_EQ(components[3], 2);
+
+ struct DummyConsumer : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+
// Create a EGLSurface
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
diff --git a/opengl/tests/configdump/configdump.cpp b/opengl/tests/configdump/configdump.cpp
index 2a94598..c423105 100644
--- a/opengl/tests/configdump/configdump.cpp
+++ b/opengl/tests/configdump/configdump.cpp
@@ -66,8 +66,7 @@
};
// clang-format on
-int main(int argc, char** argv)
-{
+int main(int /*argc*/, char** /*argv*/) {
EGLConfig* configs;
EGLint n;
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index 9f8d166..ee88667 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -30,6 +30,7 @@
#include <EGLUtils.h>
using namespace android;
+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
static void printGLString(const char *name, GLenum s) {
// fprintf(stderr, "printGLString %s, %d\n", name, s);
@@ -46,7 +47,8 @@
static void printEGLString(EGLDisplay dpy, const char *name, GLenum s) {
const char *v = (const char *) eglQueryString(dpy, s);
- fprintf(stderr, "GL %s = %s\n", name, v);
+ const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s);
+ fprintf(stderr, "GL %s = %s\nImplementationANDROID: %s\n", name, v, va);
}
static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
@@ -263,7 +265,7 @@
return true;
}
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
EGLBoolean returnValue;
EGLConfig myConfig = {0};
diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
index 98d8aa8..22128ab 100644
--- a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
+++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
@@ -331,7 +331,7 @@
printf("\n");
}
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
EGLBoolean returnValue;
EGLConfig myConfig = {0};
diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
index c923b07..fad26a6 100644
--- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
+++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
@@ -221,7 +221,7 @@
printf("\n");
}
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
EGLBoolean returnValue;
EGLConfig myConfig = {0};
diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp
new file mode 100644
index 0000000..425f374
--- /dev/null
+++ b/opengl/tests/hwc/Android.bp
@@ -0,0 +1,107 @@
+// Copyright (C) 2010 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_defaults {
+
+ name: "hwc_tests_defaults",
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
+
+cc_library_static {
+
+ name: "libhwcTest",
+ srcs: ["hwcTestLib.cpp"],
+
+ static_libs: [
+ "libarect",
+ "libglTest",
+ "libtestUtil",
+ ],
+ shared_libs: [
+ "libui",
+ "libnativewindow"
+ ],
+ defaults: ["hwc_tests_defaults"],
+}
+
+cc_defaults {
+
+ name: "hwc_lib_defaults",
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libhardware",
+ "liblog",
+ "libui",
+ "libutils",
+ "libnativewindow"
+ ],
+
+ static_libs: [
+ "libglTest",
+ "libhwcTest",
+ "libtestUtil",
+ ],
+}
+
+cc_test {
+
+ name: "hwcStress",
+ srcs: ["hwcStress.cpp"],
+
+ defaults: [
+ "hwc_lib_defaults",
+ "hwc_tests_defaults",
+ ],
+}
+
+cc_test {
+
+ name: "hwcRects",
+ srcs: ["hwcRects.cpp"],
+
+ defaults: [
+ "hwc_lib_defaults",
+ "hwc_tests_defaults",
+ ],
+}
+
+cc_test {
+
+ name: "hwcColorEquiv",
+ srcs: ["hwcColorEquiv.cpp"],
+
+ defaults: [
+ "hwc_lib_defaults",
+ "hwc_tests_defaults",
+ ],
+}
+
+cc_test {
+
+ name: "hwcCommit",
+ srcs: ["hwcCommit.cpp"],
+
+ defaults: [
+ "hwc_lib_defaults",
+ "hwc_tests_defaults",
+ ],
+}
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk
deleted file mode 100644
index 13337c2..0000000
--- a/opengl/tests/hwc/Android.mk
+++ /dev/null
@@ -1,150 +0,0 @@
-# Copyright (C) 2010 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE:= libhwcTest
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcTestLib.cpp
-LOCAL_C_INCLUDES += system/extras/tests/include \
- $(call include-path-for, opengl-tests-includes) \
-
-LOCAL_STATIC_LIBRARIES := libarect
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE:= hwcStress
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcStress.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv2 \
- libutils \
- liblog \
- libui \
- libhardware \
-
-LOCAL_STATIC_LIBRARIES := \
- libtestUtil \
- libglTest \
- libhwcTest \
-
-LOCAL_C_INCLUDES += \
- system/extras/tests/include \
- hardware/libhardware/include \
- $(call include-path-for, opengl-tests-includes) \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE:= hwcRects
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcRects.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv2 \
- libutils \
- liblog \
- libui \
- libhardware \
-
-LOCAL_STATIC_LIBRARIES := \
- libtestUtil \
- libglTest \
- libhwcTest \
-
-LOCAL_C_INCLUDES += \
- system/extras/tests/include \
- hardware/libhardware/include \
- $(call include-path-for, opengl-tests-includes) \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE:= hwcColorEquiv
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcColorEquiv.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv2 \
- libutils \
- liblog \
- libui \
- libhardware \
-
-LOCAL_STATIC_LIBRARIES := \
- libtestUtil \
- libglTest \
- libhwcTest \
-
-LOCAL_C_INCLUDES += \
- system/extras/tests/include \
- hardware/libhardware/include \
- $(call include-path-for, opengl-tests-includes) \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE:= hwcCommit
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcCommit.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv2 \
- libutils \
- liblog \
- libui \
- libhardware \
-
-LOCAL_STATIC_LIBRARIES := \
- libtestUtil \
- libglTest \
- libhwcTest \
-
-LOCAL_C_INCLUDES += \
- system/extras/tests/include \
- hardware/libhardware/include \
- $(call include-path-for, opengl-tests-includes) \
-
-include $(BUILD_NATIVE_TEST)
diff --git a/opengl/tests/lib/Android.bp b/opengl/tests/lib/Android.bp
new file mode 100644
index 0000000..2f6095d
--- /dev/null
+++ b/opengl/tests/lib/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2010 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_static {
+
+ name: "libglTest",
+ srcs: [
+ "glTestLib.cpp",
+ "WindowSurface.cpp",
+ ],
+ export_include_dirs: ["include"],
+
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+ shared_libs: ["libgui"],
+ static_libs: [
+ "libarect",
+ "libtestUtil",
+ ],
+
+}
diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk
deleted file mode 100644
index ea94bc1..0000000
--- a/opengl/tests/lib/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2010 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE:= libglTest
-LOCAL_SRC_FILES:= glTestLib.cpp WindowSurface.cpp
-LOCAL_C_INCLUDES += system/extras/tests/include \
- $(call include-path-for, opengl-tests-includes)
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-
-LOCAL_SHARED_LIBRARIES += libgui
-LOCAL_STATIC_LIBRARIES := libarect
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/opengl/tests/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h
similarity index 100%
rename from opengl/tests/include/EGLUtils.h
rename to opengl/tests/lib/include/EGLUtils.h
diff --git a/opengl/tests/include/WindowSurface.h b/opengl/tests/lib/include/WindowSurface.h
similarity index 100%
rename from opengl/tests/include/WindowSurface.h
rename to opengl/tests/lib/include/WindowSurface.h
diff --git a/opengl/tests/include/glTestLib.h b/opengl/tests/lib/include/glTestLib.h
similarity index 100%
rename from opengl/tests/include/glTestLib.h
rename to opengl/tests/lib/include/glTestLib.h
diff --git a/opengl/tools/glgen2/registry/egl.xml b/opengl/tools/glgen2/registry/egl.xml
index af13395..c2d3494 100755
--- a/opengl/tools/glgen2/registry/egl.xml
+++ b/opengl/tools/glgen2/registry/egl.xml
@@ -191,6 +191,7 @@
<enum value="((EGLSync)0)" name="EGL_NO_SYNC"/>
<enum value="((EGLSyncKHR)0)" name="EGL_NO_SYNC_KHR" alias="EGL_NO_SYNC"/>
<enum value="((EGLSyncNV)0)" name="EGL_NO_SYNC_NV" alias="EGL_NO_SYNC"/>
+ <enum value="EGL_CAST(EGLConfig,0)" name="EGL_NO_CONFIG_KHR"/>
<enum value="10000" name="EGL_DISPLAY_SCALING"/>
<enum value="0xFFFFFFFFFFFFFFFF" name="EGL_FOREVER" type="ull"/>
<enum value="0xFFFFFFFFFFFFFFFF" name="EGL_FOREVER_KHR" type="ull" alias="EGL_FOREVER"/>
@@ -739,7 +740,10 @@
<enum value="50000" name="EGL_METADATA_SCALING_EXT"/>
<unused start="0x334B" end="0x334F"/>
<enum value="0x3350" name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/>
- <unused start="0x3351" end="0x339F"/>
+ <unused start="0x3351" end="0x3361"/>
+ <enum value="0x3362" name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/>
+ <enum value="0x3363" name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/>
+ <unused start="0x3364" end="0x339F"/>
</enums>
<enums namespace="EGL" start="0x33A0" end="0x33AF" vendor="ANGLE" comment="Reserved for Shannon Woods (Bug 13175)">
@@ -1891,6 +1895,16 @@
<enum name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/>
</require>
</extension>
+ <extension name="EGL_EXT_gl_colorspace_display_p3_linear" supported="egl">
+ <require>
+ <enum name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/>
+ </require>
+ </extension>
+ <extension name="EGL_EXT_gl_colorspace_display_p3" supported="egl">
+ <require>
+ <enum name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/>
+ </require>
+ </extension>
<extension name="EGL_EXT_image_dma_buf_import" supported="egl">
<require>
<enum name="EGL_LINUX_DMA_BUF_EXT"/>
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
new file mode 100644
index 0000000..4fd98e2
--- /dev/null
+++ b/services/inputflinger/Android.bp
@@ -0,0 +1,51 @@
+// Copyright (C) 2013 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: "libinputflinger",
+
+ srcs: [
+ "EventHub.cpp",
+ "InputApplication.cpp",
+ "InputDispatcher.cpp",
+ "InputListener.cpp",
+ "InputManager.cpp",
+ "InputReader.cpp",
+ "InputWindow.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcrypto",
+ "libcutils",
+ "libinput",
+ "liblog",
+ "libutils",
+ "libui",
+ "libhardware_legacy",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ // TODO: Move inputflinger to its own process and mark it hidden
+ //-fvisibility=hidden
+ ],
+
+ export_include_dirs: ["."],
+}
+
+subdirs = [
+ "host",
+ "tests",
+]
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
deleted file mode 100644
index ed867d8..0000000
--- a/services/inputflinger/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- EventHub.cpp \
- InputApplication.cpp \
- InputDispatcher.cpp \
- InputListener.cpp \
- InputManager.cpp \
- InputReader.cpp \
- InputWindow.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libcrypto \
- libcutils \
- libinput \
- liblog \
- libutils \
- libui \
- libhardware_legacy
-
-
-# TODO: Move inputflinger to its own process and mark it hidden
-#LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-LOCAL_MODULE := libinputflinger
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index d2f8995..50589b4 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -150,7 +150,8 @@
fd(fd), id(id), path(path), identifier(identifier),
classes(0), configuration(NULL), virtualKeyMap(NULL),
ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
- timestampOverrideSec(0), timestampOverrideUsec(0) {
+ timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true),
+ isVirtual(fd < 0) {
memset(keyBitmask, 0, sizeof(keyBitmask));
memset(absBitmask, 0, sizeof(absBitmask));
memset(relBitmask, 0, sizeof(relBitmask));
@@ -173,6 +174,25 @@
}
}
+status_t EventHub::Device::enable() {
+ fd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+ if(fd < 0) {
+ ALOGE("could not open %s, %s\n", path.string(), strerror(errno));
+ return -errno;
+ }
+ enabled = true;
+ return OK;
+}
+
+status_t EventHub::Device::disable() {
+ close();
+ enabled = false;
+ return OK;
+}
+
+bool EventHub::Device::hasValidFd() {
+ return !isVirtual && enabled;
+}
// --- EventHub ---
@@ -286,7 +306,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
+ if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
@@ -337,7 +357,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) {
+ if (device && device->hasValidFd() && test_bit(scanCode, device->keyBitmask)) {
uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
memset(keyState, 0, sizeof(keyState));
if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
@@ -352,7 +372,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) {
+ if (device && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
Vector<int32_t> scanCodes;
device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
if (scanCodes.size() != 0) {
@@ -377,7 +397,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) {
+ if (device && device->hasValidFd() && test_bit(sw, device->swBitmask)) {
uint8_t swState[sizeof_bit_array(SW_MAX + 1)];
memset(swState, 0, sizeof(swState));
if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) {
@@ -395,7 +415,7 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
+ if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
@@ -532,7 +552,7 @@
void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) {
int32_t sc;
- if (device && !device->isVirtual() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
+ if (device && device->hasValidFd() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
struct input_event ev;
ev.time.tv_sec = 0;
ev.time.tv_usec = 0;
@@ -636,7 +656,7 @@
void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual()) {
+ if (device && device->hasValidFd()) {
ff_effect effect;
memset(&effect, 0, sizeof(effect));
effect.type = FF_RUMBLE;
@@ -670,7 +690,7 @@
void EventHub::cancelVibrate(int32_t deviceId) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual()) {
+ if (device && device->hasValidFd()) {
if (device->ffEffectPlaying) {
device->ffEffectPlaying = false;
@@ -1065,12 +1085,37 @@
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.u32 = device->id;
+ if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) {
+ ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
+ return -errno;
+ }
+ return OK;
+}
+
+status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) {
+ if (device->hasValidFd()) {
+ if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
+ ALOGW("Could not remove device fd from epoll instance. errno=%d", errno);
+ return -errno;
+ }
+ }
+ return OK;
+}
+
status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];
ALOGV("Opening device: %s", devicePath);
- int fd = open(devicePath, O_RDWR | O_CLOEXEC);
+ int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
if(fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
@@ -1135,13 +1180,6 @@
// Fill in the descriptor.
assignDescriptorLocked(identifier);
- // Make file descriptor non-blocking for use with poll().
- if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
- ALOGE("Error %d making device file descriptor non-blocking.", errno);
- close(fd);
- return -1;
- }
-
// Allocate device. (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
@@ -1303,12 +1341,6 @@
break;
}
}
-
- // Disable kernel key repeat since we handle it ourselves
- unsigned int repeatRate[] = {0,0};
- if (ioctl(fd, EVIOCSREP, repeatRate)) {
- ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno));
- }
}
// If the device isn't recognized as something we handle, don't monitor it.
@@ -1332,23 +1364,41 @@
if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD)
&& device->classes & INPUT_DEVICE_CLASS_GAMEPAD) {
device->controllerNumber = getNextControllerNumberLocked(device);
- setLedForController(device);
+ setLedForControllerLocked(device);
}
- // Register with epoll.
- struct epoll_event eventItem;
- memset(&eventItem, 0, sizeof(eventItem));
- eventItem.events = EPOLLIN;
- if (mUsingEpollWakeup) {
- eventItem.events |= EPOLLWAKEUP;
- }
- eventItem.data.u32 = deviceId;
- if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
- ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
+
+ if (registerDeviceForEpollLocked(device) != OK) {
delete device;
return -1;
}
+ configureFd(device);
+
+ ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
+ "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
+ deviceId, fd, devicePath, device->identifier.name.string(),
+ device->classes,
+ device->configurationFile.string(),
+ device->keyMap.keyLayoutFile.string(),
+ device->keyMap.keyCharacterMapFile.string(),
+ toString(mBuiltInKeyboardId == deviceId));
+
+ addDeviceLocked(device);
+ return OK;
+}
+
+void EventHub::configureFd(Device* device) {
+ // Set fd parameters with ioctl, such as key repeat, suspend block, and clock type
+ if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
+ // Disable kernel key repeat since we handle it ourselves
+ unsigned int repeatRate[] = {0, 0};
+ if (ioctl(device->fd, EVIOCSREP, repeatRate)) {
+ ALOGW("Unable to disable kernel key repeat for %s: %s",
+ device->path.string(), strerror(errno));
+ }
+ }
+
String8 wakeMechanism("EPOLLWAKEUP");
if (!mUsingEpollWakeup) {
#ifndef EVIOCSSUSPENDBLOCK
@@ -1357,44 +1407,67 @@
// this feature, we need to be prepared to define the ioctl ourselves.
#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int)
#endif
- if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) {
+ if (ioctl(device->fd, EVIOCSSUSPENDBLOCK, 1)) {
wakeMechanism = "<none>";
} else {
wakeMechanism = "EVIOCSSUSPENDBLOCK";
}
}
-
// Tell the kernel that we want to use the monotonic clock for reporting timestamps
// associated with input events. This is important because the input system
// uses the timestamps extensively and assumes they were recorded using the monotonic
// clock.
- //
- // In older kernel, before Linux 3.4, there was no way to tell the kernel which
- // clock to use to input event timestamps. The standard kernel behavior was to
- // record a real time timestamp, which isn't what we want. Android kernels therefore
- // contained a patch to the evdev_event() function in drivers/input/evdev.c to
- // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic
- // clock to be used instead of the real time clock.
- //
- // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock.
- // Therefore, we no longer require the Android-specific kernel patch described above
- // as long as we make sure to set select the monotonic clock. We do that here.
int clockId = CLOCK_MONOTONIC;
- bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);
+ bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId);
+ ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.string(),
+ toString(usingClockIoctl));
+}
- ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
- "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
- "wakeMechanism=%s, usingClockIoctl=%s",
- deviceId, fd, devicePath, device->identifier.name.string(),
- device->classes,
- device->configurationFile.string(),
- device->keyMap.keyLayoutFile.string(),
- device->keyMap.keyCharacterMapFile.string(),
- toString(mBuiltInKeyboardId == deviceId),
- wakeMechanism.string(), toString(usingClockIoctl));
+bool EventHub::isDeviceEnabled(int32_t deviceId) {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device == NULL) {
+ ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
+ return false;
+ }
+ return device->enabled;
+}
- addDeviceLocked(device);
- return 0;
+status_t EventHub::enableDevice(int32_t deviceId) {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device == NULL) {
+ ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
+ return BAD_VALUE;
+ }
+ if (device->enabled) {
+ ALOGW("Duplicate call to %s, input device %" PRId32 " already enabled", __func__, deviceId);
+ return OK;
+ }
+ status_t result = device->enable();
+ if (result != OK) {
+ ALOGE("Failed to enable device %" PRId32, deviceId);
+ return result;
+ }
+
+ configureFd(device);
+
+ return registerDeviceForEpollLocked(device);
+}
+
+status_t EventHub::disableDevice(int32_t deviceId) {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device == NULL) {
+ ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
+ return BAD_VALUE;
+ }
+ if (!device->enabled) {
+ ALOGW("Duplicate call to %s, input device already disabled", __func__);
+ return OK;
+ }
+ unregisterDeviceFromEpollLocked(device);
+ return device->disable();
}
void EventHub::createVirtualKeyboardLocked() {
@@ -1490,7 +1563,7 @@
mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1));
}
-void EventHub::setLedForController(Device* device) {
+void EventHub::setLedForControllerLocked(Device* device) {
for (int i = 0; i < MAX_CONTROLLER_LEDS; i++) {
setLedStateLocked(device, ALED_CONTROLLER_1 + i, device->controllerNumber == i + 1);
}
@@ -1500,7 +1573,7 @@
if (!device->keyMap.haveKeyLayout()) {
return false;
}
-
+
Vector<int32_t> scanCodes;
device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
const size_t N = scanCodes.size();
@@ -1510,7 +1583,7 @@
return true;
}
}
-
+
return false;
}
@@ -1556,11 +1629,7 @@
mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
}
- if (!device->isVirtual()) {
- if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
- ALOGW("Could not remove device fd from epoll instance. errno=%d", errno);
- }
- }
+ unregisterDeviceFromEpollLocked(device);
releaseControllerNumberLocked(device);
@@ -1691,6 +1760,7 @@
}
dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
+ dump.appendFormat(INDENT3 "Enabled: %s\n", toString(device->enabled));
dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 6869253..727b73a 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -25,9 +25,8 @@
#include <input/KeyCharacterMap.h>
#include <input/VirtualKeyMap.h>
#include <utils/String8.h>
-#include <utils/threads.h>
+#include <utils/Mutex.h>
#include <utils/Log.h>
-#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Errors.h>
#include <utils/PropertyMap.h>
@@ -267,6 +266,15 @@
/* Called by the heatbeat to ensures that the reader has not deadlocked. */
virtual void monitor() = 0;
+
+ /* Return true if the device is enabled. */
+ virtual bool isDeviceEnabled(int32_t deviceId) = 0;
+
+ /* Enable an input device */
+ virtual status_t enableDevice(int32_t deviceId) = 0;
+
+ /* Disable an input device. Closes file descriptor to that device. */
+ virtual status_t disableDevice(int32_t deviceId) = 0;
};
class EventHub : public EventHubInterface
@@ -335,7 +343,7 @@
struct Device {
Device* next;
- int fd; // may be -1 if device is virtual
+ int fd; // may be -1 if device is closed
const int32_t id;
const String8 path;
const InputDeviceIdentifier identifier;
@@ -371,7 +379,11 @@
void close();
- inline bool isVirtual() const { return fd < 0; }
+ bool enabled; // initially true
+ status_t enable();
+ status_t disable();
+ bool hasValidFd();
+ const bool isVirtual; // set if fd < 0 is passed to constructor
const sp<KeyCharacterMap>& getKeyCharacterMap() const {
if (combinedKeyMap != NULL) {
@@ -390,6 +402,14 @@
void closeDeviceLocked(Device* device);
void closeAllDevicesLocked();
+ void configureFd(Device* device);
+
+ bool isDeviceEnabled(int32_t deviceId);
+ status_t enableDevice(int32_t deviceId);
+ status_t disableDevice(int32_t deviceId);
+ status_t registerDeviceForEpollLocked(Device* device);
+ status_t unregisterDeviceFromEpollLocked(Device* device);
+
status_t scanDirLocked(const char *dirname);
void scanDevicesLocked();
status_t readNotifyLocked();
@@ -409,7 +429,7 @@
int32_t getNextControllerNumberLocked(Device* device);
void releaseControllerNumberLocked(Device* device);
- void setLedForController(Device* device);
+ void setLedForControllerLocked(Device* device);
status_t mapLed(Device* device, int32_t led, int32_t* outScanCode) const;
void setLedStateLocked(Device* device, int32_t led, bool on);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2efb340..69067d2 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -869,10 +869,7 @@
return true;
}
- // TODO: support sending secondary display events to input monitors
- if (isMainDisplay(entry->displayId)) {
- addMonitoringTargetsLocked(inputTargets);
- }
+ addMonitoringTargetsLocked(inputTargets);
// Dispatch the motion.
if (conflictingPointerActions) {
@@ -2026,7 +2023,7 @@
// Publish the motion event.
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
- motionEntry->deviceId, motionEntry->source,
+ motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
motionEntry->metaState, motionEntry->buttonState,
@@ -2600,8 +2597,9 @@
uint32_t policyFlags) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x",
- event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags);
+ "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x, displayId=%d",
+ event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags,
+ displayId);
#endif
nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 73255dd..cc81a29 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -835,6 +835,18 @@
}
}
+bool InputReader::isInputDeviceEnabled(int32_t deviceId) {
+ AutoMutex _l(mLock);
+
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex >= 0) {
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ return device->isEnabled();
+ }
+ ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId);
+ return false;
+}
+
void InputReader::dump(String8& dump) {
AutoMutex _l(mLock);
@@ -1011,6 +1023,26 @@
mMappers.clear();
}
+bool InputDevice::isEnabled() {
+ return getEventHub()->isDeviceEnabled(mId);
+}
+
+void InputDevice::setEnabled(bool enabled, nsecs_t when) {
+ if (isEnabled() == enabled) {
+ return;
+ }
+
+ if (enabled) {
+ getEventHub()->enableDevice(mId);
+ reset(when);
+ } else {
+ reset(when);
+ getEventHub()->disableDevice(mId);
+ }
+ // Must change generation to flag this device as changed
+ bumpGeneration();
+}
+
void InputDevice::dump(String8& dump) {
InputDeviceInfo deviceInfo;
getDeviceInfo(& deviceInfo);
@@ -1082,6 +1114,12 @@
}
}
+ if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) {
+ ssize_t index = config->disabledDevices.indexOf(mId);
+ bool enabled = index < 0;
+ setEnabled(enabled, when);
+ }
+
size_t numMappers = mMappers.size();
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
@@ -2291,6 +2329,35 @@
|| (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
}
+bool KeyboardInputMapper::isMediaKey(int32_t keyCode) {
+ switch (keyCode) {
+ case AKEYCODE_MEDIA_PLAY:
+ case AKEYCODE_MEDIA_PAUSE:
+ case AKEYCODE_MEDIA_PLAY_PAUSE:
+ case AKEYCODE_MUTE:
+ case AKEYCODE_HEADSETHOOK:
+ case AKEYCODE_MEDIA_STOP:
+ case AKEYCODE_MEDIA_NEXT:
+ case AKEYCODE_MEDIA_PREVIOUS:
+ case AKEYCODE_MEDIA_REWIND:
+ case AKEYCODE_MEDIA_RECORD:
+ case AKEYCODE_MEDIA_FAST_FORWARD:
+ case AKEYCODE_MEDIA_SKIP_FORWARD:
+ case AKEYCODE_MEDIA_SKIP_BACKWARD:
+ case AKEYCODE_MEDIA_STEP_FORWARD:
+ case AKEYCODE_MEDIA_STEP_BACKWARD:
+ case AKEYCODE_MEDIA_AUDIO_TRACK:
+ case AKEYCODE_VOLUME_UP:
+ case AKEYCODE_VOLUME_DOWN:
+ case AKEYCODE_VOLUME_MUTE:
+ case AKEYCODE_TV_AUDIO_DESCRIPTION:
+ case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
+ case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
+ return true;
+ }
+ return false;
+}
+
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
int32_t usageCode) {
int32_t keyCode;
@@ -2364,7 +2431,7 @@
// For internal keyboards, the key layout file should specify the policy flags for
// each wake key individually.
// TODO: Use the input device configuration to control this behavior more finely.
- if (down && getDevice()->isExternal()) {
+ if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) {
policyFlags |= POLICY_FLAG_WAKE;
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index edb6fcc..c4f786a 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -27,11 +27,14 @@
#include <input/VelocityTracker.h>
#include <ui/DisplayInfo.h>
#include <utils/KeyedVector.h>
-#include <utils/threads.h>
+#include <utils/Condition.h>
+#include <utils/Thread.h>
+#include <utils/Mutex.h>
#include <utils/Timers.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/BitSet.h>
+#include <utils/SortedVector.h>
#include <stddef.h>
#include <unistd.h>
@@ -84,6 +87,9 @@
// The pointer capture mode has changed.
CHANGE_POINTER_CAPTURE = 1 << 8,
+ // The set of disabled input devices (disabledDevices) has changed.
+ CHANGE_ENABLED_STATE = 1 << 9,
+
// All devices must be reopened.
CHANGE_MUST_REOPEN = 1 << 31,
};
@@ -174,6 +180,9 @@
// True if pointer capture is enabled.
bool pointerCapture;
+ // The set of currently disabled input devices.
+ SortedVector<int32_t> disabledDevices;
+
InputReaderConfiguration() :
virtualKeyQuietTime(0),
pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f),
@@ -288,6 +297,9 @@
/* Called by the heatbeat to ensures that the reader has not deadlocked. */
virtual void monitor() = 0;
+ /* Returns true if the input device is enabled. */
+ virtual bool isInputDeviceEnabled(int32_t deviceId) = 0;
+
/* Runs a single iteration of the processing loop.
* Nominally reads and processes one incoming message from the EventHub.
*
@@ -407,6 +419,8 @@
virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices);
+ virtual bool isInputDeviceEnabled(int32_t deviceId);
+
virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
int32_t scanCode);
virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
@@ -552,6 +566,9 @@
inline bool isIgnored() { return mMappers.isEmpty(); }
+ bool isEnabled();
+ void setEnabled(bool enabled, nsecs_t when);
+
void dump(String8& dump);
void addMapper(InputMapper* mapper);
void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
@@ -1111,6 +1128,7 @@
void dumpParameters(String8& dump);
bool isKeyboardOrGamepadKey(int32_t scanCode);
+ bool isMediaKey(int32_t keyCode);
void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode);
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index 5e82d75..b54752b 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -46,8 +46,10 @@
|| layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
|| layoutParamsType == TYPE_STATUS_BAR
|| layoutParamsType == TYPE_NAVIGATION_BAR
+ || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
- || layoutParamsType == TYPE_DOCK_DIVIDER;
+ || layoutParamsType == TYPE_DOCK_DIVIDER
+ || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY;
}
bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index feca6cf..610290b 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -101,7 +101,9 @@
TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
- TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+22,
+ TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
+ TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
+ TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34,
LAST_SYSTEM_WINDOW = 2999,
};
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
new file mode 100644
index 0000000..b8e9bce
--- /dev/null
+++ b/services/inputflinger/host/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2015 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: "libinputflingerhost",
+
+ srcs: [
+ "InputFlinger.cpp",
+ "InputDriver.cpp",
+ "InputHost.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcrypto",
+ "libcutils",
+ "libinput",
+ "liblog",
+ "libutils",
+ "libhardware",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ // TODO: Move inputflinger to its own process and mark it hidden
+ //-fvisibility=hidden
+ ],
+
+ export_include_dirs: ["."],
+}
+
+//#######################################################################
+// build input flinger executable
+cc_binary {
+ name: "inputflinger",
+
+ srcs: ["main.cpp"],
+
+ shared_libs: [
+ "libbinder",
+ "libinputflingerhost",
+ "libutils",
+ ],
+
+ init_rc: ["inputflinger.rc"],
+}
diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk
deleted file mode 100644
index 0a7fc27..0000000
--- a/services/inputflinger/host/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_SRC_FILES:= \
- InputFlinger.cpp \
- InputDriver.cpp \
- InputHost.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libcrypto \
- libcutils \
- libinput \
- liblog \
- libutils \
- libhardware
-
-
-# TODO: Move inputflinger to its own process and mark it hidden
-#LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-LOCAL_MODULE := libinputflingerhost
-
-include $(BUILD_SHARED_LIBRARY)
-
-########################################################################
-# build input flinger executable
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_SRC_FILES:= \
- main.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libinputflingerhost \
- libutils
-
-LOCAL_MODULE := inputflinger
-LOCAL_INIT_RC := inputflinger.rc
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
new file mode 100644
index 0000000..29d93f0
--- /dev/null
+++ b/services/inputflinger/tests/Android.bp
@@ -0,0 +1,23 @@
+// Build the unit tests.
+
+cc_test {
+ name: "inputflinger_tests",
+ srcs: [
+ "InputReader_test.cpp",
+ "InputDispatcher_test.cpp",
+ ],
+ test_per_src: true,
+ cflags: ["-Wno-unused-parameter"],
+ shared_libs = [
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "libhardware_legacy",
+ "libui",
+ "libskia",
+ "libinput",
+ "libinputflinger",
+ "libinputservice",
+ ],
+}
diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk
deleted file mode 100644
index 4c43392..0000000
--- a/services/inputflinger/tests/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# Build the unit tests.
-test_src_files := \
- InputReader_test.cpp \
- InputDispatcher_test.cpp
-
-shared_libraries := \
- libcutils \
- liblog \
- libutils \
- libhardware \
- libhardware_legacy \
- libui \
- libskia \
- libinput \
- libinputflinger \
- libinputservice
-
-c_includes := \
- external/skia/include/core
-
-
-module_tags := tests
-
-$(foreach file,$(test_src_files), \
- $(eval include $(CLEAR_VARS)) \
- $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
- $(eval LOCAL_C_INCLUDES := $(c_includes)) \
- $(eval LOCAL_CFLAGS += -Wno-unused-parameter) \
- $(eval LOCAL_SRC_FILES := $(file)) \
- $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
- $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
- $(eval include $(BUILD_NATIVE_TEST)) \
-)
-
-# Build the manual test programs.
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index dcfe114..76291a5 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -16,6 +16,7 @@
#include "../InputReader.h"
+#include <inttypes.h>
#include <utils/List.h>
#include <gtest/gtest.h>
#include <math.h>
@@ -159,6 +160,22 @@
mConfig.excludedDeviceNames.push(deviceName);
}
+ void addDisabledDevice(int32_t deviceId) {
+ ssize_t index = mConfig.disabledDevices.indexOf(deviceId);
+ bool currentlyEnabled = index < 0;
+ if (currentlyEnabled) {
+ mConfig.disabledDevices.add(deviceId);
+ }
+ }
+
+ void removeDisabledDevice(int32_t deviceId) {
+ ssize_t index = mConfig.disabledDevices.indexOf(deviceId);
+ bool currentlyEnabled = index < 0;
+ if (!currentlyEnabled) {
+ mConfig.disabledDevices.remove(deviceId);
+ }
+ }
+
void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) {
mPointerControllers.add(deviceId, controller);
}
@@ -255,6 +272,11 @@
mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin());
}
+ void assertNotifyConfigurationChangedWasNotCalled() {
+ ASSERT_TRUE(mNotifyConfigurationChangedArgsQueue.empty())
+ << "Expected notifyConfigurationChanged() to not have been called.";
+ }
+
void assertNotifyDeviceResetWasCalled(
NotifyDeviceResetArgs* outEventArgs = NULL) {
ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty())
@@ -265,6 +287,11 @@
mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin());
}
+ void assertNotifyDeviceResetWasNotCalled() {
+ ASSERT_TRUE(mNotifyDeviceResetArgsQueue.empty())
+ << "Expected notifyDeviceReset() to not have been called.";
+ }
+
void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) {
ASSERT_FALSE(mNotifyKeyArgsQueue.empty())
<< "Expected notifyKey() to have been called.";
@@ -347,9 +374,20 @@
KeyedVector<int32_t, KeyInfo> keysByUsageCode;
KeyedVector<int32_t, bool> leds;
Vector<VirtualKeyDefinition> virtualKeys;
+ bool enabled;
+
+ status_t enable() {
+ enabled = true;
+ return OK;
+ }
+
+ status_t disable() {
+ enabled = false;
+ return OK;
+ }
explicit Device(uint32_t classes) :
- classes(classes) {
+ classes(classes), enabled(true) {
}
};
@@ -382,6 +420,43 @@
enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0);
}
+ bool isDeviceEnabled(int32_t deviceId) {
+ Device* device = getDevice(deviceId);
+ if (device == NULL) {
+ ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
+ return false;
+ }
+ return device->enabled;
+ }
+
+ status_t enableDevice(int32_t deviceId) {
+ status_t result;
+ Device* device = getDevice(deviceId);
+ if (device == NULL) {
+ ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
+ return BAD_VALUE;
+ }
+ if (device->enabled) {
+ ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId);
+ return OK;
+ }
+ result = device->enable();
+ return result;
+ }
+
+ status_t disableDevice(int32_t deviceId) {
+ Device* device = getDevice(deviceId);
+ if (device == NULL) {
+ ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
+ return BAD_VALUE;
+ }
+ if (!device->enabled) {
+ ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId);
+ return OK;
+ }
+ return device->disable();
+ }
+
void finishDeviceScan() {
enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0);
}
@@ -1039,6 +1114,20 @@
mFakeEventHub->assertQueueIsEmpty();
}
+ void disableDevice(int32_t deviceId, InputDevice* device) {
+ mFakePolicy->addDisabledDevice(deviceId);
+ configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE, device);
+ }
+
+ void enableDevice(int32_t deviceId, InputDevice* device) {
+ mFakePolicy->removeDisabledDevice(deviceId);
+ configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE, device);
+ }
+
+ void configureDevice(uint32_t changes, InputDevice* device) {
+ device->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
+ }
+
FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
const String8& name, uint32_t classes, uint32_t sources,
const PropertyMap* configuration) {
@@ -1077,6 +1166,46 @@
ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
}
+TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
+ constexpr int32_t deviceId = 1;
+ constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ InputDevice* device = mReader->newDevice(deviceId, 0, String8("fake"), deviceClass);
+ // Must add at least one mapper or the device will be ignored!
+ FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
+ device->addMapper(mapper);
+ mReader->setNextDevice(device);
+ addDevice(deviceId, String8("fake"), deviceClass, NULL);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(NULL));
+
+ NotifyDeviceResetArgs resetArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+ ASSERT_EQ(deviceId, resetArgs.deviceId);
+
+ ASSERT_EQ(device->isEnabled(), true);
+ disableDevice(deviceId, device);
+ mReader->loopOnce();
+
+ mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs);
+ ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+ ASSERT_EQ(deviceId, resetArgs.deviceId);
+ ASSERT_EQ(device->isEnabled(), false);
+
+ disableDevice(deviceId, device);
+ mReader->loopOnce();
+ mFakeListener->assertNotifyDeviceResetWasNotCalled();
+ mFakeListener->assertNotifyConfigurationChangedWasNotCalled();
+ ASSERT_EQ(device->isEnabled(), false);
+
+ enableDevice(deviceId, device);
+ mReader->loopOnce();
+ mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs);
+ ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+ ASSERT_EQ(deviceId, resetArgs.deviceId);
+ ASSERT_EQ(device->isEnabled(), true);
+}
+
TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
FakeInputMapper* mapper = NULL;
ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
@@ -1274,6 +1403,10 @@
ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses());
}
+TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsTrue) {
+ ASSERT_EQ(mDevice->isEnabled(), true);
+}
+
TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) {
// Configuration.
InputReaderConfiguration config;
diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp
index 1f1340c..ca91b8e 100644
--- a/services/schedulerservice/Android.bp
+++ b/services/schedulerservice/Android.bp
@@ -10,7 +10,6 @@
"libmediautils",
"liblog",
"libutils",
- "android.hidl.base@1.0",
"android.frameworks.schedulerservice@1.0",
],
header_libs: [
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 8c2300e..8d381b1 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -1,3 +1,73 @@
subdirs = [
"hidl"
]
+cc_library_shared {
+ name: "libsensorservice",
+
+ srcs: [
+ "BatteryService.cpp",
+ "CorrectedGyroSensor.cpp",
+ "Fusion.cpp",
+ "GravitySensor.cpp",
+ "LinearAccelerationSensor.cpp",
+ "OrientationSensor.cpp",
+ "RecentEventLogger.cpp",
+ "RotationVectorSensor.cpp",
+ "SensorDevice.cpp",
+ "SensorDirectConnection.cpp",
+ "SensorEventConnection.cpp",
+ "SensorFusion.cpp",
+ "SensorInterface.cpp",
+ "SensorList.cpp",
+ "SensorRecord.cpp",
+ "SensorService.cpp",
+ "SensorServiceUtils.cpp",
+ ],
+
+ cflags: [
+ "-DLOG_TAG=\"SensorService\"",
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-fvisibility=hidden"
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "libhardware",
+ "libhardware_legacy",
+ "libutils",
+ "liblog",
+ "libbinder",
+ "libsensor",
+ "libcrypto",
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "android.hardware.sensors@1.0",
+ ],
+
+ static_libs: ["android.hardware.sensors@1.0-convert"],
+
+ // our public headers depend on libsensor
+ export_shared_lib_headers: ["libsensor"],
+}
+
+cc_binary {
+ name: "sensorservice",
+
+ srcs: ["main_sensorservice.cpp"],
+
+ shared_libs: [
+ "libsensorservice",
+ "libbinder",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
deleted file mode 100644
index cfb7231..0000000
--- a/services/sensorservice/Android.mk
+++ /dev/null
@@ -1,73 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- BatteryService.cpp \
- CorrectedGyroSensor.cpp \
- Fusion.cpp \
- GravitySensor.cpp \
- LinearAccelerationSensor.cpp \
- OrientationSensor.cpp \
- RecentEventLogger.cpp \
- RotationVectorSensor.cpp \
- SensorDevice.cpp \
- SensorDirectConnection.cpp \
- SensorEventConnection.cpp \
- SensorFusion.cpp \
- SensorInterface.cpp \
- SensorList.cpp \
- SensorRecord.cpp \
- SensorService.cpp \
- SensorServiceUtils.cpp \
-
-LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
-
-LOCAL_CFLAGS += -Wall -Werror -Wextra
-
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libhardware \
- libhardware_legacy \
- libutils \
- liblog \
- libbinder \
- libsensor \
- libcrypto \
- libbase \
- libhidlbase \
- libhidltransport \
- libhwbinder \
- android.hardware.sensors@1.0
-
-LOCAL_STATIC_LIBRARIES := \
- android.hardware.sensors@1.0-convert
-
-# our public headers depend on libsensor
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
- libsensor \
-
-LOCAL_MODULE:= libsensorservice
-
-include $(BUILD_SHARED_LIBRARY)
-
-#####################################################################
-# build executable
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- main_sensorservice.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libsensorservice \
- libbinder \
- libutils
-
-LOCAL_CFLAGS := -Wall -Werror -Wextra
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= sensorservice
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 870635b..538d728 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -27,12 +27,21 @@
const String16& opPackageName)
: mService(service), mUid(uid), mMem(*mem),
mHalChannelHandle(halChannelHandle),
- mOpPackageName(opPackageName) {
+ mOpPackageName(opPackageName), mDestroyed(false) {
ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
}
SensorService::SensorDirectConnection::~SensorDirectConnection() {
ALOGD_IF(DEBUG_CONNECTIONS, "~SensorDirectConnection %p", this);
+ destroy();
+}
+
+void SensorService::SensorDirectConnection::destroy() {
+ Mutex::Autolock _l(mDestroyLock);
+ // destroy once only
+ if (mDestroyed) {
+ return;
+ }
stopAll();
mService->cleanupConnection(this);
@@ -40,6 +49,7 @@
native_handle_close(mMem.handle);
native_handle_delete(const_cast<struct native_handle*>(mMem.handle));
}
+ mDestroyed = true;
}
void SensorService::SensorDirectConnection::onFirstRef() {
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 27458d4..5c398a8 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -47,7 +47,7 @@
// stop all active sensor report. if backupRecord is set to false,
// those report can be recovered by recoverAll
// called by SensorService when enter restricted mode
- void stopAll(bool clearRecord = false);
+ void stopAll(bool backupRecord = false);
// recover sensor reports previously stopped by stopAll(true)
// called by SensorService when return to NORMAL mode.
@@ -63,7 +63,7 @@
virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
virtual status_t flush();
virtual int32_t configureChannel(int handle, int rateLevel);
-
+ virtual void destroy();
private:
const sp<SensorService> mService;
const uid_t mUid;
@@ -74,6 +74,9 @@
mutable Mutex mConnectionLock;
std::unordered_map<int, int> mActivated;
std::unordered_map<int, int> mActivatedBackup;
+
+ mutable Mutex mDestroyLock;
+ bool mDestroyed;
};
} // namepsace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index fad046c..0a05dd1 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -32,7 +32,8 @@
const String16& opPackageName)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
- mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) {
+ mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
+ mDestroyed(false) {
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -42,10 +43,22 @@
SensorService::SensorEventConnection::~SensorEventConnection() {
ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
+ destroy();
+}
+
+void SensorService::SensorEventConnection::destroy() {
+ Mutex::Autolock _l(mDestroyLock);
+
+ // destroy once only
+ if (mDestroyed) {
+ return;
+ }
+
mService->cleanupConnection(this);
if (mEventCache != NULL) {
delete mEventCache;
}
+ mDestroyed = true;
}
void SensorService::SensorEventConnection::onFirstRef() {
@@ -477,7 +490,14 @@
// separately before the next batch of events.
for (int j = 0; j < numEventsDropped; ++j) {
if (scratch[j].type == SENSOR_TYPE_META_DATA) {
- FlushInfo& flushInfo = mSensorInfo.editValueFor(scratch[j].meta_data.sensor);
+ ssize_t index = mSensorInfo.indexOfKey(scratch[j].meta_data.sensor);
+ if (index < 0) {
+ ALOGW("%s: sensor 0x%x is not found in connection",
+ __func__, scratch[j].meta_data.sensor);
+ continue;
+ }
+
+ FlushInfo& flushInfo = mSensorInfo.editValueAt(index);
flushInfo.mPendingFlushEventsToSend++;
ALOGD_IF(DEBUG_CONNECTIONS, "increment pendingFlushCount %d",
flushInfo.mPendingFlushEventsToSend);
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index c81e015..6f282cd 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -75,6 +75,7 @@
virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
virtual status_t flush();
virtual int32_t configureChannel(int handle, int rateLevel);
+ virtual void destroy();
// Count the number of flush complete events which are about to be dropped in the buffer.
// Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be sent
@@ -164,6 +165,8 @@
int mTotalAcksNeeded, mTotalAcksReceived;
#endif
+ mutable Mutex mDestroyLock;
+ bool mDestroyed;
};
} // namepsace android
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index ab08cac..aa306d8 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -124,14 +124,15 @@
forEachSensor([&result] (const Sensor& s) -> bool {
result.appendFormat(
"%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32
- ") | perm: %s\n",
+ ") | perm: %s | flags: 0x%08x\n",
s.getHandle(),
s.getName().string(),
s.getVendor().string(),
s.getVersion(),
s.getStringType().string(),
s.getType(),
- s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a");
+ s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a",
+ static_cast<int>(s.getFlags()));
result.append("\t");
const int reportingMode = s.getReportingMode();
@@ -173,9 +174,14 @@
result.appendFormat("non-wakeUp | ");
}
+ if (s.isDataInjectionSupported()) {
+ result.appendFormat("data-injection, ");
+ }
+
if (s.isDynamicSensor()) {
result.appendFormat("dynamic, ");
}
+
if (s.hasAdditionalInfo()) {
result.appendFormat("has-additional-info, ");
}
@@ -190,7 +196,6 @@
if (s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_GRALLOC)) {
result.append("gralloc, ");
}
- result.appendFormat("flag =0x%08x", static_cast<int>(s.getFlags()));
result.append("\n");
}
return true;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 11d1c2a..89943f7 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -395,6 +395,7 @@
}
} else if (!mSensors.hasAnySensor()) {
result.append("No Sensors on the device\n");
+ result.appendFormat("devInitCheck : %d\n", SensorDevice::getInstance().initCheck());
} else {
// Default dump the sensor list and debugging information.
//
@@ -1038,17 +1039,16 @@
}
int SensorService::setOperationParameter(
- int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) {
+ int32_t handle, int32_t type,
+ const Vector<float> &floats, const Vector<int32_t> &ints) {
Mutex::Autolock _l(mLock);
- // check permission
- int32_t uid;
- bool hasPermission = checkCallingPermission(sLocationHardwarePermission, nullptr, &uid);
- if (!hasPermission || (uid != 1000 && uid != 0)) {
+ if (!checkCallingPermission(sLocationHardwarePermission, nullptr, nullptr)) {
return PERMISSION_DENIED;
}
bool isFloat = true;
+ bool isCustom = false;
size_t expectSize = INT32_MAX;
switch (type) {
case AINFO_LOCAL_GEOMAGNETIC_FIELD:
@@ -1066,7 +1066,21 @@
expectSize = 1;
break;
default:
- return BAD_VALUE;
+ // CUSTOM events must only contain float data; it may have variable size
+ if (type < AINFO_CUSTOM_START || type >= AINFO_DEBUGGING_START ||
+ ints.size() ||
+ sizeof(additional_info_event_t::data_float)/sizeof(float) < floats.size() ||
+ handle < 0) {
+ return BAD_VALUE;
+ }
+ isFloat = true;
+ isCustom = true;
+ expectSize = floats.size();
+ break;
+ }
+
+ if (!isCustom && handle != -1) {
+ return BAD_VALUE;
}
// three events: first one is begin tag, last one is end tag, the one in the middle
@@ -1076,7 +1090,7 @@
for (sensors_event_t* i = event; i < event + 3; i++) {
*i = (sensors_event_t) {
.version = sizeof(sensors_event_t),
- .sensor = SENSORS_HANDLE_BASE - 1, // sensor that never exists
+ .sensor = handle,
.type = SENSOR_TYPE_ADDITIONAL_INFO,
.timestamp = timestamp++,
.additional_info = (additional_info_event_t) {
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 2a9d6e8..3e18394 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -159,7 +159,7 @@
virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
uint32_t size, int32_t type, int32_t format, const native_handle *resource);
virtual int setOperationParameter(
- int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
+ int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
virtual status_t dump(int fd, const Vector<String16>& args);
String8 getSensorName(int handle) const;
diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp
index 748dafc..8bbc4c5 100644
--- a/services/sensorservice/hidl/Android.bp
+++ b/services/sensorservice/hidl/Android.bp
@@ -18,7 +18,6 @@
"libsensor",
"android.frameworks.sensorservice@1.0",
"android.hardware.sensors@1.0",
- "android.hidl.base@1.0",
],
static_libs: [
"android.hardware.sensors@1.0-convert",
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index 25a3dc5..cf5ab05 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -24,7 +24,6 @@
#include <sched.h>
-#include <thread>
#include "EventQueue.h"
#include "DirectReportChannel.h"
@@ -40,20 +39,24 @@
using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
using ::android::hardware::hidl_vec;
using ::android::hardware::Void;
-using ::android::sp;
static const char* POLL_THREAD_NAME = "hidl_ssvc_poll";
SensorManager::SensorManager(JavaVM* vm)
- : mJavaVm(vm) {
+ : mLooper(new Looper(false /*allowNonCallbacks*/)), mStopThread(true), mJavaVm(vm) {
}
SensorManager::~SensorManager() {
// Stops pollAll inside the thread.
- std::unique_lock<std::mutex> lock(mLooperMutex);
+ std::lock_guard<std::mutex> lock(mThreadMutex);
+
+ mStopThread = true;
if (mLooper != nullptr) {
mLooper->wake();
}
+ if (mPollThread.joinable()) {
+ mPollThread.join();
+ }
}
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
@@ -128,12 +131,13 @@
}
/* One global looper for all event queues created from this SensorManager. */
-sp<::android::Looper> SensorManager::getLooper() {
- std::unique_lock<std::mutex> lock(mLooperMutex);
- if (mLooper == nullptr) {
- std::condition_variable looperSet;
+sp<Looper> SensorManager::getLooper() {
+ std::lock_guard<std::mutex> lock(mThreadMutex);
- std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet, javaVm = mJavaVm] {
+ if (!mPollThread.joinable()) {
+ // if thread not initialized, start thread
+ mStopThread = false;
+ std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] {
struct sched_param p = {0};
p.sched_priority = 10;
@@ -142,16 +146,11 @@
<< strerror(errno);
}
- std::unique_lock<std::mutex> lock(mutex);
- if (looper != nullptr) {
- LOG(INFO) << "Another thread has already set the looper, exiting this one.";
- return;
- }
- looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */);
- lock.unlock();
+ // set looper
+ Looper::setForThread(looper);
- // Attach the thread to JavaVM so that pollAll do not crash if the event
- // is from Java.
+ // Attach the thread to JavaVM so that pollAll do not crash if the thread
+ // eventually calls into Java.
JavaVMAttachArgs args{
.version = JNI_VERSION_1_2,
.name = POLL_THREAD_NAME,
@@ -162,19 +161,30 @@
LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
}
- looperSet.notify_one();
- int pollResult = looper->pollAll(-1 /* timeout */);
- if (pollResult != ALOOPER_POLL_WAKE) {
- LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult;
+ LOG(INFO) << POLL_THREAD_NAME << " started.";
+ for (;;) {
+ int pollResult = looper->pollAll(-1 /* timeout */);
+ if (pollResult == Looper::POLL_WAKE) {
+ if (stopThread == true) {
+ LOG(INFO) << POLL_THREAD_NAME << ": requested to stop";
+ break;
+ } else {
+ LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work";
+ }
+ } else {
+ LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected "
+ << pollResult;
+ break;
+ }
}
if (javaVm->DetachCurrentThread() != JNI_OK) {
LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM.";
}
- LOG(INFO) << "Looper thread is terminated.";
- }}.detach();
- looperSet.wait(lock, [this]{ return this->mLooper != nullptr; });
+ LOG(INFO) << POLL_THREAD_NAME << " is terminated.";
+ }};
+ mPollThread = std::move(pollThread);
}
return mLooper;
}
@@ -196,6 +206,12 @@
}
sp<::android::Looper> looper = getLooper();
+ if (looper == nullptr) {
+ LOG(ERROR) << "::android::SensorManager::createEventQueue cannot initialize looper";
+ _hidl_cb(nullptr, Result::UNKNOWN_ERROR);
+ return Void();
+ }
+
sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue();
if (internalQueue == nullptr) {
LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr.";
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index e66c8e5..ddcee28 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -20,6 +20,7 @@
#include <jni.h>
#include <mutex>
+#include <thread>
#include <android/frameworks/sensorservice/1.0/ISensorManager.h>
#include <android/frameworks/sensorservice/1.0/types.h>
@@ -38,6 +39,7 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_memory;
using ::android::hardware::Return;
+using ::android::sp;
struct SensorManager final : public ISensorManager {
@@ -54,13 +56,15 @@
private:
// Block until ::android::SensorManager is initialized.
::android::SensorManager& getInternalManager();
- sp<::android::Looper> getLooper();
+ sp<Looper> getLooper();
std::mutex mInternalManagerMutex;
::android::SensorManager* mInternalManager = nullptr; // does not own
+ sp<Looper> mLooper;
- std::mutex mLooperMutex;
- sp<::android::Looper> mLooper;
+ volatile bool mStopThread;
+ std::mutex mThreadMutex; //protects mPollThread
+ std::thread mPollThread;
JavaVM* mJavaVm;
};
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 95a522d..38529b6 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -9,7 +9,7 @@
DisplayDevice.cpp \
DispSync.cpp \
EventControlThread.cpp \
- StartBootAnimThread.cpp \
+ StartPropertySetThread.cpp \
EventThread.cpp \
FrameTracker.cpp \
GpuService.cpp \
@@ -104,7 +104,7 @@
libhidltransport \
libhwbinder
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -std=c++1z
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index bd9b8aa..ea04839 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -377,11 +377,16 @@
DispSync::DispSync(const char* name) :
mName(name),
mRefreshSkipCount(0),
- mThread(new DispSyncThread(name)),
- mIgnorePresentFences(!SurfaceFlinger::hasSyncFramework){
+ mThread(new DispSyncThread(name)) {
+}
- mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset;
+DispSync::~DispSync() {}
+
+void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
+ mIgnorePresentFences = !hasSyncFramework;
+ mPresentTimeOffset = dispSyncPresentTimeOffset;
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
+
// set DispSync to SCHED_FIFO to minimize jitter
struct sched_param param = {0};
param.sched_priority = 2;
@@ -389,7 +394,6 @@
ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
}
-
reset();
beginResync();
@@ -405,8 +409,6 @@
}
}
-DispSync::~DispSync() {}
-
void DispSync::reset() {
Mutex::Autolock lock(mMutex);
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 82ae795..3c34fb0 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -55,6 +55,8 @@
explicit DispSync(const char* name);
~DispSync();
+ void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset);
+
// reset clears the resync samples and error value.
void reset();
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b5ffc60..fc60002 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -121,7 +121,7 @@
ANativeWindow* const window = mNativeWindow.get();
#ifdef USE_HWC2
- mActiveColorMode = static_cast<android_color_mode_t>(-1);
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
mDisplayHasWideColor = supportWideColor;
#else
(void) supportWideColor;
@@ -442,6 +442,11 @@
android_color_mode_t DisplayDevice::getActiveColorMode() const {
return mActiveColorMode;
}
+
+void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) {
+ ANativeWindow* const window = mNativeWindow.get();
+ native_window_set_buffers_data_space(window, dataspace);
+}
#endif
// ----------------------------------------------------------------------------
@@ -610,23 +615,25 @@
void DisplayDevice::dump(String8& result) const {
const Transform& tr(mGlobalTransform);
- result.appendFormat(
- "+ DisplayDevice: %s\n"
- " type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), "
- "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n"
- " v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
- "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
- mDisplayName.string(), mType, mHwcDisplayId,
- mLayerStack, mDisplayWidth, mDisplayHeight, mNativeWindow.get(),
- mOrientation, tr.getType(), getPageFlipCount(),
- mIsSecure, mPowerMode, mActiveConfig,
- mVisibleLayersSortedByZ.size(),
- mViewport.left, mViewport.top, mViewport.right, mViewport.bottom,
- mFrame.left, mFrame.top, mFrame.right, mFrame.bottom,
- mScissor.left, mScissor.top, mScissor.right, mScissor.bottom,
- tr[0][0], tr[1][0], tr[2][0],
- tr[0][1], tr[1][1], tr[2][1],
- tr[0][2], tr[1][2], tr[2][2]);
+ EGLint redSize, greenSize, blueSize, alphaSize;
+ eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize);
+ eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize);
+ eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &blueSize);
+ eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &alphaSize);
+ result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string());
+ result.appendFormat(" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
+ "(%d:%d:%d:%d), orient=%2d (type=%08x), "
+ "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
+ mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight,
+ mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation,
+ tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
+ mVisibleLayersSortedByZ.size());
+ result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
+ "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
+ mViewport.left, mViewport.top, mViewport.right, mViewport.bottom,
+ mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left,
+ mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0],
+ tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
String8 surfaceDump;
mDisplaySurface->dumpAsString(surfaceDump);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e2852a7..8636e2a 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -141,6 +141,7 @@
uint32_t getLayerStack() const { return mLayerStack; }
int32_t getDisplayType() const { return mType; }
+ bool isPrimary() const { return mType == DISPLAY_PRIMARY; }
int32_t getHwcDisplayId() const { return mHwcDisplayId; }
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
@@ -189,6 +190,7 @@
#ifdef USE_HWC2
android_color_mode_t getActiveColorMode() const;
void setActiveColorMode(android_color_mode_t mode);
+ void setCompositionDataSpace(android_dataspace dataspace);
#endif
/* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 9d16044..e34fa16 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -181,6 +181,13 @@
if (mClient == nullptr) {
LOG_ALWAYS_FATAL("failed to create composer client");
}
+
+ if (mIsUsingVrComposer) {
+ sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
+ if (vrClient == nullptr) {
+ LOG_ALWAYS_FATAL("failed to create vr composer client");
+ }
+ }
}
std::vector<IComposer::Capability> Composer::getCapabilities()
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 5b869e1..68d7a18 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -106,12 +106,6 @@
if (result != NO_ERROR) {
ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
strerror(-result), result);
- return result;
- }
- result = mHwc.setClientTarget(mDisplayType, slot,
- acquireFence, buf, dataspace);
- if (result != NO_ERROR) {
- ALOGE("error posting framebuffer: %d", result);
}
return result;
#else
@@ -182,7 +176,13 @@
#else
outBuffer = mCurrentBuffer;
#endif
- return NO_ERROR;
+ status_t result =
+ mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
+ if (result != NO_ERROR) {
+ ALOGE("error posting framebuffer: %d", result);
+ }
+
+ return result;
}
#ifndef USE_HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c48a28f..270a732 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -884,6 +884,10 @@
Error Layer::setDataspace(android_dataspace_t dataspace)
{
+ if (dataspace == mDataSpace) {
+ return Error::None;
+ }
+ mDataSpace = dataspace;
auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace);
auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId,
mId, intDataspace);
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 7463e3b..404bb28 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -338,6 +338,7 @@
hwc2_display_t mDisplayId;
Device& mDevice;
hwc2_layer_t mId;
+ android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
};
} // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 8217540..c129ae5 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -16,12 +16,16 @@
// #define LOG_NDEBUG 0
#include "VirtualDisplaySurface.h"
+
+#include <inttypes.h>
+
#include "HWComposer.h"
#include "SurfaceFlinger.h"
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
#include <gui/IProducerListener.h>
+#include <system/window.h>
// ---------------------------------------------------------------------------
namespace android {
@@ -338,7 +342,7 @@
}
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
- PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence) {
+ PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
status_t result = mSource[source]->dequeueBuffer(sslot, fence,
@@ -371,7 +375,7 @@
mSource[source]->cancelBuffer(*sslot, *fence);
return result;
}
- VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x",
+ VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64,
dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
mProducerBuffers[pslot]->getPixelFormat(),
mProducerBuffers[pslot]->getUsage());
@@ -381,7 +385,7 @@
}
status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
+ uint32_t w, uint32_t h, PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps) {
if (mDisplayId < 0) {
return mSource[SOURCE_SINK]->dequeueBuffer(
@@ -392,7 +396,7 @@
"Unexpected dequeueBuffer() in %s state", dbgStateStr());
mDbgState = DBG_STATE_GLES;
- VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
+ VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#" PRIx64, w, h, format, usage);
status_t result = NO_ERROR;
Source source = fbSourceForCompositionType(mCompositionType);
@@ -422,8 +426,8 @@
(w != 0 && w != mSinkBufferWidth) ||
(h != 0 && h != mSinkBufferHeight)) {
VDS_LOGV("dequeueBuffer: dequeueing new output buffer: "
- "want %dx%d fmt=%d use=%#x, "
- "have %dx%d fmt=%d use=%#x",
+ "want %dx%d fmt=%d use=%#" PRIx64 ", "
+ "have %dx%d fmt=%d use=%#" PRIx64,
w, h, format, usage,
mSinkBufferWidth, mSinkBufferHeight,
buf->getPixelFormat(), buf->getUsage());
@@ -574,7 +578,7 @@
}
void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */,
- uint32_t /* height */, PixelFormat /* format */, uint32_t /* usage */) {
+ uint32_t /* height */, PixelFormat /* format */, uint64_t /* usage */) {
// TODO: Should we actually allocate buffers for a virtual display?
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 5c0e084..7f8b39b 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -105,7 +105,7 @@
virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
virtual status_t setAsyncMode(bool async);
virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w,
- uint32_t h, PixelFormat format, uint32_t usage,
+ uint32_t h, PixelFormat format, uint64_t usage,
FrameEventHistoryDelta *outTimestamps);
virtual status_t detachBuffer(int slot);
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
@@ -120,7 +120,7 @@
virtual status_t disconnect(int api, DisconnectMode mode);
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage);
+ PixelFormat format, uint64_t usage);
virtual status_t allowAllocation(bool allow);
virtual status_t setGenerationNumber(uint32_t generationNumber);
virtual String8 getConsumerName() const override;
@@ -135,7 +135,7 @@
// Utility methods
//
static Source fbSourceForCompositionType(CompositionType type);
- status_t dequeueBuffer(Source source, PixelFormat format, uint32_t usage,
+ status_t dequeueBuffer(Source source, PixelFormat format, uint64_t usage,
int* sslot, sp<Fence>* fence);
void updateQueueBufferOutput(QueueBufferOutput&& qbo);
void resetPerFrameState();
@@ -168,7 +168,7 @@
// the composition type changes or the GLES driver starts requesting
// different usage/format, we'll get a new buffer.
uint32_t mOutputFormat;
- uint32_t mOutputUsage;
+ uint64_t mOutputUsage;
// Since we present a single producer interface to the GLES driver, but
// are internally muxing between the sink and scratch producers, we have
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
old mode 100644
new mode 100755
index 2305206..1b864fd
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -34,6 +34,7 @@
#include <utils/StopWatch.h>
#include <utils/Trace.h>
+#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
@@ -125,6 +126,7 @@
mPremultipliedAlpha = false;
mName = name;
+ mTransactionName = String8("TX - ") + mName;
mCurrentState.active.w = w;
mCurrentState.active.h = h;
@@ -472,7 +474,7 @@
Rect activeCrop(s.active.w, s.active.h);
if (!s.crop.isEmpty()) {
- activeCrop = s.crop;
+ activeCrop.intersect(s.crop, &activeCrop);
}
Transform t = getTransform();
@@ -893,9 +895,6 @@
}
}
-android_dataspace Layer::getDataSpace() const {
- return mCurrentState.dataSpace;
-}
#else
void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer) {
@@ -1417,9 +1416,9 @@
bool Layer::isOpaque(const Layer::State& s) const
{
- // if we don't have a buffer yet, we're translucent regardless of the
+ // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
// layer's opaque flag.
- if (mActiveBuffer == 0) {
+ if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
return false;
}
@@ -1505,6 +1504,7 @@
mFlinger->setTransactionFlags(eTraversalNeeded);
}
mPendingStates.push_back(mCurrentState);
+ ATRACE_INT(mTransactionName.string(), mPendingStates.size());
}
void Layer::popPendingState(State* stateToCommit) {
@@ -1514,6 +1514,7 @@
(stateToCommit->flags & stateToCommit->mask);
mPendingStates.removeAt(0);
+ ATRACE_INT(mTransactionName.string(), mPendingStates.size());
}
bool Layer::applyPendingStates(State* stateToCommit) {
@@ -1928,6 +1929,10 @@
return true;
}
+android_dataspace Layer::getDataSpace() const {
+ return mCurrentState.dataSpace;
+}
+
uint32_t Layer::getLayerStack() const {
auto p = mDrawingParent.promote();
if (p == nullptr) {
@@ -2372,11 +2377,17 @@
visibleRegion.dump(result, "visibleRegion");
surfaceDamageRegion.dump(result, "surfaceDamageRegion");
sp<Client> client(mClientRef.promote());
+ PixelFormat pf = PIXEL_FORMAT_UNKNOWN;
+ const sp<GraphicBuffer>& buffer(getActiveBuffer());
+ if (buffer != NULL) {
+ pf = buffer->getPixelFormat();
+ }
result.appendFormat( " "
"layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), "
"crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), "
"isOpaque=%1d, invalidate=%1d, "
+ "dataspace=%s, pixelformat=%s "
#ifdef USE_HWC2
"alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
#else
@@ -2391,6 +2402,7 @@
s.finalCrop.left, s.finalCrop.top,
s.finalCrop.right, s.finalCrop.bottom,
isOpaque(s), contentDirty,
+ dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(),
s.alpha, s.flags,
s.active.transform[0][0], s.active.transform[0][1],
s.active.transform[1][0], s.active.transform[1][1],
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 24fc10d..2306d1a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -166,6 +166,8 @@
virtual ~Layer();
+ void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
+
// the this layer's size and format
status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
@@ -231,6 +233,7 @@
bool setFlags(uint8_t flags, uint8_t mask);
bool setLayerStack(uint32_t layerStack);
bool setDataSpace(android_dataspace dataSpace);
+ android_dataspace getDataSpace() const;
uint32_t getLayerStack() const;
void deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber);
void deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber);
@@ -248,6 +251,10 @@
uint32_t getTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
+ bool belongsToDisplay(uint32_t layerStack, bool isPrimaryDisplay) const {
+ return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
+ }
+
void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
bool useIdentityTransform) const;
Rect computeBounds(const Region& activeTransparentRegion) const;
@@ -314,8 +321,6 @@
void forceClientComposition(int32_t hwcId);
void setPerFrameData(const sp<const DisplayDevice>& displayDevice);
- android_dataspace getDataSpace() const;
-
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
void setCompositionType(int32_t hwcId, HWC2::Composition type,
@@ -409,6 +414,7 @@
* to figure out if the content or size of a surface has changed.
*/
Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime);
+ bool isBufferLatched() const { return mRefreshPending; }
bool isPotentialCursor() const { return mPotentialCursor;}
@@ -698,8 +704,11 @@
uint32_t mTextureName; // from GLES
bool mPremultipliedAlpha;
String8 mName;
+ String8 mTransactionName; // A cached version of "TX - " + mName for systraces
PixelFormat mFormat;
+ bool mPrimaryDisplayOnly = false;
+
// these are protected by an external lock
State mCurrentState;
State mDrawingState;
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 6e37b45..e864607 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -17,6 +17,7 @@
#include "LayerRejecter.h"
#include <gui/BufferItem.h>
+#include <system/window.h>
#include "clz.h"
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 85a33c8..14f50bb 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -30,6 +30,8 @@
#include "Barrier.h"
+#include <functional>
+
namespace android {
class IDisplayEventConnection;
@@ -58,6 +60,21 @@
mutable Barrier barrier;
};
+class LambdaMessage : public MessageBase {
+public:
+ explicit LambdaMessage(std::function<void()> handler)
+ : MessageBase(), mHandler(std::move(handler)) {}
+
+ bool handler() override {
+ mHandler();
+ // This return value is no longer checked, so it's always safe to return true
+ return true;
+ }
+
+private:
+ const std::function<void()> mHandler;
+};
+
// ---------------------------------------------------------------------------
class MessageQueue {
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 2ba1b33..e717632 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -69,7 +69,7 @@
}
status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
+ uint32_t w, uint32_t h, PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps) {
return mProducer->dequeueBuffer(
slot, fence, w, h, format, usage, outTimestamps);
@@ -116,7 +116,7 @@
}
void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) {
+ PixelFormat format, uint64_t usage) {
mProducer->allocateBuffers(width, height, format, usage);
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index a3ec29d..58b9bc4 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -40,7 +40,7 @@
virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
virtual status_t setAsyncMode(bool async);
virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
- uint32_t h, PixelFormat format, uint32_t usage,
+ uint32_t h, PixelFormat format, uint64_t usage,
FrameEventHistoryDelta* outTimestamps);
virtual status_t detachBuffer(int slot);
virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
@@ -56,7 +56,7 @@
virtual status_t disconnect(int api, DisconnectMode mode);
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
virtual void allocateBuffers(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage);
+ PixelFormat format, uint64_t usage);
virtual status_t allowAllocation(bool allow);
virtual status_t setGenerationNumber(uint32_t generationNumber);
virtual String8 getConsumerName() const override;
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 0dab872..effd319 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -26,8 +26,7 @@
namespace android {
-Description::Description() :
- mUniformsDirty(true) {
+Description::Description() {
mPlaneAlpha = 1.0f;
mPremultipliedAlpha = false;
mOpaque = true;
@@ -41,28 +40,20 @@
}
void Description::setPlaneAlpha(GLclampf planeAlpha) {
- if (planeAlpha != mPlaneAlpha) {
- mUniformsDirty = true;
- mPlaneAlpha = planeAlpha;
- }
+ mPlaneAlpha = planeAlpha;
}
void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
- if (premultipliedAlpha != mPremultipliedAlpha) {
- mPremultipliedAlpha = premultipliedAlpha;
- }
+ mPremultipliedAlpha = premultipliedAlpha;
}
void Description::setOpaque(bool opaque) {
- if (opaque != mOpaque) {
- mOpaque = opaque;
- }
+ mOpaque = opaque;
}
void Description::setTexture(const Texture& texture) {
mTexture = texture;
mTextureEnabled = true;
- mUniformsDirty = true;
}
void Description::disableTexture() {
@@ -74,12 +65,10 @@
mColor[1] = green;
mColor[2] = blue;
mColor[3] = alpha;
- mUniformsDirty = true;
}
void Description::setProjectionMatrix(const mat4& mtx) {
mProjectionMatrix = mtx;
- mUniformsDirty = true;
}
void Description::setColorMatrix(const mat4& mtx) {
@@ -92,5 +81,8 @@
return mColorMatrix;
}
+void Description::setWideGamut(bool wideGamut) {
+ mIsWideGamut = wideGamut;
+}
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 8a3447c..3beffdf 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -54,6 +54,8 @@
bool mColorMatrixEnabled;
mat4 mColorMatrix;
+ bool mIsWideGamut;
+
public:
Description();
~Description();
@@ -67,9 +69,7 @@
void setProjectionMatrix(const mat4& mtx);
void setColorMatrix(const mat4& mtx);
const mat4& getColorMatrix() const;
-
-private:
- bool mUniformsDirty;
+ void setWideGamut(bool wideGamut);
};
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 04fe182..37a530b 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -40,9 +40,7 @@
#include "Mesh.h"
#include "Texture.h"
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <configstore/Utils.h>
-
+#include <sstream>
#include <fstream>
// ---------------------------------------------------------------------------
@@ -111,8 +109,10 @@
namespace android {
// ---------------------------------------------------------------------------
-GLES20RenderEngine::GLES20RenderEngine() :
- mVpWidth(0), mVpHeight(0) {
+GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) :
+ mVpWidth(0),
+ mVpHeight(0),
+ mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
@@ -133,23 +133,16 @@
//mColorBlindnessCorrection = M;
#ifdef USE_HWC2
- // retrieve wide-color and hdr settings from configstore
- using namespace android::hardware::configstore;
- using namespace android::hardware::configstore::V1_0;
-
- mPlatformHasWideColor =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
if (mPlatformHasWideColor) {
// Compute sRGB to DisplayP3 color transform
// NOTE: For now, we are limiting wide-color support to
// Display-P3 only.
- mat3 srgbToP3 = ColorSpace::DisplayP3().getXYZtoRGB() * ColorSpace::sRGB().getRGBtoXYZ();
+ mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform();
- // color transform needs to be transposed and expanded to 4x4
- // to be what the shader wants
+ // color transform needs to be expanded to 4x4 to be what the shader wants
// mat has an initializer that expands mat3 to mat4, but
// not an assignment operator
- mat4 gamutTransform(transpose(srgbToP3));
+ mat4 gamutTransform(srgbToP3);
mSrgbToDisplayP3 = gamutTransform;
}
#endif
@@ -392,6 +385,7 @@
Description wideColorState = mState;
if (mDataSpace != HAL_DATASPACE_DISPLAY_P3) {
wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
+ wideColorState.setWideGamut(true);
ALOGV("drawMesh: gamut transform applied");
}
ProgramCache::getInstance().useProgram(wideColorState);
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 19cbb60..eaf94af 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -59,7 +59,7 @@
virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName);
public:
- GLES20RenderEngine();
+ GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
protected:
virtual ~GLES20RenderEngine();
@@ -86,7 +86,6 @@
android_dataspace mDataSpace = HAL_DATASPACE_V0_SRGB;
// Indicate if wide-color mode is needed or not
- bool mPlatformHasWideColor = false;
bool mDisplayHasWideColor = false;
bool mUseWideColor = false;
uint64_t mWideColorFrameCount = 0;
@@ -98,6 +97,8 @@
int alpha);
virtual void setupDimLayerBlending(int alpha);
#endif
+ bool mPlatformHasWideColor = false;
+
virtual void setupLayerTexturing(const Texture& texture);
virtual void setupLayerBlackedOut();
virtual void setupFillWithColor(float r, float g, float b, float a);
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index ba11259..06b2252 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -129,7 +129,9 @@
.set(Key::OPACITY_MASK,
description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
.set(Key::COLOR_MATRIX_MASK,
- description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF);
+ description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF)
+ .set(Key::WIDE_GAMUT_MASK,
+ description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF);
return needs;
}
@@ -175,6 +177,50 @@
if (needs.hasColorMatrix()) {
fs << "uniform mat4 colorMatrix;";
}
+ if (needs.hasColorMatrix()) {
+ // When in wide gamut mode, the color matrix will contain a color space
+ // conversion matrix that needs to be applied in linear space
+ // When not in wide gamut, we can simply no-op the transfer functions
+ // and let the shader compiler get rid of them
+ if (needs.isWideGamut()) {
+ fs << R"__SHADER__(
+ float OETF_sRGB(const float linear) {
+ return linear <= 0.0031308 ?
+ linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
+ }
+
+ vec3 OETF_sRGB(const vec3 linear) {
+ return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+ }
+
+ vec3 OETF_scRGB(const vec3 linear) {
+ return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+ }
+
+ float EOTF_sRGB(float srgb) {
+ return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
+ }
+
+ vec3 EOTF_sRGB(const vec3 srgb) {
+ return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+ }
+
+ vec3 EOTF_scRGB(const vec3 srgb) {
+ return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+ }
+ )__SHADER__";
+ } else {
+ fs << R"__SHADER__(
+ vec3 OETF_scRGB(const vec3 linear) {
+ return linear;
+ }
+
+ vec3 EOTF_scRGB(const vec3 srgb) {
+ return srgb;
+ }
+ )__SHADER__";
+ }
+ }
fs << "void main(void) {" << indent;
if (needs.isTexturing()) {
fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
@@ -197,13 +243,15 @@
if (needs.hasColorMatrix()) {
if (!needs.isOpaque() && needs.isPremultiplied()) {
// un-premultiply if needed before linearization
- fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;";
+ // avoid divide by 0 by adding 0.5/256 to the alpha channel
+ fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
}
- fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);";
- fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;";
+ fs << "vec4 transformed = colorMatrix * vec4(EOTF_scRGB(gl_FragColor.rgb), 1);";
+ // We assume the last row is always {0,0,0,1} and we skip the division by w
+ fs << "gl_FragColor.rgb = OETF_scRGB(transformed.rgb);";
if (!needs.isOpaque() && needs.isPremultiplied()) {
// and re-premultiply if needed after gamma correction
- fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;";
+ fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
}
}
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index 1fa53d3..5b0fbcd 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -69,6 +69,10 @@
COLOR_MATRIX_OFF = 0x00000000,
COLOR_MATRIX_ON = 0x00000020,
COLOR_MATRIX_MASK = 0x00000020,
+
+ WIDE_GAMUT_OFF = 0x00000000,
+ WIDE_GAMUT_ON = 0x00000040,
+ WIDE_GAMUT_MASK = 0x00000040,
};
inline Key() : mKey(0) { }
@@ -97,10 +101,13 @@
inline bool hasColorMatrix() const {
return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON;
}
+ inline bool isWideGamut() const {
+ return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON;
+ }
// this is the definition of a friend function -- not a method of class Needs
friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
- return (lhs.mKey < rhs.mKey) ? 1 : 0;
+ return (lhs.mKey < rhs.mKey) ? 1 : 0;
}
};
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 7564269..ac2d8b2 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -47,19 +47,23 @@
return false;
}
-RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) {
+RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t featureFlags) {
// EGL_ANDROIDX_no_config_context is an experimental extension with no
// written specification. It will be replaced by something more formal.
// SurfaceFlinger is using it to allow a single EGLContext to render to
// both a 16-bit primary display framebuffer and a 32-bit virtual display
// framebuffer.
//
+ // EGL_KHR_no_config_context is official extension to allow creating a
+ // context that works with any surface of a display.
+ //
// The code assumes that ES2 or later is available if this extension is
// supported.
EGLConfig config = EGL_NO_CONFIG;
- if (!findExtension(
- eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
- "EGL_ANDROIDX_no_config_context")) {
+ if (!findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
+ "EGL_ANDROIDX_no_config_context") &&
+ !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
+ "EGL_KHR_no_config_context")) {
config = chooseEglConfig(display, hwcFormat);
}
@@ -131,7 +135,7 @@
break;
case GLES_VERSION_2_0:
case GLES_VERSION_3_0:
- engine = new GLES20RenderEngine();
+ engine = new GLES20RenderEngine(featureFlags);
break;
}
engine->setEGLHandles(config, ctxt);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 8b031bc..56f5827 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -59,7 +59,10 @@
virtual ~RenderEngine() = 0;
public:
- static RenderEngine* create(EGLDisplay display, int hwcFormat);
+ enum FeatureFlag {
+ WIDE_COLOR_SUPPORT = 1 << 0 // Platform has a wide color display
+ };
+ static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags);
static EGLConfig chooseEglConfig(EGLDisplay display, int format);
diff --git a/services/surfaceflinger/StartBootAnimThread.cpp b/services/surfaceflinger/StartBootAnimThread.cpp
deleted file mode 100644
index c3f7296..0000000
--- a/services/surfaceflinger/StartBootAnimThread.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 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 <cutils/properties.h>
-#include "StartBootAnimThread.h"
-
-namespace android {
-
-StartBootAnimThread::StartBootAnimThread():
- Thread(false) {
-}
-
-status_t StartBootAnimThread::Start() {
- return run("SurfaceFlinger::StartBootAnimThread", PRIORITY_NORMAL);
-}
-
-bool StartBootAnimThread::threadLoop() {
- property_set("service.bootanim.exit", "0");
- property_set("ctl.start", "bootanim");
- // Exit immediately
- return false;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/StartPropertySetThread.cpp b/services/surfaceflinger/StartPropertySetThread.cpp
new file mode 100644
index 0000000..db82772
--- /dev/null
+++ b/services/surfaceflinger/StartPropertySetThread.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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 <cutils/properties.h>
+#include "StartPropertySetThread.h"
+
+namespace android {
+
+StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):
+ Thread(false), mTimestampPropertyValue(timestampPropertyValue) {}
+
+status_t StartPropertySetThread::Start() {
+ return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
+}
+
+bool StartPropertySetThread::threadLoop() {
+ // Set property service.sf.present_timestamp, consumer need check its readiness
+ property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
+ // Clear BootAnimation exit flag
+ property_set("service.bootanim.exit", "0");
+ // Start BootAnimation if not started
+ property_set("ctl.start", "bootanim");
+ // Exit immediately
+ return false;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/StartBootAnimThread.h b/services/surfaceflinger/StartPropertySetThread.h
similarity index 78%
rename from services/surfaceflinger/StartBootAnimThread.h
rename to services/surfaceflinger/StartPropertySetThread.h
index dba2bee..a64c21b 100644
--- a/services/surfaceflinger/StartBootAnimThread.h
+++ b/services/surfaceflinger/StartPropertySetThread.h
@@ -24,17 +24,21 @@
namespace android {
-class StartBootAnimThread : public Thread {
+class StartPropertySetThread : public Thread {
// Boot animation is triggered via calls to "property_set()" which can block
// if init's executing slow operation such as 'mount_all --late' (currently
// happening 1/10th with fsck) concurrently. Running in a separate thread
// allows to pursue the SurfaceFlinger's init process without blocking.
// see b/34499826.
+// Any property_set() will block during init stage so need to be offloaded
+// to this thread. see b/63844978.
public:
- StartBootAnimThread();
+ StartPropertySetThread(bool timestampPropertyValue);
status_t Start();
private:
virtual bool threadLoop();
+ static constexpr const char* kTimestampProperty = "service.sf.present_timestamp";
+ const bool mTimestampPropertyValue;
};
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8a8fa01..fee552e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -19,12 +19,14 @@
#include <stdint.h>
#include <sys/types.h>
+#include <algorithm>
#include <errno.h>
#include <math.h>
#include <mutex>
#include <dlfcn.h>
#include <inttypes.h>
#include <stdatomic.h>
+#include <optional>
#include <EGL/egl.h>
@@ -193,6 +195,8 @@
hasWideColorDisplay =
getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+ mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -224,6 +228,11 @@
property_get("ro.sf.disable_triple_buffer", value, "1");
mLayerTripleBufferingDisabled = atoi(value);
ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
+
+ // We should be reading 'persist.sys.sf.color_saturation' here
+ // but since /data may be encrypted, we need to wait until after vold
+ // comes online to attempt to read the property. The property is
+ // instead read after the boot animation
}
void SurfaceFlinger::onFirstRef()
@@ -341,13 +350,12 @@
void SurfaceFlinger::bootFinished()
{
- if (mStartBootAnimThread->join() != NO_ERROR) {
- ALOGE("Join StartBootAnimThread failed!");
+ if (mStartPropertySetThread->join() != NO_ERROR) {
+ ALOGE("Join StartPropertySetThread failed!");
}
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
- mBootFinished = true;
// wait patiently for the window manager death
const String16 name("window");
@@ -368,6 +376,11 @@
const int LOGTAG_SF_STOP_BOOTANIM = 60110;
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+
+ sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
+ readPersistentProperties();
+ });
+ postMessageAsync(readProperties);
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -528,6 +541,8 @@
sp<VSyncSource::Callback> mCallback;
};
+// Do not call property_set on main thread which will be blocked by init
+// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
@@ -562,7 +577,8 @@
// Get a RenderEngine for the given display / config (can't fail)
mRenderEngine = RenderEngine::create(mEGLDisplay,
- HAL_PIXEL_FORMAT_RGBA_8888);
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
}
// Drop the state lock while we initialize the hardware composer. We drop
@@ -576,14 +592,6 @@
Mutex::Autolock _l(mStateLock);
- // Inform native graphics APIs whether the present timestamp is supported:
- if (getHwComposer().hasCapability(
- HWC2::Capability::PresentFenceIsNotReliable)) {
- property_set(kTimestampProperty, "0");
- } else {
- property_set(kTimestampProperty, "1");
- }
-
if (useVrFlinger) {
auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
@@ -618,21 +626,42 @@
mRenderEngine->primeCache();
- mStartBootAnimThread = new StartBootAnimThread();
- if (mStartBootAnimThread->Start() != NO_ERROR) {
- ALOGE("Run StartBootAnimThread failed!");
+ // Inform native graphics APIs whether the present timestamp is supported:
+ if (getHwComposer().hasCapability(
+ HWC2::Capability::PresentFenceIsNotReliable)) {
+ mStartPropertySetThread = new StartPropertySetThread(false);
+ } else {
+ mStartPropertySetThread = new StartPropertySetThread(true);
+ }
+
+ if (mStartPropertySetThread->Start() != NO_ERROR) {
+ ALOGE("Run StartPropertySetThread failed!");
}
ALOGV("Done initializing");
}
+void SurfaceFlinger::readPersistentProperties() {
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("persist.sys.sf.color_saturation", value, "1.0");
+ mSaturation = atof(value);
+ ALOGV("Saturation is set to %.2f", mSaturation);
+
+ property_get("persist.sys.sf.native_mode", value, "0");
+ mForceNativeColorMode = atoi(value) == 1;
+ if (mForceNativeColorMode) {
+ ALOGV("Forcing native color mode");
+ }
+}
+
void SurfaceFlinger::startBootAnim() {
// Start boot animation service by setting a property mailbox
// if property setting thread is already running, Start() will be just a NOP
- mStartBootAnimThread->Start();
+ mStartPropertySetThread->Start();
// Wait until property was set
- if (mStartBootAnimThread->join() != NO_ERROR) {
- ALOGE("Join StartBootAnimThread failed!");
+ if (mStartPropertySetThread->join() != NO_ERROR) {
+ ALOGE("Join StartPropertySetThread failed!");
}
}
@@ -1069,6 +1098,7 @@
}
void SurfaceFlinger::signalRefresh() {
+ mRefreshPending = true;
mEventQueue.refresh();
}
@@ -1207,15 +1237,17 @@
break;
}
}
+ bool useWideColorMode = hasWideColorModes && hasWideColorDisplay && !mForceNativeColorMode;
sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure,
token, fbs, producer, mRenderEngine->getEGLConfig(),
- hasWideColorModes && hasWideColorDisplay);
+ useWideColorMode);
mDisplays.add(token, hw);
android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
- if (hasWideColorModes && hasWideColorDisplay) {
+ if (useWideColorMode) {
defaultColorMode = HAL_COLOR_MODE_SRGB;
}
setActiveColorModeInternal(hw, defaultColorMode);
+ hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
}
void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) {
@@ -1269,17 +1301,14 @@
enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
}
-void SurfaceFlinger::clearHwcLayers(const LayerVector& layers) {
- for (size_t i = 0; i < layers.size(); ++i) {
- layers[i]->clearHwcLayers();
- }
-}
-
// Note: it is assumed the caller holds |mStateLock| when this is called
void SurfaceFlinger::resetHwcLocked() {
disableHardwareVsync(true);
clearHwcLayers(mDrawingState.layersSortedByZ);
clearHwcLayers(mCurrentState.layersSortedByZ);
+ for (size_t disp = 0; disp < mDisplays.size(); ++disp) {
+ clearHwcLayers(mDisplays[disp]->getVisibleLayersSortedByZ());
+ }
// Clear the drawing state so that the logic inside of
// handleTransactionLocked will fire. It will determine the delta between
// mCurrentState and mDrawingState and re-apply all changes when we make the
@@ -1339,11 +1368,21 @@
// parts of this class rely on the primary display always being available.
createDefaultDisplayDevice();
- // Reset the timing values to account for the period of the swapped in HWC
- const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
- const nsecs_t period = activeConfig->getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(period);
- setCompositorTimingSnapped(0, period, 0);
+ // Re-enable default display.
+ sp<LambdaMessage> requestMessage = new LambdaMessage([&]() {
+ sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
+ setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL);
+
+ // Reset the timing values to account for the period of the swapped in HWC
+ const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const nsecs_t period = activeConfig->getVsyncPeriod();
+ mAnimFrameTracker.setDisplayRefreshPeriod(period);
+
+ // Use phase of 0 since phase is not known.
+ // Use latency of 0, which will snap to the ideal latency.
+ setCompositorTimingSnapped(0, period, 0);
+ });
+ postMessageAsync(requestMessage);
android_atomic_or(1, &mRepaintEverything);
setTransactionFlags(eDisplayTransactionNeeded);
@@ -1404,6 +1443,8 @@
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
+ mRefreshPending = false;
+
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
preComposition(refreshStartTime);
@@ -1665,12 +1706,11 @@
const Transform& tr(displayDevice->getTransform());
const Rect bounds(displayDevice->getBounds());
if (displayDevice->isDisplayOn()) {
- computeVisibleRegions(
- displayDevice->getLayerStack(), dirtyRegion,
- opaqueRegion);
+ computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->getLayerStack() == displayDevice->getLayerStack()) {
+ if (layer->belongsToDisplay(displayDevice->getLayerStack(),
+ displayDevice->isPrimary())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
@@ -1700,9 +1740,29 @@
}
}
+mat4 SurfaceFlinger::computeSaturationMatrix() const {
+ if (mSaturation == 1.0f) {
+ return mat4();
+ }
+
+ // Rec.709 luma coefficients
+ float3 luminance{0.213f, 0.715f, 0.072f};
+ luminance *= 1.0f - mSaturation;
+ return mat4(
+ vec4{luminance.r + mSaturation, luminance.r, luminance.r, 0.0f},
+ vec4{luminance.g, luminance.g + mSaturation, luminance.g, 0.0f},
+ vec4{luminance.b, luminance.b, luminance.b + mSaturation, 0.0f},
+ vec4{0.0f, 0.0f, 0.0f, 1.0f}
+ );
+}
+
// pickColorMode translates a given dataspace into the best available color mode.
// Currently only support sRGB and Display-P3.
-android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) {
+android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const {
+ if (mForceNativeColorMode) {
+ return HAL_COLOR_MODE_NATIVE;
+ }
+
switch (dataSpace) {
// treat Unknown as regular SRGB buffer, since that's what the rest of the
// system expects.
@@ -1725,11 +1785,19 @@
}
}
-android_dataspace SurfaceFlinger::bestTargetDataSpace(android_dataspace a, android_dataspace b) {
+android_dataspace SurfaceFlinger::bestTargetDataSpace(
+ android_dataspace a, android_dataspace b) const {
// Only support sRGB and Display-P3 right now.
if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) {
return HAL_DATASPACE_DISPLAY_P3;
}
+ if (a == HAL_DATASPACE_V0_SCRGB_LINEAR || b == HAL_DATASPACE_V0_SCRGB_LINEAR) {
+ return HAL_DATASPACE_DISPLAY_P3;
+ }
+ if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) {
+ return HAL_DATASPACE_DISPLAY_P3;
+ }
+
return HAL_DATASPACE_V0_SRGB;
}
@@ -1797,7 +1865,7 @@
}
- mat4 colorMatrix = mColorMatrix * mDaltonizer();
+ mat4 colorMatrix = mColorMatrix * computeSaturationMatrix() * mDaltonizer();
// Set the per-frame data
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
@@ -2163,7 +2231,7 @@
disp.clear();
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
- if (hw->getLayerStack() == currentlayerStack) {
+ if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
if (disp == NULL) {
disp = hw;
} else {
@@ -2212,7 +2280,7 @@
// TODO: we could cache the transformed region
Region visibleReg;
visibleReg.set(layer->computeScreenBounds());
- invalidateLayerStack(layer->getLayerStack(), visibleReg);
+ invalidateLayerStack(layer, visibleReg);
}
});
}
@@ -2261,7 +2329,7 @@
mTransactionCV.broadcast();
}
-void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& outDirtyRegion, Region& outOpaqueRegion)
{
ATRACE_CALL();
@@ -2278,7 +2346,7 @@
const Layer::State& s(layer->getDrawingState());
// only consider the layers on the given layer stack
- if (layer->getLayerStack() != layerStack)
+ if (!layer->belongsToDisplay(displayDevice->getLayerStack(), displayDevice->isPrimary()))
return;
/*
@@ -2393,11 +2461,10 @@
outOpaqueRegion = aboveOpaqueLayers;
}
-void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
- const Region& dirty) {
+void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
- if (hw->getLayerStack() == layerStack) {
+ if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
hw->dirtyRegion.orSelf(dirty);
}
}
@@ -2438,8 +2505,8 @@
for (auto& layer : mLayersWithQueuedFrames) {
const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
layer->useSurfaceDamage();
- invalidateLayerStack(layer->getLayerStack(), dirty);
- if (!dirty.isEmpty()) {
+ invalidateLayerStack(layer, dirty);
+ if (layer->isBufferLatched()) {
newDataLatched = true;
}
}
@@ -2449,7 +2516,7 @@
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
- if (frameQueued && mLayersWithQueuedFrames.empty()) {
+ if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
signalLayerUpdate();
}
@@ -2533,8 +2600,10 @@
ALOGV("hasClientComposition");
#ifdef USE_HWC2
- mRenderEngine->setColorMode(displayDevice->getActiveColorMode());
- mRenderEngine->setWideColor(displayDevice->getWideColorSupport());
+ mRenderEngine->setWideColor(
+ displayDevice->getWideColorSupport() && !mForceNativeColorMode);
+ mRenderEngine->setColorMode(mForceNativeColorMode ?
+ HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
#endif
if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
@@ -2677,6 +2746,8 @@
{
Mutex::Autolock _l(mStateLock);
if (mNumLayers >= MAX_LAYERS) {
+ ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers,
+ MAX_LAYERS);
return NO_MEMORY;
}
if (parent == nullptr) {
@@ -2813,10 +2884,12 @@
}
}
- // If a synchronous transaction is explicitly requested without any changes,
- // force a transaction anyway. This can be used as a flush mechanism for
- // previous async transactions.
- if (transactionFlags == 0 && (flags & eSynchronous)) {
+ // If a synchronous transaction is explicitly requested without any changes, force a transaction
+ // anyway. This can be used as a flush mechanism for previous async transactions.
+ // Empty animation transaction can be used to simulate back-pressure, so also force a
+ // transaction for empty animation transactions.
+ if (transactionFlags == 0 &&
+ ((flags & eSynchronous) || (flags & eAnimation))) {
transactionFlags = eTransactionNeeded;
}
@@ -3058,6 +3131,13 @@
return result;
}
+ // window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java
+ // TODO b/64227542
+ if (windowType == 441731) {
+ windowType = 2024; // TYPE_NAVIGATION_BAR_PANEL
+ layer->setPrimaryDisplayOnly();
+ }
+
layer->setInfo(windowType, ownerUid);
result = addClientLayer(client, *handle, *gbp, layer, *parent);
@@ -3230,7 +3310,8 @@
if (currentMode == HWC_POWER_MODE_OFF) {
// Turn on the display
getHwComposer().setPowerMode(type, mode);
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (type == DisplayDevice::DISPLAY_PRIMARY &&
+ mode != HWC_POWER_MODE_DOZE_SUSPEND) {
// FIXME: eventthread only knows about the main display right now
mEventThread->onScreenAcquired();
resyncToHardwareVsync(true);
@@ -3262,7 +3343,25 @@
getHwComposer().setPowerMode(type, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
+ } else if (mode == HWC_POWER_MODE_DOZE ||
+ mode == HWC_POWER_MODE_NORMAL) {
+ // Update display while dozing
+ getHwComposer().setPowerMode(type, mode);
+ if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ // FIXME: eventthread only knows about the main display right now
+ mEventThread->onScreenAcquired();
+ resyncToHardwareVsync(true);
+ }
+ } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
+ // Leave display going to doze
+ if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ disableHardwareVsync(true); // also cancels any in-progress resync
+ // FIXME: eventthread only knows about the main display right now
+ mEventThread->onScreenReleased();
+ }
+ getHwComposer().setPowerMode(type, mode);
} else {
+ ALOGE("Attempting to set unknown power mode: %d\n", mode);
getHwComposer().setPowerMode(type, mode);
}
}
@@ -3542,6 +3641,7 @@
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
+ result.appendFormat("forceNativeColorMode: %d\n", mForceNativeColorMode);
// TODO: print out if wide-color mode is active or not
@@ -3731,6 +3831,15 @@
*/
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
+
+ /*
+ * Dump VrFlinger state if in use.
+ */
+ if (mVrFlingerRequestsDisplay && mVrFlinger) {
+ result.append("VrFlinger state:\n");
+ result.append(mVrFlinger->Dump().c_str());
+ result.append("\n");
+ }
}
const Vector< sp<Layer> >&
@@ -3831,10 +3940,11 @@
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) {
- IPCThreadState* ipc = IPCThreadState::self();
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int uid = ipc->getCallingUid();
+ if (CC_UNLIKELY(uid != AID_SYSTEM
+ && !PermissionCache::checkCallingPermission(sHardwareTest))) {
const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
ALOGE("Permission Denial: "
"can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
@@ -3919,9 +4029,7 @@
// apply a color matrix
n = data.readInt32();
if (n) {
- // color matrix is sent as mat3 matrix followed by vec3
- // offset, then packed into a mat4 where the last row is
- // the offset and extra values are 0
+ // color matrix is sent as a column-major mat4 matrix
for (size_t i = 0 ; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
mColorMatrix[i][j] = data.readFloat();
@@ -3930,6 +4038,14 @@
} else {
mColorMatrix = mat4();
}
+
+ // Check that supplied matrix's last row is {0,0,0,1} so we can avoid
+ // the division by w in the fragment shader
+ float4 lastRow(transpose(mColorMatrix)[3]);
+ if (any(greaterThan(abs(lastRow - float4{0, 0, 0, 1}), float4{1e-4f}))) {
+ ALOGE("The color transform's last row must be (0, 0, 0, 1)");
+ }
+
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
@@ -3973,6 +4089,24 @@
mUseHwcVirtualDisplays = !n;
return NO_ERROR;
}
+ case 1022: { // Set saturation boost
+ mSaturation = std::max(0.0f, std::min(data.readFloat(), 2.0f));
+
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ }
+ case 1023: { // Set native mode
+ mForceNativeColorMode = data.readInt32() == 1;
+
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ }
+ case 1024: { // Is wide color gamut rendering/color management supported?
+ reply->writeBool(hasWideColorDisplay);
+ return NO_ERROR;
+ }
}
}
return err;
@@ -3983,128 +4117,88 @@
signalTransaction();
}
-// ---------------------------------------------------------------------------
-// Capture screen into an IGraphiBufferProducer
-// ---------------------------------------------------------------------------
+// Checks that the requested width and height are valid and updates them to the display dimensions
+// if they are set to 0
+static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice,
+ Transform::orientation_flags rotation,
+ uint32_t* requestedWidth, uint32_t* requestedHeight) {
+ // get screen geometry
+ uint32_t displayWidth = displayDevice->getWidth();
+ uint32_t displayHeight = displayDevice->getHeight();
-/* The code below is here to handle b/8734824
- *
- * We create a IGraphicBufferProducer wrapper that forwards all calls
- * from the surfaceflinger thread to the calling binder thread, where they
- * are executed. This allows the calling thread in the calling process to be
- * reused and not depend on having "enough" binder threads to handle the
- * requests.
- */
-class GraphicProducerWrapper : public BBinder, public MessageHandler {
- /* Parts of GraphicProducerWrapper are run on two different threads,
- * communicating by sending messages via Looper but also by shared member
- * data. Coherence maintenance is subtle and in places implicit (ugh).
- *
- * Don't rely on Looper's sendMessage/handleMessage providing
- * release/acquire semantics for any data not actually in the Message.
- * Data going from surfaceflinger to binder threads needs to be
- * synchronized explicitly.
- *
- * Barrier open/wait do provide release/acquire semantics. This provides
- * implicit synchronization for data coming back from binder to
- * surfaceflinger threads.
- */
-
- sp<IGraphicBufferProducer> impl;
- sp<Looper> looper;
- status_t result;
- bool exitPending;
- bool exitRequested;
- Barrier barrier;
- uint32_t code;
- Parcel const* data;
- Parcel* reply;
-
- enum {
- MSG_API_CALL,
- MSG_EXIT
- };
-
- /*
- * Called on surfaceflinger thread. This is called by our "fake"
- * BpGraphicBufferProducer. We package the data and reply Parcel and
- * forward them to the binder thread.
- */
- virtual status_t transact(uint32_t code,
- const Parcel& data, Parcel* reply, uint32_t /* flags */) {
- this->code = code;
- this->data = &data;
- this->reply = reply;
- if (exitPending) {
- // if we've exited, we run the message synchronously right here.
- // note (JH): as far as I can tell from looking at the code, this
- // never actually happens. if it does, i'm not sure if it happens
- // on the surfaceflinger or binder thread.
- handleMessage(Message(MSG_API_CALL));
- } else {
- barrier.close();
- // Prevent stores to this->{code, data, reply} from being
- // reordered later than the construction of Message.
- atomic_thread_fence(memory_order_release);
- looper->sendMessage(this, Message(MSG_API_CALL));
- barrier.wait();
- }
- return result;
+ if (rotation & Transform::ROT_90) {
+ std::swap(displayWidth, displayHeight);
}
- /*
- * here we run on the binder thread. All we've got to do is
- * call the real BpGraphicBufferProducer.
- */
- virtual void handleMessage(const Message& message) {
- int what = message.what;
- // Prevent reads below from happening before the read from Message
- atomic_thread_fence(memory_order_acquire);
- if (what == MSG_API_CALL) {
- result = IInterface::asBinder(impl)->transact(code, data[0], reply);
- barrier.open();
- } else if (what == MSG_EXIT) {
- exitRequested = true;
- }
+ if ((*requestedWidth > displayWidth) || (*requestedHeight > displayHeight)) {
+ ALOGE("size mismatch (%d, %d) > (%d, %d)",
+ *requestedWidth, *requestedHeight, displayWidth, displayHeight);
+ return BAD_VALUE;
}
+ if (*requestedWidth == 0) {
+ *requestedWidth = displayWidth;
+ }
+ if (*requestedHeight == 0) {
+ *requestedHeight = displayHeight;
+ }
+
+ return NO_ERROR;
+}
+
+// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
+class WindowDisconnector {
public:
- explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
- : impl(impl),
- looper(new Looper(true)),
- result(NO_ERROR),
- exitPending(false),
- exitRequested(false),
- code(0),
- data(NULL),
- reply(NULL)
- {}
-
- // Binder thread
- status_t waitForResponse() {
- do {
- looper->pollOnce(-1);
- } while (!exitRequested);
- return result;
+ WindowDisconnector(ANativeWindow* window, int api) : mWindow(window), mApi(api) {}
+ ~WindowDisconnector() {
+ native_window_api_disconnect(mWindow, mApi);
}
- // Client thread
- void exit(status_t result) {
- this->result = result;
- exitPending = true;
- // Ensure this->result is visible to the binder thread before it
- // handles the message.
- atomic_thread_fence(memory_order_release);
- looper->sendMessage(this, Message(MSG_EXIT));
- }
+private:
+ ANativeWindow* mWindow;
+ const int mApi;
};
+static status_t getWindowBuffer(ANativeWindow* window, uint32_t requestedWidth,
+ uint32_t requestedHeight, bool hasWideColorDisplay,
+ bool renderEngineUsesWideColor, ANativeWindowBuffer** outBuffer) {
+ const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+
+ int err = 0;
+ err = native_window_set_buffers_dimensions(window, requestedWidth, requestedHeight);
+ err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+ err |= native_window_set_usage(window, usage);
+
+ if (hasWideColorDisplay) {
+ err |= native_window_set_buffers_data_space(window,
+ renderEngineUsesWideColor
+ ? HAL_DATASPACE_DISPLAY_P3
+ : HAL_DATASPACE_V0_SRGB);
+ }
+
+ if (err != NO_ERROR) {
+ return BAD_VALUE;
+ }
+
+ /* TODO: Once we have the sync framework everywhere this can use
+ * server-side waits on the fence that dequeueBuffer returns.
+ */
+ err = native_window_dequeue_buffer_and_wait(window, outBuffer);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ return NO_ERROR;
+}
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
int32_t minLayerZ, int32_t maxLayerZ,
bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+ ATRACE_CALL();
if (CC_UNLIKELY(display == 0))
return BAD_VALUE;
@@ -4138,65 +4232,96 @@
break;
}
- class MessageCaptureScreen : public MessageBase {
- SurfaceFlinger* flinger;
- sp<IBinder> display;
- sp<IGraphicBufferProducer> producer;
- Rect sourceCrop;
- uint32_t reqWidth, reqHeight;
- uint32_t minLayerZ,maxLayerZ;
- bool useIdentityTransform;
- Transform::orientation_flags rotation;
- status_t result;
- bool isLocalScreenshot;
- public:
- MessageCaptureScreen(SurfaceFlinger* flinger,
- const sp<IBinder>& display,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform,
- Transform::orientation_flags rotation,
- bool isLocalScreenshot)
- : flinger(flinger), display(display), producer(producer),
- sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
- minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
- useIdentityTransform(useIdentityTransform),
- rotation(rotation), result(PERMISSION_DENIED),
- isLocalScreenshot(isLocalScreenshot)
- {
- }
- status_t getResult() const {
- return result;
- }
- virtual bool handler() {
- Mutex::Autolock _l(flinger->mStateLock);
- sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display));
- result = flinger->captureScreenImplLocked(hw, producer,
- sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotation, isLocalScreenshot);
- static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
- return true;
- }
- };
-
- // this creates a "fake" BBinder which will serve as a "fake" remote
- // binder to receive the marshaled calls and forward them to the
- // real remote (a BpGraphicBufferProducer)
- sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer);
-
- // the asInterface() call below creates our "fake" BpGraphicBufferProducer
- // which does the marshaling work forwards to our "fake remote" above.
- sp<MessageBase> msg = new MessageCaptureScreen(this,
- display, IGraphicBufferProducer::asInterface( wrapper ),
- sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
- useIdentityTransform, rotationFlags, isLocalScreenshot);
-
- status_t res = postMessageAsync(msg);
- if (res == NO_ERROR) {
- res = wrapper->waitForResponse();
+ { // Autolock scope
+ Mutex::Autolock lock(mStateLock);
+ sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display));
+ updateDimensionsLocked(displayDevice, rotationFlags, &reqWidth, &reqHeight);
}
- return res;
+
+ // create a surface (because we're a producer, and we need to
+ // dequeue/queue a buffer)
+ sp<Surface> surface = new Surface(producer, false);
+
+ // Put the screenshot Surface into async mode so that
+ // Layer::headFenceHasSignaled will always return true and we'll latch the
+ // first buffer regardless of whether or not its acquire fence has
+ // signaled. This is needed to avoid a race condition in the rotation
+ // animation. See b/30209608
+ surface->setAsyncMode(true);
+
+ ANativeWindow* window = surface.get();
+
+ status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL);
+
+ ANativeWindowBuffer* buffer = nullptr;
+ result = getWindowBuffer(window, reqWidth, reqHeight,
+ hasWideColorDisplay && !mForceNativeColorMode,
+ getRenderEngine().usesWideColor(), &buffer);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ // This mutex protects syncFd and captureResult for communication of the return values from the
+ // main thread back to this Binder thread
+ std::mutex captureMutex;
+ std::condition_variable captureCondition;
+ std::unique_lock<std::mutex> captureLock(captureMutex);
+ int syncFd = -1;
+ std::optional<status_t> captureResult;
+
+ sp<LambdaMessage> message = new LambdaMessage([&]() {
+ // If there is a refresh pending, bug out early and tell the binder thread to try again
+ // after the refresh.
+ if (mRefreshPending) {
+ ATRACE_NAME("Skipping screenshot for now");
+ std::unique_lock<std::mutex> captureLock(captureMutex);
+ captureResult = std::make_optional<status_t>(EAGAIN);
+ captureCondition.notify_one();
+ return;
+ }
+
+ status_t result = NO_ERROR;
+ int fd = -1;
+ {
+ Mutex::Autolock _l(mStateLock);
+ sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
+ result = captureScreenImplLocked(device, buffer, sourceCrop, reqWidth, reqHeight,
+ minLayerZ, maxLayerZ, useIdentityTransform,
+ rotationFlags, isLocalScreenshot, &fd);
+ }
+
+ {
+ std::unique_lock<std::mutex> captureLock(captureMutex);
+ syncFd = fd;
+ captureResult = std::make_optional<status_t>(result);
+ captureCondition.notify_one();
+ }
+ });
+
+ result = postMessageAsync(message);
+ if (result == NO_ERROR) {
+ captureCondition.wait(captureLock, [&]() { return captureResult; });
+ while (*captureResult == EAGAIN) {
+ captureResult.reset();
+ result = postMessageAsync(message);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ captureCondition.wait(captureLock, [&]() { return captureResult; });
+ }
+ result = *captureResult;
+ }
+
+ if (result == NO_ERROR) {
+ // queueBuffer takes ownership of syncFd
+ result = window->queueBuffer(window, buffer, syncFd);
+ }
+
+ return result;
}
@@ -4236,6 +4361,11 @@
ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
}
+#ifdef USE_HWC2
+ engine.setWideColor(hw->getWideColorSupport() && !mForceNativeColorMode);
+ engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : hw->getActiveColorMode());
+#endif
+
// make sure to clear all GL error flags
engine.checkErrors();
@@ -4250,7 +4380,7 @@
// We loop through the first level of layers without traversing,
// as we need to interpret min/max layer Z in the top level Z space.
for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (layer->getLayerStack() != hw->getLayerStack()) {
+ if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
continue;
}
const Layer::State& state(layer->getDrawingState());
@@ -4270,38 +4400,39 @@
hw->setViewportAndProjection();
}
+// A simple RAII class that holds an EGLImage and destroys it either:
+// a) When the destroy() method is called
+// b) When the object goes out of scope
+class ImageHolder {
+public:
+ ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {}
+ ~ImageHolder() { destroy(); }
-status_t SurfaceFlinger::captureScreenImplLocked(
- const sp<const DisplayDevice>& hw,
- const sp<IGraphicBufferProducer>& producer,
- Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- int32_t minLayerZ, int32_t maxLayerZ,
- bool useIdentityTransform, Transform::orientation_flags rotation,
- bool isLocalScreenshot)
-{
+ void destroy() {
+ if (mImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mDisplay, mImage);
+ mImage = EGL_NO_IMAGE_KHR;
+ }
+ }
+
+private:
+ const EGLDisplay mDisplay;
+ EGLImageKHR mImage;
+};
+
+status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& hw,
+ ANativeWindowBuffer* buffer, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight,
+ int32_t minLayerZ, int32_t maxLayerZ,
+ bool useIdentityTransform,
+ Transform::orientation_flags rotation,
+ bool isLocalScreenshot, int* outSyncFd) {
ATRACE_CALL();
- // get screen geometry
- uint32_t hw_w = hw->getWidth();
- uint32_t hw_h = hw->getHeight();
-
- if (rotation & Transform::ROT_90) {
- std::swap(hw_w, hw_h);
- }
-
- if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
- ALOGE("size mismatch (%d, %d) > (%d, %d)",
- reqWidth, reqHeight, hw_w, hw_h);
- return BAD_VALUE;
- }
-
- reqWidth = (!reqWidth) ? hw_w : reqWidth;
- reqHeight = (!reqHeight) ? hw_h : reqHeight;
-
bool secureLayerIsVisible = false;
for (const auto& layer : mDrawingState.layersSortedByZ) {
const Layer::State& state(layer->getDrawingState());
- if ((layer->getLayerStack() != hw->getLayerStack()) ||
+ if (!layer->belongsToDisplay(hw->getLayerStack(), false) ||
(state.z < minLayerZ || state.z > maxLayerZ)) {
continue;
}
@@ -4316,123 +4447,84 @@
return PERMISSION_DENIED;
}
- // create a surface (because we're a producer, and we need to
- // dequeue/queue a buffer)
- sp<Surface> sur = new Surface(producer, false);
-
- // Put the screenshot Surface into async mode so that
- // Layer::headFenceHasSignaled will always return true and we'll latch the
- // first buffer regardless of whether or not its acquire fence has
- // signaled. This is needed to avoid a race condition in the rotation
- // animation. See b/30209608
- sur->setAsyncMode(true);
-
- ANativeWindow* window = sur.get();
-
- status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
- if (result == NO_ERROR) {
- uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-
- int err = 0;
- err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
- err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
- err |= native_window_set_usage(window, usage);
-
- if (err == NO_ERROR) {
- ANativeWindowBuffer* buffer;
- /* TODO: Once we have the sync framework everywhere this can use
- * server-side waits on the fence that dequeueBuffer returns.
- */
- result = native_window_dequeue_buffer_and_wait(window, &buffer);
- if (result == NO_ERROR) {
- int syncFd = -1;
- // create an EGLImage from the buffer so we can later
- // turn it into a texture
- EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
- if (image != EGL_NO_IMAGE_KHR) {
- // this binds the given EGLImage as a framebuffer for the
- // duration of this scope.
- RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
- if (imageBond.getStatus() == NO_ERROR) {
- // this will in fact render into our dequeued buffer
- // via an FBO, which means we didn't have to create
- // an EGLSurface and therefore we're not
- // dependent on the context's EGLConfig.
- renderScreenImplLocked(
- hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
- useIdentityTransform, rotation);
-
- // Attempt to create a sync khr object that can produce a sync point. If that
- // isn't available, create a non-dupable sync object in the fallback path and
- // wait on it directly.
- EGLSyncKHR sync;
- if (!DEBUG_SCREENSHOTS) {
- sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
- // native fence fd will not be populated until flush() is done.
- getRenderEngine().flush();
- } else {
- sync = EGL_NO_SYNC_KHR;
- }
- if (sync != EGL_NO_SYNC_KHR) {
- // get the sync fd
- syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
- if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- ALOGW("captureScreen: failed to dup sync khr object");
- syncFd = -1;
- }
- eglDestroySyncKHR(mEGLDisplay, sync);
- } else {
- // fallback path
- sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
- if (sync != EGL_NO_SYNC_KHR) {
- EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
- EGLint eglErr = eglGetError();
- if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ALOGW("captureScreen: fence wait timed out");
- } else {
- ALOGW_IF(eglErr != EGL_SUCCESS,
- "captureScreen: error waiting on EGL fence: %#x", eglErr);
- }
- eglDestroySyncKHR(mEGLDisplay, sync);
- } else {
- ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
- }
- }
- if (DEBUG_SCREENSHOTS) {
- uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
- getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
- checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
- hw, minLayerZ, maxLayerZ);
- delete [] pixels;
- }
-
- } else {
- ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
- result = INVALID_OPERATION;
- window->cancelBuffer(window, buffer, syncFd);
- buffer = NULL;
- }
- // destroy our image
- eglDestroyImageKHR(mEGLDisplay, image);
- } else {
- result = BAD_VALUE;
- }
- if (buffer) {
- // queueBuffer takes ownership of syncFd
- result = window->queueBuffer(window, buffer, syncFd);
- }
- }
- } else {
- result = BAD_VALUE;
- }
- native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ int syncFd = -1;
+ // create an EGLImage from the buffer so we can later
+ // turn it into a texture
+ EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
+ if (image == EGL_NO_IMAGE_KHR) {
+ return BAD_VALUE;
}
- return result;
+ // This will automatically destroy the image if we return before calling its destroy method
+ ImageHolder imageHolder(mEGLDisplay, image);
+
+ // this binds the given EGLImage as a framebuffer for the
+ // duration of this scope.
+ RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
+ if (imageBond.getStatus() != NO_ERROR) {
+ ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
+ return INVALID_OPERATION;
+ }
+
+ // this will in fact render into our dequeued buffer
+ // via an FBO, which means we didn't have to create
+ // an EGLSurface and therefore we're not
+ // dependent on the context's EGLConfig.
+ renderScreenImplLocked(
+ hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
+ useIdentityTransform, rotation);
+
+ // Attempt to create a sync khr object that can produce a sync point. If that
+ // isn't available, create a non-dupable sync object in the fallback path and
+ // wait on it directly.
+ EGLSyncKHR sync = EGL_NO_SYNC_KHR;
+ if (!DEBUG_SCREENSHOTS) {
+ sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+ // native fence fd will not be populated until flush() is done.
+ getRenderEngine().flush();
+ }
+
+ if (sync != EGL_NO_SYNC_KHR) {
+ // get the sync fd
+ syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
+ if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGW("captureScreen: failed to dup sync khr object");
+ syncFd = -1;
+ }
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ } else {
+ // fallback path
+ sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
+ if (sync != EGL_NO_SYNC_KHR) {
+ EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
+ EGLint eglErr = eglGetError();
+ if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGW("captureScreen: fence wait timed out");
+ } else {
+ ALOGW_IF(eglErr != EGL_SUCCESS,
+ "captureScreen: error waiting on EGL fence: %#x", eglErr);
+ }
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ } else {
+ ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
+ }
+ }
+ *outSyncFd = syncFd;
+
+ if (DEBUG_SCREENSHOTS) {
+ uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
+ getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
+ checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
+ hw, minLayerZ, maxLayerZ);
+ delete [] pixels;
+ }
+
+ // destroy our image
+ imageHolder.destroy();
+
+ return NO_ERROR;
}
void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
@@ -4451,7 +4543,7 @@
size_t i = 0;
for (const auto& layer : mDrawingState.layersSortedByZ) {
const Layer::State& state(layer->getDrawingState());
- if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ &&
+ if (layer->belongsToDisplay(hw->getLayerStack(), false) && state.z >= minLayerZ &&
state.z <= maxLayerZ) {
layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ba4f9ae..e65a227 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -58,7 +58,7 @@
#include "LayerVector.h"
#include "MessageQueue.h"
#include "SurfaceInterceptor.h"
-#include "StartBootAnimThread.h"
+#include "StartPropertySetThread.h"
#include "DisplayHardware/HWComposer.h"
#include "Effects/Daltonizer.h"
@@ -227,7 +227,6 @@
enum { LOG_FRAME_STATS_PERIOD = 30*60*60 };
static const size_t MAX_LAYERS = 4096;
- static constexpr const char* kTimestampProperty = "service.sf.present_timestamp";
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -420,6 +419,14 @@
int32_t minLayerZ, int32_t maxLayerZ,
bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation);
+#ifdef USE_HWC2
+ status_t captureScreenImplLocked(const sp<const DisplayDevice>& device,
+ ANativeWindowBuffer* buffer, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
+ int32_t maxLayerZ, bool useIdentityTransform,
+ Transform::orientation_flags rotation, bool isLocalScreenshot,
+ int* outSyncFd);
+#else
status_t captureScreenImplLocked(
const sp<const DisplayDevice>& hw,
const sp<IGraphicBufferProducer>& producer,
@@ -427,8 +434,14 @@
int32_t minLayerZ, int32_t maxLayerZ,
bool useIdentityTransform, Transform::orientation_flags rotation,
bool isLocalScreenshot);
+#endif
- sp<StartBootAnimThread> mStartBootAnimThread = nullptr;
+ sp<StartPropertySetThread> mStartPropertySetThread = nullptr;
+
+ /* ------------------------------------------------------------------------
+ * Properties
+ */
+ void readPersistentProperties();
/* ------------------------------------------------------------------------
* EGL
@@ -484,7 +497,7 @@
// mark a region of a layer stack dirty. this updates the dirty
// region of all screens presenting this layer stack.
- void invalidateLayerStack(uint32_t layerStack, const Region& dirty);
+ void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
#ifndef USE_HWC2
int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type);
@@ -500,7 +513,7 @@
* Compositing
*/
void invalidateHwcGeometry();
- void computeVisibleRegions(uint32_t layerStack,
+ void computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& dirtyRegion, Region& opaqueRegion);
void preComposition(nsecs_t refreshStartTime);
@@ -515,8 +528,10 @@
// Given a dataSpace, returns the appropriate color_mode to use
// to display that dataSpace.
- android_color_mode pickColorMode(android_dataspace dataSpace);
- android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b);
+ android_color_mode pickColorMode(android_dataspace dataSpace) const;
+ android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b) const;
+
+ mat4 computeSaturationMatrix() const;
void setUpHWComposer();
void doComposition();
@@ -578,7 +593,12 @@
/* ------------------------------------------------------------------------
* VrFlinger
*/
- void clearHwcLayers(const LayerVector& layers);
+ template<typename T>
+ void clearHwcLayers(const T& layers) {
+ for (size_t i = 0; i < layers.size(); ++i) {
+ layers[i]->clearHwcLayers();
+ }
+ }
void resetHwcLocked();
// Check to see if we should handoff to vr flinger.
@@ -696,6 +716,8 @@
};
std::queue<CompositePresentTime> mCompositePresentTimes;
+ std::atomic<bool> mRefreshPending{false};
+
/* ------------------------------------------------------------------------
* Feature prototyping
*/
@@ -751,7 +773,10 @@
std::atomic<bool> mVrFlingerRequestsDisplay;
static bool useVrFlinger;
#endif
- };
+
+ float mSaturation = 1.0f;
+ bool mForceNativeColorMode = false;
+};
}; // namespace android
#endif // ANDROID_SURFACE_FLINGER_H
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 0904fab..247d80b 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -320,8 +320,8 @@
void SurfaceFlinger::bootFinished()
{
- if (mStartBootAnimThread->join() != NO_ERROR) {
- ALOGE("Join StartBootAnimThread failed!");
+ if (mStartPropertySetThread->join() != NO_ERROR) {
+ ALOGE("Join StartPropertySetThread failed!");
}
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
@@ -501,6 +501,8 @@
sp<VSyncSource::Callback> mCallback;
};
+// Do not call property_set on main thread which will be blocked by init
+// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
@@ -536,7 +538,8 @@
*static_cast<HWComposer::EventHandler *>(this));
// get a RenderEngine for the given display / config (can't fail)
- mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
+ mRenderEngine = RenderEngine::create(mEGLDisplay,
+ mHwc->getVisualID(), 0);
// retrieve the EGL context that was selected/created
mEGLContext = mRenderEngine->getEGLContext();
@@ -544,9 +547,6 @@
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
- // Inform native graphics APIs that the present timestamp is NOT supported:
- property_set(kTimestampProperty, "0");
-
// initialize our non-virtual displays
for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
@@ -599,9 +599,10 @@
mRenderEngine->primeCache();
- mStartBootAnimThread = new StartBootAnimThread();
- if (mStartBootAnimThread->Start() != NO_ERROR) {
- ALOGE("Run StartBootAnimThread failed!");
+ // Inform native graphics APIs that the present timestamp is NOT supported:
+ mStartPropertySetThread = new StartPropertySetThread(false);
+ if (mStartPropertySetThread->Start() != NO_ERROR) {
+ ALOGE("Run StartPropertySetThread failed!");
}
ALOGV("Done initializing");
@@ -615,10 +616,10 @@
void SurfaceFlinger::startBootAnim() {
// Start boot animation service by setting a property mailbox
// if property setting thread is already running, Start() will be just a NOP
- mStartBootAnimThread->Start();
+ mStartPropertySetThread->Start();
// Wait until property was set
- if (mStartBootAnimThread->join() != NO_ERROR) {
- ALOGE("Join StartBootAnimThread failed!");
+ if (mStartPropertySetThread->join() != NO_ERROR) {
+ ALOGE("Join StartPropertySetThread failed!");
}
}
@@ -1360,8 +1361,7 @@
const Transform& tr(hw->getTransform());
const Rect bounds(hw->getBounds());
if (hw->isDisplayOn()) {
- computeVisibleRegions(hw->getLayerStack(), dirtyRegion,
- opaqueRegion);
+ computeVisibleRegions(hw, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->getLayerStack() == hw->getLayerStack()) {
@@ -1862,7 +1862,7 @@
// TODO: we could cache the transformed region
Region visibleReg;
visibleReg.set(layer->computeScreenBounds());
- invalidateLayerStack(layer->getLayerStack(), visibleReg);
+ invalidateLayerStack(layer, visibleReg);
}
});
}
@@ -1923,7 +1923,7 @@
mTransactionCV.broadcast();
}
-void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& outDirtyRegion, Region& outOpaqueRegion)
{
ATRACE_CALL();
@@ -1939,7 +1939,7 @@
const Layer::State& s(layer->getDrawingState());
// only consider the layers on the given layer stack
- if (layer->getLayerStack() != layerStack)
+ if (layer->getLayerStack() != displayDevice->getLayerStack())
return;
/*
@@ -2054,8 +2054,8 @@
outOpaqueRegion = aboveOpaqueLayers;
}
-void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
- const Region& dirty) {
+void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
+ uint32_t layerStack = layer->getLayerStack();
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
if (hw->getLayerStack() == layerStack) {
@@ -2098,7 +2098,7 @@
Layer* layer = layersWithQueuedFrames[i];
const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
layer->useSurfaceDamage();
- invalidateLayerStack(layer->getLayerStack(), dirty);
+ invalidateLayerStack(layer, dirty);
}
mVisibleRegionsDirty |= visibleRegions;
@@ -2870,7 +2870,8 @@
if (currentMode == HWC_POWER_MODE_OFF) {
// Turn on the display
getHwComposer().setPowerMode(type, mode);
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (type == DisplayDevice::DISPLAY_PRIMARY &&
+ mode != HWC_POWER_MODE_DOZE_SUSPEND) {
// FIXME: eventthread only knows about the main display right now
mEventThread->onScreenAcquired();
resyncToHardwareVsync(true);
@@ -2902,7 +2903,25 @@
getHwComposer().setPowerMode(type, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
+ } else if (mode == HWC_POWER_MODE_DOZE ||
+ mode == HWC_POWER_MODE_NORMAL) {
+ // Update display while dozing
+ getHwComposer().setPowerMode(type, mode);
+ if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ // FIXME: eventthread only knows about the main display right now
+ mEventThread->onScreenAcquired();
+ resyncToHardwareVsync(true);
+ }
+ } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
+ // Leave display going to doze
+ if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ disableHardwareVsync(true); // also cancels any in-progress resync
+ // FIXME: eventthread only knows about the main display right now
+ mEventThread->onScreenReleased();
+ }
+ getHwComposer().setPowerMode(type, mode);
} else {
+ ALOGE("Attempting to set unknown power mode: %d\n", mode);
getHwComposer().setPowerMode(type, mode);
}
}
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index 16041da..43e22a0 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -4,7 +4,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := SurfaceFlinger_test
-
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
diff --git a/services/surfaceflinger/tests/AndroidTest.xml b/services/surfaceflinger/tests/AndroidTest.xml
new file mode 100644
index 0000000..8315037
--- /dev/null
+++ b/services/surfaceflinger/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for SurfaceFlinger_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="SurfaceFlinger_test->/data/local/tmp/SurfaceFlinger_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="SurfaceFlinger_test" />
+ </test>
+</configuration>
diff --git a/services/surfaceflinger/tests/vsync/Android.mk b/services/surfaceflinger/tests/vsync/Android.mk
index 9181760..8e41617 100644
--- a/services/surfaceflinger/tests/vsync/Android.mk
+++ b/services/surfaceflinger/tests/vsync/Android.mk
@@ -15,4 +15,6 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS := -Werror
+
include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index aa72c79..a1b45e6 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -20,7 +20,7 @@
using namespace android;
-int receiver(int fd, int events, void* data)
+int receiver(int /*fd*/, int /*events*/, void* data)
{
DisplayEventReceiver* q = (DisplayEventReceiver*)data;
@@ -47,7 +47,7 @@
return 1;
}
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
DisplayEventReceiver myDisplayEvent;
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.mk b/services/surfaceflinger/tests/waitforvsync/Android.mk
index c25f5ab..932d2be 100644
--- a/services/surfaceflinger/tests/waitforvsync/Android.mk
+++ b/services/surfaceflinger/tests/waitforvsync/Android.mk
@@ -11,4 +11,6 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS := -Werror
+
include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
index b88b04a..65eaae5 100644
--- a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
+++ b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
@@ -29,7 +29,7 @@
#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
#endif
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
int fd = open("/dev/graphics/fb0", O_RDWR);
if (fd >= 0) {
do {
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index d27f274..26843c9 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -382,7 +382,7 @@
}
Status<QueueInfo> BufferHubService::OnCreateProducerQueue(
- pdx::Message& message, size_t meta_size_bytes,
+ pdx::Message& message, const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy) {
// Use the producer channel id as the global queue id.
const int queue_id = message.GetChannelId();
@@ -396,11 +396,11 @@
return ErrorStatus(EALREADY);
}
- auto status = ProducerQueueChannel::Create(this, queue_id, meta_size_bytes,
+ auto status = ProducerQueueChannel::Create(this, queue_id, producer_config,
usage_policy);
if (status) {
message.SetChannel(status.take());
- return {{meta_size_bytes, queue_id}};
+ return {{producer_config, queue_id}};
} else {
ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!");
return status.error_status();
diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h
index 3bc2635..b0df11f 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -166,9 +166,9 @@
size_t meta_size_bytes);
pdx::Status<void> OnGetPersistentBuffer(pdx::Message& message,
const std::string& name);
- pdx::Status<QueueInfo> OnCreateProducerQueue(pdx::Message& message,
- size_t meta_size_bytes,
- const UsagePolicy& usage_policy);
+ pdx::Status<QueueInfo> OnCreateProducerQueue(
+ pdx::Message& message, const ProducerQueueConfig& producer_config,
+ const UsagePolicy& usage_policy);
BufferHubService(const BufferHubService&) = delete;
void operator=(const BufferHubService&) = delete;
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 08b2790..ac6896a 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -8,9 +8,9 @@
#include <private/dvr/bufferhub_rpc.h>
#include "producer_channel.h"
-using android::pdx::ErrorStatus;
using android::pdx::BorrowedHandle;
using android::pdx::Channel;
+using android::pdx::ErrorStatus;
using android::pdx::Message;
using android::pdx::Status;
using android::pdx::rpc::DispatchRemoteMethod;
@@ -22,8 +22,6 @@
int channel_id,
const std::shared_ptr<Channel> producer)
: BufferHubChannel(service, buffer_id, channel_id, kConsumerType),
- handled_(true),
- ignored_(false),
producer_(producer) {
GetProducer()->AddConsumer(this);
}
@@ -34,7 +32,7 @@
channel_id(), buffer_id());
if (auto producer = GetProducer()) {
- if (!handled_) // Producer is waiting for our Release.
+ if (!released_) // Producer is waiting for our Release.
producer->OnConsumerIgnored();
producer->RemoveConsumer(this);
}
@@ -108,15 +106,20 @@
if (!producer)
return ErrorStatus(EPIPE);
- if (ignored_ || handled_) {
+ if (acquired_ || released_) {
ALOGE(
"ConsumerChannel::OnConsumerAcquire: Acquire when not posted: "
- "ignored=%d handled=%d channel_id=%d buffer_id=%d",
- ignored_, handled_, message.GetChannelId(), producer->buffer_id());
+ "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
+ ignored_, acquired_, released_, message.GetChannelId(),
+ producer->buffer_id());
return ErrorStatus(EBUSY);
} else {
- ClearAvailable();
- return producer->OnConsumerAcquire(message, metadata_size);
+ auto status = producer->OnConsumerAcquire(message, metadata_size);
+ if (status) {
+ ClearAvailable();
+ acquired_ = true;
+ }
+ return status;
}
}
@@ -127,17 +130,21 @@
if (!producer)
return ErrorStatus(EPIPE);
- if (ignored_ || handled_) {
+ if (!acquired_ || released_) {
ALOGE(
"ConsumerChannel::OnConsumerRelease: Release when not acquired: "
- "ignored=%d handled=%d channel_id=%d buffer_id=%d",
- ignored_, handled_, message.GetChannelId(), producer->buffer_id());
+ "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
+ ignored_, acquired_, released_, message.GetChannelId(),
+ producer->buffer_id());
return ErrorStatus(EBUSY);
} else {
- ClearAvailable();
auto status =
producer->OnConsumerRelease(message, std::move(release_fence));
- handled_ = !!status;
+ if (status) {
+ ClearAvailable();
+ acquired_ = false;
+ released_ = true;
+ }
return status;
}
}
@@ -149,12 +156,13 @@
return ErrorStatus(EPIPE);
ignored_ = ignored;
- if (ignored_ && !handled_) {
+ if (ignored_ && acquired_) {
// Update the producer if ignore is set after the consumer acquires the
// buffer.
ClearAvailable();
producer->OnConsumerIgnored();
- handled_ = false;
+ acquired_ = false;
+ released_ = true;
}
return {};
@@ -162,10 +170,12 @@
bool ConsumerChannel::OnProducerPosted() {
if (ignored_) {
- handled_ = true;
+ acquired_ = false;
+ released_ = true;
return false;
} else {
- handled_ = false;
+ acquired_ = false;
+ released_ = false;
SignalAvailable();
return true;
}
diff --git a/services/vr/bufferhubd/consumer_channel.h b/services/vr/bufferhubd/consumer_channel.h
index d84055c..208a002 100644
--- a/services/vr/bufferhubd/consumer_channel.h
+++ b/services/vr/bufferhubd/consumer_channel.h
@@ -38,8 +38,9 @@
LocalFence release_fence);
pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore);
- bool handled_; // True if we have processed RELEASE.
- bool ignored_; // True if we are ignoring events.
+ bool acquired_{false};
+ bool released_{true};
+ bool ignored_{false}; // True if we are ignoring events.
std::weak_ptr<Channel> producer_;
ConsumerChannel(const ConsumerChannel&) = delete;
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b9984a0..b2db795 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -122,7 +122,7 @@
}
Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer(
- Message& message) {
+ Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGetBuffer");
ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
return {NativeBufferHandle<BorrowedHandle>(buffer_, buffer_id())};
@@ -204,7 +204,7 @@
return {};
}
-Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) {
+Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGain");
ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
if (producer_owns_) {
@@ -224,7 +224,7 @@
}
Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
-ProducerChannel::OnConsumerAcquire(Message& message,
+ProducerChannel::OnConsumerAcquire(Message& /*message*/,
std::size_t metadata_size) {
ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index 886e621..b8bb728 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -16,11 +16,11 @@
ProducerQueueChannel::ProducerQueueChannel(BufferHubService* service,
int channel_id,
- size_t meta_size_bytes,
+ const ProducerQueueConfig& config,
const UsagePolicy& usage_policy,
int* error)
: BufferHubChannel(service, channel_id, channel_id, kProducerQueueType),
- meta_size_bytes_(meta_size_bytes),
+ config_(config),
usage_policy_(usage_policy),
capacity_(0) {
*error = 0;
@@ -35,8 +35,8 @@
/* static */
Status<std::shared_ptr<ProducerQueueChannel>> ProducerQueueChannel::Create(
- BufferHubService* service, int channel_id, size_t meta_size_bytes,
- const UsagePolicy& usage_policy) {
+ BufferHubService* service, int channel_id,
+ const ProducerQueueConfig& config, const UsagePolicy& usage_policy) {
// Configuration between |usage_deny_set_mask| and |usage_deny_clear_mask|
// should be mutually exclusive.
if ((usage_policy.usage_deny_set_mask & usage_policy.usage_deny_clear_mask)) {
@@ -50,7 +50,7 @@
int error = 0;
std::shared_ptr<ProducerQueueChannel> producer(new ProducerQueueChannel(
- service, channel_id, meta_size_bytes, usage_policy, &error));
+ service, channel_id, config, usage_policy, &error));
if (error < 0)
return ErrorStatus(-error);
else
@@ -76,9 +76,9 @@
message);
return true;
- case BufferHubRPC::ProducerQueueDetachBuffer::Opcode:
- DispatchRemoteMethod<BufferHubRPC::ProducerQueueDetachBuffer>(
- *this, &ProducerQueueChannel::OnProducerQueueDetachBuffer, message);
+ case BufferHubRPC::ProducerQueueRemoveBuffer::Opcode:
+ DispatchRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(
+ *this, &ProducerQueueChannel::OnProducerQueueRemoveBuffer, message);
return true;
default:
@@ -134,7 +134,7 @@
}
Status<QueueInfo> ProducerQueueChannel::OnGetQueueInfo(Message&) {
- return {{meta_size_bytes_, buffer_id()}};
+ return {{config_, buffer_id()}};
}
Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
@@ -222,7 +222,7 @@
auto producer_channel_status =
ProducerChannel::Create(service(), buffer_id, width, height, layer_count,
- format, usage, meta_size_bytes_);
+ format, usage, config_.meta_size_bytes);
if (!producer_channel_status) {
ALOGE(
"ProducerQueueChannel::AllocateBuffer: Failed to create producer "
@@ -276,11 +276,11 @@
return {{std::move(buffer_handle), slot}};
}
-Status<void> ProducerQueueChannel::OnProducerQueueDetachBuffer(
+Status<void> ProducerQueueChannel::OnProducerQueueRemoveBuffer(
Message& /*message*/, size_t slot) {
if (buffers_[slot].expired()) {
ALOGE(
- "ProducerQueueChannel::OnProducerQueueDetachBuffer: trying to detach "
+ "ProducerQueueChannel::OnProducerQueueRemoveBuffer: trying to remove "
"an invalid buffer producer at slot %zu",
slot);
return ErrorStatus(EINVAL);
@@ -288,7 +288,7 @@
if (capacity_ == 0) {
ALOGE(
- "ProducerQueueChannel::OnProducerQueueDetachBuffer: trying to detach a "
+ "ProducerQueueChannel::OnProducerQueueRemoveBuffer: trying to remove a "
"buffer producer while the queue's capacity is already zero.");
return ErrorStatus(EINVAL);
}
diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h
index 28c74cd..fd519c5 100644
--- a/services/vr/bufferhubd/producer_queue_channel.h
+++ b/services/vr/bufferhubd/producer_queue_channel.h
@@ -12,8 +12,8 @@
class ProducerQueueChannel : public BufferHubChannel {
public:
static pdx::Status<std::shared_ptr<ProducerQueueChannel>> Create(
- BufferHubService* service, int channel_id, size_t meta_size_bytes,
- const UsagePolicy& usage_policy);
+ BufferHubService* service, int channel_id,
+ const ProducerQueueConfig& config, const UsagePolicy& usage_policy);
~ProducerQueueChannel() override;
bool HandleMessage(pdx::Message& message) override;
@@ -40,7 +40,7 @@
// Detach a BufferHubProducer indicated by |slot|. Note that the buffer must
// be in Gain'ed state for the producer queue to detach.
- pdx::Status<void> OnProducerQueueDetachBuffer(pdx::Message& message,
+ pdx::Status<void> OnProducerQueueRemoveBuffer(pdx::Message& message,
size_t slot);
void AddConsumer(ConsumerQueueChannel* channel);
@@ -48,8 +48,8 @@
private:
ProducerQueueChannel(BufferHubService* service, int channel_id,
- size_t meta_size_bytes, const UsagePolicy& usage_policy,
- int* error);
+ const ProducerQueueConfig& config,
+ const UsagePolicy& usage_policy, int* error);
// Allocate one single producer buffer by |OnProducerQueueAllocateBuffers|.
// Note that the newly created buffer's file handle will be pushed to client
@@ -60,10 +60,9 @@
pdx::Message& message, uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format, uint64_t usage);
- // Size of the meta data associated with all the buffers allocated from the
- // queue. Now we assume the metadata size is immutable once the queue is
- // created.
- size_t meta_size_bytes_;
+ // The producer queue's configuration. Now we assume the configuration is
+ // immutable once the queue is created.
+ ProducerQueueConfig config_;
// A set of variables to control what |usage| bits can this ProducerQueue
// allocate.
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 5cb201d..9201520 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -7,6 +7,7 @@
],
static_libs: [
+ "libbroadcastring",
"libhwcomposer-client",
"libdisplay",
"libbufferhubqueue",
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
index 5fd5c36..be1ec5b 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
@@ -17,4 +17,9 @@
* Registers a callback used to receive frame notifications.
*/
void registerObserver(in IVrComposerCallback callback);
+
+ /**
+ * Clears a previously registered frame notification callback.
+ */
+ void clearObserver();
}
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index ae54e56..c31417b 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -24,26 +24,63 @@
namespace android {
namespace dvr {
+namespace {
using android::hardware::graphics::common::V1_0::PixelFormat;
using android::frameworks::vr::composer::V1_0::IVrComposerClient;
-VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
+class ComposerClientImpl : public ComposerClient {
+ public:
+ ComposerClientImpl(android::dvr::VrHwc& hal);
+ virtual ~ComposerClientImpl();
+
+ private:
+ class VrCommandReader : public ComposerClient::CommandReader {
+ public:
+ VrCommandReader(ComposerClientImpl& client);
+ ~VrCommandReader() override;
+
+ bool parseCommand(IComposerClient::Command command,
+ uint16_t length) override;
+
+ private:
+ bool parseSetLayerInfo(uint16_t length);
+ bool parseSetClientTargetMetadata(uint16_t length);
+ bool parseSetLayerBufferMetadata(uint16_t length);
+
+ IVrComposerClient::BufferMetadata readBufferMetadata();
+
+ ComposerClientImpl& mVrClient;
+ android::dvr::VrHwc& mVrHal;
+
+ VrCommandReader(const VrCommandReader&) = delete;
+ void operator=(const VrCommandReader&) = delete;
+ };
+
+ std::unique_ptr<CommandReader> createCommandReader() override;
+
+ dvr::VrHwc& mVrHal;
+
+ ComposerClientImpl(const ComposerClientImpl&) = delete;
+ void operator=(const ComposerClientImpl&) = delete;
+};
+
+ComposerClientImpl::ComposerClientImpl(android::dvr::VrHwc& hal)
: ComposerClient(hal), mVrHal(hal) {}
-VrComposerClient::~VrComposerClient() {}
+ComposerClientImpl::~ComposerClientImpl() {}
std::unique_ptr<ComposerClient::CommandReader>
-VrComposerClient::createCommandReader() {
+ComposerClientImpl::createCommandReader() {
return std::unique_ptr<CommandReader>(new VrCommandReader(*this));
}
-VrComposerClient::VrCommandReader::VrCommandReader(VrComposerClient& client)
+ComposerClientImpl::VrCommandReader::VrCommandReader(ComposerClientImpl& client)
: CommandReader(client), mVrClient(client), mVrHal(client.mVrHal) {}
-VrComposerClient::VrCommandReader::~VrCommandReader() {}
+ComposerClientImpl::VrCommandReader::~VrCommandReader() {}
-bool VrComposerClient::VrCommandReader::parseCommand(
+bool ComposerClientImpl::VrCommandReader::parseCommand(
IComposerClient::Command command, uint16_t length) {
IVrComposerClient::VrCommand vrCommand =
static_cast<IVrComposerClient::VrCommand>(command);
@@ -59,7 +96,7 @@
}
}
-bool VrComposerClient::VrCommandReader::parseSetLayerInfo(uint16_t length) {
+bool ComposerClientImpl::VrCommandReader::parseSetLayerInfo(uint16_t length) {
if (length != 2) {
return false;
}
@@ -72,7 +109,7 @@
return true;
}
-bool VrComposerClient::VrCommandReader::parseSetClientTargetMetadata(
+bool ComposerClientImpl::VrCommandReader::parseSetClientTargetMetadata(
uint16_t length) {
if (length != 7)
return false;
@@ -84,7 +121,7 @@
return true;
}
-bool VrComposerClient::VrCommandReader::parseSetLayerBufferMetadata(
+bool ComposerClientImpl::VrCommandReader::parseSetLayerBufferMetadata(
uint16_t length) {
if (length != 7)
return false;
@@ -98,7 +135,7 @@
}
IVrComposerClient::BufferMetadata
-VrComposerClient::VrCommandReader::readBufferMetadata() {
+ComposerClientImpl::VrCommandReader::readBufferMetadata() {
IVrComposerClient::BufferMetadata metadata = {
.width = read(),
.height = read(),
@@ -110,5 +147,132 @@
return metadata;
}
+} // namespace
+
+VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
+ : client_(new ComposerClientImpl(hal)) {
+ client_->initialize();
+}
+
+VrComposerClient::~VrComposerClient() {}
+
+void VrComposerClient::onHotplug(Display display,
+ IComposerCallback::Connection connected) {
+ client_->onHotplug(display, connected);
+}
+
+Return<void> VrComposerClient::registerCallback(
+ const sp<IComposerCallback>& callback) {
+ return client_->registerCallback(callback);
+}
+
+Return<uint32_t> VrComposerClient::getMaxVirtualDisplayCount() {
+ return client_->getMaxVirtualDisplayCount();
+}
+
+Return<void> VrComposerClient::createVirtualDisplay(uint32_t width,
+ uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount,
+ createVirtualDisplay_cb hidl_cb) {
+ return client_->createVirtualDisplay(
+ width, height, formatHint, outputBufferSlotCount, hidl_cb);
+}
+
+Return<Error> VrComposerClient::destroyVirtualDisplay(Display display) {
+ return client_->destroyVirtualDisplay(display);
+}
+
+Return<void> VrComposerClient::createLayer(Display display,
+ uint32_t bufferSlotCount, createLayer_cb hidl_cb) {
+ return client_->createLayer(display, bufferSlotCount, hidl_cb);
+}
+
+Return<Error> VrComposerClient::destroyLayer(Display display, Layer layer) {
+ return client_->destroyLayer(display, layer);
+}
+
+Return<void> VrComposerClient::getActiveConfig(Display display,
+ getActiveConfig_cb hidl_cb) {
+ return client_->getActiveConfig(display, hidl_cb);
+}
+
+Return<Error> VrComposerClient::getClientTargetSupport(Display display,
+ uint32_t width, uint32_t height, PixelFormat format, Dataspace dataspace) {
+ return client_->getClientTargetSupport(display, width, height, format,
+ dataspace);
+}
+
+Return<void> VrComposerClient::getColorModes(Display display,
+ getColorModes_cb hidl_cb) {
+ return client_->getColorModes(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDisplayAttribute(Display display,
+ Config config, Attribute attribute, getDisplayAttribute_cb hidl_cb) {
+ return client_->getDisplayAttribute(display, config, attribute, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDisplayConfigs(Display display,
+ getDisplayConfigs_cb hidl_cb) {
+ return client_->getDisplayConfigs(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDisplayName(Display display,
+ getDisplayName_cb hidl_cb) {
+ return client_->getDisplayName(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDisplayType(Display display,
+ getDisplayType_cb hidl_cb) {
+ return client_->getDisplayType(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDozeSupport(
+ Display display, getDozeSupport_cb hidl_cb) {
+ return client_->getDozeSupport(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getHdrCapabilities(
+ Display display, getHdrCapabilities_cb hidl_cb) {
+ return client_->getHdrCapabilities(display, hidl_cb);
+}
+
+Return<Error> VrComposerClient::setActiveConfig(Display display,
+ Config config) {
+ return client_->setActiveConfig(display, config);
+}
+
+Return<Error> VrComposerClient::setColorMode(Display display, ColorMode mode) {
+ return client_->setColorMode(display, mode);
+}
+
+Return<Error> VrComposerClient::setPowerMode(Display display, PowerMode mode) {
+ return client_->setPowerMode(display, mode);
+}
+
+Return<Error> VrComposerClient::setVsyncEnabled(Display display,
+ Vsync enabled) {
+ return client_->setVsyncEnabled(display, enabled);
+}
+
+Return<Error> VrComposerClient::setClientTargetSlotCount(
+ Display display, uint32_t clientTargetSlotCount) {
+ return client_->setClientTargetSlotCount(display, clientTargetSlotCount);
+}
+
+Return<Error> VrComposerClient::setInputCommandQueue(
+ const hardware::MQDescriptorSync<uint32_t>& descriptor) {
+ return client_->setInputCommandQueue(descriptor);
+}
+
+Return<void> VrComposerClient::getOutputCommandQueue(
+ getOutputCommandQueue_cb hidl_cb) {
+ return client_->getOutputCommandQueue(hidl_cb);
+}
+
+Return<void> VrComposerClient::executeCommands(uint32_t inLength,
+ const hidl_vec<hidl_handle>& inHandles, executeCommands_cb hidl_cb) {
+ return client_->executeCommands(inLength, inHandles, hidl_cb);
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index 1236be9..f492230 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -29,37 +29,59 @@
using hardware::graphics::common::V1_0::PixelFormat;
using hardware::graphics::composer::V2_1::implementation::ComposerClient;
-class VrComposerClient : public ComposerClient {
+class VrComposerClient : public IVrComposerClient {
public:
VrComposerClient(android::dvr::VrHwc& hal);
virtual ~VrComposerClient();
+ void onHotplug(Display display, IComposerCallback::Connection connected);
+
+ // IComposerClient
+ Return<void> registerCallback(const sp<IComposerCallback>& callback) override;
+ Return<uint32_t> getMaxVirtualDisplayCount() override;
+ Return<void> createVirtualDisplay(
+ uint32_t width, uint32_t height, PixelFormat formatHint,
+ uint32_t outputBufferSlotCount, createVirtualDisplay_cb hidl_cb) override;
+ Return<Error> destroyVirtualDisplay(Display display) override;
+ Return<void> createLayer(Display display, uint32_t bufferSlotCount,
+ createLayer_cb hidl_cb) override;
+ Return<Error> destroyLayer(Display display, Layer layer) override;
+ Return<void> getActiveConfig(Display display,
+ getActiveConfig_cb hidl_cb) override;
+ Return<Error> getClientTargetSupport(
+ Display display, uint32_t width, uint32_t height, PixelFormat format,
+ Dataspace dataspace) override;
+ Return<void> getColorModes(Display display,
+ getColorModes_cb hidl_cb) override;
+ Return<void> getDisplayAttribute(
+ Display display, Config config, Attribute attribute,
+ getDisplayAttribute_cb hidl_cb) override;
+ Return<void> getDisplayConfigs(Display display,
+ getDisplayConfigs_cb hidl_cb) override;
+ Return<void> getDisplayName(Display display,
+ getDisplayName_cb hidl_cb) override;
+ Return<void> getDisplayType(Display display,
+ getDisplayType_cb hidl_cb) override;
+ Return<void> getDozeSupport(Display display,
+ getDozeSupport_cb hidl_cb) override;
+ Return<void> getHdrCapabilities(Display display,
+ getHdrCapabilities_cb hidl_cb) override;
+ Return<Error> setActiveConfig(Display display, Config config) override;
+ Return<Error> setColorMode(Display display, ColorMode mode) override;
+ Return<Error> setPowerMode(Display display, PowerMode mode) override;
+ Return<Error> setVsyncEnabled(Display display, Vsync enabled) override;
+ Return<Error> setClientTargetSlotCount(
+ Display display, uint32_t clientTargetSlotCount) override;
+ Return<Error> setInputCommandQueue(
+ const hardware::MQDescriptorSync<uint32_t>& descriptor) override;
+ Return<void> getOutputCommandQueue(
+ getOutputCommandQueue_cb hidl_cb) override;
+ Return<void> executeCommands(
+ uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
+ executeCommands_cb hidl_cb) override;
+
private:
- class VrCommandReader : public ComposerClient::CommandReader {
- public:
- VrCommandReader(VrComposerClient& client);
- ~VrCommandReader() override;
-
- bool parseCommand(IComposerClient::Command command,
- uint16_t length) override;
-
- private:
- bool parseSetLayerInfo(uint16_t length);
- bool parseSetClientTargetMetadata(uint16_t length);
- bool parseSetLayerBufferMetadata(uint16_t length);
-
- IVrComposerClient::BufferMetadata readBufferMetadata();
-
- VrComposerClient& mVrClient;
- android::dvr::VrHwc& mVrHal;
-
- VrCommandReader(const VrCommandReader&) = delete;
- void operator=(const VrCommandReader&) = delete;
- };
-
- std::unique_ptr<CommandReader> createCommandReader() override;
-
- dvr::VrHwc& mVrHal;
+ std::unique_ptr<ComposerClient> client_;
VrComposerClient(const VrComposerClient&) = delete;
void operator=(const VrComposerClient&) = delete;
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 5d51827..861114d 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -15,6 +15,7 @@
*/
#include "impl/vr_hwc.h"
+#include <cutils/properties.h>
#include <private/dvr/display_client.h>
#include <ui/Fence.h>
@@ -336,11 +337,30 @@
*outValue = display_ptr->height();
break;
case IComposerClient::Attribute::VSYNC_PERIOD:
- *outValue = 1000 * 1000 * 1000 / 30; // 30fps
+ {
+ int error = 0;
+ auto display_client = display::DisplayClient::Create(&error);
+ if (!display_client) {
+ ALOGE("Could not connect to display service : %s(%d)",
+ strerror(error), error);
+ // Return a default value of 30 fps
+ *outValue = 1000 * 1000 * 1000 / 30;
+ } else {
+ auto metrics = display_client->GetDisplayMetrics();
+ *outValue = metrics.get().vsync_period_ns;
+ }
+ }
break;
case IComposerClient::Attribute::DPI_X:
case IComposerClient::Attribute::DPI_Y:
- *outValue = 300 * 1000; // 300dpi
+ {
+ constexpr int32_t kDefaultDPI = 300;
+ int32_t dpi = property_get_int32("ro.vr.hwc.dpi", kDefaultDPI);
+ if (dpi <= 0) {
+ dpi = kDefaultDPI;
+ }
+ *outValue = 1000 * dpi;
+ }
break;
default:
return Error::BAD_PARAMETER;
@@ -820,7 +840,6 @@
sp<VrComposerClient> client;
if (client_ == nullptr) {
client = new VrComposerClient(*this);
- client->initialize();
} else {
ALOGE("Already have a client");
status = Error::NO_RESOURCES;
@@ -852,12 +871,5 @@
return iter == displays_.end() ? nullptr : iter->second.get();
}
-ComposerView* GetComposerViewFromIComposer(
- hardware::graphics::composer::V2_1::IComposer* composer) {
- return static_cast<VrHwc*>(composer);
-}
-
-IComposer* HIDL_FETCH_IComposer(const char*) { return new VrHwc(); }
-
} // namespace dvr
} // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index df04208..523cda3 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -309,13 +309,6 @@
void operator=(const VrHwc&) = delete;
};
-
-ComposerView* GetComposerViewFromIComposer(
- hardware::graphics::composer::V2_1::IComposer* composer);
-
-hardware::graphics::composer::V2_1::IComposer* HIDL_FETCH_IComposer(
- const char* name);
-
} // namespace dvr
} // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
index c45fbf4..36a313a 100644
--- a/services/vr/hardware_composer/vr_composer.cpp
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -42,6 +42,12 @@
return binder::Status::ok();
}
+binder::Status VrComposer::clearObserver() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ callback_ = nullptr;
+ return binder::Status::ok();
+}
+
base::unique_fd VrComposer::OnNewFrame(const ComposerView::Frame& frame) {
std::lock_guard<std::mutex> guard(mutex_);
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
index 93d1f2b..7b580c6 100644
--- a/services/vr/hardware_composer/vr_composer.h
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -27,6 +27,8 @@
binder::Status registerObserver(
const sp<IVrComposerCallback>& callback) override;
+ binder::Status clearObserver() override;
+
// ComposerView::Observer:
base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
index f980220..e36b0ae 100644
--- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -26,22 +26,18 @@
// Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR
// mode.
- const char instance[] = "vr";
- android::sp<IComposer> service =
- android::dvr::HIDL_FETCH_IComposer(instance);
+ android::sp<android::dvr::VrHwc> service = new android::dvr::VrHwc();
LOG_ALWAYS_FATAL_IF(!service.get(), "Failed to get service");
LOG_ALWAYS_FATAL_IF(service->isRemote(), "Service is remote");
+ const char instance[] = "vr";
LOG_ALWAYS_FATAL_IF(service->registerAsService(instance) != android::OK,
"Failed to register service");
android::sp<android::dvr::VrComposer> composer =
new android::dvr::VrComposer();
-
- android::dvr::ComposerView* composer_view =
- android::dvr::GetComposerViewFromIComposer(service.get());
- composer_view->RegisterObserver(composer.get());
+ service->RegisterObserver(composer.get());
android::sp<android::IServiceManager> sm(android::defaultServiceManager());
@@ -56,7 +52,7 @@
android::hardware::ProcessState::self()->startThreadPool();
android::hardware::IPCThreadState::self()->joinThreadPool();
- composer_view->UnregisterObserver(composer.get());
+ service->UnregisterObserver(composer.get());
return 0;
}
diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk
index 6256e90..dbc66f1 100644
--- a/services/vr/performanced/Android.mk
+++ b/services/vr/performanced/Android.mk
@@ -23,8 +23,10 @@
staticLibraries := \
libperformance \
libpdx_default_transport \
+ libvr_manager
sharedLibraries := \
+ libbinder \
libbase \
libcutils \
liblog \
diff --git a/services/vr/performanced/cpu_set.cpp b/services/vr/performanced/cpu_set.cpp
index 1a3723f..1a7264c 100644
--- a/services/vr/performanced/cpu_set.cpp
+++ b/services/vr/performanced/cpu_set.cpp
@@ -15,6 +15,9 @@
#include "task.h"
#include "unique_file.h"
+using android::pdx::ErrorStatus;
+using android::pdx::Status;
+
namespace {
constexpr int kDirectoryFlags = O_RDONLY | O_DIRECTORY | O_CLOEXEC;
@@ -176,11 +179,11 @@
task_id, task.name().c_str(), target_set.c_str(),
task.thread_group_id(), task.parent_process_id());
- const int ret = target->AttachTask(task_id);
- ALOGW_IF(ret < 0 && ret != -EINVAL,
+ auto status = target->AttachTask(task_id);
+ ALOGW_IF(!status && status.error() != EINVAL,
"CpuSetManager::MoveUnboundTasks: Failed to attach task_id=%d "
"to cpuset=%s: %s",
- task_id, target_set.c_str(), strerror(-ret));
+ task_id, target_set.c_str(), status.GetErrorMessage().c_str());
} else {
ALOGD_IF(TRACE,
"CpuSet::MoveUnboundTasks: Skipping task_id=%d name=%s cpus=%s.",
@@ -233,7 +236,7 @@
return fp;
}
-int CpuSet::AttachTask(pid_t task_id) const {
+Status<void> CpuSet::AttachTask(pid_t task_id) const {
auto file = OpenFile("tasks", O_RDWR);
if (file.get() >= 0) {
std::ostringstream stream;
@@ -241,11 +244,15 @@
std::string value = stream.str();
const bool ret = base::WriteStringToFd(value, file.get());
- return !ret ? -errno : 0;
+ if (!ret)
+ return ErrorStatus(errno);
+ else
+ return {};
} else {
+ const int error = errno;
ALOGE("CpuSet::AttachTask: Failed to open %s/tasks: %s", path_.c_str(),
- strerror(errno));
- return -errno;
+ strerror(error));
+ return ErrorStatus(error);
}
}
diff --git a/services/vr/performanced/cpu_set.h b/services/vr/performanced/cpu_set.h
index fcf280a..6879272 100644
--- a/services/vr/performanced/cpu_set.h
+++ b/services/vr/performanced/cpu_set.h
@@ -11,6 +11,8 @@
#include <android-base/unique_fd.h>
+#include <pdx/status.h>
+
#include "unique_file.h"
namespace android {
@@ -28,7 +30,7 @@
std::string GetCpuList() const;
- int AttachTask(pid_t task_id) const;
+ pdx::Status<void> AttachTask(pid_t task_id) const;
std::vector<pid_t> GetTasks() const;
private:
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 955c661..4b9fbe0 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -8,14 +8,20 @@
#include <pdx/rpc/argument_encoder.h>
#include <pdx/rpc/message_buffer.h>
#include <pdx/rpc/remote_method.h>
+#include <private/android_filesystem_config.h>
#include <private/dvr/performance_rpc.h>
+#include <private/dvr/trusted_uids.h>
#include "task.h"
// This prctl is only available in Android kernels.
#define PR_SET_TIMERSLACK_PID 41
+using android::dvr::IsTrustedUid;
+using android::dvr::Task;
+using android::pdx::ErrorStatus;
using android::pdx::Message;
+using android::pdx::Status;
using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::default_transport::Endpoint;
@@ -26,6 +32,68 @@
constexpr unsigned long kTimerSlackForegroundNs = 50000;
constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
+// Expands the given parameter pack expression using an initializer list to
+// guarantee ordering and a comma expression to guarantee even void expressions
+// are valid elements of the initializer list.
+#define EXPAND_PACK(...) \
+ std::initializer_list<int> { (__VA_ARGS__, 0)... }
+
+// Returns true if the sender's euid matches any of the uids in |UIDs|.
+template <uid_t... UIDs>
+struct UserId {
+ static bool Check(const Message& sender, const Task&) {
+ const uid_t uid = sender.GetEffectiveUserId();
+ bool allow = false;
+ EXPAND_PACK(allow |= (uid == UIDs));
+ return allow;
+ }
+};
+
+// Returns true if the sender's egid matches any of the gids in |GIDs|.
+template <gid_t... GIDs>
+struct GroupId {
+ static bool Check(const Message& sender, const Task&) {
+ const gid_t gid = sender.GetEffectiveGroupId();
+ bool allow = false;
+ EXPAND_PACK(allow |= (gid == GIDs));
+ return allow;
+ }
+};
+
+// Returns true if the sender's euid is trusted according to VR manager service.
+struct Trusted {
+ static bool Check(const Message& sender, const Task&) {
+ return IsTrustedUid(sender.GetEffectiveUserId());
+ }
+};
+
+// Returns returns true if the task belongs to the sending process.
+struct SameProcess {
+ static bool Check(const Message& sender, const Task& task) {
+ return sender.GetProcessId() == task.thread_group_id();
+ }
+};
+
+// Returns true if any of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckOr {
+ static bool Check(const Message& sender, const Task& task) {
+ bool allow = false;
+ EXPAND_PACK(allow |= Allows::Check(sender, task));
+ return allow;
+ }
+};
+
+// Returns true if all of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckAnd {
+ static bool Check(const Message& sender, const Task& task) {
+ bool allow = true;
+ EXPAND_PACK(allow &= Allows::Check(sender, task));
+ return allow;
+ }
+};
+
} // anonymous namespace
namespace android {
@@ -48,43 +116,79 @@
const int fifo_low = sched_fifo_min_priority_;
const int fifo_medium = sched_fifo_min_priority_ + fifo_range / 5;
- // TODO(eieio): Make this configurable on the command line.
+ // TODO(eieio): Make this configurable on the command line or config file.
cpuset_.MoveUnboundTasks("/kernel");
+ // TODO(eieio): Replace this witha device-specific config file. This is just a
+ // hack for now to put some form of permission logic in place while a longer
+ // term solution is developed.
+ using AllowRootSystem =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM>,
+ GroupId<AID_SYSTEM>>>;
+ using AllowRootSystemGraphics =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
+ GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
+ using AllowRootSystemAudio =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>,
+ GroupId<AID_SYSTEM, AID_AUDIO>>>;
+ using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>,
+ GroupId<AID_SYSTEM>>;
+
+ partition_permission_check_ = AllowRootSystemTrusted::Check;
+
// Setup the scheduler classes.
+ // TODO(eieio): Replace this with a device-specific config file.
scheduler_classes_ = {
{"audio:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemAudio::Check}},
{"audio:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium + 3}},
+ .priority = fifo_medium + 3,
+ .permission_check = AllowRootSystemAudio::Check}},
{"graphics",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"graphics:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"graphics:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium + 2}},
+ .priority = fifo_medium + 2,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"sensors",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low}},
+ .priority = fifo_low,
+ .permission_check = AllowRootSystem::Check}},
{"sensors:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low}},
+ .priority = fifo_low,
+ .permission_check = AllowRootSystem::Check}},
{"sensors:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low + 1}},
+ .priority = fifo_low + 1,
+ .permission_check = AllowRootSystem::Check}},
+ {"vr:system:arp",
+ {.timer_slack = kTimerSlackForegroundNs,
+ .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+ .priority = fifo_medium + 2,
+ .permission_check = AllowRootSystemTrusted::Check}},
+ {"vr:app:render",
+ {.timer_slack = kTimerSlackForegroundNs,
+ .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+ .priority = fifo_medium + 1,
+ .permission_check = AllowRootSystemTrusted::Check}},
{"normal",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_NORMAL,
@@ -113,67 +217,94 @@
return cpuset_.DumpState();
}
-int PerformanceService::OnSetCpuPartition(Message& message, pid_t task_id,
- const std::string& partition) {
+Status<void> PerformanceService::OnSetSchedulerPolicy(
+ Message& message, pid_t task_id, const std::string& scheduler_policy) {
+ // Forward to scheduler class handler for now. In the future this method will
+ // subsume the others by unifying both scheduler class and cpu partiton into a
+ // single policy concept.
+ ALOGI(
+ "PerformanceService::OnSetSchedulerPolicy: task_id=%d "
+ "scheduler_policy=%s",
+ task_id, scheduler_policy.c_str());
+ return OnSetSchedulerClass(message, task_id, scheduler_policy);
+}
+
+Status<void> PerformanceService::OnSetCpuPartition(
+ Message& message, pid_t task_id, const std::string& partition) {
Task task(task_id);
if (!task || task.thread_group_id() != message.GetProcessId())
- return -EINVAL;
+ return ErrorStatus(EINVAL);
+
+ // Temporary permission check.
+ // TODO(eieio): Replace this with a configuration file.
+ if (partition_permission_check_ &&
+ !partition_permission_check_(message, task)) {
+ return ErrorStatus(EINVAL);
+ }
auto target_set = cpuset_.Lookup(partition);
if (!target_set)
- return -ENOENT;
+ return ErrorStatus(ENOENT);
- const auto attach_error = target_set->AttachTask(task_id);
- if (attach_error)
- return attach_error;
+ auto attach_status = target_set->AttachTask(task_id);
+ if (!attach_status)
+ return attach_status;
- return 0;
+ return {};
}
-int PerformanceService::OnSetSchedulerClass(
+Status<void> PerformanceService::OnSetSchedulerClass(
Message& message, pid_t task_id, const std::string& scheduler_class) {
- // Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
- if (!task || task.thread_group_id() != message.GetProcessId())
- return -EINVAL;
+ if (!task)
+ return ErrorStatus(EINVAL);
- struct sched_param param;
-
- // TODO(eieio): Apply rules based on the requesting process. Applications are
- // only allowed one audio thread that runs at SCHED_FIFO. System services can
- // have more than one.
auto search = scheduler_classes_.find(scheduler_class);
if (search != scheduler_classes_.end()) {
auto config = search->second;
+
+ // Make sure the sending process is allowed to make the requested change to
+ // this task.
+ if (!config.IsAllowed(message, task))
+ return ErrorStatus(EINVAL);
+
+ struct sched_param param;
param.sched_priority = config.priority;
+
sched_setscheduler(task_id, config.scheduler_policy, ¶m);
prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id);
ALOGI("PerformanceService::OnSetSchedulerClass: Set task=%d to class=%s.",
task_id, scheduler_class.c_str());
- return 0;
+ return {};
} else {
ALOGE(
"PerformanceService::OnSetSchedulerClass: Invalid class=%s requested "
"by task=%d.",
scheduler_class.c_str(), task_id);
- return -EINVAL;
+ return ErrorStatus(EINVAL);
}
}
-std::string PerformanceService::OnGetCpuPartition(Message& message,
- pid_t task_id) {
+Status<std::string> PerformanceService::OnGetCpuPartition(Message& message,
+ pid_t task_id) {
// Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
if (!task || task.thread_group_id() != message.GetProcessId())
- REPLY_ERROR_RETURN(message, EINVAL, "");
+ return ErrorStatus(EINVAL);
return task.GetCpuSetPath();
}
-pdx::Status<void> PerformanceService::HandleMessage(Message& message) {
+Status<void> PerformanceService::HandleMessage(Message& message) {
+ ALOGD_IF(TRACE, "PerformanceService::HandleMessage: op=%d", message.GetOp());
switch (message.GetOp()) {
+ case PerformanceRPC::SetSchedulerPolicy::Opcode:
+ DispatchRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+ *this, &PerformanceService::OnSetSchedulerPolicy, message);
+ return {};
+
case PerformanceRPC::SetCpuPartition::Opcode:
- DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>(
+ DispatchRemoteMethod<PerformanceRPC::SetCpuPartition>(
*this, &PerformanceService::OnSetCpuPartition, message);
return {};
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index 34abba7..b28d94a 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -1,12 +1,14 @@
#ifndef ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
#define ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
+#include <functional>
#include <string>
#include <unordered_map>
#include <pdx/service.h>
#include "cpu_set.h"
+#include "task.h"
namespace android {
namespace dvr {
@@ -27,11 +29,15 @@
PerformanceService();
- int OnSetCpuPartition(pdx::Message& message, pid_t task_id,
- const std::string& partition);
- int OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
- const std::string& scheduler_class);
- std::string OnGetCpuPartition(pdx::Message& message, pid_t task_id);
+ pdx::Status<void> OnSetSchedulerPolicy(pdx::Message& message, pid_t task_id,
+ const std::string& scheduler_class);
+
+ pdx::Status<void> OnSetCpuPartition(pdx::Message& message, pid_t task_id,
+ const std::string& partition);
+ pdx::Status<void> OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
+ const std::string& scheduler_class);
+ pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message,
+ pid_t task_id);
CpuSetManager cpuset_;
@@ -43,10 +49,27 @@
unsigned long timer_slack;
int scheduler_policy;
int priority;
+ std::function<bool(const pdx::Message& message, const Task& task)>
+ permission_check;
+
+ // Check the permisison of the given task to use this scheduler class. If a
+ // permission check function is not set then operations are only allowed on
+ // tasks in the sender's process.
+ bool IsAllowed(const pdx::Message& sender, const Task& task) const {
+ if (permission_check)
+ return permission_check(sender, task);
+ else if (!task || task.thread_group_id() != sender.GetProcessId())
+ return false;
+ else
+ return true;
+ }
};
std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_;
+ std::function<bool(const pdx::Message& message, const Task& task)>
+ partition_permission_check_;
+
PerformanceService(const PerformanceService&) = delete;
void operator=(const PerformanceService&) = delete;
};
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index b526082..274a1b3 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -1,12 +1,22 @@
#include <errno.h>
#include <sched.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <condition_variable>
+#include <cstdlib>
#include <mutex>
#include <thread>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
+#include <private/android_filesystem_config.h>
+
+namespace {
+
+const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
+
+} // anonymous namespace
TEST(DISABLED_PerformanceTest, SetCpuPartition) {
int error;
@@ -86,6 +96,27 @@
EXPECT_EQ(-EINVAL, error);
}
+// This API mirrors SetSchedulerClass for now. Replace with with a more specific
+// test once the policy API is fully implemented.
+TEST(PerformanceTest, SetSchedulerPolicy) {
+ int error;
+
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_BATCH, sched_getscheduler(0));
+
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
+
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
+
+ error = dvrSetSchedulerPolicy(0, "foobar");
+ EXPECT_EQ(-EINVAL, error);
+}
+
TEST(PerformanceTest, SchedulerClassResetOnFork) {
int error;
@@ -135,3 +166,284 @@
error = dvrGetCpuPartition(0, nullptr, sizeof(partition));
EXPECT_EQ(-EINVAL, error);
}
+
+TEST(PerformanceTest, Permissions) {
+ int error;
+
+ const int original_uid = getuid();
+ const int original_gid = getgid();
+ int trusted_uid = -1;
+
+ // See if the environment variable GTEST_TRUSTED_UID is set. If it is enable
+ // testing the ActivityManager trusted uid permission checks using that uid.
+ const char* trusted_uid_env = std::getenv(kTrustedUidEnvironmentVariable);
+ if (trusted_uid_env)
+ trusted_uid = std::atoi(trusted_uid_env);
+
+ ASSERT_EQ(AID_ROOT, original_uid)
+ << "This test must run as root to function correctly!";
+
+ // Test unprivileged policies on a task that does not belong to this process.
+ // Use the init process (task_id=1) as the target.
+ error = dvrSetSchedulerPolicy(1, "batch");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(1, "background");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(1, "foreground");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(1, "normal");
+ EXPECT_EQ(-EINVAL, error);
+
+ // Switch the uid/gid to an id that should not have permission to access any
+ // privileged actions.
+ ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(-EINVAL, error);
+
+ // uid=AID_SYSTEM / gid=AID_NOBODY
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_SYSTEM, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+
+ // uid=AID_NOBODY / gid=AID_SYSTEM
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_SYSTEM, AID_SYSTEM, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_NOBODY, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+
+ // uid=AID_GRAPHICS / gid=AID_NOBODY
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_GRAPHICS, AID_GRAPHICS, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(-EINVAL, error);
+
+ // uid=AID_NOBODY / gid=AID_GRAPHICS
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_GRAPHICS, AID_GRAPHICS, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(-EINVAL, error);
+
+ if (trusted_uid != -1) {
+ // uid=<trusted uid> / gid=AID_NOBODY
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(trusted_uid, trusted_uid, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+ }
+
+ // Restore original effective uid/gid.
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+}
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index 3d5dfb2..6b11ce3 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -13,10 +13,15 @@
"libutils",
]
+header_libraries = [
+ "libdvr_headers"
+]
+
cc_library {
srcs: src,
export_include_dirs: ["include"],
shared_libs: shared_libs,
+ header_libs: header_libraries,
cppflags: ["-std=c++11"],
cflags: ["-DLOG_TAG=\"VrVirtualTouchpad\""],
name: "libvirtualtouchpad",
@@ -28,9 +33,6 @@
test_static_libs = [
"libcutils",
"libvirtualtouchpad",
-]
-
-test_shared_libs = [
"libbase",
"liblog",
"libutils",
@@ -41,7 +43,7 @@
cc_test {
srcs: test_src_files,
static_libs: test_static_libs,
- shared_libs: test_shared_libs,
+ header_libs: header_libraries,
cppflags = [
"-std=c++11",
],
@@ -77,6 +79,7 @@
srcs: service_src,
static_libs: service_static_libs,
shared_libs: service_shared_libs,
+ header_libs: header_libraries,
cppflags: ["-std=c++11"],
cflags: [
"-DLOG_TAG=\"VrVirtualTouchpad\"",
@@ -107,6 +110,7 @@
cc_library {
srcs: client_src,
shared_libs: client_shared_libs,
+ header_libs: header_libraries,
cppflags: ["-std=c++11"],
cflags: ["-DLOG_TAG=\"VirtualTouchpadClient\""],
host_ldlibs: ["-llog"],
diff --git a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
index eb152ed..3ab77a7 100644
--- a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
@@ -40,6 +40,11 @@
return FromC(client)->ButtonState(touchpad, buttons);
}
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+ float y) {
+ return FromC(client)->Scroll(touchpad, x, y);
+}
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/services/vr/virtual_touchpad/EvdevInjector.cpp b/services/vr/virtual_touchpad/EvdevInjector.cpp
index a4ccdd0..7fad379 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.cpp
+++ b/services/vr/virtual_touchpad/EvdevInjector.cpp
@@ -168,6 +168,25 @@
return ConfigureAbs(ABS_MT_SLOT, 0, slots, 0, 0);
}
+int EvdevInjector::ConfigureRel(uint16_t rel_type) {
+ ALOGV("ConfigureRel 0x%" PRIX16 "", rel_type);
+ if (rel_type < 0 || rel_type >= REL_CNT) {
+ ALOGE("EV_REL type 0x%" PRIX16 " out of range [0,0x%X)", rel_type, REL_CNT);
+ return Error(ERROR_REL_RANGE);
+ }
+ if (const int status = RequireState(State::CONFIGURING)) {
+ return status;
+ }
+ if (const int status = EnableEventType(EV_REL)) {
+ return status;
+ }
+ if (const int status = uinput_->IoctlSetInt(UI_SET_RELBIT, rel_type)) {
+ ALOGE("failed to enable EV_REL 0x%" PRIX16 "", rel_type);
+ return Error(status);
+ }
+ return 0;
+}
+
int EvdevInjector::ConfigureEnd() {
ALOGV("ConfigureEnd:");
ALOGV(" name=\"%s\"", uidev_.name);
@@ -236,6 +255,10 @@
return Send(EV_ABS, code, value);
}
+int EvdevInjector::SendRel(uint16_t code, int32_t value) {
+ return Send(EV_REL, code, value);
+}
+
int EvdevInjector::SendMultiTouchSlot(int32_t slot) {
if (latest_slot_ != slot) {
if (const int status = SendAbs(ABS_MT_SLOT, slot)) {
diff --git a/services/vr/virtual_touchpad/EvdevInjector.h b/services/vr/virtual_touchpad/EvdevInjector.h
index c69dbef..e87c959 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.h
+++ b/services/vr/virtual_touchpad/EvdevInjector.h
@@ -30,6 +30,7 @@
ERROR_KEY_RANGE = -3, // |KEY_*|/|BTN_*| code out of range.
ERROR_ABS_RANGE = -4, // |ABS_*| code out of range.
ERROR_SEQUENCING = -5, // Configure/Send out of order.
+ ERROR_REL_RANGE = -6, // |REL_*| code out of range.
};
// Key event |value| is not defined in <linux/input.h>.
@@ -87,6 +88,10 @@
// Configure multitouch coordinate range.
int ConfigureMultiTouchXY(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
+ // Configure a relative axis.
+ // @param rel_type One of the |REL_*| constants from <linux/input.h>.
+ int ConfigureRel(uint16_t rel_type);
+
// Complete configuration and create the input device.
int ConfigureEnd();
@@ -96,6 +101,7 @@
int SendSynReport();
int SendKey(uint16_t code, int32_t value);
int SendAbs(uint16_t code, int32_t value);
+ int SendRel(uint16_t code, int32_t value);
int SendMultiTouchSlot(int32_t slot);
int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y);
int SendMultiTouchLift(int32_t slot);
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
index c7c8184..00e4ce6 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -60,6 +60,13 @@
return service_->buttonState(touchpad, buttons).transactionError();
}
+ status_t Scroll(int touchpad, float x, float y) override {
+ if (service_ == nullptr) {
+ return NO_INIT;
+ }
+ return service_->scroll(touchpad, x, y).transactionError();
+ }
+
void dumpInternal(String8& result) override {
result.append("[virtual touchpad]\n");
result.appendFormat("connected = %s\n\n",
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index f0bdcd9..bcfdad3 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -28,6 +28,12 @@
static constexpr int32_t kHeight = 0x10000;
static constexpr int32_t kSlots = 2;
+static constexpr float kScrollScale = 100.0f;
+
+int32_t scale_relative_scroll(float x) {
+ return kScrollScale * x;
+}
+
} // anonymous namespace
std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
@@ -66,6 +72,8 @@
touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT);
touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
touchpad.injector->ConfigureAbsSlots(kSlots);
+ touchpad.injector->ConfigureRel(REL_WHEEL);
+ touchpad.injector->ConfigureRel(REL_HWHEEL);
touchpad.injector->ConfigureKey(BTN_TOUCH);
touchpad.injector->ConfigureKey(BTN_BACK);
touchpad.injector->ConfigureEnd();
@@ -86,9 +94,6 @@
if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
return EINVAL;
}
- if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
- return EINVAL;
- }
int32_t device_x = x * kWidth;
int32_t device_y = y * kHeight;
Touchpad& touchpad = touchpad_[touchpad_id];
@@ -162,6 +167,33 @@
return touchpad.injector->GetError();
}
+int VirtualTouchpadEvdev::Scroll(int touchpad_id, float x, float y) {
+ if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+ return EINVAL;
+ }
+ if ((x < -1.0f) || (x > 1.0f) || (y < -1.0f) || (y > 1.0f)) {
+ return EINVAL;
+ }
+ Touchpad& touchpad = touchpad_[touchpad_id];
+ if (!touchpad.injector) {
+ return EvdevInjector::ERROR_SEQUENCING;
+ }
+ touchpad.injector->ResetError();
+ const int32_t scaled_x = scale_relative_scroll(x);
+ const int32_t scaled_y = scale_relative_scroll(y);
+ ALOGV("(%f,%f) -> (%" PRId32 ",%" PRId32 ")", x, y, scaled_x, scaled_y);
+ if (scaled_x) {
+ touchpad.injector->SendRel(REL_HWHEEL, scaled_x);
+ }
+ if (scaled_y) {
+ touchpad.injector->SendRel(REL_WHEEL, scaled_y);
+ }
+ if (scaled_x || scaled_y) {
+ touchpad.injector->SendSynReport();
+ }
+ return touchpad.injector->GetError();
+}
+
void VirtualTouchpadEvdev::dumpInternal(String8& result) {
for (int i = 0; i < kTouchpads; ++i) {
const auto& touchpad = touchpad_[i];
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
index 2fb8ff3..c9578bf 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -21,6 +21,7 @@
status_t Detach() override;
status_t Touch(int touchpad, float x, float y, float pressure) override;
status_t ButtonState(int touchpad, int buttons) override;
+ status_t Scroll(int touchpad, float x, float y) override;
void dumpInternal(String8& result) override;
protected:
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 81edd32..523f890 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -87,6 +87,16 @@
return binder::Status::ok();
}
+binder::Status VirtualTouchpadService::scroll(int touchpad, float x, float y) {
+ if (!CheckPermissions()) {
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
+ }
+ if (const status_t error = touchpad_->Scroll(touchpad, x, y)) {
+ return binder::Status::fromStatusT(error);
+ }
+ return binder::Status::ok();
+}
+
status_t VirtualTouchpadService::dump(
int fd, const Vector<String16>& args[[gnu::unused]]) {
String8 result;
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index cf236f9..2c46209 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -23,6 +23,7 @@
binder::Status detach() override;
binder::Status touch(int touchpad, float x, float y, float pressure) override;
binder::Status buttonState(int touchpad, int buttons) override;
+ binder::Status scroll(int touchpad, float x, float y) override;
// Implements BBinder::dump().
status_t dump(int fd, const Vector<String16>& args) override;
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
index 9cfb186..256203c 100644
--- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
@@ -34,4 +34,15 @@
* @param buttons A union of MotionEvent BUTTON_* values.
*/
void buttonState(int touchpad, int buttons) = 3;
+
+ /**
+ * Generate a simulated scroll event.
+ *
+ * @param touchpad Selects touchpad.
+ * @param x Horizontal scroll increment.
+ * @param y Vertical scroll increment.
+ *
+ * Scroll values are in the range [-1.0, 1.0].
+ */
+ void scroll(int touchpad, float x, float y) = 4;
}
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
new file mode 100644
index 0000000..205e8b9
--- /dev/null
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
@@ -0,0 +1,26 @@
+# Copyright (C) 2017 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.
+
+#
+# Virtual touchpad for the primary display
+device.internal = 1
+
+touch.deviceType = touchScreen
+
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
new file mode 100644
index 0000000..d9714e0
--- /dev/null
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
@@ -0,0 +1,31 @@
+# Copyright (C) 2017 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.
+
+#
+# Virtual touchpad for the VR virtual display
+device.internal = 1
+
+touch.deviceType = touchScreen
+
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
+
+# This displayID matches the unique ID of the virtual display created for VR.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:android:277f1a09-b88d-4d1e-8716-796f114d080b
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
index da3a0b7..99b72fc 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpad.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -61,6 +61,16 @@
//
virtual status_t ButtonState(int touchpad, int buttons) = 0;
+ // Generate a simulated scroll event.
+ //
+ // @param touchpad Touchpad selector index.
+ // @param x Horizontal scroll increment.
+ // @param y Vertical scroll increment.
+ // Values must be in the range [-1.0, 1.0].
+ // @returns OK on success.
+ //
+ virtual status_t Scroll(int touchpad, float x, float y) = 0;
+
// Report state for 'dumpsys'.
virtual void dumpInternal(String8& result) = 0;
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
index 23fb9f8..7d73f06 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -17,6 +17,7 @@
status_t Detach() override;
status_t Touch(int touchpad, float x, float y, float pressure) override;
status_t ButtonState(int touchpad, int buttons) override;
+ status_t Scroll(int touchpad, float x, float y) override;
void dumpInternal(String8& result) override;
protected:
diff --git a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
index 08cca1b..09fb1cc 100644
--- a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
+++ b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
@@ -1,17 +1,14 @@
#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_H
#define ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_H
+#include <dvr/dvr_api.h>
+
#ifdef __cplusplus
extern "C" {
#endif
typedef struct DvrVirtualTouchpad DvrVirtualTouchpad;
-enum {
- DVR_VIRTUAL_TOUCHPAD_PRIMARY = 0,
- DVR_VIRTUAL_TOUCHPAD_VIRTUAL = 1,
-};
-
// Creates a new virtual touchpad client.
//
// @return Pointer to the created virtual touchpad client; nullptr on failure.
@@ -64,6 +61,17 @@
int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
int buttons);
+// Generate a simulated scroll event.
+//
+// @param client Pointer to the virtual touchpad client.
+// @param touchpad Selects touchpad.
+// @param x Horizontal scroll increment.
+// @param y Vertical scroll increment.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+ float y);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 564bcd7..b19b018 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -169,6 +169,11 @@
expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
// From ConfigureAbsSlots(kSlots):
expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
+ // From ConfigureRel(REL_WHEEL):
+ expect.IoctlSetInt(UI_SET_EVBIT, EV_REL);
+ expect.IoctlSetInt(UI_SET_RELBIT, REL_WHEEL);
+ // From ConfigureRel(REL_HWHEEL):
+ expect.IoctlSetInt(UI_SET_RELBIT, REL_HWHEEL);
// From ConfigureKey(BTN_TOUCH):
expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index a19fcf1..11161c6 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
// API version (major.minor.patch)
define VERSION_MAJOR 1
define VERSION_MINOR 0
-define VERSION_PATCH 46
+define VERSION_PATCH 49
// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -320,7 +320,7 @@
@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
-// 119
+// 120
@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
@@ -409,7 +409,7 @@
//@extension("VK_KHR_swapchain") // 2
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,
- //@extension("VK_KHR_shared_presentable_image")
+ //@extension("VK_KHR_shared_presentable_image") // 112
VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000,
}
@@ -1005,9 +1005,6 @@
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX = 1000071002,
VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX = 1000071003,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX = 1000071004,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHX = 1000071005,
- VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHX = 1000071006,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHX = 1000071007,
//@extension("VK_KHX_external_memory") // 73
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX = 1000072000,
@@ -1086,10 +1083,10 @@
//@extension("VK_EXT_hdr_metadata") // 106
VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,
- //@extension("VK_KHR_shared_presentable_image") // 111
+ //@extension("VK_KHR_shared_presentable_image") // 112
VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000,
- //@extension("VK_KHR_get_surface_capabilities2") // 119
+ //@extension("VK_KHR_get_surface_capabilities2") // 120
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000,
VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001,
VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002,
@@ -1179,6 +1176,55 @@
VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000,
}
+enum VkObjectType {
+ VK_OBJECT_TYPE_UNKNOWN = 0,
+ VK_OBJECT_TYPE_INSTANCE = 1,
+ VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2,
+ VK_OBJECT_TYPE_DEVICE = 3,
+ VK_OBJECT_TYPE_QUEUE = 4,
+ VK_OBJECT_TYPE_SEMAPHORE = 5,
+ VK_OBJECT_TYPE_COMMAND_BUFFER = 6,
+ VK_OBJECT_TYPE_FENCE = 7,
+ VK_OBJECT_TYPE_DEVICE_MEMORY = 8,
+ VK_OBJECT_TYPE_BUFFER = 9,
+ VK_OBJECT_TYPE_IMAGE = 10,
+ VK_OBJECT_TYPE_EVENT = 11,
+ VK_OBJECT_TYPE_QUERY_POOL = 12,
+ VK_OBJECT_TYPE_BUFFER_VIEW = 13,
+ VK_OBJECT_TYPE_IMAGE_VIEW = 14,
+ VK_OBJECT_TYPE_SHADER_MODULE = 15,
+ VK_OBJECT_TYPE_PIPELINE_CACHE = 16,
+ VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17,
+ VK_OBJECT_TYPE_RENDER_PASS = 18,
+ VK_OBJECT_TYPE_PIPELINE = 19,
+ VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20,
+ VK_OBJECT_TYPE_SAMPLER = 21,
+ VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22,
+ VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,
+ VK_OBJECT_TYPE_FRAMEBUFFER = 24,
+ VK_OBJECT_TYPE_COMMAND_POOL = 25,
+
+ //@extension("VK_KHR_surface") // 1
+ VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
+
+ //@extension("VK_KHR_swapchain") // 2
+ VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,
+
+ //@extension("VK_KHR_display") // 3
+ VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000,
+ VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001,
+
+ //@extension("VK_KHR_debug_report") // 12
+ VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,
+
+ //@extension("VK_KHR_descriptor_update_template") // 86
+ VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = 1000085000,
+
+ //@extension("VK_NVX_device_generated_commands") // 87
+ VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,
+ VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
+}
+
@extension("VK_KHR_surface") // 1
enum VkPresentModeKHR {
VK_PRESENT_MODE_IMMEDIATE_KHR = 0x00000000,
@@ -1186,7 +1232,7 @@
VK_PRESENT_MODE_FIFO_KHR = 0x00000002,
VK_PRESENT_MODE_FIFO_RELAXED_KHR = 0x00000003,
- //@extension("VK_KHR_shared_presentable_image")
+ //@extension("VK_KHR_shared_presentable_image") // 112
VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000,
VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001,
}
@@ -1209,6 +1255,7 @@
VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
+ VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
}
@extension("VK_EXT_debug_report") // 12
@@ -4261,28 +4308,28 @@
f32 maxFrameAverageLightLevel
}
-@extension("VK_KHR_shared_presentable_image") // 111
+@extension("VK_KHR_shared_presentable_image") // 112
class VkSharedPresentSurfaceCapabilitiesKHR {
VkStructureType sType
const void* pNext
VkImageUsageFlags sharedPresentSupportedUsageFlags
}
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
class VkPhysicalDeviceSurfaceInfo2KHR {
VkStructureType sType
const void* pNext
VkSurfaceKHR surface
}
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
class VkSurfaceCapabilities2KHR {
VkStructureType sType
void* pNext
VkSurfaceCapabilitiesKHR surfaceCapabilities
}
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
class VkSurfaceFormat2KHR {
VkStructureType sType
void* pNext
@@ -7462,7 +7509,7 @@
return ?
}
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
cmd VkResult vkGetPhysicalDeviceSurfaceCapabilities2KHR(
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
@@ -7470,7 +7517,7 @@
return ?
}
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
cmd VkResult vkGetPhysicalDeviceSurfaceFormats2KHR(
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h
index 43a9a9c..d3e5f0f 100644
--- a/vulkan/include/vulkan/vk_android_native_buffer.h
+++ b/vulkan/include/vulkan/vk_android_native_buffer.h
@@ -17,7 +17,7 @@
#ifndef __VK_ANDROID_NATIVE_BUFFER_H__
#define __VK_ANDROID_NATIVE_BUFFER_H__
-#include <system/window.h>
+#include <cutils/native_handle.h>
#include <vulkan/vulkan.h>
#ifdef __cplusplus
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 67eba86..f0209d6 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -43,11 +43,11 @@
#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
// Version of this file
-#define VK_HEADER_VERSION 46
+#define VK_HEADER_VERSION 49
#define VK_NULL_HANDLE 0
-
+
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
@@ -60,7 +60,7 @@
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
#endif
#endif
-
+
typedef uint32_t VkFlags;
@@ -261,9 +261,6 @@
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX = 1000071002,
VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX = 1000071003,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX = 1000071004,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHX = 1000071005,
- VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHX = 1000071006,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHX = 1000071007,
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX = 1000072000,
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHX = 1000072001,
VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHX = 1000072002,
@@ -901,6 +898,47 @@
VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF
} VkSubpassContents;
+typedef enum VkObjectType {
+ VK_OBJECT_TYPE_UNKNOWN = 0,
+ VK_OBJECT_TYPE_INSTANCE = 1,
+ VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2,
+ VK_OBJECT_TYPE_DEVICE = 3,
+ VK_OBJECT_TYPE_QUEUE = 4,
+ VK_OBJECT_TYPE_SEMAPHORE = 5,
+ VK_OBJECT_TYPE_COMMAND_BUFFER = 6,
+ VK_OBJECT_TYPE_FENCE = 7,
+ VK_OBJECT_TYPE_DEVICE_MEMORY = 8,
+ VK_OBJECT_TYPE_BUFFER = 9,
+ VK_OBJECT_TYPE_IMAGE = 10,
+ VK_OBJECT_TYPE_EVENT = 11,
+ VK_OBJECT_TYPE_QUERY_POOL = 12,
+ VK_OBJECT_TYPE_BUFFER_VIEW = 13,
+ VK_OBJECT_TYPE_IMAGE_VIEW = 14,
+ VK_OBJECT_TYPE_SHADER_MODULE = 15,
+ VK_OBJECT_TYPE_PIPELINE_CACHE = 16,
+ VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17,
+ VK_OBJECT_TYPE_RENDER_PASS = 18,
+ VK_OBJECT_TYPE_PIPELINE = 19,
+ VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20,
+ VK_OBJECT_TYPE_SAMPLER = 21,
+ VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22,
+ VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,
+ VK_OBJECT_TYPE_FRAMEBUFFER = 24,
+ VK_OBJECT_TYPE_COMMAND_POOL = 25,
+ VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
+ VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,
+ VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000,
+ VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001,
+ VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,
+ VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = 1000085000,
+ VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,
+ VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
+ VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN,
+ VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL,
+ VK_OBJECT_TYPE_RANGE_SIZE = (VK_OBJECT_TYPE_COMMAND_POOL - VK_OBJECT_TYPE_UNKNOWN + 1),
+ VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkObjectType;
+
typedef VkFlags VkInstanceCreateFlags;
typedef enum VkFormatFeatureFlagBits {
@@ -3317,6 +3355,7 @@
VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
+ VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -4107,6 +4146,64 @@
const void* pData);
#endif
+#define VK_KHR_shared_presentable_image 1
+#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
+#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
+
+typedef struct VkSharedPresentSurfaceCapabilitiesKHR {
+ VkStructureType sType;
+ void* pNext;
+ VkImageUsageFlags sharedPresentSupportedUsageFlags;
+} VkSharedPresentSurfaceCapabilitiesKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR(
+ VkDevice device,
+ VkSwapchainKHR swapchain);
+#endif
+
+#define VK_KHR_get_surface_capabilities2 1
+#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
+#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
+
+typedef struct VkPhysicalDeviceSurfaceInfo2KHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkSurfaceKHR surface;
+} VkPhysicalDeviceSurfaceInfo2KHR;
+
+typedef struct VkSurfaceCapabilities2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkSurfaceCapabilitiesKHR surfaceCapabilities;
+} VkSurfaceCapabilities2KHR;
+
+typedef struct VkSurfaceFormat2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkSurfaceFormatKHR surfaceFormat;
+} VkSurfaceFormat2KHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+ VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+ uint32_t* pSurfaceFormatCount,
+ VkSurfaceFormat2KHR* pSurfaceFormats);
+#endif
+
#define VK_EXT_debug_report 1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
@@ -5733,7 +5830,7 @@
#endif
#define VK_EXT_swapchain_colorspace 1
-#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 3
#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
@@ -5770,66 +5867,6 @@
const VkHdrMetadataEXT* pMetadata);
#endif
-#define VK_KHR_shared_presentable_image 1
-#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
-#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
-
-typedef struct VkSharedPresentSurfaceCapabilitiesKHR {
- VkStructureType sType;
- void* pNext;
- VkImageUsageFlags sharedPresentSupportedUsageFlags;
-} VkSharedPresentSurfaceCapabilitiesKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR(
- VkDevice device,
- VkSwapchainKHR swapchain);
-#endif
-
-#define VK_KHR_get_surface_capabilities2 1
-#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
-#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
-
-typedef struct VkPhysicalDeviceSurfaceInfo2KHR {
- VkStructureType sType;
- const void* pNext;
- VkSurfaceKHR surface;
-} VkPhysicalDeviceSurfaceInfo2KHR;
-
-typedef struct VkSurfaceCapabilities2KHR {
- VkStructureType sType;
- void* pNext;
- VkSurfaceCapabilitiesKHR surfaceCapabilities;
-} VkSurfaceCapabilities2KHR;
-
-typedef struct VkSurfaceFormat2KHR {
- VkStructureType sType;
- void* pNext;
- VkSurfaceFormatKHR surfaceFormat;
-} VkSurfaceFormat2KHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
- VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
- uint32_t* pSurfaceFormatCount,
- VkSurfaceFormat2KHR* pSurfaceFormats);
-#endif
-
-
-
#ifdef VK_USE_PLATFORM_IOS_MVK
#define VK_MVK_ios_surface 1
#define VK_MVK_IOS_SURFACE_SPEC_VERSION 2
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 6149894..5f9b357 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -75,6 +75,7 @@
"libbase",
"liblog",
"libui",
+ "libgraphicsenv",
"libutils",
"libcutils",
"libz",
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 6f425f5..947a2f7 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -28,9 +28,11 @@
#include <android/dlext.h>
#include <cutils/properties.h>
-#include <ui/GraphicsEnv.h>
+#include <graphicsenv/GraphicsEnv.h>
#include <utils/Vector.h>
+#include "android-base/properties.h"
+
#include "driver.h"
#include "stubhal.h"
@@ -822,9 +824,9 @@
// conditionally add VK_GOOGLE_display_timing if present timestamps are
// supported by the driver:
- char timestamp_property[PROPERTY_VALUE_MAX];
- property_get("service.sf.present_timestamp", timestamp_property, "1");
- if (strcmp(timestamp_property, "1") == 0) {
+ const std::string timestamp_property("service.sf.present_timestamp");
+ android::base::WaitForPropertyCreation(timestamp_property);
+ if (android::base::GetBoolProperty(timestamp_property, true)) {
loader_extensions.push_back({
VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e2c8c06..a346c0a 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -22,6 +22,7 @@
#include <sync/sync.h>
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
+#include <system/window.h>
#include "driver.h"
@@ -429,6 +430,8 @@
return HAL_DATASPACE_DISPLAY_P3;
case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
return HAL_DATASPACE_V0_SCRGB_LINEAR;
+ case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT:
+ return HAL_DATASPACE_V0_SCRGB;
case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
return HAL_DATASPACE_DCI_P3_LINEAR;
case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT:
@@ -639,6 +642,8 @@
const VkSurfaceFormatKHR kWideColorFormats[] = {
{VK_FORMAT_R16G16B16A16_SFLOAT,
VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
+ {VK_FORMAT_R16G16B16A16_SFLOAT,
+ VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
{VK_FORMAT_A2R10G10B10_UNORM_PACK32,
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
};
@@ -1014,7 +1019,7 @@
return VK_ERROR_SURFACE_LOST_KHR;
}
}
- err = native_window_set_usage(surface.window.get(), gralloc_usage);
+ err = native_window_set_usage(surface.window.get(), uint64_t(gralloc_usage));
if (err != 0) {
// TODO(jessehall): Improve error reporting. Can we enumerate possible
// errors and translate them to valid Vulkan result codes?
@@ -1091,8 +1096,8 @@
image_native_buffer.handle = img.buffer->handle;
image_native_buffer.stride = img.buffer->stride;
image_native_buffer.format = img.buffer->format;
- image_native_buffer.usage = img.buffer->usage;
- android_convertGralloc0To1Usage(img.buffer->usage,
+ image_native_buffer.usage = int(img.buffer->usage);
+ android_convertGralloc0To1Usage(int(img.buffer->usage),
&image_native_buffer.usage2.producer,
&image_native_buffer.usage2.consumer);