[automerger] DO NOT MERGE Remove window obscurement information. am: edac95e737 am: dda3bdf8a8 am: 3cd049ca28 skipped: 2564b9fdf5 am: 67c9dace8b am: 09c59e7f69 am: a31fb53edd am: b63caaf102 skipped: c2116af15c
am: dfe44a12ab
Change-Id: I90f59bd979e33e39a9f9cfa8ca8f58d93a00994f
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 f31bcea..efa1ffb 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -65,6 +65,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;
@@ -83,6 +84,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;
@@ -232,6 +234,7 @@
uint32_t seq,
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t actionButton,
int32_t flags,
@@ -303,7 +306,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
@@ -424,9 +427,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 fda5b94..7c0552e 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 af1c0af..d5c5927 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -285,6 +285,7 @@
uint32_t seq,
int32_t deviceId,
int32_t source,
+ int32_t displayId,
int32_t action,
int32_t actionButton,
int32_t flags,
@@ -327,6 +328,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;
@@ -396,7 +398,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);
@@ -404,6 +407,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.
@@ -418,7 +422,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",
@@ -462,7 +466,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;
@@ -496,6 +500,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);
@@ -513,14 +518,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;
}
@@ -534,7 +539,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);
@@ -552,7 +557,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;
@@ -567,6 +572,7 @@
mSeqChains.push(seqChain);
addSample(motionEvent, &msg);
} else {
+ *displayId = msg.body.motion.displayId;
initializeMotionEvent(motionEvent, &msg);
}
chain = msg.body.motion.seq;
@@ -842,15 +848,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 81b9953..d19f3b8 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);
}
} // namespace android
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 c2d477e..a0e368c 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 3fbc5eb..6fe72a1 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..c880500 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,21 @@
status_t GraphicBuffer::unflatten(
void const*& buffer, size_t& size, int const*& fds, size_t& count) {
- if (size < 12 * sizeof(int)) 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 +396,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 +422,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 +459,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 submi