diff options
342 files changed, 9112 insertions, 3295 deletions
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp index 5548699c3e..abf7b06687 100644 --- a/cmds/atrace/Android.bp +++ b/cmds/atrace/Android.bp @@ -14,6 +14,9 @@ cc_binary { "libz", "libbase", ], + static_libs: [ + "libpdx_default_transport", + ], init_rc: ["atrace.rc"], diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index a07bfef9ba..2d9a98c7a2 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -40,6 +40,7 @@ #include <android/hidl/manager/1.0/IServiceManager.h> #include <hidl/ServiceManagement.h> +#include <pdx/default_transport/service_utility.h> #include <utils/String8.h> #include <utils/Timers.h> #include <utils/Tokenizer.h> @@ -50,6 +51,7 @@ #include <android-base/stringprintf.h> using namespace android; +using pdx::default_transport::ServiceUtility; using std::string; @@ -61,6 +63,7 @@ const char* k_traceTagsProperty = "debug.atrace.tags.enableflags"; 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 @@ struct TracingCategory { /* 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 @@ static const TracingCategory k_categories[] = { { "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 @@ static const TracingCategory k_categories[] = { { 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,6 +188,7 @@ static const TracingCategory k_categories[] = { { "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, { { OPT, "events/binder/binder_lock/enable" }, @@ -205,6 +213,7 @@ static const char* g_debugAppCmdLine = ""; static const char* g_outputFile = nullptr; /* Global state */ +static bool g_tracePdx = false; static bool g_traceAborted = false; static bool g_categoryEnables[arraysize(k_categories)] = {}; static std::string g_traceFolder; @@ -364,6 +373,10 @@ static bool isCategorySupported(const TracingCategory& category) return !android::base::GetProperty(k_coreServicesProp, "").empty(); } + if (strcmp(category.name, k_pdxServiceCategory) == 0) { + return true; + } + bool ok = category.tags != 0; for (int i = 0; i < MAX_SYS_FILES; i++) { const char* path = category.sysfiles[i].path; @@ -786,6 +799,11 @@ static bool setUpTrace() 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); @@ -799,6 +817,10 @@ static bool setUpTrace() 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(); @@ -836,6 +858,10 @@ static void cleanUpTrace() clearAppProperties(); pokeBinderServices(); + if (g_tracePdx) { + ServiceUtility::PokeServices(); + } + // Set the options back to their defaults. setTraceOverwriteEnable(true); setTraceBufferSizeKB(1); diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index d5381457c0..526fd19e30 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -53,6 +53,8 @@ on post-fs 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 @@ on post-fs 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 880bc75bc3..10dda56b75 100644 --- a/cmds/bugreportz/Android.mk +++ b/cmds/bugreportz/Android.mk @@ -25,6 +25,7 @@ include $(BUILD_EXECUTABLE) 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 0000000000..38b6276b13 --- /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 18a4078d36..a1b6a51699 100644 --- a/cmds/dumpstate/Android.mk +++ b/cmds/dumpstate/Android.mk @@ -138,7 +138,7 @@ include $(BUILD_NATIVE_TEST) 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 0000000000..f189489fde --- /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 2f7704d273..10db5d65e3 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 f84d86d93b..4161bd79d9 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 @@ void add_mountinfo(); #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 @@ void add_mountinfo(); #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_"; + +struct DumpData { + std::string name; + int fd; + time_t mtime; +}; -static tombstone_data_t tombstone_data[NUM_TOMBSTONES]; +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 int DumpFile(const std::string& title, const std::string& path) { 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 constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.descript 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; +/* + * 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 { - close(fd); - data[i].fd = -1; + 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 @@ static void dump_raft() { } } -/** - * 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 @@ static bool skip_none(const char* path __attribute__((unused))) { return false; } -static const char mmcblk0[] = "/sys/block/mmcblk0/"; unsigned long worst_write_perf = 20000; /* in KB/s */ // @@ -586,11 +578,13 @@ static int dump_stat_from_fd(const char *title __unused, const char *path, int f 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 @@ static int dump_stat_from_fd(const char *title __unused, const char *path, int f / 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 @@ static void DoLogcat() { "-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 @@ static void DumpIpTables() { 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 @@ static void AddAnrTraceFiles() { } } - 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 @@ static void AddAnrTraceFiles() { // 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)); + } + } + + // 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; } - if (add_to_zip && already_dumped) { - MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str()); + // 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 @@ static void dumpstate() { 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 @@ static void dumpstate() { 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 @@ static void dumpstate() { 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 @@ void Dumpstate::DumpstateBoard() { 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 @@ void Dumpstate::DumpstateBoard() { 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 @@ int main(int argc, char *argv[]) { 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 @@ int main(int argc, char *argv[]) { 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 @@ int main(int argc, char *argv[]) { 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 91deb36152..93f4c22e43 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 @@ static const char* hal_interfaces_to_dump[] { "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 @@ std::set<int> get_interesting_hal_pids() { 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); + } + + 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(); - std::string traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", ""); - if (traces_path.empty()) return nullptr; + 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) { diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 60c89a97b7..e3021d8905 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -1786,6 +1786,16 @@ binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::strin 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 4011315175..5756b8275a 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -91,6 +91,8 @@ public: 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 f09a3975d3..c8e76b0ae1 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -57,6 +57,8 @@ interface IInstalld { 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 487f6b39ef..9466259fc2 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -853,6 +853,70 @@ bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_pat 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")) { @@ -932,14 +996,22 @@ static bool IsOutputDalvikCache(const char* oat_dir) { 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; } @@ -1299,36 +1371,32 @@ void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) // 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) { const char* dexoptanalyzer_bin = is_debug_runtime() ? "/system/bin/dexoptanalyzerd" : "/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; } @@ -1442,6 +1510,9 @@ static bool process_secondary_dex_dexopt(const char* original_dex_path, const ch } } 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; @@ -1512,6 +1583,10 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins 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; @@ -1701,6 +1776,10 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, /*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 cb8aaeba75..d171ee534e 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -50,6 +50,10 @@ bool analyze_primary_profiles(uid_t uid, const std::string& pkgname); 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 6a81cfc34a..2597c7956c 100644 --- a/cmds/installd/installd_constants.h +++ b/cmds/installd/installd_constants.h @@ -31,7 +31,7 @@ constexpr const char* SECONDARY_USER_PREFIX = "user/"; 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/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 39d92a7561..d3d396f025 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -46,7 +46,6 @@ cc_binary { 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 3b93332cd2..31cd0cb5ac 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -286,7 +286,11 @@ int svcmgr_handler(struct binder_state *bs, } 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 aec211abac..d336a436d7 100644 --- a/cmds/servicemanager/servicemanager.rc +++ b/cmds/servicemanager/servicemanager.rc @@ -12,3 +12,4 @@ service servicemanager /system/bin/servicemanager 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 d5ddaaf5bc..3fa4d7debd 100644 --- a/cmds/servicemanager/vndservicemanager.rc +++ b/cmds/servicemanager/vndservicemanager.rc @@ -3,4 +3,4 @@ service vndservicemanager /vendor/bin/vndservicemanager /dev/vndbinder 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 0000000000..d4c037ab7d --- /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 0000000000..dda80bb565 --- /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/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp new file mode 100644 index 0000000000..5caceec89f --- /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 1dd926c06b..0000000000 --- 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 dd1dd7daf1..7090bdb503 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 0000000000..f718c47cab --- /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 0000000000..167ed6a5bf --- /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 0000000000..4698bb3a09 --- /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 7f460873b5..a88733cac7 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -388,13 +388,13 @@ ASensorManager* ASensorManager_getInstance(); #endif #if __ANDROID_API__ >= __ANDROID_API_O__ -/* +/** * Get a reference to the sensor manager. ASensorManager is a singleton * per package as different packages may have access to different sensors. * * Example: * - * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz"); + * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz"); * */ ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName); @@ -503,14 +503,12 @@ void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) * {@link ASensor_isDirectChannelTypeSupported}, respectively. * * Example: - * \code{.cpp} - * ASensorManager *manager = ...; - * ASensor *sensor = ...; - * int channelId = ...; * - * ASensorManager_configureDirectReport( - * manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST); - * \endcode + * ASensorManager *manager = ...; + * ASensor *sensor = ...; + * int channelId = ...; + * + * ASensorManager_configureDirectReport(manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST); * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. @@ -530,50 +528,86 @@ int ASensorManager_configureDirectReport( /*****************************************************************************/ /** - * Enable the selected sensor with a specified sampling period and max batch report latency. - * Returns a negative error code on failure. - * Note: To disable the selected sensor, use ASensorEventQueue_disableSensor() same as before. + * Enable the selected sensor with sampling and report parameters + * + * Enable the selected sensor at a specified sampling period and max batch report latency. + * To disable sensor, use {@link ASensorEventQueue_disableSensor}. + * + * \param queue {@link ASensorEventQueue} for sensor event to be report to. + * \param sensor {@link ASensor} to be enabled. + * \param samplingPeriodUs sampling period of sensor in microseconds. + * \param maxBatchReportLatencyus maximum time interval between two batch of sensor events are + * delievered in microseconds. For sensor streaming, set to 0. + * \return 0 on success or a negative error code on failure. */ int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor, int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs); /** - * Enable the selected sensor. Returns a negative error code on failure. + * Enable the selected sensor at default sampling rate. + * + * Start event reports of a sensor to specified sensor event queue at a default rate. + * + * \param queue {@link ASensorEventQueue} for sensor event to be report to. + * \param sensor {@link ASensor} to be enabled. + * + * \return 0 on success or a negative error code on failure. */ int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor); /** - * Disable the selected sensor. Returns a negative error code on failure. + * Disable the selected sensor. + * + * Stop event reports from the sensor to specified sensor event queue. + * + * \param queue {@link ASensorEventQueue} to be changed + * \param sensor {@link ASensor} to be disabled + * \return 0 on success or a negative error code on failure. */ int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor); /** * Sets the delivery rate of events in microseconds for the given sensor. + * + * This function has to be called after {@link ASensorEventQueue_enableSensor}. * Note that this is a hint only, generally event will arrive at a higher * rate. It is an error to set a rate inferior to the value returned by * ASensor_getMinDelay(). - * Returns a negative error code on failure. + * + * \param queue {@link ASensorEventQueue} to which sensor event is delivered. + * \param sensor {@link ASensor} of which sampling rate to be updated. + * \param usec sensor sampling period (1/sampling rate) in microseconds + * \return 0 on sucess or a negative error code on failure. */ int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec); /** - * Returns true if there are one or more events available in the - * sensor queue. Returns 1 if the queue has events; 0 if - * it does not have events; and a negative value if there is an error. + * Determine if a sensor event queue has pending event to be processed. + * + * \param queue {@link ASensorEventQueue} to be queried + * \return 1 if the queue has events; 0 if it does not have events; + * or a negative value if there is an error. */ int ASensorEventQueue_hasEvents(ASensorEventQueue* queue); /** - * Returns the next available events from the queue. Returns a negative - * value if no events are available or an error has occurred, otherwise - * the number of events returned. + * Retrieve pending events in sensor event queue + * + * Retrieve next available events from the queue to a specified event array. + * + * \param queue {@link ASensorEventQueue} to get events from + * \param events pointer to an array of {@link ASensorEvents}. + * \param count max number of event that can be filled into array event. + * \return number of events returned on success; negative error code when + * no events are pending or an error has occurred. * * Examples: - * ASensorEvent event; - * ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1); * - * ASensorEvent eventBuffer[8]; - * ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8); + * ASensorEvent event; + * ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1); + * + * ASensorEvent eventBuffer[8]; + * ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8); * */ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count); diff --git a/include/gui b/include/gui new file mode 120000 index 0000000000..3b796f340f --- /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 f31bceabd7..efa1ffbfee 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -65,6 +65,7 @@ struct InputMessage { 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 @@ struct InputMessage { 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 @@ public: 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 @@ public: * 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 @@ private: 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 30cd5fd9f2..7797bb2ab4 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 cecf7152f4..6c1ba3de00 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 0000000000..99de2dc166 --- /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 0000000000..2fb3147669 --- /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 0d25176f98..a20154f834 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -23,5 +23,6 @@ ndk_headers { 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 256a636717..09fd0cb482 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -97,10 +97,6 @@ cc_library { "libbinder_headers", ], - export_include_dirs: [ - "include", - ], - clang: true, sanitize: { misc_undefined: ["integer"], diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp new file mode 100644 index 0000000000..f2686d5748 --- /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 index 8182c07001..39b5829faf 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 index 781707694a..781707694a 100644 --- a/include/ui/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index f1d1346366..4558fe87c6 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: [ @@ -117,13 +123,24 @@ cc_library_shared { "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 873814913f..17cf677e09 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -37,6 +37,8 @@ #include <binder/IPCThreadState.h> #include <binder/PermissionCache.h> +#include <system/window.h> + namespace android { BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) : @@ -702,9 +704,9 @@ status_t BufferQueueConsumer::setDefaultBufferDataSpace( 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 cfb25e0503..bb703da3dd 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 @@ BufferQueueCore::~BufferQueueCore() {} 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 838586411d..3d94a029e5 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::waitForFreeSlotThenRelock(FreeSlotCaller caller, 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 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, } } // 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 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, // 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 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, 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 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, } 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 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) } 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 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, 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 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, 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/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index c2b10a91dd..3d3637648c 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -106,7 +106,7 @@ void ConsumerBase::onFrameAvailable(const BufferItem& item) { sp<FrameAvailableListener> listener; { // scope for the lock - Mutex::Autolock lock(mMutex); + Mutex::Autolock lock(mFrameAvailableMutex); listener = mFrameAvailableListener.promote(); } @@ -121,7 +121,7 @@ void ConsumerBase::onFrameReplaced(const BufferItem &item) { sp<FrameAvailableListener> listener; { - Mutex::Autolock lock(mMutex); + Mutex::Autolock lock(mFrameAvailableMutex); listener = mFrameAvailableListener.promote(); } @@ -185,7 +185,7 @@ bool ConsumerBase::isAbandoned() { void ConsumerBase::setFrameAvailableListener( const wp<FrameAvailableListener>& listener) { CB_LOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); + Mutex::Autolock lock(mFrameAvailableMutex); mFrameAvailableListener = listener; } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index c654f083b3..34c9d7805a 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 @@ status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, 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 a573bee651..c705d3926d 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -132,7 +132,7 @@ public: 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 8481b502a0..1b0fe06810 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -125,7 +125,7 @@ public: } 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 @@ public: 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 @@ public: } 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 @@ public: } 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 @@ public: } 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 @@ status_t BnGraphicBufferProducer::onTransact( 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 @@ status_t BnGraphicBufferProducer::onTransact( 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 bafe947efe..52c906775e 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 7b2b5c37f1..409a3cb076 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 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { uint32_t reqWidth; uint32_t reqHeight; PixelFormat reqFormat; - uint32_t reqUsage; + uint64_t reqUsage; bool enableFrameTimestamps; { @@ -511,8 +513,8 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { 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 @@ int Surface::perform(int operation, va_list args) 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::dispatchDisconnect(va_list args) { } 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 @@ int Surface::attachBuffer(ANativeWindowBuffer* buffer) 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 @@ int Surface::attachBuffer(ANativeWindowBuffer* buffer) 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 @@ static status_t copyBlt( 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 8c8384399c..7ae2672249 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1080,5 +1080,9 @@ size_t ScreenshotClient::getSize() const { 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 fda5b945da..7c0552e0dc 100644 --- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp +++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp @@ -125,7 +125,7 @@ inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) { 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 @@ status_t H2BGraphicBufferProducer::setAsyncMode(bool async) { 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 @@ status_t H2BGraphicBufferProducer::setSidebandStream( 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 index 55637a9be4..55637a9be4 100644 --- a/include/gui/BufferItem.h +++ b/libs/gui/include/gui/BufferItem.h diff --git a/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index 217fe6ad81..217fe6ad81 100644 --- a/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h diff --git a/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index ba5cbf7eb4..ba5cbf7eb4 100644 --- a/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h diff --git a/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h index f194bdf758..d108120777 100644 --- a/include/gui/BufferQueueConsumer.h +++ b/libs/gui/include/gui/BufferQueueConsumer.h @@ -121,13 +121,12 @@ public: // 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 index dd8b992ce1..537c957746 100644 --- a/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -170,7 +170,7 @@ private: // 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 index ffafb49615..ffafb49615 100644 --- a/include/gui/BufferQueueDefs.h +++ b/libs/gui/include/gui/BufferQueueDefs.h diff --git a/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 87bc8008e1..0f8917aa6d 100644 --- a/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -80,9 +80,9 @@ public: // // 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 @@ public: // 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 index 57704b1d09..57704b1d09 100644 --- a/include/gui/BufferSlot.h +++ b/libs/gui/include/gui/BufferSlot.h diff --git a/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index d1a9b04ad6..e9fc8fd1ea 100644 --- a/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -241,7 +241,9 @@ protected: // mFrameAvailableListener is the listener object that will be called when a // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. + // queueBuffer. The listener object is protected by mFrameAvailableMutex + // (not mMutex). + Mutex mFrameAvailableMutex; wp<FrameAvailableListener> mFrameAvailableListener; // The ConsumerBase has-a BufferQueue and is responsible for creating this object diff --git a/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h index 58602bf321..58602bf321 100644 --- a/include/gui/CpuConsumer.h +++ b/libs/gui/include/gui/CpuConsumer.h diff --git a/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 32ce59a765..32ce59a765 100644 --- a/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h diff --git a/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h index 9716be4bfd..9716be4bfd 100644 --- a/include/gui/FrameTimestamps.h +++ b/libs/gui/include/gui/FrameTimestamps.h diff --git a/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 2cf6162fd8..2cf6162fd8 100644 --- a/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h diff --git a/include/gui/GuiConfig.h b/libs/gui/include/gui/GuiConfig.h index b020ed9b6a..b020ed9b6a 100644 --- a/include/gui/GuiConfig.h +++ b/libs/gui/include/gui/GuiConfig.h diff --git a/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h index c0828820e3..c0828820e3 100644 --- a/include/gui/IConsumerListener.h +++ b/libs/gui/include/gui/IConsumerListener.h diff --git a/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h index d783f74d7c..d783f74d7c 100644 --- a/include/gui/IDisplayEventConnection.h +++ b/libs/gui/include/gui/IDisplayEventConnection.h diff --git a/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h index 3d069dfe48..9fb7580912 100644 --- a/include/gui/IGraphicBufferConsumer.h +++ b/libs/gui/include/gui/IGraphicBufferConsumer.h @@ -241,7 +241,7 @@ public: // 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 index 925080663e..6d16e7426c 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -195,7 +195,7 @@ public: // 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 @@ public: // 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 index e808bd3bc3..e808bd3bc3 100644 --- a/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h diff --git a/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index f80ba000b4..f80ba000b4 100644 --- a/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h diff --git a/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 2c613ea8c5..2c613ea8c5 100644 --- a/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h diff --git a/include/gui/OccupancyTracker.h b/libs/gui/include/gui/OccupancyTracker.h index d4de8f2b14..d4de8f2b14 100644 --- a/include/gui/OccupancyTracker.h +++ b/libs/gui/include/gui/OccupancyTracker.h diff --git a/include/gui/StreamSplitter.h b/libs/gui/include/gui/StreamSplitter.h index 8f47eb47ac..8f47eb47ac 100644 --- a/include/gui/StreamSplitter.h +++ b/libs/gui/include/gui/StreamSplitter.h diff --git a/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index e8dc83e951..0f7e12a228 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 @@ private: 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 @@ protected: 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 @@ protected: // 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 index ec310cf6f9..145c0597bd 100644 --- a/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -271,6 +271,7 @@ public: 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 index 8bb705cf77..8bb705cf77 100644 --- a/include/gui/SurfaceControl.h +++ b/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 index fa6c2d9f7f..fa6c2d9f7f 100644 --- a/include/gui/bufferqueue/1.0/B2HProducerListener.h +++ b/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 index 93c452a0d6..c3a9d443ec 100644 --- a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h +++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h @@ -65,7 +65,7 @@ struct H2BGraphicBufferProducer : public ::android::H2BConverter< 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 @@ struct H2BGraphicBufferProducer : public ::android::H2BConverter< 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 index cc64fd45dd..cc64fd45dd 100644 --- a/include/gui/view/Surface.h +++ b/libs/gui/include/gui/view/Surface.h diff --git a/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h index 50bd742b6a..50bd742b6a 100644 --- a/include/private/gui/ComposerService.h +++ b/libs/gui/include/private/gui/ComposerService.h diff --git a/include/private/gui/LayerState.h b/libs/gui/include/private/gui/LayerState.h index 307c764702..307c764702 100644 --- a/include/private/gui/LayerState.h +++ b/libs/gui/include/private/gui/LayerState.h diff --git a/include/private/gui/SyncFeatures.h b/libs/gui/include/private/gui/SyncFeatures.h index 79fb75bcbe..79fb75bcbe 100644 --- a/include/private/gui/SyncFeatures.h +++ b/libs/gui/include/private/gui/SyncFeatures.h diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 60c1277db0..4220aafa07 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 aa071f68b0..bcfc91c3f5 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 7ecf08cdb0..6bc3ccf53d 100644 --- a/libs/gui/tests/Malicious.cpp +++ b/libs/gui/tests/Malicious.cpp @@ -38,7 +38,7 @@ public: } 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 @@ public: 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 @@ public: // 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 80e30da84a..e2f494898e 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 8b3a1d0d4e..63e98bb540 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -285,6 +285,7 @@ status_t InputPublisher::publishMotionEvent( 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 @@ status_t InputPublisher::publishMotionEvent( 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 @@ bool InputConsumer::isTouchResamplingEnabled() { } 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 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, *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 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, 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 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, // 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 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, 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::consume(InputEventFactoryInterface* factory, } 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 @@ status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, 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::consumeBatch(InputEventFactoryInterface* factory, } 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 @@ status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory, mSeqChains.push(seqChain); addSample(motionEvent, &msg); } else { + *displayId = msg.body.motion.displayId; initializeMotionEvent(motionEvent, &msg); } chain = msg.body.motion.seq; diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 8e69c9cb30..a1367387bc 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -89,7 +89,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { 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 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { 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 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { 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 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { 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 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha 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 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater 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 81b99531c1..d19f3b8066 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -38,31 +38,33 @@ void TestInputMessageAlignment() { 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 3ef8b4aa05..693bace1f4 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 5cb725d10a..1423adea2c 100644 --- a/libs/math/include/math/TMatHelpers.h +++ b/libs/math/include/math/TMatHelpers.h @@ -342,9 +342,9 @@ TQuaternion<typename MATRIX::value_type> extractQuat(const MATRIX& mat) { 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/tests/mat_test.cpp b/libs/math/tests/mat_test.cpp index c365366384..3217a1a44b 100644 --- a/libs/math/tests/mat_test.cpp +++ b/libs/math/tests/mat_test.cpp @@ -487,7 +487,7 @@ do { \ 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 @@ do { \ 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 0000000000..7375a2bc2f --- /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 0000000000..e69de29bb2 --- /dev/null +++ b/libs/nativebase/MODULE_LICENSE_APACHE2 diff --git a/libs/nativebase/NOTICE b/libs/nativebase/NOTICE new file mode 100644 index 0000000000..c5b1efa7aa --- /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 0000000000..7ecdfbd745 --- /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 f64bab13f0..c6994c30b4 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_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffe } 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 d759acbbc1..e61fbd6e8b 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -57,10 +57,25 @@ cc_library { "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 45110c490b..3df97a1b4a 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -60,25 +60,6 @@ __BEGIN_DECLS // --------------------------------------------------------------------------- -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 { */ 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 @@ struct ANativeWindow /* 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 @@ static inline int native_window_set_crop( } /* - * 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 95618c472d..a7b340aea3 100644 --- a/libs/nativewindow/include/vndk/window.h +++ b/libs/nativewindow/include/vndk/window.h @@ -17,87 +17,13 @@ #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; +__BEGIN_DECLS /* * Convert this ANativeWindowBuffer into a AHardwareBuffer diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index b1d1a725a1..58045be03e 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -4,22 +4,40 @@ LIBNATIVEWINDOW { 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 8a3a623983..1cd8e01643 100644 --- a/libs/sensor/ISensorEventConnection.cpp +++ b/libs/sensor/ISensorEventConnection.cpp @@ -36,7 +36,8 @@ enum { ENABLE_DISABLE, SET_EVENT_RATE, FLUSH_SENSOR, - CONFIGURE_CHANNEL + CONFIGURE_CHANNEL, + DESTROY, }; class BpSensorEventConnection : public BpInterface<ISensorEventConnection> @@ -96,11 +97,22 @@ public: 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 @@ status_t BnSensorEventConnection::onTransact( 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 74186dfcb9..f20668d1e9 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -119,10 +119,12 @@ public: 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 @@ status_t BnSensorServer::onTransact( } 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 @@ status_t BnSensorServer::onTransact( 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 c2d477e4b5..a0e368c7e4 100644 --- a/libs/sensor/Sensor.cpp +++ b/libs/sensor/Sensor.cpp @@ -30,7 +30,7 @@ Sensor::Sensor(const char * name) : 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::Sensor(struct sensor_t const* hwSensor, int halVersion) : 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 @@ bool Sensor::isDynamicSensor() const { 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 3fbc5ebba8..6fe72a13ba 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -305,12 +305,13 @@ int SensorManager::configureDirectChannel(int channelNativeHandle, int sensorHan } 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 07cc7e84ad..b62e18c63c 100644 --- a/libs/sensor/include/sensor/ISensorEventConnection.h +++ b/libs/sensor/include/sensor/ISensorEventConnection.h @@ -42,6 +42,8 @@ public: 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 8d5006258f..edf3e0f4cf 100644 --- a/libs/sensor/include/sensor/ISensorServer.h +++ b/libs/sensor/include/sensor/ISensorServer.h @@ -52,7 +52,7 @@ public: 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 043e6352a7..6926f7f341 100644 --- a/libs/sensor/include/sensor/Sensor.h +++ b/libs/sensor/include/sensor/Sensor.h @@ -90,6 +90,7 @@ public: 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 5fc85d329b..23f7a918bb 100644 --- a/libs/sensor/include/sensor/SensorManager.h +++ b/libs/sensor/include/sensor/SensorManager.h @@ -64,7 +64,7 @@ public: 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 5edd664345..6630d9060a 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -54,7 +54,6 @@ cc_library_shared { "GraphicBuffer.cpp", "GraphicBufferAllocator.cpp", "GraphicBufferMapper.cpp", - "GraphicsEnv.cpp", "HdrCapabilities.cpp", "PixelFormat.cpp", "Rect.cpp", @@ -70,9 +69,8 @@ cc_library_shared { "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 @@ cc_library_shared { "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 882bd7c7b2..d5676cc2b8 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 @@ std::string decodeStandard(android_dataspace dataspace) { 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 decodeStandard(android_dataspace dataspace) { } 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 decodeTransfer(android_dataspace dataspace) { } 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 decodeRange(android_dataspace dataspace) { } 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 @@ std::string decodeColorMode(android_color_mode colorMode) { 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 87dbaf47d3..0eb08e59a9 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 @@ namespace Gralloc2 { 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 ee85c9bad9..c8805000a4 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -51,6 +51,7 @@ GraphicBuffer::GraphicBuffer() height = stride = format = + usage_deprecated = 0; usage = 0; layerCount = 0; handle = NULL; @@ -59,14 +60,12 @@ GraphicBuffer::GraphicBuffer() // 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 @@ status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight, 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 @@ status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight, 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 @@ bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight, 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 @@ status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight, 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 @@ status_t GraphicBuffer::initWithHandle(const native_handle_t* handle, 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 @@ status_t GraphicBuffer::lockAsyncYCbCr(uint32_t inUsage, const Rect& rect, 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 @@ status_t GraphicBuffer::unlockAsync(int *fenceFd) } 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 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& 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::flatten(void*& buffer, size_t& size, int*& fds, size_t& 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 @@ status_t GraphicBuffer::unflatten( // 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 @@ status_t GraphicBuffer::unflatten( 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 @@ status_t GraphicBuffer::unflatten( 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 b9fa6400f5..d52c508003 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -42,6 +42,10 @@ namespace android { 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 index 640e34b509..e9d5d8d40b 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 @@ namespace android { * 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 @@ public: } 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 @@ protected: 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 index 56de181bca..56de181bca 100644 --- a/include/ui/BufferQueueDefs.h +++ b/libs/ui/include/ui/BufferQueueDefs.h diff --git a/include/ui/ColorSpace.h b/libs/ui/include/ui/ColorSpace.h index 8ccf6d36e5..8ccf6d36e5 100644 --- a/include/ui/ColorSpace.h +++ b/libs/ui/include/ui/ColorSpace.h diff --git a/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h index 84838088af..30f4a59fe0 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 decodeTransfer(android_dataspace dataspace); 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 index 94caf6b9d3..94caf6b9d3 100644 --- a/include/ui/DisplayInfo.h +++ b/libs/ui/include/ui/DisplayInfo.h diff --git a/include/ui/DisplayStatInfo.h b/libs/ui/include/ui/DisplayStatInfo.h index 09543ec13a..09543ec13a 100644 --- a/include/ui/DisplayStatInfo.h +++ b/libs/ui/include/ui/DisplayStatInfo.h diff --git a/include/ui/Fence.h b/libs/ui/include/ui/Fence.h index 37811bcd7c..37811bcd7c 100644 --- a/include/ui/Fence.h +++ b/libs/ui/include/ui/Fence.h diff --git a/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h index 871fcf2dfe..871fcf2dfe 100644 --- a/include/ui/FenceTime.h +++ b/libs/ui/include/ui/FenceTime.h diff --git a/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h index 270675cba2..270675cba2 100644 --- a/include/ui/FloatRect.h +++ b/libs/ui/include/ui/FloatRect.h diff --git a/include/ui/FrameStats.h b/libs/ui/include/ui/FrameStats.h index bc9d3ec1f1..bc9d3ec1f1 100644 --- a/include/ui/FrameStats.h +++ b/libs/ui/include/ui/FrameStats.h diff --git a/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h index f826b92c31..8aee16033a 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 @@ using hardware::graphics::mapper::V2_0::YCbCrLayout; // 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 index 4b82cffb2d..95c2d2272e 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 GraphicBufferMapper; // =========================================================================== class GraphicBuffer - : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >, + : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>, public Flattenable<GraphicBuffer> { friend class Flattenable<GraphicBuffer>; @@ -141,7 +141,7 @@ public: 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 index fe99de1dd9..14a865e16c 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 index e0702e96a1..06961b11b5 100644 --- a/include/ui/GraphicBufferMapper.h +++ b/libs/ui/include/ui/GraphicBufferMapper.h @@ -43,6 +43,7 @@ class Rect; 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 index 925aa1b7b3..925aa1b7b3 100644 --- a/include/ui/HdrCapabilities.h +++ b/libs/ui/include/ui/HdrCapabilities.h diff --git a/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h index 02773d92fc..02773d92fc 100644 --- a/include/ui/PixelFormat.h +++ b/libs/ui/include/ui/PixelFormat.h diff --git a/include/ui/Point.h b/libs/ui/include/ui/Point.h index d050ede02d..d050ede02d 100644 --- a/include/ui/Point.h +++ b/libs/ui/include/ui/Point.h diff --git a/include/ui/Rect.h b/libs/ui/include/ui/Rect.h index b50e4ec656..b50e4ec656 100644 --- a/include/ui/Rect.h +++ b/libs/ui/include/ui/Rect.h diff --git a/include/ui/Region.h b/libs/ui/include/ui/Region.h index 778845295f..778845295f 100644 --- a/include/ui/Region.h +++ b/libs/ui/include/ui/Region.h diff --git a/include/ui/UiConfig.h b/libs/ui/include/ui/UiConfig.h index fcf8ed5d6b..fcf8ed5d6b 100644 --- a/include/ui/UiConfig.h +++ b/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 69cb64826e..f2e5034879 100644 --- a/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h +++ b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h @@ -174,8 +174,6 @@ class BroadcastRing { // // 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 @@ class BroadcastRing { // // 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 @@ class BroadcastRing { 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 @@ class BroadcastRing { 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 452bad0bce..da0ea24dab 100644 --- a/libs/vr/libbufferhub/Android.bp +++ b/libs/vr/libbufferhub/Android.bp @@ -34,6 +34,11 @@ sharedLibraries = [ "liblog", "libui", "libutils", + "libnativewindow" +] + +HeaderLibraries = [ + "libnativebase_headers", ] cc_library { @@ -45,7 +50,11 @@ cc_library { 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 fa61c4a215..1daa5d62d7 100644 --- a/libs/vr/libbufferhub/bufferhub_tests.cpp +++ b/libs/vr/libbufferhub/bufferhub_tests.cpp @@ -62,6 +62,57 @@ TEST_F(LibBufferHubTest, TestBasicUsage) { 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 ffdc9e2e79..ca0e0e0820 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 @@ class FenceHandle { 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 @@ struct BufferHubRPC { kOpCreateConsumerQueue, kOpGetQueueInfo, kOpProducerQueueAllocateBuffers, - kOpProducerQueueDetachBuffer, + kOpProducerQueueRemoveBuffer, kOpConsumerQueueImportBuffers, }; @@ -219,7 +302,7 @@ struct BufferHubRPC { // 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 @@ struct BufferHubRPC { 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 b4ef2f50d7..140ffc5a5a 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 @@ class NativeBuffer 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 @@ class NativeBufferProducer : public android::ANativeObjectBase< 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 @@ class NativeBufferProducer : public android::ANativeObjectBase< 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 a587f95879..0b3b2f0fb9 100644 --- a/libs/vr/libbufferhubqueue/Android.bp +++ b/libs/vr/libbufferhubqueue/Android.bp @@ -21,10 +21,6 @@ includeFiles = [ "include", ] -headerLibraries = [ - "libdvr_headers", -] - staticLibraries = [ "libbufferhub", "libdvrcommon", @@ -42,6 +38,11 @@ sharedLibraries = [ "libgui", ] +headerLibraries = [ + "libdvr_headers", + "libnativebase_headers", +] + cc_library { name: "libbufferhubqueue", cflags: [ @@ -51,9 +52,9 @@ cc_library { 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 012a4e70e4..bfb9a55e93 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 @@ void BufferHubQueue::Initialize() { 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<void> BufferHubQueue::ImportQueue() { 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 @@ bool BufferHubQueue::WaitForBuffers(int timeout) { // 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 @@ bool BufferHubQueue::WaitForBuffers(int timeout) { 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 @@ void BufferHubQueue::HandleBufferEvent(size_t slot, int poll_events) { "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 @@ void BufferHubQueue::HandleQueueEvent(int poll_event) { } 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); - 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; + 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_--; } - buffers_[slot] = nullptr; - capacity_--; - return 0; + return {}; } -void BufferHubQueue::Enqueue(const std::shared_ptr<BufferHubBuffer>& buf, - size_t slot) { - if (count() == capacity_) { - ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!"); - return; - } +Status<void> BufferHubQueue::Enqueue(Entry entry) { + if (!is_full()) { + available_buffers_.Append(std::move(entry)); - // 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_); + // Trigger OnBufferAvailable callback if registered. + if (on_buffer_available_) + on_buffer_available_(); - available_buffers_.Append(std::move(buffer_info)); + return {}; + } else { + ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!"); + return ErrorStatus(E2BIG); + } } 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(); - - *fence = std::move(fences_[buffer_info.slot]); + auto& entry = available_buffers_.Front(); - // 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_); + 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)); + } 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_, - reinterpret_cast<uint8_t*>(meta)); - } + return {std::move(buffer)}; +} - return {std::move(buf)}; +void BufferHubQueue::SetBufferAvailableCallback( + BufferAvailableCallback callback) { + on_buffer_available_ = callback; } -ProducerQueue::ProducerQueue(size_t meta_size) - : ProducerQueue(meta_size, 0, 0, 0, 0) {} +void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) { + on_buffer_removed_ = callback; +} ProducerQueue::ProducerQueue(LocalChannelHandle handle) : BASE(std::move(handle)) { @@ -370,14 +427,11 @@ ProducerQueue::ProducerQueue(LocalChannelHandle handle) } } -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 @@ ProducerQueue::ProducerQueue(size_t meta_size, uint64_t usage_set_mask, 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; - } - - if (is_full()) { - ALOGE("ProducerQueue::AllocateBuffer queue is at maximum capacity: %zu", - capacity()); - return -E2BIG; +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); } - 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()); + + std::vector<size_t> buffer_slots; + buffer_slots.reserve(buffer_count); + + // Bookkeeping for each buffer. + for (auto& hs : buffer_handle_slots) { + auto& buffer_handle = hs.first; + size_t buffer_slot = hs.second; + + // 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); + } + } + + 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. - 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()); + 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(); + } - *out_slot = buffer_slot; - return AddBuffer(BufferProducer::Import(std::move(buffer_handle)), - buffer_slot); + if (status.get().size() == 0) { + ALOGE_IF(TRACE, "ProducerQueue::AllocateBuffer: no buffer allocated."); + ErrorStatus(ENOMEM); + } + + return {status.get()[0]}; } -int ProducerQueue::AddBuffer(const std::shared_ptr<BufferProducer>& buf, - size_t slot) { +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(), buf->id(), slot); + 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. - const int ret = BufferHubQueue::AddBuffer(buf, slot); - if (ret < 0) - return ret; + auto status = BufferHubQueue::AddBuffer(buffer, slot); + if (!status) + return status; - Enqueue(buf, slot); - return 0; + return Enqueue(buffer, slot); } -int ProducerQueue::DetachBuffer(size_t slot) { +Status<void> ProducerQueue::RemoveBuffer(size_t slot) { auto status = - InvokeRemoteMethod<BufferHubRPC::ProducerQueueDetachBuffer>(slot); + InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot); if (!status) { - ALOGE("ProducerQueue::DetachBuffer: Failed to detach producer buffer: %s", + ALOGE("ProducerQueue::RemoveBuffer: Failed to remove producer buffer: %s", status.GetErrorMessage().c_str()); - return -status.error(); + return status.error_status(); } - return BufferHubQueue::DetachBuffer(slot); + return BufferHubQueue::RemoveBuffer(slot); } Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue( @@ -471,12 +557,22 @@ Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue( 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 @@ Status<size_t> ConsumerQueue::ImportBuffers() { 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 @@ Status<size_t> ConsumerQueue::ImportBuffers() { 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 @@ Status<size_t> ConsumerQueue::ImportBuffers() { "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 @@ Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue( 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 8582bbf3a6..0f75a5c3d8 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 @@ namespace dvr { /* 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::setAsyncMode(bool async) { 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 @@ status_t BufferHubQueueProducer::dequeueBuffer( 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 @@ status_t BufferHubQueueProducer::setSidebandStream( 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 @@ status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height, 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::AllocateBuffer(uint32_t width, uint32_t height, } 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 ed67f79951..d57c7af882 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 @@ class ConsumerQueue; // 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_; } + + // Returns the default buffer width of this buffer queue. + uint32_t default_width() const { return default_width_; } - // Return the default buffer height of this buffer queue. - size_t default_height() const { return default_height_; } + // Returns the default buffer height of this buffer queue. + uint32_t default_height() const { return default_height_; } - // Return the default buffer format of this buffer queue. - int32_t default_format() const { return default_format_; } + // Returns the default buffer format of this buffer queue. + uint32_t default_format() const { return default_format_; } - // Create a new consumer in handle form for immediate transport over RPC. - Status<LocalChannelHandle> CreateConsumerQueueHandle(); + // Creates a new consumer in handle form for immediate transport over RPC. + pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(); - // Return the number of buffers avaiable for dequeue. + // 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 @@ class BufferHubQueue : public pdx::Client { 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 @@ class BufferHubQueue : public pdx::Client { // 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; - // Called when a buffer is allocated remotely. - virtual Status<void> OnBufferAllocated() { return {}; } + std::shared_ptr<BufferHubBuffer> buffer; + std::unique_ptr<uint8_t[]> metadata; + pdx::LocalHandle fence; + size_t slot; + }; - // 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_; + // Enqueues a buffer to the available list (Gained for producer or Acquireed + // for consumer). + pdx::Status<void> Enqueue(Entry entry); - // 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_; + virtual pdx::Status<Entry> OnBufferReady( + const std::shared_ptr<BufferHubBuffer>& buf, size_t slot) = 0; + + // Called when a buffer is allocated remotely. + virtual pdx::Status<void> OnBufferAllocated() { return {}; } + + // 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 @@ class BufferHubQueue : public pdx::Client { 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; - - // A BufferHubBuffer client. - std::shared_ptr<BufferHubBuffer> buffer; + // 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}; - // Metadata associated with the buffer. - std::unique_ptr<uint8_t[]> metadata; + // Default buffer width that is set during ProducerQueue's creation. + size_t default_width_{1}; - BufferInfo() : BufferInfo(-1, 0) {} + // Default buffer height that is set during ProducerQueue's creation. + size_t default_height_{1}; - BufferInfo(size_t slot, size_t metadata_size) - : slot(slot), - buffer(nullptr), - metadata(metadata_size ? new uint8_t[metadata_size] : nullptr) {} + // Default buffer format that is set during ProducerQueue's creation. + int32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888 - BufferInfo(BufferInfo&& other) - : slot(other.slot), - buffer(std::move(other.buffer)), - metadata(std::move(other.metadata)) {} + // 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}; - BufferInfo& operator=(BufferInfo&& other) { - slot = other.slot; - buffer = std::move(other.buffer); - metadata = std::move(other.metadata); - return *this; - } + // Buffers and related data that are available for dequeue. + RingBuffer<Entry> available_buffers_{kMaxQueueCapacity}; - private: - BufferInfo(const BufferInfo&) = delete; - void operator=(BufferInfo&) = delete; - }; + // Keeps track with how many buffers have been added into the queue. + size_t capacity_{0}; - // Default buffer width that can be set to override the buffer width when a - // width and height of 0 are specified in AllocateBuffer. - 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. - 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}; - - // Buffer queue: - // |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|. - std::vector<std::shared_ptr<BufferHubBuffer>> buffers_; - - // |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_; - - // |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_; - - // 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 @@ class BufferHubQueue : public pdx::Client { 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 BufferHubQueue : public pdx::Client { 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 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { // 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,28 +315,12 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { // 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); - - int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf, - LocalHandle* release_fence) override; -}; + explicit ProducerQueue(pdx::LocalChannelHandle handle); + ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage); -// 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); -} + pdx::Status<Entry> OnBufferReady( + const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override; +}; class ConsumerQueue : public BufferHubQueue { public: @@ -399,7 +338,7 @@ class ConsumerQueue : public BufferHubQueue { // 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 @@ class ConsumerQueue : public BufferHubQueue { // 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 @@ class ConsumerQueue : public BufferHubQueue { // 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 7890176f04..638a56caef 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 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer { // 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 @@ class BufferHubQueueProducer : public BnGraphicBufferProducer { // 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 fe0b12aa44..e0a4052ec2 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 @@ using pdx::LocalHandle; 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 @@ class BufferHubQueueTest : public ::testing::Test { } } - 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 @@ class BufferHubQueueTest : public ::testing::Test { 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, TestDequeue) { } 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 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { 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 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { 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 @@ struct TestMetadata { }; 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, TestMetadata) { } 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, TestMetadataMismatch) { } 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, TestEnqueue) { } 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, TestAllocateBuffer) { 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, TestUsageSetMask) { 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, TestUsageClearMask) { 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 2b6239f499..c7692d05b0 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 @@ TEST_F(BufferHubQueueProducerTest, Query_Succeeds) { 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 d90521a810..e3ab7fa26b 100644 --- a/libs/vr/libdisplay/Android.bp +++ b/libs/vr/libdisplay/Android.bp @@ -17,6 +17,7 @@ sourceFiles = [ "display_manager_client.cpp", "display_protocol.cpp", "vsync_client.cpp", + "shared_buffer_helpers.cpp", ] localIncludeFiles = [ @@ -39,12 +40,13 @@ staticLibraries = [ "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 935ca2ef81..442c82d17f 100644 --- a/libs/vr/libdisplay/display_client.cpp +++ b/libs/vr/libdisplay/display_client.cpp @@ -104,9 +104,16 @@ Status<void> Surface::SetAttributes(const SurfaceAttributes& attributes) { 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() { 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 @@ Status<Metrics> DisplayClient::GetDisplayMetrics() { 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,50 @@ Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface( 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::SetupGlobalBuffer: Failed to create the global 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::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::GetNamedBuffer: Failed to get named buffer: name=%s; " + "DisplayClient::GetGlobalBuffer: Failed to get named buffer: key=%d; " "error=%s", - name.c_str(), status.GetErrorMessage().c_str()); + key, status.GetErrorMessage().c_str()); return status.error_status(); } @@ -192,9 +240,9 @@ Status<std::unique_ptr<IonBuffer>> DisplayClient::GetNamedBuffer( 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); } diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp index 82dacf707d..974c231375 100644 --- a/libs/vr/libdisplay/display_manager_client.cpp +++ b/libs/vr/libdisplay/display_manager_client.cpp @@ -32,32 +32,6 @@ DisplayManagerClient::GetSurfaceState() { 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 7a7f670ffa..caf3182e91 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 @@ class Surface : public pdx::ClientBase<Surface> { 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 @@ class Surface : public pdx::ClientBase<Surface> { 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 Surface : public pdx::ClientBase<Surface> { 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 fea841595a..45aef51baf 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 @@ class DisplayManagerClient : public pdx::ClientBase<DisplayManagerClient> { ~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 f34d61fe49..eff50ba41a 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 @@ struct SurfaceInfo { 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 @@ struct DisplayProtocol { // Op codes. enum { kOpGetMetrics = 0, - kOpGetNamedBuffer, + kOpGetConfigurationData, + kOpSetupGlobalBuffer, + kOpDeleteGlobalBuffer, + kOpGetGlobalBuffer, kOpIsVrAppRunning, kOpCreateSurface, kOpGetSurfaceInfo, @@ -205,14 +216,22 @@ struct DisplayProtocol { // 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 @@ struct DisplayManagerProtocol { enum { kOpGetSurfaceState = 0, kOpGetSurfaceQueue, - kOpSetupNamedBuffer, }; // Aliases. @@ -237,9 +255,6 @@ struct DisplayManagerProtocol { 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 0000000000..20541a69a5 --- /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 0000000000..6ebf487d16 --- /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 fa78b1c136..7fe9825eb7 100644 --- a/libs/vr/libdvr/Android.bp +++ b/libs/vr/libdvr/Android.bp @@ -21,27 +21,32 @@ cc_library_headers { 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 2c95583d20..7d4e2d130f 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 @@ int dvrGetApi(void* api, size_t struct_size, int version) { 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 82469b81bf..4d9b215361 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 @@ int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer, 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 f668510304..018abbb2a7 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; +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" { + +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()) {} -namespace android { -namespace dvr { +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; + } -DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue( - const std::shared_ptr<dvr::ProducerQueue>& producer_queue) { - return new DvrWriteBufferQueue{std::move(producer_queue)}; + 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; } -DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue( - const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) { - return new DvrReadBufferQueue{std::move(consumer_queue)}; +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; } -dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue( - DvrWriteBufferQueue* write_queue) { - return write_queue->producer_queue.get(); +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; } -} // namespace dvr -} // namespace android +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; + } -extern "C" { + width_ = width; + height_ = height; + return 0; +} void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) { - if (write_queue != nullptr && write_queue->native_window != nullptr) - ANativeWindow_release(write_queue->native_window); - 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,74 +179,111 @@ int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, 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 write_queue->GetNativeWindow(out_window); +} + +int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue, + DvrReadBufferQueue** out_read_queue) { + if (!write_queue || !out_read_queue) 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); - } + return write_queue->CreateReadQueue(out_read_queue); +} - *out_window = write_queue->native_window; - return 0; +int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout, + DvrWriteBuffer* write_buffer, + int* out_fence_fd) { + if (!write_queue || !write_buffer || !out_fence_fd) + return -EINVAL; + + return write_queue->Dequeue(timeout, write_buffer, out_fence_fd); } -int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue, - DvrReadBufferQueue** out_read_queue) { - if (!write_queue || !write_queue->producer_queue || !out_read_queue) +int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue, + uint32_t width, uint32_t height) { + if (!write_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) { + return write_queue->ResizeBuffer(width, height); +} + +// ReadBufferQueue + +DvrReadBufferQueue::DvrReadBufferQueue( + const std::shared_ptr<ConsumerQueue>& consumer_queue) + : consumer_queue_(consumer_queue) {} + +int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { + std::unique_ptr<ConsumerQueue> consumer_queue = + consumer_queue_->CreateConsumerQueue(); + if (consumer_queue == nullptr) { ALOGE( - "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue " - "from DvrWriteBufferQueue[%p].", - write_queue); + "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue " + "from producer queue: queue_id=%d.", consumer_queue_->id()); return -ENOMEM; } - *out_read_queue = read_queue.release(); + *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue)); return 0; } -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) { +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( + "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), " + "but actual (%zu).", + consumer_queue_->metadata_size(), meta_size_bytes); return -EINVAL; } size_t slot; - pdx::LocalHandle release_fence; - auto buffer_status = - write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence); + pdx::LocalHandle acquire_fence; + auto buffer_status = consumer_queue_->Dequeue( + timeout, &slot, out_meta, meta_size_bytes, &acquire_fence); if (!buffer_status) { ALOGE_IF(buffer_status.error() != ETIMEDOUT, - "dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s", + "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s", buffer_status.GetErrorMessage().c_str()); return -buffer_status.error(); } - write_buffer->write_buffer = buffer_status.take(); - *out_fence_fd = release_fence.Release(); + read_buffer->read_buffer = buffer_status.take(); + *out_fence_fd = acquire_fence.Release(); + 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; } -// ReadBufferQueue void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) { delete read_queue; } @@ -139,66 +292,69 @@ ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) { if (!read_queue) return -EINVAL; - return read_queue->consumer_queue->capacity(); + return read_queue->capacity(); } int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) { if (!read_queue) return -EINVAL; - return read_queue->consumer_queue->id(); + 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 || !read_queue->consumer_queue || !out_read_queue) + if (!read_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) { - ALOGE( - "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue " - "from DvrReadBufferQueue[%p].", - read_queue); - return -ENOMEM; - } - - *out_read_queue = new_read_queue.release(); - return 0; + 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_queue->consumer_queue || !read_buffer || - !out_fence_fd || !out_meta) { + if (!read_queue || !read_buffer || !out_fence_fd) return -EINVAL; - } - if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) { - ALOGE( - "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), " - "but actual (%zu).", - read_queue->consumer_queue->metadata_size(), meta_size_bytes); + if (meta_size_bytes != 0 && !out_meta) return -EINVAL; - } - size_t slot; - pdx::LocalHandle acquire_fence; - auto buffer_status = read_queue->consumer_queue->Dequeue( - timeout, &slot, out_meta, meta_size_bytes, &acquire_fence); - if (!buffer_status) { - ALOGE_IF(buffer_status.error() != ETIMEDOUT, - "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s", - buffer_status.GetErrorMessage().c_str()); - return -buffer_status.error(); - } + return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta, + meta_size_bytes); +} - read_buffer->read_buffer = buffer_status.take(); - *out_fence_fd = acquire_fence.Release(); +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 0000000000..ffbe7a5836 --- /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 0000000000..df0d54e1a2 --- /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 87636ecd91..852f9a4726 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 @@ int dvrDisplayManagerCreate(DvrDisplayManager** client_out) { 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 @@ int dvrDisplayManagerGetReadBufferQueue(DvrDisplayManager* client, 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 d3ae299cb9..4e87cf6b8f 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 @@ namespace { 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 @@ class HwcCallback : public android::dvr::BnVrComposerCallback { 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 @@ DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, void* data) { 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 @@ DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, void* data) { } 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 89bef09871..28b6c28e9f 100644 --- a/libs/vr/libdvr/dvr_internal.h +++ b/libs/vr/libdvr/dvr_internal.h @@ -10,8 +10,6 @@ extern "C" { 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 @@ namespace dvr { class BufferProducer; class BufferConsumer; -class ConsumerQueue; class IonBuffer; -class ProducerQueue; DvrBuffer* CreateDvrBufferFromIonBuffer( const std::shared_ptr<IonBuffer>& ion_buffer); @@ -32,13 +28,6 @@ DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer( 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 @@ struct DvrBuffer { 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 0000000000..599101fea3 --- /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 67e2ae88ac..a3a47f10f5 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 @@ bool ConvertSurfaceAttributes(const DvrSurfaceAttribute* attributes, 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 dvrSurfaceSetAttributes(DvrSurface* surface, 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,38 +164,114 @@ int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width, 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) { +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; + } + + 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) { + 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("dvrGetNamedBuffer: Failed to create display client!"); + ALOGE("dvrGetNativeDisplayMetrics: 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); + if (metrics == nullptr) { + ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null"); return -EINVAL; } - auto status = client->GetNamedBuffer(name); + auto status = client->GetDisplayMetrics(); + 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()); + + 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; } diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index 8a203e0694..d0dbd8d390 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 struct DvrPoseAsync DvrPoseAsync; 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 DvrWriteBufferQueue DvrWriteBufferQueue; 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 (*DvrDisplayManagerGetSurfaceStatePtr)( 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 const struct native_handle* (*DvrReadBufferGetNativeHandlePtr)( 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 @@ typedef int (*DvrWriteBufferQueueDequeuePtr)(DvrWriteBufferQueue* write_queue, 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 @@ typedef int (*DvrReadBufferQueueDequeuePtr)(DvrReadBufferQueue* read_queue, 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 @@ typedef int (*DvrSurfaceSetAttributesPtr)(DvrSurface* surface, 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 @@ typedef int (*DvrVSyncClientGetSchedInfoPtr)(DvrVSyncClient* client, 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); - -// virtual_touchpad_client.h -typedef DvrVirtualTouchpad* (*DvrVirtualTouchpadCreatePtr)(void); +// 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); + +// 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 @@ typedef int (*DvrVirtualTouchpadTouchPtr)(DvrVirtualTouchpad* client, 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 @@ typedef DvrHwcRecti (*DvrHwcFrameGetLayerDamagedRegionPtr)(DvrHwcFrame* frame, 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 @@ struct DvrApi_v1 { // 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 @@ struct DvrApi_v1 { 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 09568fd9dc..72e0f674f4 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(ReadBufferGetNativeHandle); 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(WriteBufferQueueGetId); 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(ReadBufferQueueGetCapacity); 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(SurfaceDestroy); 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(HwcFrameGetLayerNumVisibleRegions); 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 af55698b74..935a7b2b8a 100644 --- a/libs/vr/libdvr/include/dvr/dvr_buffer.h +++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h @@ -95,6 +95,9 @@ void dvrBufferDestroy(DvrBuffer* buffer); 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 dd669dc30f..e2127f8e31 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 ANativeWindow ANativeWindow; 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 0000000000..3d2c0668da --- /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 0000000000..22a509f6eb --- /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 d5aef8b18b..f910d610f5 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 @@ int dvrDisplayManagerCreate(DvrDisplayManager** client_out); // 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 @@ int dvrSurfaceStateGetSurfaceCount(DvrSurfaceState* surface_state, 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 @@ ssize_t dvrSurfaceStateGetAttributes(DvrSurfaceState* surface_state, __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 index 25364d8590..25364d8590 100644 --- a/libs/vr/libdisplay/include/dvr/dvr_display_types.h +++ b/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 7ee7f9ede7..0ba76e267d 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 @@ typedef int(*DvrHwcOnFrameCallback)(void* client_state, DvrHwcFrame* frame); 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 @@ AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame, // 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 index 36c30f9be5..1d5eda614b 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 @@ enum DvrHwcComposition { 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 0000000000..5df35ad9d9 --- /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 0000000000..b3df0285d7 --- /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 0000000000..63c73855f4 --- /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 361488e671..74a68a16ee 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 dvrSurfaceSetAttributes(DvrSurface* surface, 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 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 dvrGetNamedBuffer(const char* name, DvrBuffer** out_buffer); +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 1eea3d9133..87fdf31b2b 100644 --- a/libs/vr/libdvr/include/dvr/dvr_vsync.h +++ b/libs/vr/libdvr/include/dvr/dvr_vsync.h @@ -8,6 +8,27 @@ __BEGIN_DECLS 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 ef746e207a..ab2ee75a3e 100644 --- a/libs/vr/libdvr/tests/Android.bp +++ b/libs/vr/libdvr/tests/Android.bp @@ -32,6 +32,7 @@ static_libraries = [ "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 474e9684c2..16da1d9e54 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 @@ class DvrBufferQueueTest : public ::testing::Test { } } + void CreateWriteBufferQueue() { + write_queue_ = new DvrWriteBufferQueue( + ProducerQueue::Create(config_builder_.Build(), UsagePolicy{})); + ASSERT_NE(nullptr, write_queue_); + } + 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); - } + 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, TestWrite_QueueGetCapacity) { } 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, TestCreateReadQueueFromWriteQueue) { } 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, TestCreateReadQueueFromReadQueue) { } 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, CreateEmptyBuffer) { } 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 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { 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 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { 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, TestDequeuePostDequeueRelease) { } 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 @@ TEST_F(DvrBufferQueueTest, TestGetExternalSurface) { 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 @@ TEST_F(DvrBufferQueueTest, TestGetExternalSurface) { 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 a2414d65d8..f83b26e86c 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,28 +27,96 @@ namespace dvr { 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_BOOL; - attribute.value.bool_value = value; + attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE; return attribute; } -DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, int32_t value) { +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; attribute.value.bool_value = value; return attribute; } +DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, float value) { + DvrSurfaceAttribute attribute; + attribute.key = key; + 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; +} + Status<UniqueDvrSurface> CreateApplicationSurface(bool visible = false, 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<UniqueDvrSurface> CreateApplicationSurface(bool visible = false, 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 @@ class TestDisplayManager { 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 @@ class TestDisplayManager { 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,22 +542,220 @@ TEST_F(DvrDisplayManagerTest, SurfaceAttributeEvent) { 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) { // Create an application surface. auto surface_status = CreateApplicationSurface(); @@ -480,13 +769,14 @@ TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) { 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 @@ TEST_F(DvrDisplayManagerTest, MultiLayerBufferQueue) { 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 @@ TEST_F(DvrDisplayManagerTest, MultiLayerBufferQueue) { 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 e65f6d5b01..c21deb0d0e 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 dvr { 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 @@ TEST_F(DvrNamedBufferTest, TestNamedBuffersSameName) { 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 @@ TEST_F(DvrNamedBufferTest, TestNamedBuffersSameName) { 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 @@ TEST_F(DvrNamedBufferTest, TestNamedBufferUsage) { 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 @@ TEST_F(DvrNamedBufferTest, TestNamedBufferUsage) { 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 527cdbdd2a..62aeb7996c 100644 --- a/libs/vr/libdvrcommon/Android.bp +++ b/libs/vr/libdvrcommon/Android.bp @@ -28,7 +28,7 @@ sharedLibraries = [ "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 cb44a51b8d..80b17694ce 100644 --- a/libs/vr/libpdx/private/pdx/rpc/variant.h +++ b/libs/vr/libpdx/private/pdx/rpc/variant.h @@ -26,14 +26,35 @@ using TypeForIndex = std::tuple_element_t<I, std::tuple<Types...>>; 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 @@ template <typename... Types> 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 @@ union Union<Type> { : 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 @@ union Union<First, Rest...> { 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 @@ union Union<First, Rest...> { } // 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 @@ class Variant { 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 @@ class Variant { 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 @@ class Variant { // 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 @@ class Variant { 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 @@ class Variant { 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 305c3b87a4..08fcaea575 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 @@ class ByteBuffer { 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 @@ class ByteBuffer { 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 325f33f3c5..e3520f5fe9 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 @@ TEST(Variant, CopyMoveConstructAssign) { 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 @@ TEST(Variant, Swap) { 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 @@ TEST(Variant, Swap) { 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 @@ TEST(Variant, HasType) { 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 ac4dea993b..ebe7cea7e3 100644 --- a/libs/vr/libpdx_uds/channel_event_set.cpp +++ b/libs/vr/libpdx_uds/channel_event_set.cpp @@ -100,6 +100,9 @@ Status<int> ChannelEventReceiver::GetPendingEvents() const { 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 2216e3869a..9d617cbaba 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 a61c6b2773..3bd90dc1f3 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 @@ namespace dvr { 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 73bdaa7d5c..d57bbe8361 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 @@ struct PerformanceRPC { 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 2124162bf7..bf3726e346 100644 --- a/libs/vr/libperformance/performance_client.cpp +++ b/libs/vr/libperformance/performance_client.cpp @@ -37,6 +37,26 @@ int PerformanceClient::SetCpuPartition(pid_t task_id, const char* partition) { 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 @@ extern "C" int dvrSetCpuPartition(pid_t task_id, const char* partition) { 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 de26a74f48..0fb2d84026 100644 --- a/libs/vr/libvrflinger/Android.bp +++ b/libs/vr/libvrflinger/Android.bp @@ -34,8 +34,10 @@ staticLibraries = [ "libdvrcommon", "libperformance", "libvrsensor", + "libbroadcastring", "libpdx_default_transport", "libvr_manager", + "libbroadcastring", ] sharedLibraries = [ @@ -61,6 +63,10 @@ sharedLibraries = [ "libfmq", ] +headerLibraries = [ + "libdvr_headers" +] + cc_library_static { srcs: sourceFiles, export_include_dirs: includeFiles, @@ -74,5 +80,6 @@ cc_library_static { ], 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 7932a9c9d3..fda9585dc4 100644 --- a/libs/vr/libvrflinger/acquired_buffer.cpp +++ b/libs/vr/libvrflinger/acquired_buffer.cpp @@ -55,9 +55,9 @@ bool AcquiredBuffer::IsAvailable() const { 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 @@ std::shared_ptr<BufferConsumer> AcquiredBuffer::ClaimBuffer() { } 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 dd4fcc5e73..e0dc9f2ac2 100644 --- a/libs/vr/libvrflinger/acquired_buffer.h +++ b/libs/vr/libvrflinger/acquired_buffer.h @@ -67,13 +67,13 @@ class AcquiredBuffer { 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 a0b3efea7e..40396b90c5 100644 --- a/libs/vr/libvrflinger/display_manager_service.cpp +++ b/libs/vr/libvrflinger/display_manager_service.cpp @@ -78,11 +78,6 @@ pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) { *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 @@ pdx::Status<pdx::LocalChannelHandle> DisplayManagerService::OnGetSurfaceQueue( 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 0857eb5298..3133fe1884 100644 --- a/libs/vr/libvrflinger/display_manager_service.h +++ b/libs/vr/libvrflinger/display_manager_service.h @@ -56,9 +56,6 @@ class DisplayManagerService : public pdx::ServiceBase<DisplayManagerService> { 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 47efa7653d..733edc659c 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::Status; 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 @@ bool DisplayService::IsInitialized() const { } 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 @@ void DisplayService::OnChannelClose(pdx::Message& message, surface->OnSetAttributes(message, {{display::SurfaceAttribute::Visible, display::SurfaceAttributeValue{false}}}); - SurfaceUpdated(surface->surface_type(), - display::SurfaceUpdateFlags::VisibilityChanged); } } @@ -60,14 +132,29 @@ Status<void> DisplayService::HandleMessage(pdx::Message& message) { *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 @@ Status<display::Metrics> DisplayService::OnGetMetrics( {}}}; } +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 @@ void DisplayService::SurfaceUpdated(SurfaceType surface_type, } } -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 @@ void DisplayService::UpdateActiveDisplaySurfaces() { 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 bb4eeef1c6..6efe264b09 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 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { // 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 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { 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 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { 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 fb2751b77d..0d6a732a8e 100644 --- a/libs/vr/libvrflinger/display_surface.cpp +++ b/libs/vr/libvrflinger/display_surface.cpp @@ -68,7 +68,7 @@ Status<void> DisplaySurface::OnSetAttributes( 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 @@ Status<void> DisplaySurface::OnSetAttributes( 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::SurfaceUpdated(display::SurfaceUpdateFlags update_flags) { } 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 @@ std::shared_ptr<ConsumerQueue> ApplicationDisplaySurface::GetQueue( "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::shared_ptr<ConsumerQueue> ApplicationDisplaySurface::GetQueue( } 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 @@ std::vector<int32_t> ApplicationDisplaySurface::GetQueueIds() const { } 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 @@ void ApplicationDisplaySurface::OnQueueEvent( "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 @@ void ApplicationDisplaySurface::OnQueueEvent( } } +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 @@ void DirectDisplaySurface::OnQueueEvent( 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 @@ void DirectDisplaySurface::DequeueBuffersLocked() { 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 DirectDisplaySurface::AcquireCurrentBuffer() { } 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 @@ AcquiredBuffer DirectDisplaySurface::AcquireNewestAvailableBuffer( 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 c456b1050f..5cbee57bf9 100644 --- a/libs/vr/libvrflinger/display_surface.h +++ b/libs/vr/libvrflinger/display_surface.h @@ -66,7 +66,7 @@ class DisplaySurface : public pdx::Channel { } 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 @@ class ApplicationDisplaySurface : public DisplaySurface { 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 @@ class DirectDisplaySurface : public DisplaySurface { : 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 @@ class DirectDisplaySurface : public DisplaySurface { 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 06b69bbc26..962c7459fd 100644 --- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp +++ b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp @@ -101,12 +101,12 @@ void EpollEventDispatcher::EventThread() { 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 34474d969a..def9b7da33 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 dvr { 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::UpdatePostThreadState(PostThreadStateType state, void HardwareComposer::OnPostThreadResumed() { hwc2_hidl_->resetCommands(); - // Connect to pose service. - pose_client_ = dvrPoseCreate(); - ALOGE_IF(!pose_client_, "HardwareComposer: Failed to create pose client"); - // HIDL HWC seems to have an internal race condition. If we submit a frame too // soon after turning on VSync we don't get any VSync signals. Give poor HWC // implementations a chance to enable VSync before we continue. @@ -253,11 +240,6 @@ void HardwareComposer::OnPostThreadPaused() { } active_layer_count_ = 0; - if (pose_client_) { - dvrPoseDestroy(pose_client_); - pose_client_ = nullptr; - } - EnableVsync(false); hwc2_hidl_->resetCommands(); @@ -367,7 +349,36 @@ HWC::Error HardwareComposer::GetDisplayMetrics( return HWC::Error::None; } -std::string HardwareComposer::Dump() { return hwc2_hidl_->dumpDebugInfo(); } +std::string HardwareComposer::Dump() { + std::unique_lock<std::mutex> lock(post_thread_mutex_); + std::ostringstream stream; + + stream << "Display metrics: " << display_metrics_.width << "x" + << display_metrics_.height << " " << (display_metrics_.dpi.x / 1000.0) + << "x" << (display_metrics_.dpi.y / 1000.0) << " dpi @ " + << (1000000000.0 / display_metrics_.vsync_period_ns) << " Hz" + << std::endl; + + stream << "Post thread resumed: " << post_thread_resumed_ << std::endl; + stream << "Active layers: " << active_layer_count_ << std::endl; + stream << std::endl; + + for (size_t i = 0; i < active_layer_count_; i++) { + stream << "Layer " << i << ":"; + stream << " type=" << layers_[i].GetCompositionType().to_string(); + stream << " surface_id=" << layers_[i].GetSurfaceId(); + stream << " buffer_id=" << layers_[i].GetBufferId(); + stream << std::endl; + } + stream << std::endl; + + if (post_thread_resumed_) { + stream << "Hardware Composer Debug Info:" << std::endl; + stream << hwc2_hidl_->dumpDebugInfo(); + } + + return stream.str(); +} void HardwareComposer::PostLayers() { ATRACE_NAME("HardwareComposer::PostLayers"); @@ -397,8 +408,8 @@ void HardwareComposer::PostLayers() { } const bool is_frame_pending = IsFramePendingInDriver(); - const bool is_fence_pending = - retire_fence_fds_.size() > kAllowedPendingFenceCount; + const bool is_fence_pending = retire_fence_fds_.size() > + post_thread_config_.allowed_pending_fence_count; if (is_fence_pending || is_frame_pending) { ATRACE_INT("frame_skip_count", ++frame_skip_count_); @@ -418,10 +429,12 @@ void HardwareComposer::PostLayers() { ATRACE_INT("frame_skip_count", 0); } -#if TRACE - for (size_t i = 0; i < active_layer_count_; i++) - ALOGI("HardwareComposer::PostLayers: layer=%zu composition=%s", i, +#if TRACE > 1 + for (size_t i = 0; i < active_layer_count_; i++) { + ALOGI("HardwareComposer::PostLayers: layer=%zu buffer_id=%d composition=%s", + i, layers_[i].GetBufferId(), layers_[i].GetCompositionType().to_string().c_str()); + } #endif error = Present(HWC_DISPLAY_PRIMARY); @@ -460,19 +473,76 @@ void HardwareComposer::SetDisplaySurfaces( pending_surfaces_ = std::move(surfaces); } + if (request_display_callback_) + request_display_callback_(!display_idle); + // Set idle state based on whether there are any surfaces to handle. UpdatePostThreadState(PostThreadState::Idle, display_idle); +} - // XXX: TEMPORARY - // Request control of the display based on whether there are any surfaces to - // handle. This callback sets the post thread active state once the transition - // is complete in SurfaceFlinger. - // TODO(eieio): Unify the control signal used to move SurfaceFlinger into VR - // mode. Currently this is hooked up to persistent VR mode, but perhaps this - // makes more sense to control it from VrCore, which could in turn base its - // decision on persistent VR mode. - if (request_display_callback_) - request_display_callback_(!display_idle); +int HardwareComposer::OnNewGlobalBuffer(DvrGlobalBufferKey key, + IonBuffer& ion_buffer) { + if (key == DvrGlobalBuffers::kVsyncBuffer) { + vsync_ring_ = std::make_unique<CPUMappedBroadcastRing<DvrVsyncRing>>( + &ion_buffer, CPUUsageMode::WRITE_OFTEN); + + if (vsync_ring_->IsMapped() == false) { + return -EPERM; + } + } + + if (key == DvrGlobalBuffers::kVrFlingerConfigBufferKey) { + return MapConfigBuffer(ion_buffer); + } + + return 0; +} + +void HardwareComposer::OnDeletedGlobalBuffer(DvrGlobalBufferKey key) { + if (key == DvrGlobalBuffers::kVrFlingerConfigBufferKey) { + ConfigBufferDeleted(); + } +} + +int HardwareComposer::MapConfigBuffer(IonBuffer& ion_buffer) { + std::lock_guard<std::mutex> lock(shared_config_mutex_); + shared_config_ring_ = DvrConfigRing(); + + if (ion_buffer.width() < DvrConfigRing::MemorySize()) { + ALOGE("HardwareComposer::MapConfigBuffer: invalid buffer size."); + return -EINVAL; + } + + void* buffer_base = 0; + int result = ion_buffer.Lock(ion_buffer.usage(), 0, 0, ion_buffer.width(), + ion_buffer.height(), &buffer_base); + if (result != 0) { + ALOGE( + "HardwareComposer::MapConfigBuffer: Failed to map vrflinger config " + "buffer."); + return -EPERM; + } + + shared_config_ring_ = DvrConfigRing::Create(buffer_base, ion_buffer.width()); + ion_buffer.Unlock(); + + return 0; +} + +void HardwareComposer::ConfigBufferDeleted() { + std::lock_guard<std::mutex> lock(shared_config_mutex_); + shared_config_ring_ = DvrConfigRing(); +} + +void HardwareComposer::UpdateConfigBuffer() { + std::lock_guard<std::mutex> lock(shared_config_mutex_); + if (!shared_config_ring_.is_valid()) + return; + // Copy from latest record in shared_config_ring_ to local copy. + DvrConfig record; + if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) { + post_thread_config_ = record; + } } int HardwareComposer::PostThreadPollInterruptible( @@ -744,12 +814,16 @@ void HardwareComposer::PostThread() { while (1) { ATRACE_NAME("HardwareComposer::PostThread"); + // Check for updated config once per vsync. + UpdateConfigBuffer(); + while (post_thread_quiescent_) { std::unique_lock<std::mutex> lock(post_thread_mutex_); ALOGI("HardwareComposer::PostThread: Entering quiescent state."); - // Tear down resources. - OnPostThreadPaused(); + // Tear down resources if necessary. + if (was_running) + OnPostThreadPaused(); was_running = false; post_thread_resumed_ = false; @@ -801,16 +875,20 @@ void HardwareComposer::PostThread() { ++vsync_count_; - if (pose_client_) { - // Signal the pose service with vsync info. - // Display timestamp is in the middle of scanout. - privateDvrPoseNotifyVsync(pose_client_, vsync_count_, - vsync_timestamp + photon_offset_ns, - ns_per_frame, right_eye_photon_offset_ns); - } - const bool layer_config_changed = UpdateLayerConfig(); + // Publish the vsync event. + if (vsync_ring_) { + DvrVsync vsync; + vsync.vsync_count = vsync_count_; + vsync.vsync_timestamp_ns = vsync_timestamp; + vsync.vsync_left_eye_offset_ns = photon_offset_ns; + vsync.vsync_right_eye_offset_ns = right_eye_photon_offset_ns; + vsync.vsync_period_ns = ns_per_frame; + + vsync_ring_->Publish(vsync); + } + // Signal all of the vsync clients. Because absolute time is used for the // wakeup time below, this can take a little time if necessary. if (vsync_callback_) @@ -823,9 +901,10 @@ void HardwareComposer::PostThread() { const int64_t display_time_est_ns = vsync_timestamp + ns_per_frame; const int64_t now_ns = GetSystemClockNs(); - const int64_t sleep_time_ns = - display_time_est_ns - now_ns - kFramePostOffsetNs; - const int64_t wakeup_time_ns = display_time_est_ns - kFramePostOffsetNs; + const int64_t sleep_time_ns = display_time_est_ns - now_ns - + post_thread_config_.frame_post_offset_ns; + const int64_t wakeup_time_ns = + display_time_est_ns - post_thread_config_.frame_post_offset_ns; ATRACE_INT64("sleep_time_ns", sleep_time_ns); if (sleep_time_ns > 0) { diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index 8ba72ab773..a0c50e14d8 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -5,6 +5,7 @@ #include "DisplayHardware/ComposerHal.h" #include "hwc_types.h" +#include <dvr/dvr_shared_buffers.h> #include <hardware/gralloc.h> #include <log/log.h> @@ -16,10 +17,12 @@ #include <tuple> #include <vector> -#include <dvr/pose_client.h> +#include <dvr/dvr_config.h> +#include <dvr/dvr_vsync.h> #include <pdx/file_handle.h> #include <pdx/rpc/variant.h> #include <private/dvr/buffer_hub_client.h> +#include <private/dvr/shared_buffer_helpers.h> #include "acquired_buffer.h" #include "display_surface.h" @@ -124,11 +127,20 @@ class Layer { int surface_id = -1; pdx::rpc::IfAnyOf<SourceSurface>::Call( &source_, [&surface_id](const SourceSurface& surface_source) { - surface_id = surface_source.surface->surface_id(); + surface_id = surface_source.GetSurfaceId(); }); return surface_id; } + int GetBufferId() const { + int buffer_id = -1; + pdx::rpc::IfAnyOf<SourceSurface>::Call( + &source_, [&buffer_id](const SourceSurface& surface_source) { + buffer_id = surface_source.GetBufferId(); + }); + return buffer_id; + } + private: void CommonLayerSetup(); @@ -189,7 +201,15 @@ class Layer { } // Returns the surface id of the surface. - int GetSurfaceId() { return surface->surface_id(); } + int GetSurfaceId() const { return surface->surface_id(); } + + // Returns the buffer id for the current buffer. + int GetBufferId() const { + if (acquired_buffer.IsAvailable()) + return acquired_buffer.buffer()->id(); + else + return -1; + } }; // State when the layer is connected to a buffer. Provides the same interface @@ -210,6 +230,7 @@ class Layer { IonBuffer* GetBuffer() { return buffer.get(); } int GetSurfaceId() const { return -1; } + int GetBufferId() const { return -1; } }; // The underlying hardware composer layer is supplied buffers either from a @@ -284,6 +305,9 @@ class HardwareComposer { void SetDisplaySurfaces( std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces); + int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer); + void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); + void OnHardwareComposerRefresh(); private: @@ -365,6 +389,13 @@ class HardwareComposer { // Called on the post thread when the post thread is paused or quits. void OnPostThreadPaused(); + // Map the given shared memory buffer to our broadcast ring to track updates + // to the config parameters. + int MapConfigBuffer(IonBuffer& ion_buffer); + void ConfigBufferDeleted(); + // Poll for config udpates. + void UpdateConfigBuffer(); + bool initialized_; // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own @@ -435,9 +466,15 @@ class HardwareComposer { // us to detect when the display driver begins queuing frames. std::vector<pdx::LocalHandle> retire_fence_fds_; - // Pose client for frame count notifications. Pose client predicts poses - // out to display frame boundaries, so we need to tell it about vsyncs. - DvrPose* pose_client_ = nullptr; + // If we are publishing vsync data, we will put it here. + std::unique_ptr<CPUMappedBroadcastRing<DvrVsyncRing>> vsync_ring_; + + // Broadcast ring for receiving config data from the DisplayManager. + DvrConfigRing shared_config_ring_; + uint32_t shared_config_ring_sequence_{0}; + // Config buffer for reading from the post thread. + DvrConfig post_thread_config_; + std::mutex shared_config_mutex_; static constexpr int kPostThreadInterrupted = 1; diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h index 145852e949..f41da87596 100644 --- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h +++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h @@ -32,6 +32,9 @@ class VrFlinger { // Called on a binder thread. void OnHardwareComposerRefresh(); + // dump all vr flinger state. + std::string Dump(); + private: VrFlinger(); bool Init(Hwc2::Composer* hidl, diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp index b2dc1d86e8..3a0ca4a417 100644 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ b/libs/vr/libvrflinger/vr_flinger.cpp @@ -139,6 +139,11 @@ void VrFlinger::OnHardwareComposerRefresh() { display_service_->OnHardwareComposerRefresh(); } +std::string VrFlinger::Dump() { + // TODO(karthikrs): Add more state information here. + return display_service_->DumpState(0/*unused*/); +} + void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged( bool enabled) { ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off"); @@ -146,6 +151,5 @@ void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged( // Persistent VR mode is not enough. // request_display_callback_(enabled); } - } // namespace dvr } // namespace android diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp index 2a83933470..3098b43318 100644 --- a/libs/vr/libvrflinger/vsync_service.cpp +++ b/libs/vr/libvrflinger/vsync_service.cpp @@ -200,12 +200,12 @@ pdx::Status<int64_t> VSyncWaiter::OnWait(pdx::Message& /*message*/) { } void VSyncChannel::Ack() { - ALOGD_IF(TRACE, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_); + ALOGD_IF(TRACE > 1, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_); service_.ModifyChannelEvents(cid_, POLLPRI, 0); } void VSyncChannel::Signal() { - ALOGD_IF(TRACE, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_); + ALOGD_IF(TRACE > 1, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_); service_.ModifyChannelEvents(cid_, 0, POLLPRI); } diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp index abad78b338..d022adf4f8 100644 --- a/libs/vr/libvrsensor/Android.bp +++ b/libs/vr/libvrsensor/Android.bp @@ -23,9 +23,11 @@ includeFiles = [ ] staticLibraries = [ + "libdisplay", "libbufferhub", "libbufferhubqueue", "libdvrcommon", + "libbroadcastring", "libpdx_default_transport", ] @@ -43,6 +45,7 @@ cc_library { export_include_dirs: includeFiles, static_libs: staticLibraries, shared_libs: sharedLibraries, + header_libs: ["libdvr_headers"], name: "libvrsensor", } diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h index ed75f84216..d684ddcc57 100644 --- a/libs/vr/libvrsensor/include/dvr/pose_client.h +++ b/libs/vr/libvrsensor/include/dvr/pose_client.h @@ -14,63 +14,13 @@ typedef struct float32x4x4_t { float32x4_t val[4]; }; #include <stdbool.h> #include <stdint.h> +#include <dvr/dvr_pose.h> + #ifdef __cplusplus extern "C" { #endif -typedef struct DvrPose DvrPose; - -// Represents the current state provided by the pose service, containing a -// rotation and translation. -typedef struct __attribute__((packed, aligned(8))) DvrPoseState { - // A quaternion representing the rotation of the HMD in Start Space. - struct __attribute__((packed)) { - float x, y, z, w; - } head_from_start_rotation; - // The position of the HMD in Start Space. - struct __attribute__((packed)) { - float x, y, z; - } head_from_start_translation; - // Time in nanoseconds for the current pose. - uint64_t timestamp_ns; - // The rotational velocity of the HMD. - struct __attribute__((packed)) { - float x, y, z; - } sensor_from_start_rotation_velocity; -} DvrPoseState; - -enum { - DVR_POSE_FLAG_VALID = (1UL << 0), // This pose is valid. - DVR_POSE_FLAG_HEAD = (1UL << 1), // This pose is the head. - DVR_POSE_FLAG_CONTROLLER = (1UL << 2), // This pose is a controller. -}; - -// Represents an estimated pose, accessed asynchronously through a shared ring -// buffer. No assumptions should be made about the data in padding space. -// The size of this struct is 128 bytes. -typedef struct __attribute__((packed, aligned(16))) DvrPoseAsync { - // Left eye head-from-start orientation quaternion x,y,z,w. - float32x4_t orientation; - // Left eye head-from-start translation x,y,z,pad in meters. - float32x4_t translation; - // Right eye head-from-start orientation quaternion x,y,z,w. - float32x4_t right_orientation; - // Right eye head-from-start translation x,y,z,pad in meters. - float32x4_t right_translation; - // Start-space angular velocity x,y,z,pad in radians per second. - float32x4_t angular_velocity; - // Start-space positional velocity x,y,z,pad in meters per second. - float32x4_t velocity; - // Timestamp of when this pose is predicted for, typically halfway through - // scanout. - int64_t timestamp_ns; - // Bitmask of DVR_POSE_FLAG_* constants that apply to this pose. - // - // If DVR_POSE_FLAG_VALID is not set, the pose is indeterminate. - uint64_t flags; - // Reserved padding to 128 bytes. - uint8_t pad[16]; -} DvrPoseAsync; +typedef struct DvrPoseClient DvrPoseClient; // Returned by the async pose ring buffer access API. typedef struct DvrPoseRingBufferInfo { @@ -105,6 +55,8 @@ typedef enum DvrPoseMode { DVR_POSE_MODE_MOCK_ROTATE_MEDIUM, DVR_POSE_MODE_MOCK_ROTATE_FAST, DVR_POSE_MODE_MOCK_CIRCLE_STRAFE, + DVR_POSE_MODE_FLOAT, + DVR_POSE_MODE_MOCK_MOTION_SICKNESS, // Always last. DVR_POSE_MODE_COUNT, @@ -118,12 +70,12 @@ typedef enum DvrControllerId { // Creates a new pose client. // // @return Pointer to the created pose client, nullptr on failure. -DvrPose* dvrPoseCreate(); +DvrPoseClient* dvrPoseClientCreate(); // Destroys a pose client. // // @param client Pointer to the pose client to be destroyed. -void dvrPoseDestroy(DvrPose* client); +void dvrPoseClientDestroy(DvrPoseClient* client); // Gets the pose for the given vsync count. // @@ -132,10 +84,11 @@ void dvrPoseDestroy(DvrPose* client); // Typically this is the count returned by dvrGetNextVsyncCount. // @param out_pose Struct to store pose state. // @return Zero on success, negative error code on failure. -int dvrPoseGet(DvrPose* client, uint32_t vsync_count, DvrPoseAsync* out_pose); +int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count, + DvrPoseAsync* out_pose); // Gets the current vsync count. -uint32_t dvrPoseGetVsyncCount(DvrPose* client); +uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client); // Gets the pose for the given controller at the given vsync count. // @@ -145,15 +98,15 @@ uint32_t dvrPoseGetVsyncCount(DvrPose* client); // Typically this is the count returned by dvrGetNextVsyncCount. // @param out_pose Struct to store pose state. // @return Zero on success, negative error code on failure. -int dvrPoseGetController(DvrPose* client, int32_t controller_id, - uint32_t vsync_count, DvrPoseAsync* out_pose); +int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id, + uint32_t vsync_count, DvrPoseAsync* out_pose); // Enables/disables logging for the controller fusion. // // @param client Pointer to the pose client. // @param enable True starts logging, False stops. // @return Zero on success, negative error code on failure. -int dvrPoseLogController(DvrPose* client, bool enable); +int dvrPoseClientLogController(DvrPoseClient* client, bool enable); // DEPRECATED // Polls current pose state. @@ -161,30 +114,30 @@ int dvrPoseLogController(DvrPose* client, bool enable); // @param client Pointer to the pose client. // @param state Struct to store polled state. // @return Zero on success, negative error code on failure. -int dvrPosePoll(DvrPose* client, DvrPoseState* state); +int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state); // Freezes the pose to the provided state. // // Future poll operations will return this state until a different state is -// frozen or dvrPoseSetMode() is called with a different mode. The timestamp is +// frozen or dvrPoseClientModeSet() is called with a different mode. The timestamp is // not frozen. // // @param client Pointer to the pose client. // @param frozen_state State pose to be frozen to. // @return Zero on success, negative error code on failure. -int dvrPoseFreeze(DvrPose* client, const DvrPoseState* frozen_state); +int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state); // Sets the pose service mode. // // @param mode The requested pose mode. // @return Zero on success, negative error code on failure. -int dvrPoseSetMode(DvrPose* client, DvrPoseMode mode); +int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode); // Gets the pose service mode. // // @param mode Return value for the current pose mode. // @return Zero on success, negative error code on failure. -int dvrPoseGetMode(DvrPose* client, DvrPoseMode* mode); +int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode); // Get access to the shared memory pose ring buffer. // A future pose at vsync <current> + <offset> is accessed at index: @@ -195,8 +148,14 @@ int dvrPoseGetMode(DvrPose* client, DvrPoseMode* mode); // |out_fd| will be set to the gralloc buffer file descriptor, which is // required for binding this buffer for GPU use. // Returns 0 on success. -int dvrPoseGetRingBuffer(DvrPose* client, DvrPoseRingBufferInfo* out_info); +int dvrPoseClientGetRingBuffer(DvrPoseClient* client, + DvrPoseRingBufferInfo* out_info); +// Sets enabled state for sensors pose processing. +// +// @param enabled Whether sensors are enabled or disabled. +// @return Zero on success +int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled); #ifdef __cplusplus } // extern "C" diff --git a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h index 0616d46106..e4455f1840 100644 --- a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h +++ b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h @@ -11,14 +11,12 @@ extern "C" { #define DVR_POSE_SERVICE_CLIENT (DVR_POSE_SERVICE_BASE "/client") enum { - DVR_POSE_POLL = 0, - DVR_POSE_FREEZE, + DVR_POSE_FREEZE = 0, DVR_POSE_SET_MODE, - DVR_POSE_GET_RING_BUFFER, - DVR_POSE_NOTIFY_VSYNC, DVR_POSE_GET_MODE, DVR_POSE_GET_CONTROLLER_RING_BUFFER, DVR_POSE_LOG_CONTROLLER, + DVR_POSE_SENSORS_ENABLE, }; #ifdef __cplusplus diff --git a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h deleted file mode 100644 index 66c4c7c49d..0000000000 --- a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef ANDROID_DVR_POSE_CLIENT_INTERNAL_H_ -#define ANDROID_DVR_POSE_CLIENT_INTERNAL_H_ - -#include <stdint.h> - -#include <dvr/pose_client.h> -#include <pdx/file_handle.h> -#include <private/dvr/sensor_constants.h> - -#ifdef __cplusplus -extern "C" { -#endif - -// Sensord head pose ring buffer. -typedef struct __attribute__((packed, aligned(16))) DvrPoseRingBuffer { - // Ring buffer always at the beginning of the structure, as consumers may - // not have access to this parent structure definition. - DvrPoseAsync ring[kPoseAsyncBufferTotalCount]; - // Current vsync_count (where sensord is writing poses from). - uint32_t vsync_count; -} DvrPoseMetadata; - -// Called by displayd to give vsync count info to the pose service. -// |display_timestamp| Display timestamp is in the middle of scanout. -// |display_period_ns| Nanos between vsyncs. -// |right_eye_photon_offset_ns| Nanos to shift the prediction timestamp for -// the right eye head pose (relative to the left eye prediction). -int privateDvrPoseNotifyVsync(DvrPose* client, uint32_t vsync_count, - int64_t display_timestamp, - int64_t display_period_ns, - int64_t right_eye_photon_offset_ns); - -// Get file descriptor for access to the shared memory pose buffer. This can be -// used with GL extensions that support shared memory buffer objects. The caller -// takes ownership of the returned fd and must close it or pass on ownership. -int privateDvrPoseGetRingBufferFd(DvrPose* client, - android::pdx::LocalHandle* fd); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // ANDROID_DVR_POSE_CLIENT_INTERNAL_H_ diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor_constants.h b/libs/vr/libvrsensor/include/private/dvr/sensor_constants.h deleted file mode 100644 index 8fa87b39a0..0000000000 --- a/libs/vr/libvrsensor/include/private/dvr/sensor_constants.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef ANDROID_DVR_SENSOR_CONSTANTS_H_ -#define ANDROID_DVR_SENSOR_CONSTANTS_H_ - -namespace android { -namespace dvr { - -// Number of elements in the async pose buffer. -// Must be power of two. -// Macro so that shader code can easily include this value. -#define kPoseAsyncBufferTotalCount 8 - -// Mask for accessing the current ring buffer array element: -// index = vsync_count & kPoseAsyncBufferIndexMask -constexpr uint32_t kPoseAsyncBufferIndexMask = kPoseAsyncBufferTotalCount - 1; - -// Number of pose frames including the current frame that are kept updated with -// pose forecast data. The other poses are left their last known estimates. -constexpr uint32_t kPoseAsyncBufferMinFutureCount = 4; - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_SENSOR_CONSTANTS_H_ diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp index 9eae3aab86..4ddf1f33cb 100644 --- a/libs/vr/libvrsensor/pose_client.cpp +++ b/libs/vr/libvrsensor/pose_client.cpp @@ -1,4 +1,5 @@ #define LOG_TAG "PoseClient" +#include <dvr/dvr_shared_buffers.h> #include <dvr/pose_client.h> #include <stdint.h> @@ -8,9 +9,9 @@ #include <pdx/default_transport/client_channel_factory.h> #include <pdx/file_handle.h> #include <private/dvr/buffer_hub_client.h> +#include <private/dvr/display_client.h> #include <private/dvr/pose-ipc.h> -#include <private/dvr/pose_client_internal.h> -#include <private/dvr/sensor_constants.h> +#include <private/dvr/shared_buffer_helpers.h> using android::pdx::LocalHandle; using android::pdx::LocalChannelHandle; @@ -21,6 +22,11 @@ using android::pdx::Transaction; namespace android { namespace dvr { +namespace { + +typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing; + +} // namespace // PoseClient is a remote interface to the pose service in sensord. class PoseClient : public pdx::ClientBase<PoseClient> { @@ -28,39 +34,49 @@ class PoseClient : public pdx::ClientBase<PoseClient> { ~PoseClient() override {} // Casts C handle into an instance of this class. - static PoseClient* FromC(DvrPose* client) { + static PoseClient* FromC(DvrPoseClient* client) { return reinterpret_cast<PoseClient*>(client); } // Polls the pose service for the current state and stores it in *state. // Returns zero on success, a negative error code otherwise. - int Poll(DvrPoseState* state) { - Transaction trans{*this}; - Status<int> status = - trans.Send<int>(DVR_POSE_POLL, nullptr, 0, state, sizeof(*state)); - ALOGE_IF(!status, "Pose poll() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); + int Poll(DvrPose* state) { + // Allocate the helper class to access the sensor pose buffer. + if (sensor_pose_buffer_ == nullptr) { + sensor_pose_buffer_ = std::make_unique<SensorPoseRing>( + DvrGlobalBuffers::kSensorPoseBuffer, CPUUsageMode::READ_RARELY); + } + + if (state) { + if (sensor_pose_buffer_->GetNewest(state)) { + return 0; + } else { + return -EAGAIN; + } + } + + return -EINVAL; } int GetPose(uint32_t vsync_count, DvrPoseAsync* out_pose) { - if (!mapped_pose_buffer_) { - int ret = GetRingBuffer(nullptr); - if (ret < 0) - return ret; + const auto vsync_buffer = GetVsyncBuffer(); + if (vsync_buffer) { + *out_pose = + vsync_buffer + ->vsync_poses[vsync_count & DvrVsyncPoseBuffer::kIndexMask]; + return 0; + } else { + return -EAGAIN; } - *out_pose = - mapped_pose_buffer_->ring[vsync_count & kPoseAsyncBufferIndexMask]; - return 0; } uint32_t GetVsyncCount() { - if (!mapped_pose_buffer_) { - int ret = GetRingBuffer(nullptr); - if (ret < 0) - return 0; + const auto vsync_buffer = GetVsyncBuffer(); + if (vsync_buffer) { + return vsync_buffer->vsync_count; } - return mapped_pose_buffer_->vsync_count; + + return 0; } int GetControllerPose(int32_t controller_id, uint32_t vsync_count, @@ -75,7 +91,7 @@ class PoseClient : public pdx::ClientBase<PoseClient> { } *out_pose = controllers_[controller_id] - .mapped_pose_buffer[vsync_count & kPoseAsyncBufferIndexMask]; + .mapped_pose_buffer[vsync_count & DvrVsyncPoseBuffer::kIndexMask]; return 0; } @@ -92,7 +108,7 @@ class PoseClient : public pdx::ClientBase<PoseClient> { // this state until a different state is frozen or SetMode() is called with a // different mode. // Returns zero on success, a negative error code otherwise. - int Freeze(const DvrPoseState& frozen_state) { + int Freeze(const DvrPose& frozen_state) { Transaction trans{*this}; Status<int> status = trans.Send<int>(DVR_POSE_FREEZE, &frozen_state, sizeof(frozen_state), nullptr, 0); @@ -124,48 +140,29 @@ class PoseClient : public pdx::ClientBase<PoseClient> { return ReturnStatusOrError(status); } + // Enables or disables all pose processing from sensors + int EnableSensors(bool enabled) { + Transaction trans{*this}; + Status<int> status = trans.Send<int>(DVR_POSE_SENSORS_ENABLE, &enabled, + sizeof(enabled), nullptr, 0); + ALOGE_IF(!status, "Pose EnableSensors() failed because: %s\n", + status.GetErrorMessage().c_str()); + return ReturnStatusOrError(status); + } + int GetRingBuffer(DvrPoseRingBufferInfo* out_info) { - if (pose_buffer_.get()) { + // First time mapping the buffer? + const auto vsync_buffer = GetVsyncBuffer(); + if (vsync_buffer) { if (out_info) { - GetPoseRingBufferInfo(out_info); + out_info->min_future_count = DvrVsyncPoseBuffer::kMinFutureCount; + out_info->total_count = DvrVsyncPoseBuffer::kSize; + out_info->buffer = vsync_buffer->vsync_poses; } - return 0; - } - - Transaction trans{*this}; - Status<LocalChannelHandle> status = - trans.Send<LocalChannelHandle>(DVR_POSE_GET_RING_BUFFER); - if (!status) { - ALOGE("Pose GetRingBuffer() failed because: %s", - status.GetErrorMessage().c_str()); - return -status.error(); + return -EINVAL; } - auto buffer = BufferConsumer::Import(status.take()); - if (!buffer) { - ALOGE("Pose failed to import ring buffer"); - return -EIO; - } - void* addr = nullptr; - int ret = buffer->GetBlobReadOnlyPointer(sizeof(DvrPoseRingBuffer), &addr); - if (ret < 0 || !addr) { - ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr); - return -EIO; - } - pose_buffer_.swap(buffer); - mapped_pose_buffer_ = static_cast<const DvrPoseRingBuffer*>(addr); - ALOGI("Mapped pose data translation %f,%f,%f quat %f,%f,%f,%f", - mapped_pose_buffer_->ring[0].translation[0], - mapped_pose_buffer_->ring[0].translation[1], - mapped_pose_buffer_->ring[0].translation[2], - mapped_pose_buffer_->ring[0].orientation[0], - mapped_pose_buffer_->ring[0].orientation[1], - mapped_pose_buffer_->ring[0].orientation[2], - mapped_pose_buffer_->ring[0].orientation[3]); - if (out_info) { - GetPoseRingBufferInfo(out_info); - } - return 0; + return -EAGAIN; } int GetControllerRingBuffer(int32_t controller_id) { @@ -190,7 +187,7 @@ class PoseClient : public pdx::ClientBase<PoseClient> { ALOGE("Pose failed to import ring buffer"); return -EIO; } - constexpr size_t size = kPoseAsyncBufferTotalCount * sizeof(DvrPoseAsync); + constexpr size_t size = DvrVsyncPoseBuffer::kSize * sizeof(DvrPoseAsync); void* addr = nullptr; int ret = buffer->GetBlobReadOnlyPointer(size, &addr); if (ret < 0 || !addr) { @@ -201,9 +198,9 @@ class PoseClient : public pdx::ClientBase<PoseClient> { client_state.mapped_pose_buffer = static_cast<const DvrPoseAsync*>(addr); ALOGI( "Mapped controller %d pose data translation %f,%f,%f quat %f,%f,%f,%f", - controller_id, client_state.mapped_pose_buffer[0].translation[0], - client_state.mapped_pose_buffer[0].translation[1], - client_state.mapped_pose_buffer[0].translation[2], + controller_id, client_state.mapped_pose_buffer[0].position[0], + client_state.mapped_pose_buffer[0].position[1], + client_state.mapped_pose_buffer[0].position[2], client_state.mapped_pose_buffer[0].orientation[0], client_state.mapped_pose_buffer[0].orientation[1], client_state.mapped_pose_buffer[0].orientation[2], @@ -211,32 +208,6 @@ class PoseClient : public pdx::ClientBase<PoseClient> { return 0; } - int NotifyVsync(uint32_t vsync_count, int64_t display_timestamp, - int64_t display_period_ns, - int64_t right_eye_photon_offset_ns) { - const struct iovec data[] = { - {.iov_base = &vsync_count, .iov_len = sizeof(vsync_count)}, - {.iov_base = &display_timestamp, .iov_len = sizeof(display_timestamp)}, - {.iov_base = &display_period_ns, .iov_len = sizeof(display_period_ns)}, - {.iov_base = &right_eye_photon_offset_ns, - .iov_len = sizeof(right_eye_photon_offset_ns)}, - }; - Transaction trans{*this}; - Status<int> status = - trans.SendVector<int>(DVR_POSE_NOTIFY_VSYNC, data, nullptr); - ALOGE_IF(!status, "Pose NotifyVsync() failed because: %s\n", - status.GetErrorMessage().c_str()); - return ReturnStatusOrError(status); - } - - int GetRingBufferFd(LocalHandle* fd) { - int ret = GetRingBuffer(nullptr); - if (ret < 0) - return ret; - *fd = pose_buffer_->GetBlobFd(); - return 0; - } - private: friend BASE; @@ -252,14 +223,32 @@ class PoseClient : public pdx::ClientBase<PoseClient> { PoseClient(const PoseClient&) = delete; PoseClient& operator=(const PoseClient&) = delete; - void GetPoseRingBufferInfo(DvrPoseRingBufferInfo* out_info) const { - out_info->min_future_count = kPoseAsyncBufferMinFutureCount; - out_info->total_count = kPoseAsyncBufferTotalCount; - out_info->buffer = mapped_pose_buffer_->ring; + const DvrVsyncPoseBuffer* GetVsyncBuffer() { + if (mapped_vsync_pose_buffer_ == nullptr) { + if (vsync_pose_buffer_ == nullptr) { + // The constructor tries mapping it so we do not need TryMapping after. + vsync_pose_buffer_ = std::make_unique<CPUMappedBuffer>( + DvrGlobalBuffers::kVsyncPoseBuffer, CPUUsageMode::READ_OFTEN); + } else if (vsync_pose_buffer_->IsMapped() == false) { + vsync_pose_buffer_->TryMapping(); + } + + if (vsync_pose_buffer_->IsMapped()) { + mapped_vsync_pose_buffer_ = + static_cast<DvrVsyncPoseBuffer*>(vsync_pose_buffer_->Address()); + } + } + + return mapped_vsync_pose_buffer_; } - std::unique_ptr<BufferConsumer> pose_buffer_; - const DvrPoseRingBuffer* mapped_pose_buffer_ = nullptr; + // The vsync pose buffer if already mapped. + std::unique_ptr<CPUMappedBuffer> vsync_pose_buffer_; + + // The direct sensor pose buffer. + std::unique_ptr<SensorPoseRing> sensor_pose_buffer_; + + const DvrVsyncPoseBuffer* mapped_vsync_pose_buffer_ = nullptr; struct ControllerClientState { std::unique_ptr<BufferConsumer> pose_buffer; @@ -273,66 +262,55 @@ class PoseClient : public pdx::ClientBase<PoseClient> { using android::dvr::PoseClient; -struct DvrPose {}; - extern "C" { -DvrPose* dvrPoseCreate() { - PoseClient* client = PoseClient::Create().release(); - return reinterpret_cast<DvrPose*>(client); +DvrPoseClient* dvrPoseClientCreate() { + auto* client = PoseClient::Create().release(); + return reinterpret_cast<DvrPoseClient*>(client); } -void dvrPoseDestroy(DvrPose* client) { delete PoseClient::FromC(client); } +void dvrPoseClientDestroy(DvrPoseClient* client) { + delete PoseClient::FromC(client); +} -int dvrPoseGet(DvrPose* client, uint32_t vsync_count, DvrPoseAsync* out_pose) { +int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count, + DvrPoseAsync* out_pose) { return PoseClient::FromC(client)->GetPose(vsync_count, out_pose); } -uint32_t dvrPoseGetVsyncCount(DvrPose* client) { +uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client) { return PoseClient::FromC(client)->GetVsyncCount(); } -int dvrPoseGetController(DvrPose* client, int32_t controller_id, - uint32_t vsync_count, DvrPoseAsync* out_pose) { +int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id, + uint32_t vsync_count, DvrPoseAsync* out_pose) { return PoseClient::FromC(client)->GetControllerPose(controller_id, vsync_count, out_pose); } -int dvrPoseLogController(DvrPose* client, bool enable) { +int dvrPoseClientLogController(DvrPoseClient* client, bool enable) { return PoseClient::FromC(client)->LogController(enable); } -int dvrPosePoll(DvrPose* client, DvrPoseState* state) { +int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state) { return PoseClient::FromC(client)->Poll(state); } -int dvrPoseFreeze(DvrPose* client, const DvrPoseState* frozen_state) { +int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state) { return PoseClient::FromC(client)->Freeze(*frozen_state); } -int dvrPoseSetMode(DvrPose* client, DvrPoseMode mode) { +int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode) { return PoseClient::FromC(client)->SetMode(mode); } -int dvrPoseGetMode(DvrPose* client, DvrPoseMode* mode) { +int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode) { return PoseClient::FromC(client)->GetMode(mode); } -int dvrPoseGetRingBuffer(DvrPose* client, DvrPoseRingBufferInfo* out_info) { - return PoseClient::FromC(client)->GetRingBuffer(out_info); -} - -int privateDvrPoseNotifyVsync(DvrPose* client, uint32_t vsync_count, - int64_t display_timestamp, - int64_t display_period_ns, - int64_t right_eye_photon_offset_ns) { - return PoseClient::FromC(client)->NotifyVsync(vsync_count, display_timestamp, - display_period_ns, - right_eye_photon_offset_ns); -} -int privateDvrPoseGetRingBufferFd(DvrPose* client, LocalHandle* fd) { - return PoseClient::FromC(client)->GetRingBufferFd(fd); +int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled) { + return PoseClient::FromC(client)->EnableSensors(enabled); } } // extern "C" diff --git a/opengl/Android.bp b/opengl/Android.bp index c520bda140..aec5a95628 100644 --- a/opengl/Android.bp +++ b/opengl/Android.bp @@ -52,6 +52,12 @@ ndk_headers { license: "include/KHR/NOTICE", } +cc_library_headers { + name: "gl_headers", + vendor_available: true, + export_include_dirs: ["include"], +} + subdirs = [ "*", ] diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index 466768ae2c..c4073a9505 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -534,6 +534,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglPresentationTimeANDROID (EGLDisplay dpy, EGLSur #endif #endif /* EGL_ANDROID_presentation_time */ +#ifndef EGL_KHR_no_config_context +#define EGL_KHR_no_config_context 1 +#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0) +#endif /* EGL_KHR_no_config_context */ + #ifndef EGL_ANDROID_get_frame_timestamps #define EGL_ANDROID_get_frame_timestamps 1 #define EGL_TIMESTAMPS_ANDROID 0x3430 diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk index 4b08749b22..c7635e27c7 100644 --- a/opengl/libagl/Android.mk +++ b/opengl/libagl/Android.mk @@ -26,7 +26,7 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libagl\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden -LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui +LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui libnativewindow LOCAL_SRC_FILES_arm += fixed_asm.S iterators.S LOCAL_CFLAGS_arm += -fstrict-aliasing diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index 04f6d6d1a3..b79051c499 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -56,6 +56,24 @@ EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height); + +typedef struct egl_native_pixmap_t +{ + int32_t version; /* must be 32 */ + int32_t width; + int32_t height; + int32_t stride; + uint8_t* data; + uint8_t format; + uint8_t rfu[3]; + union { + uint32_t compressedFormat; + int32_t vstride; + }; + int32_t reserved; +} egl_native_pixmap_t; + + // ---------------------------------------------------------------------------- namespace android { diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index d6bdc81020..b4cc2113e9 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -64,6 +64,16 @@ cc_defaults { "liblog", "libdl", ], + static_libs: [ + "libarect", + ], + header_libs: [ + "gl_headers", + "libsystem_headers", + "libhardware_headers", + "libnativebase_headers", + ], + export_header_lib_headers: ["gl_headers"], // we need to access the private Bionic header <bionic_tls.h> include_dirs: ["bionic/libc/private"], @@ -75,16 +85,22 @@ cc_defaults { cc_defaults { name: "egl_libs_defaults", defaults: ["gl_libs_defaults"], + vendor_available: true, cflags: [ "-DLOG_TAG=\"libEGL\"", ], shared_libs: [ // ***** DO NOT ADD NEW DEPENDENCIES HERE ***** // In particular, DO NOT add libutils nor anything "above" libui - "libui", + "libgraphicsenv", "libnativewindow", "libbacktrace", ], + target: { + vendor: { + exclude_shared_libs: ["libgraphicsenv"], + }, + }, } cc_library_static { @@ -111,7 +127,14 @@ cc_library_shared { "EGL/Loader.cpp", "EGL/BlobCache.cpp", ], - shared_libs: ["libvndksupport"], + shared_libs: [ + "libvndksupport", + "android.hardware.configstore@1.0", + "android.hardware.configstore-utils", + "libhidlbase", + "libhidltransport", + "libutils", + ], static_libs: ["libEGL_getProcAddress"], ldflags: ["-Wl,--exclude-libs=ALL"], export_include_dirs: ["EGL/include"], @@ -129,6 +152,7 @@ cc_test { cc_defaults { name: "gles_libs_defaults", defaults: ["gl_libs_defaults"], + vendor_available: true, arch: { arm: { instruction_set: "arm", diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 823b502ad8..32f8caa989 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -28,7 +28,9 @@ #include <cutils/properties.h> #include <log/log.h> -#include <ui/GraphicsEnv.h> +#ifndef __ANDROID_VNDK__ +#include <graphicsenv/GraphicsEnv.h> +#endif #include <vndksupport/linker.h> #include "egl_trace.h" @@ -477,10 +479,12 @@ void *Loader::load_driver(const char* kind, ATRACE_CALL(); void* dso = nullptr; +#ifndef __ANDROID_VNDK__ android_namespace_t* ns = android_getDriverNamespace(); if (ns) { dso = load_updated_driver(kind, ns); } +#endif if (!dso) { dso = load_system_driver(kind); if (!dso) diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index ba3a5f91a3..0214b0eb56 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -79,6 +79,7 @@ struct extention_map_t { extern char const * const gBuiltinExtensionString; extern char const * const gExtensionString; +// clang-format off char const * const gBuiltinExtensionString = "EGL_KHR_get_all_proc_addresses " "EGL_ANDROID_presentation_time " @@ -123,6 +124,7 @@ char const * const gExtensionString = "EGL_IMG_context_priority " "EGL_KHR_no_config_context " ; +// clang-format on // extensions not exposed to applications but used by the ANDROID system // "EGL_ANDROID_blob_cache " // strongly recommended @@ -452,16 +454,216 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, // EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear // formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where // the modification isn't possible, the original dataSpace is returned. -static android_dataspace modifyBufferDataspace( android_dataspace dataSpace, - EGLint colorspace) { +static android_dataspace modifyBufferDataspace(android_dataspace dataSpace, + EGLint colorspace) { if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) { return HAL_DATASPACE_SRGB_LINEAR; } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { return HAL_DATASPACE_SRGB; + } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) { + return HAL_DATASPACE_DISPLAY_P3; + } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) { + return HAL_DATASPACE_DISPLAY_P3_LINEAR; + } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) { + return HAL_DATASPACE_V0_SCRGB; + } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) { + return HAL_DATASPACE_V0_SCRGB_LINEAR; } return dataSpace; } +// Return true if we stripped any EGL_GL_COLORSPACE_KHR attributes. +static EGLBoolean stripColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list, + EGLint format, + std::vector<EGLint>& stripped_attrib_list) { + std::vector<EGLint> allowedColorSpaces; + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGB_565: + // driver okay with linear & sRGB for 8888, but can't handle + // Display-P3 or other spaces. + allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR); + allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); + break; + + case HAL_PIXEL_FORMAT_RGBA_FP16: + case HAL_PIXEL_FORMAT_RGBA_1010102: + default: + // driver does not want to see colorspace attributes for 1010102 or fp16. + // Future: if driver supports XXXX extension, we can pass down that colorspace + break; + } + + bool stripped = false; + if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) { + for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) { + if (attr[0] == EGL_GL_COLORSPACE_KHR) { + EGLint colorSpace = attr[1]; + bool found = false; + // Verify that color space is allowed + for (auto it : allowedColorSpaces) { + if (colorSpace == it) { + found = true; + } + } + if (!found) { + stripped = true; + } else { + stripped_attrib_list.push_back(attr[0]); + stripped_attrib_list.push_back(attr[1]); + } + } else { + stripped_attrib_list.push_back(attr[0]); + stripped_attrib_list.push_back(attr[1]); + } + } + } + if (stripped) { + stripped_attrib_list.push_back(EGL_NONE); + stripped_attrib_list.push_back(EGL_NONE); + } + return stripped; +} + +static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType window, + const EGLint* attrib_list, EGLint& colorSpace, + android_dataspace& dataSpace) { + colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; + dataSpace = HAL_DATASPACE_UNKNOWN; + + if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) { + for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) { + if (*attr == EGL_GL_COLORSPACE_KHR) { + colorSpace = attr[1]; + bool found = false; + bool verify = true; + // Verify that color space is allowed + if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || + colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) { + // SRGB and LINEAR are always supported when EGL_KHR_gl_colorspace + // is available, so no need to verify. + found = true; + verify = false; + } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_linear && + dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) { + found = true; + } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_pq && + dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) { + found = true; + } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_EXT && + dp->haveExtension("EGL_EXT_gl_colorspace_scrgb")) { + found = true; + } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT && + dp->haveExtension("EGL_EXT_gl_colorspace_scrgb_linear")) { + found = true; + } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT && + dp->haveExtension("EGL_EXT_gl_colorspace_display_p3_linear")) { + found = true; + } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT && + dp->haveExtension("EGL_EXT_gl_colorspace_display_p3")) { + found = true; + } + if (!found) { + return false; + } + if (verify && window) { + bool wide_color_support = true; + // Ordinarily we'd put a call to native_window_get_wide_color_support + // at the beginning of the function so that we'll have the + // result when needed elsewhere in the function. + // However, because eglCreateWindowSurface is called by SurfaceFlinger and + // SurfaceFlinger is required to answer the call below we would + // end up in a deadlock situation. By moving the call to only happen + // if the application has specifically asked for wide-color we avoid + // the deadlock with SurfaceFlinger since it will not ask for a + // wide-color surface. + int err = native_window_get_wide_color_support(window, &wide_color_support); + + if (err) { + ALOGE("getColorSpaceAttribute: invalid window (win=%p) " + "failed (%#x) (already connected to another API?)", + window, err); + return false; + } + if (!wide_color_support) { + // Application has asked for a wide-color colorspace but + // wide-color support isn't available on the display the window is on. + return false; + } + } + // Only change the dataSpace from default if the application + // has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute. + dataSpace = modifyBufferDataspace(dataSpace, colorSpace); + } + } + } + return true; +} + +static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list, + EGLint& colorSpace, android_dataspace& dataSpace) { + return getColorSpaceAttribute(dp, NULL, attrib_list, colorSpace, dataSpace); +} + +void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) { + // Set the native window's buffers format to match what this config requests. + // Whether to use sRGB gamma is not part of the EGLconfig, but is part + // of our native format. So if sRGB gamma is requested, we have to + // modify the EGLconfig's format before setting the native window's + // format. + + EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, &componentType); + + EGLint a = 0; + EGLint r, g, b; + r = g = b = 0; + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r); + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g); + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b); + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a); + EGLint colorDepth = r + g + b; + + // Today, the driver only understands sRGB and linear on 888X + // formats. Strip other colorspaces from the attribute list and + // only use them to set the dataspace via + // native_window_set_buffers_dataspace + // if pixel format is RGBX 8888 + // TBD: Can test for future extensions that indicate that driver + // handles requested color space and we can let it through. + // allow SRGB and LINEAR. All others need to be stripped. + // else if 565, 4444 + // TBD: Can we assume these are supported if 8888 is? + // else if FP16 or 1010102 + // strip colorspace from attribs. + // endif + if (a == 0) { + if (colorDepth <= 16) { + format = HAL_PIXEL_FORMAT_RGB_565; + } else { + if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { + if (colorDepth > 24) { + format = HAL_PIXEL_FORMAT_RGBA_1010102; + } else { + format = HAL_PIXEL_FORMAT_RGBX_8888; + } + } else { + format = HAL_PIXEL_FORMAT_RGBA_FP16; + } + } + } else { + if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { + if (colorDepth > 24) { + format = HAL_PIXEL_FORMAT_RGBA_1010102; + } else { + format = HAL_PIXEL_FORMAT_RGBA_8888; + } + } else { + format = HAL_PIXEL_FORMAT_RGBA_FP16; + } + } +} + EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list) @@ -491,60 +693,22 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); } - // Set the native window's buffers format to match what this config requests. - // Whether to use sRGB gamma is not part of the EGLconfig, but is part - // of our native format. So if sRGB gamma is requested, we have to - // modify the EGLconfig's format before setting the native window's - // format. - - EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; - cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, - &componentType); - EGLint format; - android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN; - EGLint a = 0; - EGLint r, g, b; - r = g = b = 0; - cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE, &r); - cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g); - cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE, &b); - cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a); - EGLint colorDepth = r + g + b; - - if (a == 0) { - if (colorDepth <= 16) { - format = HAL_PIXEL_FORMAT_RGB_565; - } else { - if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { - if (colorDepth > 24) { - format = HAL_PIXEL_FORMAT_RGBA_1010102; - } else { - format = HAL_PIXEL_FORMAT_RGBX_8888; - } - } else { - format = HAL_PIXEL_FORMAT_RGBA_FP16; - } - } - } else { - if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { - if (colorDepth > 24) { - format = HAL_PIXEL_FORMAT_RGBA_1010102; - } else { - format = HAL_PIXEL_FORMAT_RGBA_8888; - } - } else { - format = HAL_PIXEL_FORMAT_RGBA_FP16; - } + getNativePixelFormat(iDpy, cnx, config, format); + + // now select correct colorspace and dataspace based on user's attribute list + EGLint colorSpace; + android_dataspace dataSpace; + if (!getColorSpaceAttribute(dp, window, attrib_list, colorSpace, dataSpace)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } - // now select a corresponding sRGB format if needed - if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) { - for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) { - if (*attr == EGL_GL_COLORSPACE_KHR) { - dataSpace = modifyBufferDataspace(dataSpace, *(attr+1)); - } - } + std::vector<EGLint> strippedAttribList; + if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) { + // Had to modify the attribute list due to use of color space. + // Use modified list from here on. + attrib_list = strippedAttribList.data(); } if (format != 0) { @@ -575,8 +739,8 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, EGLSurface surface = cnx->egl.eglCreateWindowSurface( iDpy, config, window, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dp.get(), config, window, - surface, cnx); + egl_surface_t* s = + new egl_surface_t(dp.get(), config, window, surface, colorSpace, cnx); return s; } @@ -595,12 +759,19 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); + EGLint colorSpace; + android_dataspace dataSpace; if (dp) { + // now select a corresponding sRGB format if needed + if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + EGLSurface surface = cnx->egl.eglCreatePixmapSurface( dp->disp.dpy, config, pixmap, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, - surface, cnx); + egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); return s; } } @@ -615,11 +786,32 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { + EGLDisplay iDpy = dp->disp.dpy; + EGLint format; + getNativePixelFormat(iDpy, cnx, config, format); + + // now select correct colorspace and dataspace based on user's attribute list + EGLint colorSpace; + android_dataspace dataSpace; + if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + + // Pbuffers are not displayed so we don't need to store the + // colorspace. We do need to filter out color spaces the + // driver doesn't know how to process. + std::vector<EGLint> strippedAttribList; + if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) { + // Had to modify the attribute list due to use of color space. + // Use modified list from here on. + attrib_list = strippedAttribList.data(); + } + EGLSurface surface = cnx->egl.eglCreatePbufferSurface( dp->disp.dpy, config, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, - surface, cnx); + egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); return s; } } @@ -658,6 +850,10 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); egl_surface_t const * const s = get_surface(surface); + if (attribute == EGL_GL_COLORSPACE_KHR) { + *value = s->getColorSpace(); + return EGL_TRUE; + } return s->cnx->egl.eglQuerySurface( dp->disp.dpy, s->surface, attribute, value); } @@ -1729,13 +1925,22 @@ EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SURFACE; + EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; + android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN; + // TODO: Probably need to update EGL_KHR_stream_producer_eglsurface to + // indicate support for EGL_GL_COLORSPACE_KHR. + // now select a corresponding sRGB format if needed + if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) { EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR( dp->disp.dpy, config, stream, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, - surface, cnx); + egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); return s; } } @@ -1886,8 +2091,15 @@ EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { clearError(); + // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus + // this function cannot be implemented when this libEGL is built for + // vendors. +#ifndef __ANDROID_VNDK__ if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); +#else + return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); +#endif } // ---------------------------------------------------------------------------- diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp index dc1a4af46e..579e422c1a 100644 --- a/opengl/libs/EGL/egl_cache.cpp +++ b/opengl/libs/EGL/egl_cache.cpp @@ -26,6 +26,7 @@ #include <inttypes.h> #include <sys/mman.h> #include <sys/stat.h> +#include <unistd.h> #include <thread> diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index b696920023..4e5833ab12 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -30,6 +30,12 @@ #include "Loader.h" #include <cutils/properties.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> +#include <configstore/Utils.h> + +using namespace android::hardware::configstore; +using namespace android::hardware::configstore::V1_0; + // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- @@ -192,6 +198,18 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { mClientApiString = sClientApiString; mExtensionString = gBuiltinExtensionString; + + bool wideColorBoardConfig = + getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>( + false); + + // Add wide-color extensions if device can support wide-color + if (wideColorBoardConfig) { + mExtensionString.append( + "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear " + "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 "); + } + char const* start = gExtensionString; do { // length of the extension name diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index 623878062b..837cfa92ca 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -55,12 +55,15 @@ bool egl_object_t::get(egl_display_t const* display, egl_object_t* object) { // ---------------------------------------------------------------------------- -egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config, - EGLNativeWindowType win, EGLSurface surface, - egl_connection_t const* cnx) : - egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx), - connected(true) -{ +egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, + EGLSurface surface, EGLint colorSpace, egl_connection_t const* cnx) + : egl_object_t(dpy), + surface(surface), + config(config), + win(win), + cnx(cnx), + connected(true), + colorSpace(colorSpace) { if (win) { win->incStrong(this); } diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h index 8988905a25..7c3075c9fc 100644 --- a/opengl/libs/EGL/egl_object.h +++ b/opengl/libs/EGL/egl_object.h @@ -131,12 +131,12 @@ protected: public: typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref; - egl_surface_t(egl_display_t* dpy, EGLConfig config, - EGLNativeWindowType win, EGLSurface surface, - egl_connection_t const* cnx); + egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, EGLSurface surface, + EGLint colorSpace, egl_connection_t const* cnx); ANativeWindow* getNativeWindow() { return win; } ANativeWindow* getNativeWindow() const { return win; } + EGLint getColorSpace() const { return colorSpace; } // Try to keep the order of these fields and size unchanged. It's not public API, but // it's not hard to imagine native games accessing them. @@ -149,6 +149,7 @@ public: private: bool connected; void disconnect(); + EGLint colorSpace; }; class egl_context_t: public egl_object_t { diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp new file mode 100644 index 0000000000..bf7aeb117f --- /dev/null +++ b/opengl/tests/Android.bp @@ -0,0 +1,4 @@ +subdirs = [ + "hwc", + "lib", +] diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk index 3ae3b4eaef..92d223cc7e 100644 --- a/opengl/tests/Android.mk +++ b/opengl/tests/Android.mk @@ -12,7 +12,6 @@ dirs := \ gl_perf \ gl_yuvtex \ gralloc \ - hwc \ include \ lib \ linetex \ diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index 24b131539a..62e6bd3055 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -28,18 +28,17 @@ #include <gui/IGraphicBufferConsumer.h> #include <gui/BufferQueue.h> -#define PIXEL_FORMAT_FLOAT "EGL_EXT_pixel_format_float" - -bool hasEglPixelFormatFloat() { - EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); +bool hasEglExtension(EGLDisplay dpy, const char* extensionName) { const char* exts = eglQueryString(dpy, EGL_EXTENSIONS); - size_t cropExtLen = strlen(PIXEL_FORMAT_FLOAT); + size_t cropExtLen = strlen(extensionName); size_t extsLen = strlen(exts); - bool equal = !strcmp(PIXEL_FORMAT_FLOAT, exts); - bool atStart = !strncmp(PIXEL_FORMAT_FLOAT " ", exts, cropExtLen + 1); + bool equal = !strcmp(extensionName, exts); + android::String8 extString(extensionName); + android::String8 space(" "); + bool atStart = !strncmp(extString + space, exts, cropExtLen + 1); bool atEnd = (cropExtLen + 1) < extsLen && - !strcmp(" " PIXEL_FORMAT_FLOAT, exts + extsLen - (cropExtLen + 1)); - bool inMiddle = strstr(exts, " " PIXEL_FORMAT_FLOAT " "); + !strcmp(space + extString, exts + extsLen - (cropExtLen + 1)); + bool inMiddle = strstr(exts, space + extString + space); return equal || atStart || atEnd || inMiddle; } @@ -194,6 +193,176 @@ TEST_F(EGLTest, EGLConfigRGBA8888First) { EXPECT_GE(components[3], 8); } +TEST_F(EGLTest, EGLDisplayP3) { + EGLint numConfigs; + EGLConfig config; + EGLBoolean success; + + if (!hasWideColorDisplay) { + // skip this test if device does not have wide-color display + return; + } + + // Test that display-p3 extensions exist + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3")); + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear")); + + // Use 8-bit to keep forcus on Display-P3 aspect + EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(1, numConfigs); + + EGLint components[4]; + EGLint value; + eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value); + + success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EXPECT_EQ(components[0], 8); + EXPECT_EQ(components[1], 8); + EXPECT_EQ(components[2], 8); + EXPECT_EQ(components[3], 8); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + // Create a EGLSurface + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, value); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} + +TEST_F(EGLTest, EGLDisplayP31010102) { + EGLint numConfigs; + EGLConfig config; + EGLBoolean success; + + if (!hasWideColorDisplay) { + // skip this test if device does not have wide-color display + return; + } + + // Test that display-p3 extensions exist + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3")); + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear")); + + // Use 8-bit to keep forcus on Display-P3 aspect + EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_RED_SIZE, 10, + EGL_GREEN_SIZE, 10, + EGL_BLUE_SIZE, 10, + EGL_ALPHA_SIZE, 2, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(1, numConfigs); + + EGLint components[4]; + EGLint value; + eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value); + + success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EXPECT_EQ(components[0], 10); + EXPECT_EQ(components[1], 10); + EXPECT_EQ(components[2], 10); + EXPECT_EQ(components[3], 2); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + // Create a EGLSurface + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, value); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} + TEST_F(EGLTest, EGLConfigFP16) { EGLint numConfigs; EGLConfig config; @@ -204,23 +373,20 @@ TEST_F(EGLTest, EGLConfigFP16) { return; } - ASSERT_TRUE(hasEglPixelFormatFloat()); - - EGLint attrs[] = {EGL_SURFACE_TYPE, - EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, - 16, - EGL_GREEN_SIZE, - 16, - EGL_BLUE_SIZE, - 16, - EGL_ALPHA_SIZE, - 16, - EGL_COLOR_COMPONENT_TYPE_EXT, - EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, - EGL_NONE}; + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_pixel_format_float")); + + EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 16, + EGL_GREEN_SIZE, 16, + EGL_BLUE_SIZE, 16, + EGL_ALPHA_SIZE, 16, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(1, numConfigs); @@ -251,6 +417,108 @@ TEST_F(EGLTest, EGLConfigFP16) { void onSidebandStreamChanged() override {} }; + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} + +TEST_F(EGLTest, EGL_KHR_no_config_context) { + if (!hasWideColorDisplay) { + // skip this test if device does not have wide-color display + return; + } + + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_KHR_no_config_context")); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + std::vector<EGLint> contextAttributes; + contextAttributes.reserve(4); + contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION); + contextAttributes.push_back(2); + contextAttributes.push_back(EGL_NONE); + contextAttributes.push_back(EGL_NONE); + + EGLContext eglContext = eglCreateContext(mEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, + contextAttributes.data()); + EXPECT_NE(EGL_NO_CONTEXT, eglContext); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + + if (eglContext != EGL_NO_CONTEXT) { + eglDestroyContext(mEglDisplay, eglContext); + } +} + +// Emulate what a native application would do to create a +// 10:10:10:2 surface. +TEST_F(EGLTest, EGLConfig1010102) { + EGLint numConfigs; + EGLConfig config; + EGLBoolean success; + + if (!hasWideColorDisplay) { + // skip this test if device does not have wide-color display + return; + } + + EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_RED_SIZE, 10, + EGL_GREEN_SIZE, 10, + EGL_BLUE_SIZE, 10, + EGL_ALPHA_SIZE, 2, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(1, numConfigs); + + EGLint components[4]; + EGLint value; + eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value); + + success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EXPECT_EQ(components[0], 10); + EXPECT_EQ(components[1], 10); + EXPECT_EQ(components[2], 10); + EXPECT_EQ(components[3], 2); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + // Create a EGLSurface sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; diff --git a/opengl/tests/configdump/configdump.cpp b/opengl/tests/configdump/configdump.cpp index 2a945982a9..c423105a11 100644 --- a/opengl/tests/configdump/configdump.cpp +++ b/opengl/tests/configdump/configdump.cpp @@ -66,8 +66,7 @@ Attribute attributes[] = { }; // clang-format on -int main(int argc, char** argv) -{ +int main(int /*argc*/, char** /*argv*/) { EGLConfig* configs; EGLint n; diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp index 9f8d166c7a..ee88667328 100644 --- a/opengl/tests/gl2_basic/gl2_basic.cpp +++ b/opengl/tests/gl2_basic/gl2_basic.cpp @@ -30,6 +30,7 @@ #include <EGLUtils.h> using namespace android; +EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); static void printGLString(const char *name, GLenum s) { // fprintf(stderr, "printGLString %s, %d\n", name, s); @@ -46,7 +47,8 @@ static void printGLString(const char *name, GLenum s) { static void printEGLString(EGLDisplay dpy, const char *name, GLenum s) { const char *v = (const char *) eglQueryString(dpy, s); - fprintf(stderr, "GL %s = %s\n", name, v); + const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s); + fprintf(stderr, "GL %s = %s\nImplementationANDROID: %s\n", name, v, va); } static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { @@ -263,7 +265,7 @@ int printEGLConfigurations(EGLDisplay dpy) { return true; } -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { EGLBoolean returnValue; EGLConfig myConfig = {0}; diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp index 98d8aa8cbc..22128ab5ea 100644 --- a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp +++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp @@ -331,7 +331,7 @@ void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { printf("\n"); } -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { EGLBoolean returnValue; EGLConfig myConfig = {0}; diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp index c923b07362..fad26a69c7 100644 --- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp +++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp @@ -221,7 +221,7 @@ void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { printf("\n"); } -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { EGLBoolean returnValue; EGLConfig myConfig = {0}; diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp new file mode 100644 index 0000000000..425f3740e4 --- /dev/null +++ b/opengl/tests/hwc/Android.bp @@ -0,0 +1,107 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_defaults { + + name: "hwc_tests_defaults", + cflags: [ + "-DGL_GLEXT_PROTOTYPES", + "-DEGL_EGLEXT_PROTOTYPES", + "-Wall", + "-Wextra", + "-Werror", + ], +} + +cc_library_static { + + name: "libhwcTest", + srcs: ["hwcTestLib.cpp"], + + static_libs: [ + "libarect", + "libglTest", + "libtestUtil", + ], + shared_libs: [ + "libui", + "libnativewindow" + ], + defaults: ["hwc_tests_defaults"], +} + +cc_defaults { + + name: "hwc_lib_defaults", + shared_libs: [ + "libcutils", + "libEGL", + "libGLESv2", + "libhardware", + "liblog", + "libui", + "libutils", + "libnativewindow" + ], + + static_libs: [ + "libglTest", + "libhwcTest", + "libtestUtil", + ], +} + +cc_test { + + name: "hwcStress", + srcs: ["hwcStress.cpp"], + + defaults: [ + "hwc_lib_defaults", + "hwc_tests_defaults", + ], +} + +cc_test { + + name: "hwcRects", + srcs: ["hwcRects.cpp"], + + defaults: [ + "hwc_lib_defaults", + "hwc_tests_defaults", + ], +} + +cc_test { + + name: "hwcColorEquiv", + srcs: ["hwcColorEquiv.cpp"], + + defaults: [ + "hwc_lib_defaults", + "hwc_tests_defaults", + ], +} + +cc_test { + + name: "hwcCommit", + srcs: ["hwcCommit.cpp"], + + defaults: [ + "hwc_lib_defaults", + "hwc_tests_defaults", + ], +} diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk deleted file mode 100644 index 13337c2753..0000000000 --- a/opengl/tests/hwc/Android.mk +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright (C) 2010 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE:= libhwcTest -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcTestLib.cpp -LOCAL_C_INCLUDES += system/extras/tests/include \ - $(call include-path-for, opengl-tests-includes) \ - -LOCAL_STATIC_LIBRARIES := libarect - -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE:= hwcStress -LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcStress.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libutils \ - liblog \ - libui \ - libhardware \ - -LOCAL_STATIC_LIBRARIES := \ - libtestUtil \ - libglTest \ - libhwcTest \ - -LOCAL_C_INCLUDES += \ - system/extras/tests/include \ - hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) \ - -include $(BUILD_NATIVE_TEST) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE:= hwcRects -LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcRects.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libutils \ - liblog \ - libui \ - libhardware \ - -LOCAL_STATIC_LIBRARIES := \ - libtestUtil \ - libglTest \ - libhwcTest \ - -LOCAL_C_INCLUDES += \ - system/extras/tests/include \ - hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) \ - -include $(BUILD_NATIVE_TEST) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE:= hwcColorEquiv -LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcColorEquiv.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libutils \ - liblog \ - libui \ - libhardware \ - -LOCAL_STATIC_LIBRARIES := \ - libtestUtil \ - libglTest \ - libhwcTest \ - -LOCAL_C_INCLUDES += \ - system/extras/tests/include \ - hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) \ - -include $(BUILD_NATIVE_TEST) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE:= hwcCommit -LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcCommit.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libutils \ - liblog \ - libui \ - libhardware \ - -LOCAL_STATIC_LIBRARIES := \ - libtestUtil \ - libglTest \ - libhwcTest \ - -LOCAL_C_INCLUDES += \ - system/extras/tests/include \ - hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) \ - -include $(BUILD_NATIVE_TEST) diff --git a/opengl/tests/lib/Android.bp b/opengl/tests/lib/Android.bp new file mode 100644 index 0000000000..2f6095d8e7 --- /dev/null +++ b/opengl/tests/lib/Android.bp @@ -0,0 +1,38 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_static { + + name: "libglTest", + srcs: [ + "glTestLib.cpp", + "WindowSurface.cpp", + ], + export_include_dirs: ["include"], + + cflags: [ + "-DGL_GLEXT_PROTOTYPES", + "-DEGL_EGLEXT_PROTOTYPES", + "-Wall", + "-Wextra", + "-Werror", + ], + + shared_libs: ["libgui"], + static_libs: [ + "libarect", + "libtestUtil", + ], + +} diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk deleted file mode 100644 index ea94bc199f..0000000000 --- a/opengl/tests/lib/Android.mk +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) 2010 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE:= libglTest -LOCAL_SRC_FILES:= glTestLib.cpp WindowSurface.cpp -LOCAL_C_INCLUDES += system/extras/tests/include \ - $(call include-path-for, opengl-tests-includes) - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror - -LOCAL_SHARED_LIBRARIES += libgui -LOCAL_STATIC_LIBRARIES := libarect - -include $(BUILD_STATIC_LIBRARY) diff --git a/opengl/tests/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h index 014c2611ae..014c2611ae 100644 --- a/opengl/tests/include/EGLUtils.h +++ b/opengl/tests/lib/include/EGLUtils.h diff --git a/opengl/tests/include/WindowSurface.h b/opengl/tests/lib/include/WindowSurface.h index 0ec1404556..0ec1404556 100644 --- a/opengl/tests/include/WindowSurface.h +++ b/opengl/tests/lib/include/WindowSurface.h diff --git a/opengl/tests/include/glTestLib.h b/opengl/tests/lib/include/glTestLib.h index c91c594882..c91c594882 100644 --- a/opengl/tests/include/glTestLib.h +++ b/opengl/tests/lib/include/glTestLib.h diff --git a/opengl/tools/glgen2/registry/egl.xml b/opengl/tools/glgen2/registry/egl.xml index af13395bb1..c2d3494404 100755 --- a/opengl/tools/glgen2/registry/egl.xml +++ b/opengl/tools/glgen2/registry/egl.xml @@ -191,6 +191,7 @@ <enum value="((EGLSync)0)" name="EGL_NO_SYNC"/> <enum value="((EGLSyncKHR)0)" name="EGL_NO_SYNC_KHR" alias="EGL_NO_SYNC"/> <enum value="((EGLSyncNV)0)" name="EGL_NO_SYNC_NV" alias="EGL_NO_SYNC"/> + <enum value="EGL_CAST(EGLConfig,0)" name="EGL_NO_CONFIG_KHR"/> <enum value="10000" name="EGL_DISPLAY_SCALING"/> <enum value="0xFFFFFFFFFFFFFFFF" name="EGL_FOREVER" type="ull"/> <enum value="0xFFFFFFFFFFFFFFFF" name="EGL_FOREVER_KHR" type="ull" alias="EGL_FOREVER"/> @@ -739,7 +740,10 @@ <enum value="50000" name="EGL_METADATA_SCALING_EXT"/> <unused start="0x334B" end="0x334F"/> <enum value="0x3350" name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/> - <unused start="0x3351" end="0x339F"/> + <unused start="0x3351" end="0x3361"/> + <enum value="0x3362" name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/> + <enum value="0x3363" name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/> + <unused start="0x3364" end="0x339F"/> </enums> <enums namespace="EGL" start="0x33A0" end="0x33AF" vendor="ANGLE" comment="Reserved for Shannon Woods (Bug 13175)"> @@ -1891,6 +1895,16 @@ <enum name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/> </require> </extension> + <extension name="EGL_EXT_gl_colorspace_display_p3_linear" supported="egl"> + <require> + <enum name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/> + </require> + </extension> + <extension name="EGL_EXT_gl_colorspace_display_p3" supported="egl"> + <require> + <enum name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/> + </require> + </extension> <extension name="EGL_EXT_image_dma_buf_import" supported="egl"> <require> <enum name="EGL_LINUX_DMA_BUF_EXT"/> diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp index d2f89959e1..50589b484a 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -150,7 +150,8 @@ EventHub::Device::Device(int fd, int32_t id, const String8& path, fd(fd), id(id), path(path), identifier(identifier), classes(0), configuration(NULL), virtualKeyMap(NULL), ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0), - timestampOverrideSec(0), timestampOverrideUsec(0) { + timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true), + isVirtual(fd < 0) { memset(keyBitmask, 0, sizeof(keyBitmask)); memset(absBitmask, 0, sizeof(absBitmask)); memset(relBitmask, 0, sizeof(relBitmask)); @@ -173,6 +174,25 @@ void EventHub::Device::close() { } } +status_t EventHub::Device::enable() { + fd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK); + if(fd < 0) { + ALOGE("could not open %s, %s\n", path.string(), strerror(errno)); + return -errno; + } + enabled = true; + return OK; +} + +status_t EventHub::Device::disable() { + close(); + enabled = false; + return OK; +} + +bool EventHub::Device::hasValidFd() { + return !isVirtual && enabled; +} // --- EventHub --- @@ -286,7 +306,7 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { + if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", @@ -337,7 +357,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) { + if (device && device->hasValidFd() && test_bit(scanCode, device->keyBitmask)) { uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; memset(keyState, 0, sizeof(keyState)); if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { @@ -352,7 +372,7 @@ int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) { + if (device && device->hasValidFd() && device->keyMap.haveKeyLayout()) { Vector<int32_t> scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes); if (scanCodes.size() != 0) { @@ -377,7 +397,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) { + if (device && device->hasValidFd() && test_bit(sw, device->swBitmask)) { uint8_t swState[sizeof_bit_array(SW_MAX + 1)]; memset(swState, 0, sizeof(swState)); if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) { @@ -395,7 +415,7 @@ status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { + if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", @@ -532,7 +552,7 @@ void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) { int32_t sc; - if (device && !device->isVirtual() && mapLed(device, led, &sc) != NAME_NOT_FOUND) { + if (device && device->hasValidFd() && mapLed(device, led, &sc) != NAME_NOT_FOUND) { struct input_event ev; ev.time.tv_sec = 0; ev.time.tv_usec = 0; @@ -636,7 +656,7 @@ void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) { void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { + if (device && device->hasValidFd()) { ff_effect effect; memset(&effect, 0, sizeof(effect)); effect.type = FF_RUMBLE; @@ -670,7 +690,7 @@ void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { void EventHub::cancelVibrate(int32_t deviceId) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { + if (device && device->hasValidFd()) { if (device->ffEffectPlaying) { device->ffEffectPlaying = false; @@ -1065,12 +1085,37 @@ static const int32_t GAMEPAD_KEYCODES[] = { AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, }; +status_t EventHub::registerDeviceForEpollLocked(Device* device) { + struct epoll_event eventItem; + memset(&eventItem, 0, sizeof(eventItem)); + eventItem.events = EPOLLIN; + if (mUsingEpollWakeup) { + eventItem.events |= EPOLLWAKEUP; + } + eventItem.data.u32 = device->id; + if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) { + ALOGE("Could not add device fd to epoll instance. errno=%d", errno); + return -errno; + } + return OK; +} + +status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) { + if (device->hasValidFd()) { + if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) { + ALOGW("Could not remove device fd from epoll instance. errno=%d", errno); + return -errno; + } + } + return OK; +} + status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGV("Opening device: %s", devicePath); - int fd = open(devicePath, O_RDWR | O_CLOEXEC); + int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK); if(fd < 0) { ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; @@ -1135,13 +1180,6 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { // Fill in the descriptor. assignDescriptorLocked(identifier); - // Make file descriptor non-blocking for use with poll(). - if (fcntl(fd, F_SETFL, O_NONBLOCK)) { - ALOGE("Error %d making device file descriptor non-blocking.", errno); - close(fd); - return -1; - } - // Allocate device. (The device object takes ownership of the fd at this point.) int32_t deviceId = mNextDeviceId++; Device* device = new Device(fd, deviceId, String8(devicePath), identifier); @@ -1303,12 +1341,6 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { break; } } - - // Disable kernel key repeat since we handle it ourselves - unsigned int repeatRate[] = {0,0}; - if (ioctl(fd, EVIOCSREP, repeatRate)) { - ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno)); - } } // If the device isn't recognized as something we handle, don't monitor it. @@ -1332,23 +1364,41 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD) && device->classes & INPUT_DEVICE_CLASS_GAMEPAD) { device->controllerNumber = getNextControllerNumberLocked(device); - setLedForController(device); + setLedForControllerLocked(device); } - // Register with epoll. - struct epoll_event eventItem; - memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = EPOLLIN; - if (mUsingEpollWakeup) { - eventItem.events |= EPOLLWAKEUP; - } - eventItem.data.u32 = deviceId; - if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { - ALOGE("Could not add device fd to epoll instance. errno=%d", errno); + + if (registerDeviceForEpollLocked(device) != OK) { delete device; return -1; } + configureFd(device); + + ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " + "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ", + deviceId, fd, devicePath, device->identifier.name.string(), + device->classes, + device->configurationFile.string(), + device->keyMap.keyLayoutFile.string(), + device->keyMap.keyCharacterMapFile.string(), + toString(mBuiltInKeyboardId == deviceId)); + + addDeviceLocked(device); + return OK; +} + +void EventHub::configureFd(Device* device) { + // Set fd parameters with ioctl, such as key repeat, suspend block, and clock type + if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { + // Disable kernel key repeat since we handle it ourselves + unsigned int repeatRate[] = {0, 0}; + if (ioctl(device->fd, EVIOCSREP, repeatRate)) { + ALOGW("Unable to disable kernel key repeat for %s: %s", + device->path.string(), strerror(errno)); + } + } + String8 wakeMechanism("EPOLLWAKEUP"); if (!mUsingEpollWakeup) { #ifndef EVIOCSSUSPENDBLOCK @@ -1357,44 +1407,67 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { // this feature, we need to be prepared to define the ioctl ourselves. #define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) #endif - if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) { + if (ioctl(device->fd, EVIOCSSUSPENDBLOCK, 1)) { wakeMechanism = "<none>"; } else { wakeMechanism = "EVIOCSSUSPENDBLOCK"; } } - // Tell the kernel that we want to use the monotonic clock for reporting timestamps // associated with input events. This is important because the input system // uses the timestamps extensively and assumes they were recorded using the monotonic // clock. - // - // In older kernel, before Linux 3.4, there was no way to tell the kernel which - // clock to use to input event timestamps. The standard kernel behavior was to - // record a real time timestamp, which isn't what we want. Android kernels therefore - // contained a patch to the evdev_event() function in drivers/input/evdev.c to - // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic - // clock to be used instead of the real time clock. - // - // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock. - // Therefore, we no longer require the Android-specific kernel patch described above - // as long as we make sure to set select the monotonic clock. We do that here. int clockId = CLOCK_MONOTONIC; - bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); + bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId); + ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.string(), + toString(usingClockIoctl)); +} - ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " - "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, " - "wakeMechanism=%s, usingClockIoctl=%s", - deviceId, fd, devicePath, device->identifier.name.string(), - device->classes, - device->configurationFile.string(), - device->keyMap.keyLayoutFile.string(), - device->keyMap.keyCharacterMapFile.string(), - toString(mBuiltInKeyboardId == deviceId), - wakeMechanism.string(), toString(usingClockIoctl)); +bool EventHub::isDeviceEnabled(int32_t deviceId) { + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device == NULL) { + ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__); + return false; + } + return device->enabled; +} - addDeviceLocked(device); - return 0; +status_t EventHub::enableDevice(int32_t deviceId) { + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device == NULL) { + ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (device->enabled) { + ALOGW("Duplicate call to %s, input device %" PRId32 " already enabled", __func__, deviceId); + return OK; + } + status_t result = device->enable(); + if (result != OK) { + ALOGE("Failed to enable device %" PRId32, deviceId); + return result; + } + + configureFd(device); + + return registerDeviceForEpollLocked(device); +} + +status_t EventHub::disableDevice(int32_t deviceId) { + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device == NULL) { + ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (!device->enabled) { + ALOGW("Duplicate call to %s, input device already disabled", __func__); + return OK; + } + unregisterDeviceFromEpollLocked(device); + return device->disable(); } void EventHub::createVirtualKeyboardLocked() { @@ -1490,7 +1563,7 @@ void EventHub::releaseControllerNumberLocked(Device* device) { mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1)); } -void EventHub::setLedForController(Device* device) { +void EventHub::setLedForControllerLocked(Device* device) { for (int i = 0; i < MAX_CONTROLLER_LEDS; i++) { setLedStateLocked(device, ALED_CONTROLLER_1 + i, device->controllerNumber == i + 1); } @@ -1500,7 +1573,7 @@ bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { if (!device->keyMap.haveKeyLayout()) { return false; } - + Vector<int32_t> scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); const size_t N = scanCodes.size(); @@ -1510,7 +1583,7 @@ bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { return true; } } - + return false; } @@ -1556,11 +1629,7 @@ void EventHub::closeDeviceLocked(Device* device) { mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD; } - if (!device->isVirtual()) { - if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) { - ALOGW("Could not remove device fd from epoll instance. errno=%d", errno); - } - } + unregisterDeviceFromEpollLocked(device); releaseControllerNumberLocked(device); @@ -1691,6 +1760,7 @@ void EventHub::dump(String8& dump) { } dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); + dump.appendFormat(INDENT3 "Enabled: %s\n", toString(device->enabled)); dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string()); dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber); diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index 686925311f..727b73aeb8 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -25,9 +25,8 @@ #include <input/KeyCharacterMap.h> #include <input/VirtualKeyMap.h> #include <utils/String8.h> -#include <utils/threads.h> +#include <utils/Mutex.h> #include <utils/Log.h> -#include <utils/threads.h> #include <utils/List.h> #include <utils/Errors.h> #include <utils/PropertyMap.h> @@ -267,6 +266,15 @@ public: /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; + + /* Return true if the device is enabled. */ + virtual bool isDeviceEnabled(int32_t deviceId) = 0; + + /* Enable an input device */ + virtual status_t enableDevice(int32_t deviceId) = 0; + + /* Disable an input device. Closes file descriptor to that device. */ + virtual status_t disableDevice(int32_t deviceId) = 0; }; class EventHub : public EventHubInterface @@ -335,7 +343,7 @@ private: struct Device { Device* next; - int fd; // may be -1 if device is virtual + int fd; // may be -1 if device is closed const int32_t id; const String8 path; const InputDeviceIdentifier identifier; @@ -371,7 +379,11 @@ private: void close(); - inline bool isVirtual() const { return fd < 0; } + bool enabled; // initially true + status_t enable(); + status_t disable(); + bool hasValidFd(); + const bool isVirtual; // set if fd < 0 is passed to constructor const sp<KeyCharacterMap>& getKeyCharacterMap() const { if (combinedKeyMap != NULL) { @@ -390,6 +402,14 @@ private: void closeDeviceLocked(Device* device); void closeAllDevicesLocked(); + void configureFd(Device* device); + + bool isDeviceEnabled(int32_t deviceId); + status_t enableDevice(int32_t deviceId); + status_t disableDevice(int32_t deviceId); + status_t registerDeviceForEpollLocked(Device* device); + status_t unregisterDeviceFromEpollLocked(Device* device); + status_t scanDirLocked(const char *dirname); void scanDevicesLocked(); status_t readNotifyLocked(); @@ -409,7 +429,7 @@ private: int32_t getNextControllerNumberLocked(Device* device); void releaseControllerNumberLocked(Device* device); - void setLedForController(Device* device); + void setLedForControllerLocked(Device* device); status_t mapLed(Device* device, int32_t led, int32_t* outScanCode) const; void setLedStateLocked(Device* device, int32_t led, bool on); diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 2efb340eba..69067d225b 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -869,10 +869,7 @@ bool InputDispatcher::dispatchMotionLocked( return true; } - // TODO: support sending secondary display events to input monitors - if (isMainDisplay(entry->displayId)) { - addMonitoringTargetsLocked(inputTargets); - } + addMonitoringTargetsLocked(inputTargets); // Dispatch the motion. if (conflictingPointerActions) { @@ -2026,7 +2023,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, // Publish the motion event. status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, - motionEntry->deviceId, motionEntry->source, + motionEntry->deviceId, motionEntry->source, motionEntry->displayId, dispatchEntry->resolvedAction, motionEntry->actionButton, dispatchEntry->resolvedFlags, motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, @@ -2600,8 +2597,9 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ uint32_t policyFlags) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " - "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", - event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); + "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x, displayId=%d", + event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags, + displayId); #endif nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 73255dd292..cc81a298a2 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -835,6 +835,18 @@ void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { } } +bool InputReader::isInputDeviceEnabled(int32_t deviceId) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + return device->isEnabled(); + } + ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); + return false; +} + void InputReader::dump(String8& dump) { AutoMutex _l(mLock); @@ -1011,6 +1023,26 @@ InputDevice::~InputDevice() { mMappers.clear(); } +bool InputDevice::isEnabled() { + return getEventHub()->isDeviceEnabled(mId); +} + +void InputDevice::setEnabled(bool enabled, nsecs_t when) { + if (isEnabled() == enabled) { + return; + } + + if (enabled) { + getEventHub()->enableDevice(mId); + reset(when); + } else { + reset(when); + getEventHub()->disableDevice(mId); + } + // Must change generation to flag this device as changed + bumpGeneration(); +} + void InputDevice::dump(String8& dump) { InputDeviceInfo deviceInfo; getDeviceInfo(& deviceInfo); @@ -1082,6 +1114,12 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } } + if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) { + ssize_t index = config->disabledDevices.indexOf(mId); + bool enabled = index < 0; + setEnabled(enabled, when); + } + size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; @@ -2291,6 +2329,35 @@ bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); } +bool KeyboardInputMapper::isMediaKey(int32_t keyCode) { + switch (keyCode) { + case AKEYCODE_MEDIA_PLAY: + case AKEYCODE_MEDIA_PAUSE: + case AKEYCODE_MEDIA_PLAY_PAUSE: + case AKEYCODE_MUTE: + case AKEYCODE_HEADSETHOOK: + case AKEYCODE_MEDIA_STOP: + case AKEYCODE_MEDIA_NEXT: + case AKEYCODE_MEDIA_PREVIOUS: + case AKEYCODE_MEDIA_REWIND: + case AKEYCODE_MEDIA_RECORD: + case AKEYCODE_MEDIA_FAST_FORWARD: + case AKEYCODE_MEDIA_SKIP_FORWARD: + case AKEYCODE_MEDIA_SKIP_BACKWARD: + case AKEYCODE_MEDIA_STEP_FORWARD: + case AKEYCODE_MEDIA_STEP_BACKWARD: + case AKEYCODE_MEDIA_AUDIO_TRACK: + case AKEYCODE_VOLUME_UP: + case AKEYCODE_VOLUME_DOWN: + case AKEYCODE_VOLUME_MUTE: + case AKEYCODE_TV_AUDIO_DESCRIPTION: + case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP: + case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN: + return true; + } + return false; +} + void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) { int32_t keyCode; @@ -2364,7 +2431,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, // For internal keyboards, the key layout file should specify the policy flags for // each wake key individually. // TODO: Use the input device configuration to control this behavior more finely. - if (down && getDevice()->isExternal()) { + if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) { policyFlags |= POLICY_FLAG_WAKE; } diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index edb6fcc284..c4f786ad0e 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -27,11 +27,14 @@ #include <input/VelocityTracker.h> #include <ui/DisplayInfo.h> #include <utils/KeyedVector.h> -#include <utils/threads.h> +#include <utils/Condition.h> +#include <utils/Thread.h> +#include <utils/Mutex.h> #include <utils/Timers.h> #include <utils/RefBase.h> #include <utils/String8.h> #include <utils/BitSet.h> +#include <utils/SortedVector.h> #include <stddef.h> #include <unistd.h> @@ -84,6 +87,9 @@ struct InputReaderConfiguration { // The pointer capture mode has changed. CHANGE_POINTER_CAPTURE = 1 << 8, + // The set of disabled input devices (disabledDevices) has changed. + CHANGE_ENABLED_STATE = 1 << 9, + // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, }; @@ -174,6 +180,9 @@ struct InputReaderConfiguration { // True if pointer capture is enabled. bool pointerCapture; + // The set of currently disabled input devices. + SortedVector<int32_t> disabledDevices; + InputReaderConfiguration() : virtualKeyQuietTime(0), pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f), @@ -288,6 +297,9 @@ public: /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; + /* Returns true if the input device is enabled. */ + virtual bool isInputDeviceEnabled(int32_t deviceId) = 0; + /* Runs a single iteration of the processing loop. * Nominally reads and processes one incoming message from the EventHub. * @@ -407,6 +419,8 @@ public: virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices); + virtual bool isInputDeviceEnabled(int32_t deviceId); + virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode); virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, @@ -552,6 +566,9 @@ public: inline bool isIgnored() { return mMappers.isEmpty(); } + bool isEnabled(); + void setEnabled(bool enabled, nsecs_t when); + void dump(String8& dump); void addMapper(InputMapper* mapper); void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); @@ -1111,6 +1128,7 @@ private: void dumpParameters(String8& dump); bool isKeyboardOrGamepadKey(int32_t scanCode); + bool isMediaKey(int32_t keyCode); void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode); diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp index 5e82d75c94..b54752b08b 100644 --- a/services/inputflinger/InputWindow.cpp +++ b/services/inputflinger/InputWindow.cpp @@ -46,8 +46,10 @@ bool InputWindowInfo::isTrustedOverlay() const { || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_STATUS_BAR || layoutParamsType == TYPE_NAVIGATION_BAR + || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY - || layoutParamsType == TYPE_DOCK_DIVIDER; + || layoutParamsType == TYPE_DOCK_DIVIDER + || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY; } bool InputWindowInfo::supportsSplitTouch() const { diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h index 0ac868b1c5..610290b2e2 100644 --- a/services/inputflinger/InputWindow.h +++ b/services/inputflinger/InputWindow.h @@ -101,7 +101,9 @@ struct InputWindowInfo { TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19, TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20, TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21, + TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24, TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27, + TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32, TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34, LAST_SYSTEM_WINDOW = 2999, }; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index dcfe114203..76291a5786 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -16,6 +16,7 @@ #include "../InputReader.h" +#include <inttypes.h> #include <utils/List.h> #include <gtest/gtest.h> #include <math.h> @@ -159,6 +160,22 @@ public: mConfig.excludedDeviceNames.push(deviceName); } + void addDisabledDevice(int32_t deviceId) { + ssize_t index = mConfig.disabledDevices.indexOf(deviceId); + bool currentlyEnabled = index < 0; + if (currentlyEnabled) { + mConfig.disabledDevices.add(deviceId); + } + } + + void removeDisabledDevice(int32_t deviceId) { + ssize_t index = mConfig.disabledDevices.indexOf(deviceId); + bool currentlyEnabled = index < 0; + if (!currentlyEnabled) { + mConfig.disabledDevices.remove(deviceId); + } + } + void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) { mPointerControllers.add(deviceId, controller); } @@ -255,6 +272,11 @@ public: mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin()); } + void assertNotifyConfigurationChangedWasNotCalled() { + ASSERT_TRUE(mNotifyConfigurationChangedArgsQueue.empty()) + << "Expected notifyConfigurationChanged() to not have been called."; + } + void assertNotifyDeviceResetWasCalled( NotifyDeviceResetArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty()) @@ -265,6 +287,11 @@ public: mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin()); } + void assertNotifyDeviceResetWasNotCalled() { + ASSERT_TRUE(mNotifyDeviceResetArgsQueue.empty()) + << "Expected notifyDeviceReset() to not have been called."; + } + void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to have been called."; @@ -347,9 +374,20 @@ class FakeEventHub : public EventHubInterface { KeyedVector<int32_t, KeyInfo> keysByUsageCode; KeyedVector<int32_t, bool> leds; Vector<VirtualKeyDefinition> virtualKeys; + bool enabled; + + status_t enable() { + enabled = true; + return OK; + } + + status_t disable() { + enabled = false; + return OK; + } explicit Device(uint32_t classes) : - classes(classes) { + classes(classes), enabled(true) { } }; @@ -382,6 +420,43 @@ public: enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0); } + bool isDeviceEnabled(int32_t deviceId) { + Device* device = getDevice(deviceId); + if (device == NULL) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return false; + } + return device->enabled; + } + + status_t enableDevice(int32_t deviceId) { + status_t result; + Device* device = getDevice(deviceId); + if (device == NULL) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (device->enabled) { + ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId); + return OK; + } + result = device->enable(); + return result; + } + + status_t disableDevice(int32_t deviceId) { + Device* device = getDevice(deviceId); + if (device == NULL) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (!device->enabled) { + ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId); + return OK; + } + return device->disable(); + } + void finishDeviceScan() { enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); } @@ -1039,6 +1114,20 @@ protected: mFakeEventHub->assertQueueIsEmpty(); } + void disableDevice(int32_t deviceId, InputDevice* device) { + mFakePolicy->addDisabledDevice(deviceId); + configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE, device); + } + + void enableDevice(int32_t deviceId, InputDevice* device) { + mFakePolicy->removeDisabledDevice(deviceId); + configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE, device); + } + + void configureDevice(uint32_t changes, InputDevice* device) { + device->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes); + } + FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber, const String8& name, uint32_t classes, uint32_t sources, const PropertyMap* configuration) { @@ -1077,6 +1166,46 @@ TEST_F(InputReaderTest, GetInputDevices) { ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); } +TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { + constexpr int32_t deviceId = 1; + constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; + InputDevice* device = mReader->newDevice(deviceId, 0, String8("fake"), deviceClass); + // Must add at least one mapper or the device will be ignored! + FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD); + device->addMapper(mapper); + mReader->setNextDevice(device); + addDevice(deviceId, String8("fake"), deviceClass, NULL); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(NULL)); + + NotifyDeviceResetArgs resetArgs; + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); + ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); + ASSERT_EQ(deviceId, resetArgs.deviceId); + + ASSERT_EQ(device->isEnabled(), true); + disableDevice(deviceId, device); + mReader->loopOnce(); + + mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs); + ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); + ASSERT_EQ(deviceId, resetArgs.deviceId); + ASSERT_EQ(device->isEnabled(), false); + + disableDevice(deviceId, device); + mReader->loopOnce(); + mFakeListener->assertNotifyDeviceResetWasNotCalled(); + mFakeListener->assertNotifyConfigurationChangedWasNotCalled(); + ASSERT_EQ(device->isEnabled(), false); + + enableDevice(deviceId, device); + mReader->loopOnce(); + mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs); + ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); + ASSERT_EQ(deviceId, resetArgs.deviceId); + ASSERT_EQ(device->isEnabled(), true); +} + TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), @@ -1274,6 +1403,10 @@ TEST_F(InputDeviceTest, ImmutableProperties) { ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses()); } +TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsTrue) { + ASSERT_EQ(mDevice->isEnabled(), true); +} + TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { // Configuration. InputReaderConfiguration config; diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index 8c2300e9d0..8d381b1c31 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -1,3 +1,73 @@ subdirs = [ "hidl" ] +cc_library_shared { + name: "libsensorservice", + + srcs: [ + "BatteryService.cpp", + "CorrectedGyroSensor.cpp", + "Fusion.cpp", + "GravitySensor.cpp", + "LinearAccelerationSensor.cpp", + "OrientationSensor.cpp", + "RecentEventLogger.cpp", + "RotationVectorSensor.cpp", + "SensorDevice.cpp", + "SensorDirectConnection.cpp", + "SensorEventConnection.cpp", + "SensorFusion.cpp", + "SensorInterface.cpp", + "SensorList.cpp", + "SensorRecord.cpp", + "SensorService.cpp", + "SensorServiceUtils.cpp", + ], + + cflags: [ + "-DLOG_TAG=\"SensorService\"", + "-Wall", + "-Werror", + "-Wextra", + "-fvisibility=hidden" + ], + + shared_libs: [ + "libcutils", + "libhardware", + "libhardware_legacy", + "libutils", + "liblog", + "libbinder", + "libsensor", + "libcrypto", + "libbase", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "android.hardware.sensors@1.0", + ], + + static_libs: ["android.hardware.sensors@1.0-convert"], + + // our public headers depend on libsensor + export_shared_lib_headers: ["libsensor"], +} + +cc_binary { + name: "sensorservice", + + srcs: ["main_sensorservice.cpp"], + + shared_libs: [ + "libsensorservice", + "libbinder", + "libutils", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], +} diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk deleted file mode 100644 index cfb72310d5..0000000000 --- a/services/sensorservice/Android.mk +++ /dev/null @@ -1,73 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - BatteryService.cpp \ - CorrectedGyroSensor.cpp \ - Fusion.cpp \ - GravitySensor.cpp \ - LinearAccelerationSensor.cpp \ - OrientationSensor.cpp \ - RecentEventLogger.cpp \ - RotationVectorSensor.cpp \ - SensorDevice.cpp \ - SensorDirectConnection.cpp \ - SensorEventConnection.cpp \ - SensorFusion.cpp \ - SensorInterface.cpp \ - SensorList.cpp \ - SensorRecord.cpp \ - SensorService.cpp \ - SensorServiceUtils.cpp \ - -LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\" - -LOCAL_CFLAGS += -Wall -Werror -Wextra - -LOCAL_CFLAGS += -fvisibility=hidden - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libhardware \ - libhardware_legacy \ - libutils \ - liblog \ - libbinder \ - libsensor \ - libcrypto \ - libbase \ - libhidlbase \ - libhidltransport \ - libhwbinder \ - android.hardware.sensors@1.0 - -LOCAL_STATIC_LIBRARIES := \ - android.hardware.sensors@1.0-convert - -# our public headers depend on libsensor -LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ - libsensor \ - -LOCAL_MODULE:= libsensorservice - -include $(BUILD_SHARED_LIBRARY) - -##################################################################### -# build executable -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - main_sensorservice.cpp - -LOCAL_SHARED_LIBRARIES := \ - libsensorservice \ - libbinder \ - libutils - -LOCAL_CFLAGS := -Wall -Werror -Wextra - -LOCAL_MODULE_TAGS := optional - -LOCAL_MODULE:= sensorservice - -include $(BUILD_EXECUTABLE) diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp index 870635bf05..538d72822e 100644 --- a/services/sensorservice/SensorDirectConnection.cpp +++ b/services/sensorservice/SensorDirectConnection.cpp @@ -27,12 +27,21 @@ SensorService::SensorDirectConnection::SensorDirectConnection(const sp<SensorSer const String16& opPackageName) : mService(service), mUid(uid), mMem(*mem), mHalChannelHandle(halChannelHandle), - mOpPackageName(opPackageName) { + mOpPackageName(opPackageName), mDestroyed(false) { ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection"); } SensorService::SensorDirectConnection::~SensorDirectConnection() { ALOGD_IF(DEBUG_CONNECTIONS, "~SensorDirectConnection %p", this); + destroy(); +} + +void SensorService::SensorDirectConnection::destroy() { + Mutex::Autolock _l(mDestroyLock); + // destroy once only + if (mDestroyed) { + return; + } stopAll(); mService->cleanupConnection(this); @@ -40,6 +49,7 @@ SensorService::SensorDirectConnection::~SensorDirectConnection() { native_handle_close(mMem.handle); native_handle_delete(const_cast<struct native_handle*>(mMem.handle)); } + mDestroyed = true; } void SensorService::SensorDirectConnection::onFirstRef() { diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h index 27458d4a2f..5c398a8caa 100644 --- a/services/sensorservice/SensorDirectConnection.h +++ b/services/sensorservice/SensorDirectConnection.h @@ -47,7 +47,7 @@ public: // stop all active sensor report. if backupRecord is set to false, // those report can be recovered by recoverAll // called by SensorService when enter restricted mode - void stopAll(bool clearRecord = false); + void stopAll(bool backupRecord = false); // recover sensor reports previously stopped by stopAll(true) // called by SensorService when return to NORMAL mode. @@ -63,7 +63,7 @@ protected: virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs); virtual status_t flush(); virtual int32_t configureChannel(int handle, int rateLevel); - + virtual void destroy(); private: const sp<SensorService> mService; const uid_t mUid; @@ -74,6 +74,9 @@ private: mutable Mutex mConnectionLock; std::unordered_map<int, int> mActivated; std::unordered_map<int, int> mActivatedBackup; + + mutable Mutex mDestroyLock; + bool mDestroyed; }; } // namepsace android diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp index fad046cf53..0a05dd1b18 100644 --- a/services/sensorservice/SensorEventConnection.cpp +++ b/services/sensorservice/SensorEventConnection.cpp @@ -32,7 +32,8 @@ SensorService::SensorEventConnection::SensorEventConnection( const String16& opPackageName) : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false), mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL), - mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) { + mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName), + mDestroyed(false) { mChannel = new BitTube(mService->mSocketBufferSize); #if DEBUG_CONNECTIONS mEventsReceived = mEventsSentFromCache = mEventsSent = 0; @@ -42,10 +43,22 @@ SensorService::SensorEventConnection::SensorEventConnection( SensorService::SensorEventConnection::~SensorEventConnection() { ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this); + destroy(); +} + +void SensorService::SensorEventConnection::destroy() { + Mutex::Autolock _l(mDestroyLock); + + // destroy once only + if (mDestroyed) { + return; + } + mService->cleanupConnection(this); if (mEventCache != NULL) { delete mEventCache; } + mDestroyed = true; } void SensorService::SensorEventConnection::onFirstRef() { @@ -477,7 +490,14 @@ void SensorService::SensorEventConnection::countFlushCompleteEventsLocked( // separately before the next batch of events. for (int j = 0; j < numEventsDropped; ++j) { if (scratch[j].type == SENSOR_TYPE_META_DATA) { - FlushInfo& flushInfo = mSensorInfo.editValueFor(scratch[j].meta_data.sensor); + ssize_t index = mSensorInfo.indexOfKey(scratch[j].meta_data.sensor); + if (index < 0) { + ALOGW("%s: sensor 0x%x is not found in connection", + __func__, scratch[j].meta_data.sensor); + continue; + } + + FlushInfo& flushInfo = mSensorInfo.editValueAt(index); flushInfo.mPendingFlushEventsToSend++; ALOGD_IF(DEBUG_CONNECTIONS, "increment pendingFlushCount %d", flushInfo.mPendingFlushEventsToSend); diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h index c81e015dbe..6f282cdc60 100644 --- a/services/sensorservice/SensorEventConnection.h +++ b/services/sensorservice/SensorEventConnection.h @@ -75,6 +75,7 @@ private: virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs); virtual status_t flush(); virtual int32_t configureChannel(int handle, int rateLevel); + virtual void destroy(); // Count the number of flush complete events which are about to be dropped in the buffer. // Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be sent @@ -164,6 +165,8 @@ private: int mTotalAcksNeeded, mTotalAcksReceived; #endif + mutable Mutex mDestroyLock; + bool mDestroyed; }; } // namepsace android diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp index ab08cac2c8..aa306d885e 100644 --- a/services/sensorservice/SensorList.cpp +++ b/services/sensorservice/SensorList.cpp @@ -124,14 +124,15 @@ std::string SensorList::dump() const { forEachSensor([&result] (const Sensor& s) -> bool { result.appendFormat( "%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32 - ") | perm: %s\n", + ") | perm: %s | flags: 0x%08x\n", s.getHandle(), s.getName().string(), s.getVendor().string(), s.getVersion(), s.getStringType().string(), s.getType(), - s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a"); + s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a", + static_cast<int>(s.getFlags())); result.append("\t"); const int reportingMode = s.getReportingMode(); @@ -173,9 +174,14 @@ std::string SensorList::dump() const { result.appendFormat("non-wakeUp | "); } + if (s.isDataInjectionSupported()) { + result.appendFormat("data-injection, "); + } + if (s.isDynamicSensor()) { result.appendFormat("dynamic, "); } + if (s.hasAdditionalInfo()) { result.appendFormat("has-additional-info, "); } @@ -190,7 +196,6 @@ std::string SensorList::dump() const { if (s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_GRALLOC)) { result.append("gralloc, "); } - result.appendFormat("flag =0x%08x", static_cast<int>(s.getFlags())); result.append("\n"); } return true; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index d60768c98d..62c2756d2f 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -394,6 +394,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { } } else if (!mSensors.hasAnySensor()) { result.append("No Sensors on the device\n"); + result.appendFormat("devInitCheck : %d\n", SensorDevice::getInstance().initCheck()); } else { // Default dump the sensor list and debugging information. // @@ -1032,17 +1033,16 @@ sp<ISensorEventConnection> SensorService::createSensorDirectConnection( } int SensorService::setOperationParameter( - int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) { + int32_t handle, int32_t type, + const Vector<float> &floats, const Vector<int32_t> &ints) { Mutex::Autolock _l(mLock); - // check permission - int32_t uid; - bool hasPermission = checkCallingPermission(sLocationHardwarePermission, nullptr, &uid); - if (!hasPermission || (uid != 1000 && uid != 0)) { + if (!checkCallingPermission(sLocationHardwarePermission, nullptr, nullptr)) { return PERMISSION_DENIED; } bool isFloat = true; + bool isCustom = false; size_t expectSize = INT32_MAX; switch (type) { case AINFO_LOCAL_GEOMAGNETIC_FIELD: @@ -1060,7 +1060,21 @@ int SensorService::setOperationParameter( expectSize = 1; break; default: - return BAD_VALUE; + // CUSTOM events must only contain float data; it may have variable size + if (type < AINFO_CUSTOM_START || type >= AINFO_DEBUGGING_START || + ints.size() || + sizeof(additional_info_event_t::data_float)/sizeof(float) < floats.size() || + handle < 0) { + return BAD_VALUE; + } + isFloat = true; + isCustom = true; + expectSize = floats.size(); + break; + } + + if (!isCustom && handle != -1) { + return BAD_VALUE; } // three events: first one is begin tag, last one is end tag, the one in the middle @@ -1070,7 +1084,7 @@ int SensorService::setOperationParameter( for (sensors_event_t* i = event; i < event + 3; i++) { *i = (sensors_event_t) { .version = sizeof(sensors_event_t), - .sensor = SENSORS_HANDLE_BASE - 1, // sensor that never exists + .sensor = handle, .type = SENSOR_TYPE_ADDITIONAL_INFO, .timestamp = timestamp++, .additional_info = (additional_info_event_t) { diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 2a9d6e86ba..3e183942ff 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -159,7 +159,7 @@ private: virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName, uint32_t size, int32_t type, int32_t format, const native_handle *resource); virtual int setOperationParameter( - int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints); + int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints); virtual status_t dump(int fd, const Vector<String16>& args); String8 getSensorName(int handle) const; diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp index 25a3dc50d2..cf5ab05082 100644 --- a/services/sensorservice/hidl/SensorManager.cpp +++ b/services/sensorservice/hidl/SensorManager.cpp @@ -24,7 +24,6 @@ #include <sched.h> -#include <thread> #include "EventQueue.h" #include "DirectReportChannel.h" @@ -40,20 +39,24 @@ using ::android::hardware::sensors::V1_0::SensorInfo; using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset; using ::android::hardware::hidl_vec; using ::android::hardware::Void; -using ::android::sp; static const char* POLL_THREAD_NAME = "hidl_ssvc_poll"; SensorManager::SensorManager(JavaVM* vm) - : mJavaVm(vm) { + : mLooper(new Looper(false /*allowNonCallbacks*/)), mStopThread(true), mJavaVm(vm) { } SensorManager::~SensorManager() { // Stops pollAll inside the thread. - std::unique_lock<std::mutex> lock(mLooperMutex); + std::lock_guard<std::mutex> lock(mThreadMutex); + + mStopThread = true; if (mLooper != nullptr) { mLooper->wake(); } + if (mPollThread.joinable()) { + mPollThread.join(); + } } // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow. @@ -128,12 +131,13 @@ Return<void> SensorManager::createGrallocDirectChannel( } /* One global looper for all event queues created from this SensorManager. */ -sp<::android::Looper> SensorManager::getLooper() { - std::unique_lock<std::mutex> lock(mLooperMutex); - if (mLooper == nullptr) { - std::condition_variable looperSet; +sp<Looper> SensorManager::getLooper() { + std::lock_guard<std::mutex> lock(mThreadMutex); - std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet, javaVm = mJavaVm] { + if (!mPollThread.joinable()) { + // if thread not initialized, start thread + mStopThread = false; + std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] { struct sched_param p = {0}; p.sched_priority = 10; @@ -142,16 +146,11 @@ sp<::android::Looper> SensorManager::getLooper() { << strerror(errno); } - std::unique_lock<std::mutex> lock(mutex); - if (looper != nullptr) { - LOG(INFO) << "Another thread has already set the looper, exiting this one."; - return; - } - looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */); - lock.unlock(); + // set looper + Looper::setForThread(looper); - // Attach the thread to JavaVM so that pollAll do not crash if the event - // is from Java. + // Attach the thread to JavaVM so that pollAll do not crash if the thread + // eventually calls into Java. JavaVMAttachArgs args{ .version = JNI_VERSION_1_2, .name = POLL_THREAD_NAME, @@ -162,19 +161,30 @@ sp<::android::Looper> SensorManager::getLooper() { LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM."; } - looperSet.notify_one(); - int pollResult = looper->pollAll(-1 /* timeout */); - if (pollResult != ALOOPER_POLL_WAKE) { - LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult; + LOG(INFO) << POLL_THREAD_NAME << " started."; + for (;;) { + int pollResult = looper->pollAll(-1 /* timeout */); + if (pollResult == Looper::POLL_WAKE) { + if (stopThread == true) { + LOG(INFO) << POLL_THREAD_NAME << ": requested to stop"; + break; + } else { + LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work"; + } + } else { + LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected " + << pollResult; + break; + } } if (javaVm->DetachCurrentThread() != JNI_OK) { LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM."; } - LOG(INFO) << "Looper thread is terminated."; - }}.detach(); - looperSet.wait(lock, [this]{ return this->mLooper != nullptr; }); + LOG(INFO) << POLL_THREAD_NAME << " is terminated."; + }}; + mPollThread = std::move(pollThread); } return mLooper; } @@ -196,6 +206,12 @@ Return<void> SensorManager::createEventQueue( } sp<::android::Looper> looper = getLooper(); + if (looper == nullptr) { + LOG(ERROR) << "::android::SensorManager::createEventQueue cannot initialize looper"; + _hidl_cb(nullptr, Result::UNKNOWN_ERROR); + return Void(); + } + sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(); if (internalQueue == nullptr) { LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr."; diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h index e66c8e5d22..ddcee288e1 100644 --- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h +++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h @@ -20,6 +20,7 @@ #include <jni.h> #include <mutex> +#include <thread> #include <android/frameworks/sensorservice/1.0/ISensorManager.h> #include <android/frameworks/sensorservice/1.0/types.h> @@ -38,6 +39,7 @@ using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_memory; using ::android::hardware::Return; +using ::android::sp; struct SensorManager final : public ISensorManager { @@ -54,13 +56,15 @@ struct SensorManager final : public ISensorManager { private: // Block until ::android::SensorManager is initialized. ::android::SensorManager& getInternalManager(); - sp<::android::Looper> getLooper(); + sp<Looper> getLooper(); std::mutex mInternalManagerMutex; ::android::SensorManager* mInternalManager = nullptr; // does not own + sp<Looper> mLooper; - std::mutex mLooperMutex; - sp<::android::Looper> mLooper; + volatile bool mStopThread; + std::mutex mThreadMutex; //protects mPollThread + std::thread mPollThread; JavaVM* mJavaVm; }; diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 95a522d11c..38529b6d0a 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -9,7 +9,7 @@ LOCAL_SRC_FILES := \ DisplayDevice.cpp \ DispSync.cpp \ EventControlThread.cpp \ - StartBootAnimThread.cpp \ + StartPropertySetThread.cpp \ EventThread.cpp \ FrameTracker.cpp \ GpuService.cpp \ @@ -104,7 +104,7 @@ LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ libhidltransport \ libhwbinder -LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code +LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -std=c++1z include $(BUILD_SHARED_LIBRARY) diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp index bd9b8aafcd..ea048397d0 100644 --- a/services/surfaceflinger/DispSync.cpp +++ b/services/surfaceflinger/DispSync.cpp @@ -377,11 +377,16 @@ private: DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0), - mThread(new DispSyncThread(name)), - mIgnorePresentFences(!SurfaceFlinger::hasSyncFramework){ + mThread(new DispSyncThread(name)) { +} + +DispSync::~DispSync() {} - mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset; +void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) { + mIgnorePresentFences = !hasSyncFramework; + mPresentTimeOffset = dispSyncPresentTimeOffset; mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); + // set DispSync to SCHED_FIFO to minimize jitter struct sched_param param = {0}; param.sched_priority = 2; @@ -389,7 +394,6 @@ DispSync::DispSync(const char* name) : ALOGE("Couldn't set SCHED_FIFO for DispSyncThread"); } - reset(); beginResync(); @@ -405,8 +409,6 @@ DispSync::DispSync(const char* name) : } } -DispSync::~DispSync() {} - void DispSync::reset() { Mutex::Autolock lock(mMutex); diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h index 82ae79590a..3c34fb08a4 100644 --- a/services/surfaceflinger/DispSync.h +++ b/services/surfaceflinger/DispSync.h @@ -55,6 +55,8 @@ public: explicit DispSync(const char* name); ~DispSync(); + void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset); + // reset clears the resync samples and error value. void reset(); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b5ffc60b55..fc60002334 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -121,7 +121,7 @@ DisplayDevice::DisplayDevice( ANativeWindow* const window = mNativeWindow.get(); #ifdef USE_HWC2 - mActiveColorMode = static_cast<android_color_mode_t>(-1); + mActiveColorMode = HAL_COLOR_MODE_NATIVE; mDisplayHasWideColor = supportWideColor; #else (void) supportWideColor; @@ -442,6 +442,11 @@ void DisplayDevice::setActiveColorMode(android_color_mode_t mode) { android_color_mode_t DisplayDevice::getActiveColorMode() const { return mActiveColorMode; } + +void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) { + ANativeWindow* const window = mNativeWindow.get(); + native_window_set_buffers_data_space(window, dataspace); +} #endif // ---------------------------------------------------------------------------- @@ -610,23 +615,25 @@ uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() { void DisplayDevice::dump(String8& result) const { const Transform& tr(mGlobalTransform); - result.appendFormat( - "+ DisplayDevice: %s\n" - " type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), " - "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n" - " v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d]," - "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n", - mDisplayName.string(), mType, mHwcDisplayId, - mLayerStack, mDisplayWidth, mDisplayHeight, mNativeWindow.get(), - mOrientation, tr.getType(), getPageFlipCount(), - mIsSecure, mPowerMode, mActiveConfig, - mVisibleLayersSortedByZ.size(), - mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, - mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, - mScissor.left, mScissor.top, mScissor.right, mScissor.bottom, - tr[0][0], tr[1][0], tr[2][0], - tr[0][1], tr[1][1], tr[2][1], - tr[0][2], tr[1][2], tr[2][2]); + EGLint redSize, greenSize, blueSize, alphaSize; + eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize); + eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize); + eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &blueSize); + eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &alphaSize); + result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string()); + result.appendFormat(" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p " + "(%d:%d:%d:%d), orient=%2d (type=%08x), " + "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n", + mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, + mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation, + tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, + mVisibleLayersSortedByZ.size()); + result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d]," + "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n", + mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, + mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, + mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], + tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]); String8 surfaceDump; mDisplaySurface->dumpAsString(surfaceDump); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index e2852a7c69..8636e2af79 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -141,6 +141,7 @@ public: uint32_t getLayerStack() const { return mLayerStack; } int32_t getDisplayType() const { return mType; } + bool isPrimary() const { return mType == DISPLAY_PRIMARY; } int32_t getHwcDisplayId() const { return mHwcDisplayId; } const wp<IBinder>& getDisplayToken() const { return mDisplayToken; } @@ -189,6 +190,7 @@ public: #ifdef USE_HWC2 android_color_mode_t getActiveColorMode() const; void setActiveColorMode(android_color_mode_t mode); + void setCompositionDataSpace(android_dataspace dataspace); #endif /* ------------------------------------------------------------------------ diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 9d16044395..e34fa163c4 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -181,6 +181,13 @@ Composer::Composer(bool useVrComposer) if (mClient == nullptr) { LOG_ALWAYS_FATAL("failed to create composer client"); } + + if (mIsUsingVrComposer) { + sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient); + if (vrClient == nullptr) { + LOG_ALWAYS_FATAL("failed to create vr composer client"); + } + } } std::vector<IComposer::Capability> Composer::getCapabilities() diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 5b869e12c7..68d7a18d3a 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -106,12 +106,6 @@ status_t FramebufferSurface::advanceFrame() { if (result != NO_ERROR) { ALOGE("error latching next FramebufferSurface buffer: %s (%d)", strerror(-result), result); - return result; - } - result = mHwc.setClientTarget(mDisplayType, slot, - acquireFence, buf, dataspace); - if (result != NO_ERROR) { - ALOGE("error posting framebuffer: %d", result); } return result; #else @@ -182,7 +176,13 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& #else outBuffer = mCurrentBuffer; #endif - return NO_ERROR; + status_t result = + mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace); + if (result != NO_ERROR) { + ALOGE("error posting framebuffer: %d", result); + } + + return result; } #ifndef USE_HWC2 diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index c48a28f694..270a73228b 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -884,6 +884,10 @@ Error Layer::setCompositionType(Composition type) Error Layer::setDataspace(android_dataspace_t dataspace) { + if (dataspace == mDataSpace) { + return Error::None; + } + mDataSpace = dataspace; auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace); auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId, mId, intDataspace); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 7463e3b76f..404bb284c5 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -338,6 +338,7 @@ private: hwc2_display_t mDisplayId; Device& mDevice; hwc2_layer_t mId; + android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; }; } // namespace HWC2 diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 8217540215..c129ae546c 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -16,12 +16,16 @@ // #define LOG_NDEBUG 0 #include "VirtualDisplaySurface.h" + +#include <inttypes.h> + #include "HWComposer.h" #include "SurfaceFlinger.h" #include <gui/BufferItem.h> #include <gui/BufferQueue.h> #include <gui/IProducerListener.h> +#include <system/window.h> // --------------------------------------------------------------------------- namespace android { @@ -338,7 +342,7 @@ status_t VirtualDisplaySurface::setAsyncMode(bool async) { } status_t VirtualDisplaySurface::dequeueBuffer(Source source, - PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence) { + PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) { LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId); status_t result = mSource[source]->dequeueBuffer(sslot, fence, @@ -371,7 +375,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, mSource[source]->cancelBuffer(*sslot, *fence); return result; } - VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x", + VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64, dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(), mProducerBuffers[pslot]->getPixelFormat(), mProducerBuffers[pslot]->getUsage()); @@ -381,7 +385,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, } status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, - uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, + uint32_t w, uint32_t h, PixelFormat format, uint64_t usage, FrameEventHistoryDelta* outTimestamps) { if (mDisplayId < 0) { return mSource[SOURCE_SINK]->dequeueBuffer( @@ -392,7 +396,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, "Unexpected dequeueBuffer() in %s state", dbgStateStr()); mDbgState = DBG_STATE_GLES; - VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage); + VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#" PRIx64, w, h, format, usage); status_t result = NO_ERROR; Source source = fbSourceForCompositionType(mCompositionType); @@ -422,8 +426,8 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, (w != 0 && w != mSinkBufferWidth) || (h != 0 && h != mSinkBufferHeight)) { VDS_LOGV("dequeueBuffer: dequeueing new output buffer: " - "want %dx%d fmt=%d use=%#x, " - "have %dx%d fmt=%d use=%#x", + "want %dx%d fmt=%d use=%#" PRIx64 ", " + "have %dx%d fmt=%d use=%#" PRIx64, w, h, format, usage, mSinkBufferWidth, mSinkBufferHeight, buf->getPixelFormat(), buf->getUsage()); @@ -574,7 +578,7 @@ status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stre } void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */, - uint32_t /* height */, PixelFormat /* format */, uint32_t /* usage */) { + uint32_t /* height */, PixelFormat /* format */, uint64_t /* usage */) { // TODO: Should we actually allocate buffers for a virtual display? } diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 5c0e084fb9..7f8b39b62b 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -105,7 +105,7 @@ private: virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, - uint32_t h, PixelFormat format, uint32_t usage, + uint32_t h, PixelFormat format, uint64_t usage, FrameEventHistoryDelta *outTimestamps); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, @@ -120,7 +120,7 @@ private: virtual status_t disconnect(int api, DisconnectMode mode); virtual status_t setSidebandStream(const sp<NativeHandle>& stream); virtual void allocateBuffers(uint32_t width, uint32_t height, - PixelFormat format, uint32_t usage); + PixelFormat format, uint64_t usage); virtual status_t allowAllocation(bool allow); virtual status_t setGenerationNumber(uint32_t generationNumber); virtual String8 getConsumerName() const override; @@ -135,7 +135,7 @@ private: // Utility methods // static Source fbSourceForCompositionType(CompositionType type); - status_t dequeueBuffer(Source source, PixelFormat format, uint32_t usage, + status_t dequeueBuffer(Source source, PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence); void updateQueueBufferOutput(QueueBufferOutput&& qbo); void resetPerFrameState(); @@ -168,7 +168,7 @@ private: // the composition type changes or the GLES driver starts requesting // different usage/format, we'll get a new buffer. uint32_t mOutputFormat; - uint32_t mOutputUsage; + uint64_t mOutputUsage; // Since we present a single producer interface to the GLES driver, but // are internally muxing between the sink and scratch producers, we have diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b4d6dcaff9..1b864fd2d8 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -34,6 +34,7 @@ #include <utils/StopWatch.h> #include <utils/Trace.h> +#include <ui/DebugUtils.h> #include <ui/GraphicBuffer.h> #include <ui/PixelFormat.h> @@ -125,6 +126,7 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mPremultipliedAlpha = false; mName = name; + mTransactionName = String8("TX - ") + mName; mCurrentState.active.w = w; mCurrentState.active.h = h; @@ -472,7 +474,7 @@ Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& hw) const { Rect activeCrop(s.active.w, s.active.h); if (!s.crop.isEmpty()) { - activeCrop = s.crop; + activeCrop.intersect(s.crop, &activeCrop); } Transform t = getTransform(); @@ -893,9 +895,6 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) { } } -android_dataspace Layer::getDataSpace() const { - return mCurrentState.dataSpace; -} #else void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer) { @@ -1505,6 +1504,7 @@ void Layer::pushPendingState() { mFlinger->setTransactionFlags(eTraversalNeeded); } mPendingStates.push_back(mCurrentState); + ATRACE_INT(mTransactionName.string(), mPendingStates.size()); } void Layer::popPendingState(State* stateToCommit) { @@ -1514,6 +1514,7 @@ void Layer::popPendingState(State* stateToCommit) { (stateToCommit->flags & stateToCommit->mask); mPendingStates.removeAt(0); + ATRACE_INT(mTransactionName.string(), mPendingStates.size()); } bool Layer::applyPendingStates(State* stateToCommit) { @@ -1928,6 +1929,10 @@ bool Layer::setDataSpace(android_dataspace dataSpace) { return true; } +android_dataspace Layer::getDataSpace() const { + return mCurrentState.dataSpace; +} + uint32_t Layer::getLayerStack() const { auto p = mDrawingParent.promote(); if (p == nullptr) { @@ -1947,7 +1952,6 @@ void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer, mCurrentState.barrierLayer = nullptr; mCurrentState.frameNumber = 0; mCurrentState.modified = false; - ALOGE("Deferred transaction"); } void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle, @@ -2373,11 +2377,17 @@ void Layer::dump(String8& result, Colorizer& colorizer) const visibleRegion.dump(result, "visibleRegion"); surfaceDamageRegion.dump(result, "surfaceDamageRegion"); sp<Client> client(mClientRef.promote()); + PixelFormat pf = PIXEL_FORMAT_UNKNOWN; + const sp<GraphicBuffer>& buffer(getActiveBuffer()); + if (buffer != NULL) { + pf = buffer->getPixelFormat(); + } result.appendFormat( " " "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), " "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, invalidate=%1d, " + "dataspace=%s, pixelformat=%s " #ifdef USE_HWC2 "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" #else @@ -2392,6 +2402,7 @@ void Layer::dump(String8& result, Colorizer& colorizer) const s.finalCrop.left, s.finalCrop.top, s.finalCrop.right, s.finalCrop.bottom, isOpaque(s), contentDirty, + dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(), s.alpha, s.flags, s.active.transform[0][0], s.active.transform[0][1], s.active.transform[1][0], s.active.transform[1][1], @@ -2683,7 +2694,7 @@ Transform Layer::getTransform() const { // for in the transform. We need to mirror this scaling in child surfaces // or we will break the contract where WM can treat child surfaces as // pixels in the parent surface. - if (p->isFixedSize()) { + if (p->isFixedSize() && p->mActiveBuffer != nullptr) { int bufferWidth; int bufferHeight; if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 24fc10dd2b..2306d1a43a 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -166,6 +166,8 @@ public: virtual ~Layer(); + void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; } + // the this layer's size and format status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); @@ -231,6 +233,7 @@ public: bool setFlags(uint8_t flags, uint8_t mask); bool setLayerStack(uint32_t layerStack); bool setDataSpace(android_dataspace dataSpace); + android_dataspace getDataSpace() const; uint32_t getLayerStack() const; void deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber); void deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber); @@ -248,6 +251,10 @@ public: uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); + bool belongsToDisplay(uint32_t layerStack, bool isPrimaryDisplay) const { + return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay); + } + void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, bool useIdentityTransform) const; Rect computeBounds(const Region& activeTransparentRegion) const; @@ -314,8 +321,6 @@ public: void forceClientComposition(int32_t hwcId); void setPerFrameData(const sp<const DisplayDevice>& displayDevice); - android_dataspace getDataSpace() const; - // callIntoHwc exists so we can update our local state and call // acceptDisplayChanges without unnecessarily updating the device's state void setCompositionType(int32_t hwcId, HWC2::Composition type, @@ -409,6 +414,7 @@ public: * to figure out if the content or size of a surface has changed. */ Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime); + bool isBufferLatched() const { return mRefreshPending; } bool isPotentialCursor() const { return mPotentialCursor;} @@ -698,8 +704,11 @@ private: uint32_t mTextureName; // from GLES bool mPremultipliedAlpha; String8 mName; + String8 mTransactionName; // A cached version of "TX - " + mName for systraces PixelFormat mFormat; + bool mPrimaryDisplayOnly = false; + // these are protected by an external lock State mCurrentState; State mDrawingState; diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp index 6e37b45819..e8646076a5 100644 --- a/services/surfaceflinger/LayerRejecter.cpp +++ b/services/surfaceflinger/LayerRejecter.cpp @@ -17,6 +17,7 @@ #include "LayerRejecter.h" #include <gui/BufferItem.h> +#include <system/window.h> #include "clz.h" diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h index 85a33c868c..14f50bbdce 100644 --- a/services/surfaceflinger/MessageQueue.h +++ b/services/surfaceflinger/MessageQueue.h @@ -30,6 +30,8 @@ #include "Barrier.h" +#include <functional> + namespace android { class IDisplayEventConnection; @@ -58,6 +60,21 @@ private: mutable Barrier barrier; }; +class LambdaMessage : public MessageBase { +public: + explicit LambdaMessage(std::function<void()> handler) + : MessageBase(), mHandler(std::move(handler)) {} + + bool handler() override { + mHandler(); + // This return value is no longer checked, so it's always safe to return true + return true; + } + +private: + const std::function<void()> mHandler; +}; + // --------------------------------------------------------------------------- class MessageQueue { diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index 2ba1b338dd..e717632c0f 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -69,7 +69,7 @@ status_t MonitoredProducer::setAsyncMode(bool async) { } status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, - uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, + uint32_t w, uint32_t h, PixelFormat format, uint64_t usage, FrameEventHistoryDelta* outTimestamps) { return mProducer->dequeueBuffer( slot, fence, w, h, format, usage, outTimestamps); @@ -116,7 +116,7 @@ status_t MonitoredProducer::setSidebandStream(const sp<NativeHandle>& stream) { } void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height, - PixelFormat format, uint32_t usage) { + PixelFormat format, uint64_t usage) { mProducer->allocateBuffers(width, height, format, usage); } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index a3ec29d711..58b9bc4e2e 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -40,7 +40,7 @@ public: virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, - uint32_t h, PixelFormat format, uint32_t usage, + uint32_t h, PixelFormat format, uint64_t usage, FrameEventHistoryDelta* outTimestamps); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, @@ -56,7 +56,7 @@ public: virtual status_t disconnect(int api, DisconnectMode mode); virtual status_t setSidebandStream(const sp<NativeHandle>& stream); virtual void allocateBuffers(uint32_t width, uint32_t height, - PixelFormat format, uint32_t usage); + PixelFormat format, uint64_t usage); virtual status_t allowAllocation(bool allow); virtual status_t setGenerationNumber(uint32_t generationNumber); virtual String8 getConsumerName() const override; diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp index 0dab872682..effd3191c8 100644 --- a/services/surfaceflinger/RenderEngine/Description.cpp +++ b/services/surfaceflinger/RenderEngine/Description.cpp @@ -26,8 +26,7 @@ namespace android { -Description::Description() : - mUniformsDirty(true) { +Description::Description() { mPlaneAlpha = 1.0f; mPremultipliedAlpha = false; mOpaque = true; @@ -41,28 +40,20 @@ Description::~Description() { } void Description::setPlaneAlpha(GLclampf planeAlpha) { - if (planeAlpha != mPlaneAlpha) { - mUniformsDirty = true; - mPlaneAlpha = planeAlpha; - } + mPlaneAlpha = planeAlpha; } void Description::setPremultipliedAlpha(bool premultipliedAlpha) { - if (premultipliedAlpha != mPremultipliedAlpha) { - mPremultipliedAlpha = premultipliedAlpha; - } + mPremultipliedAlpha = premultipliedAlpha; } void Description::setOpaque(bool opaque) { - if (opaque != mOpaque) { - mOpaque = opaque; - } + mOpaque = opaque; } void Description::setTexture(const Texture& texture) { mTexture = texture; mTextureEnabled = true; - mUniformsDirty = true; } void Description::disableTexture() { @@ -74,12 +65,10 @@ void Description::setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf mColor[1] = green; mColor[2] = blue; mColor[3] = alpha; - mUniformsDirty = true; } void Description::setProjectionMatrix(const mat4& mtx) { mProjectionMatrix = mtx; - mUniformsDirty = true; } void Description::setColorMatrix(const mat4& mtx) { @@ -92,5 +81,8 @@ const mat4& Description::getColorMatrix() const { return mColorMatrix; } +void Description::setWideGamut(bool wideGamut) { + mIsWideGamut = wideGamut; +} } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h index 8a3447c5a1..3beffdf9e1 100644 --- a/services/surfaceflinger/RenderEngine/Description.h +++ b/services/surfaceflinger/RenderEngine/Description.h @@ -54,6 +54,8 @@ class Description { bool mColorMatrixEnabled; mat4 mColorMatrix; + bool mIsWideGamut; + public: Description(); ~Description(); @@ -67,9 +69,7 @@ public: void setProjectionMatrix(const mat4& mtx); void setColorMatrix(const mat4& mtx); const mat4& getColorMatrix() const; - -private: - bool mUniformsDirty; + void setWideGamut(bool wideGamut); }; } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 04fe1824b4..37a530b33a 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -40,9 +40,7 @@ #include "Mesh.h" #include "Texture.h" -#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> -#include <configstore/Utils.h> - +#include <sstream> #include <fstream> // --------------------------------------------------------------------------- @@ -111,8 +109,10 @@ void writePPM(const char* basename, GLuint width, GLuint height) { namespace android { // --------------------------------------------------------------------------- -GLES20RenderEngine::GLES20RenderEngine() : - mVpWidth(0), mVpHeight(0) { +GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) : + mVpWidth(0), + mVpHeight(0), + mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); @@ -133,23 +133,16 @@ GLES20RenderEngine::GLES20RenderEngine() : //mColorBlindnessCorrection = M; #ifdef USE_HWC2 - // retrieve wide-color and hdr settings from configstore - using namespace android::hardware::configstore; - using namespace android::hardware::configstore::V1_0; - - mPlatformHasWideColor = - getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); if (mPlatformHasWideColor) { // Compute sRGB to DisplayP3 color transform // NOTE: For now, we are limiting wide-color support to // Display-P3 only. - mat3 srgbToP3 = ColorSpace::DisplayP3().getXYZtoRGB() * ColorSpace::sRGB().getRGBtoXYZ(); + mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform(); - // color transform needs to be transposed and expanded to 4x4 - // to be what the shader wants + // color transform needs to be expanded to 4x4 to be what the shader wants // mat has an initializer that expands mat3 to mat4, but // not an assignment operator - mat4 gamutTransform(transpose(srgbToP3)); + mat4 gamutTransform(srgbToP3); mSrgbToDisplayP3 = gamutTransform; } #endif @@ -392,6 +385,7 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { Description wideColorState = mState; if (mDataSpace != HAL_DATASPACE_DISPLAY_P3) { wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3); + wideColorState.setWideGamut(true); ALOGV("drawMesh: gamut transform applied"); } ProgramCache::getInstance().useProgram(wideColorState); diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index 19cbb60b17..eaf94af54c 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -59,7 +59,7 @@ class GLES20RenderEngine : public RenderEngine { virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName); public: - GLES20RenderEngine(); + GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag protected: virtual ~GLES20RenderEngine(); @@ -86,7 +86,6 @@ protected: android_dataspace mDataSpace = HAL_DATASPACE_V0_SRGB; // Indicate if wide-color mode is needed or not - bool mPlatformHasWideColor = false; bool mDisplayHasWideColor = false; bool mUseWideColor = false; uint64_t mWideColorFrameCount = 0; @@ -98,6 +97,8 @@ protected: int alpha); virtual void setupDimLayerBlending(int alpha); #endif + bool mPlatformHasWideColor = false; + virtual void setupLayerTexturing(const Texture& texture); virtual void setupLayerBlackedOut(); virtual void setupFillWithColor(float r, float g, float b, float a); diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index ba11259ac2..06b225299c 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -129,7 +129,9 @@ ProgramCache::Key ProgramCache::computeKey(const Description& description) { .set(Key::OPACITY_MASK, description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT) .set(Key::COLOR_MATRIX_MASK, - description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF); + description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF) + .set(Key::WIDE_GAMUT_MASK, + description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF); return needs; } @@ -175,6 +177,50 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { if (needs.hasColorMatrix()) { fs << "uniform mat4 colorMatrix;"; } + if (needs.hasColorMatrix()) { + // When in wide gamut mode, the color matrix will contain a color space + // conversion matrix that needs to be applied in linear space + // When not in wide gamut, we can simply no-op the transfer functions + // and let the shader compiler get rid of them + if (needs.isWideGamut()) { + fs << R"__SHADER__( + float OETF_sRGB(const float linear) { + return linear <= 0.0031308 ? + linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; + } + + vec3 OETF_sRGB(const vec3 linear) { + return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b)); + } + + vec3 OETF_scRGB(const vec3 linear) { + return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)); + } + + float EOTF_sRGB(float srgb) { + return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); + } + + vec3 EOTF_sRGB(const vec3 srgb) { + return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b)); + } + + vec3 EOTF_scRGB(const vec3 srgb) { + return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb)); + } + )__SHADER__"; + } else { + fs << R"__SHADER__( + vec3 OETF_scRGB(const vec3 linear) { + return linear; + } + + vec3 EOTF_scRGB(const vec3 srgb) { + return srgb; + } + )__SHADER__"; + } + } fs << "void main(void) {" << indent; if (needs.isTexturing()) { fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; @@ -197,13 +243,15 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { if (needs.hasColorMatrix()) { if (!needs.isOpaque() && needs.isPremultiplied()) { // un-premultiply if needed before linearization - fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;"; + // avoid divide by 0 by adding 0.5/256 to the alpha channel + fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);"; } - fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);"; - fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;"; + fs << "vec4 transformed = colorMatrix * vec4(EOTF_scRGB(gl_FragColor.rgb), 1);"; + // We assume the last row is always {0,0,0,1} and we skip the division by w + fs << "gl_FragColor.rgb = OETF_scRGB(transformed.rgb);"; if (!needs.isOpaque() && needs.isPremultiplied()) { // and re-premultiply if needed after gamma correction - fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;"; + fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);"; } } diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h index 1fa53d3379..5b0fbcd153 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.h +++ b/services/surfaceflinger/RenderEngine/ProgramCache.h @@ -69,6 +69,10 @@ public: COLOR_MATRIX_OFF = 0x00000000, COLOR_MATRIX_ON = 0x00000020, COLOR_MATRIX_MASK = 0x00000020, + + WIDE_GAMUT_OFF = 0x00000000, + WIDE_GAMUT_ON = 0x00000040, + WIDE_GAMUT_MASK = 0x00000040, }; inline Key() : mKey(0) { } @@ -97,10 +101,13 @@ public: inline bool hasColorMatrix() const { return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; } + inline bool isWideGamut() const { + return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON; + } // this is the definition of a friend function -- not a method of class Needs friend inline int strictly_order_type(const Key& lhs, const Key& rhs) { - return (lhs.mKey < rhs.mKey) ? 1 : 0; + return (lhs.mKey < rhs.mKey) ? 1 : 0; } }; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index 75642699c3..ac2d8b2aba 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -47,19 +47,23 @@ static bool findExtension(const char* exts, const char* name) { return false; } -RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) { +RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t featureFlags) { // EGL_ANDROIDX_no_config_context is an experimental extension with no // written specification. It will be replaced by something more formal. // SurfaceFlinger is using it to allow a single EGLContext to render to // both a 16-bit primary display framebuffer and a 32-bit virtual display // framebuffer. // + // EGL_KHR_no_config_context is official extension to allow creating a + // context that works with any surface of a display. + // // The code assumes that ES2 or later is available if this extension is // supported. EGLConfig config = EGL_NO_CONFIG; - if (!findExtension( - eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), - "EGL_ANDROIDX_no_config_context")) { + if (!findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), + "EGL_ANDROIDX_no_config_context") && + !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), + "EGL_KHR_no_config_context")) { config = chooseEglConfig(display, hwcFormat); } @@ -131,7 +135,7 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) { break; case GLES_VERSION_2_0: case GLES_VERSION_3_0: - engine = new GLES20RenderEngine(); + engine = new GLES20RenderEngine(featureFlags); break; } engine->setEGLHandles(config, ctxt); diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 8b031bc37b..56f582755e 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -59,7 +59,10 @@ protected: virtual ~RenderEngine() = 0; public: - static RenderEngine* create(EGLDisplay display, int hwcFormat); + enum FeatureFlag { + WIDE_COLOR_SUPPORT = 1 << 0 // Platform has a wide color display + }; + static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags); static EGLConfig chooseEglConfig(EGLDisplay display, int format); diff --git a/services/surfaceflinger/StartBootAnimThread.cpp b/services/surfaceflinger/StartPropertySetThread.cpp index c3f72967b9..db82772f42 100644 --- a/services/surfaceflinger/StartBootAnimThread.cpp +++ b/services/surfaceflinger/StartPropertySetThread.cpp @@ -15,20 +15,23 @@ */ #include <cutils/properties.h> -#include "StartBootAnimThread.h" +#include "StartPropertySetThread.h" namespace android { -StartBootAnimThread::StartBootAnimThread(): - Thread(false) { -} +StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue): + Thread(false), mTimestampPropertyValue(timestampPropertyValue) {} -status_t StartBootAnimThread::Start() { - return run("SurfaceFlinger::StartBootAnimThread", PRIORITY_NORMAL); +status_t StartPropertySetThread::Start() { + return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL); } -bool StartBootAnimThread::threadLoop() { +bool StartPropertySetThread::threadLoop() { + // Set property service.sf.present_timestamp, consumer need check its readiness + property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0"); + // Clear BootAnimation exit flag property_set("service.bootanim.exit", "0"); + // Start BootAnimation if not started property_set("ctl.start", "bootanim"); // Exit immediately return false; diff --git a/services/surfaceflinger/StartBootAnimThread.h b/services/surfaceflinger/StartPropertySetThread.h index dba2bee4a1..a64c21b21f 100644 --- a/services/surfaceflinger/StartBootAnimThread.h +++ b/services/surfaceflinger/StartPropertySetThread.h @@ -24,17 +24,21 @@ namespace android { -class StartBootAnimThread : public Thread { +class StartPropertySetThread : public Thread { // Boot animation is triggered via calls to "property_set()" which can block // if init's executing slow operation such as 'mount_all --late' (currently // happening 1/10th with fsck) concurrently. Running in a separate thread // allows to pursue the SurfaceFlinger's init process without blocking. // see b/34499826. +// Any property_set() will block during init stage so need to be offloaded +// to this thread. see b/63844978. public: - StartBootAnimThread(); + StartPropertySetThread(bool timestampPropertyValue); status_t Start(); private: virtual bool threadLoop(); + static constexpr const char* kTimestampProperty = "service.sf.present_timestamp"; + const bool mTimestampPropertyValue; }; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 29e7bd6792..8ed6686ebf 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -19,12 +19,14 @@ #include <stdint.h> #include <sys/types.h> +#include <algorithm> #include <errno.h> #include <math.h> #include <mutex> #include <dlfcn.h> #include <inttypes.h> #include <stdatomic.h> +#include <optional> #include <EGL/egl.h> @@ -193,6 +195,8 @@ SurfaceFlinger::SurfaceFlinger() hasWideColorDisplay = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); + mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset); + // debugging stuff... char value[PROPERTY_VALUE_MAX]; @@ -224,6 +228,11 @@ SurfaceFlinger::SurfaceFlinger() property_get("ro.sf.disable_triple_buffer", value, "1"); mLayerTripleBufferingDisabled = atoi(value); ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering"); + + // We should be reading 'persist.sys.sf.color_saturation' here + // but since /data may be encrypted, we need to wait until after vold + // comes online to attempt to read the property. The property is + // instead read after the boot animation } void SurfaceFlinger::onFirstRef() @@ -341,13 +350,12 @@ sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) { void SurfaceFlinger::bootFinished() { - if (mStartBootAnimThread->join() != NO_ERROR) { - ALOGE("Join StartBootAnimThread failed!"); + if (mStartPropertySetThread->join() != NO_ERROR) { + ALOGE("Join StartPropertySetThread failed!"); } const nsecs_t now = systemTime(); const nsecs_t duration = now - mBootTime; ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); - mBootFinished = true; // wait patiently for the window manager death const String16 name("window"); @@ -368,6 +376,11 @@ void SurfaceFlinger::bootFinished() const int LOGTAG_SF_STOP_BOOTANIM = 60110; LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); + + sp<LambdaMessage> readProperties = new LambdaMessage([&]() { + readPersistentProperties(); + }); + postMessageAsync(readProperties); } void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { @@ -526,6 +539,8 @@ private: sp<VSyncSource::Callback> mCallback; }; +// Do not call property_set on main thread which will be blocked by init +// Use StartPropertySetThread instead. void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); @@ -560,7 +575,8 @@ void SurfaceFlinger::init() { // Get a RenderEngine for the given display / config (can't fail) mRenderEngine = RenderEngine::create(mEGLDisplay, - HAL_PIXEL_FORMAT_RGBA_8888); + HAL_PIXEL_FORMAT_RGBA_8888, + hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0); } // Drop the state lock while we initialize the hardware composer. We drop @@ -574,14 +590,6 @@ void SurfaceFlinger::init() { Mutex::Autolock _l(mStateLock); - // Inform native graphics APIs whether the present timestamp is supported: - if (getHwComposer().hasCapability( - HWC2::Capability::PresentFenceIsNotReliable)) { - property_set(kTimestampProperty, "0"); - } else { - property_set(kTimestampProperty, "1"); - } - if (useVrFlinger) { auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) { ALOGI("VR request display mode: requestDisplay=%d", requestDisplay); @@ -616,21 +624,36 @@ void SurfaceFlinger::init() { mRenderEngine->primeCache(); - mStartBootAnimThread = new StartBootAnimThread(); - if (mStartBootAnimThread->Start() != NO_ERROR) { - ALOGE("Run StartBootAnimThread failed!"); + // Inform native graphics APIs whether the present timestamp is supported: + if (getHwComposer().hasCapability( + HWC2::Capability::PresentFenceIsNotReliable)) { + mStartPropertySetThread = new StartPropertySetThread(false); + } else { + mStartPropertySetThread = new StartPropertySetThread(true); + } + + if (mStartPropertySetThread->Start() != NO_ERROR) { + ALOGE("Run StartPropertySetThread failed!"); } ALOGV("Done initializing"); } +void SurfaceFlinger::readPersistentProperties() { + char value[PROPERTY_VALUE_MAX]; + + property_get("persist.sys.sf.color_saturation", value, "1.0"); + mSaturation = atof(value); + ALOGV("Saturation is set to %.2f", mSaturation); +} + void SurfaceFlinger::startBootAnim() { // Start boot animation service by setting a property mailbox // if property setting thread is already running, Start() will be just a NOP - mStartBootAnimThread->Start(); + mStartPropertySetThread->Start(); // Wait until property was set - if (mStartBootAnimThread->join() != NO_ERROR) { - ALOGE("Join StartBootAnimThread failed!"); + if (mStartPropertySetThread->join() != NO_ERROR) { + ALOGE("Join StartPropertySetThread failed!"); } } @@ -1048,6 +1071,7 @@ void SurfaceFlinger::signalLayerUpdate() { } void SurfaceFlinger::signalRefresh() { + mRefreshPending = true; mEventQueue.refresh(); } @@ -1195,6 +1219,7 @@ void SurfaceFlinger::createDefaultDisplayDevice() { defaultColorMode = HAL_COLOR_MODE_SRGB; } setActiveColorModeInternal(hw, defaultColorMode); + hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN); } void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) { @@ -1248,17 +1273,14 @@ void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) { enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); } -void SurfaceFlinger::clearHwcLayers(const LayerVector& layers) { - for (size_t i = 0; i < layers.size(); ++i) { - layers[i]->clearHwcLayers(); - } -} - // Note: it is assumed the caller holds |mStateLock| when this is called void SurfaceFlinger::resetHwcLocked() { disableHardwareVsync(true); clearHwcLayers(mDrawingState.layersSortedByZ); clearHwcLayers(mCurrentState.layersSortedByZ); + for (size_t disp = 0; disp < mDisplays.size(); ++disp) { + clearHwcLayers(mDisplays[disp]->getVisibleLayersSortedByZ()); + } // Clear the drawing state so that the logic inside of // handleTransactionLocked will fire. It will determine the delta between // mCurrentState and mDrawingState and re-apply all changes when we make the @@ -1318,11 +1340,21 @@ void SurfaceFlinger::updateVrFlinger() { // parts of this class rely on the primary display always being available. createDefaultDisplayDevice(); - // Reset the timing values to account for the period of the swapped in HWC - const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); - const nsecs_t period = activeConfig->getVsyncPeriod(); - mAnimFrameTracker.setDisplayRefreshPeriod(period); - setCompositorTimingSnapped(0, period, 0); + // Re-enable default display. + sp<LambdaMessage> requestMessage = new LambdaMessage([&]() { + sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])); + setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL); + + // Reset the timing values to account for the period of the swapped in HWC + const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY); + const nsecs_t period = activeConfig->getVsyncPeriod(); + mAnimFrameTracker.setDisplayRefreshPeriod(period); + + // Use phase of 0 since phase is not known. + // Use latency of 0, which will snap to the ideal latency. + setCompositorTimingSnapped(0, period, 0); + }); + postMessageAsync(requestMessage); android_atomic_or(1, &mRepaintEverything); setTransactionFlags(eDisplayTransactionNeeded); @@ -1383,6 +1415,8 @@ bool SurfaceFlinger::handleMessageInvalidate() { void SurfaceFlinger::handleMessageRefresh() { ATRACE_CALL(); + mRefreshPending = false; + nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC); preComposition(refreshStartTime); @@ -1644,12 +1678,11 @@ void SurfaceFlinger::rebuildLayerStacks() { const Transform& tr(displayDevice->getTransform()); const Rect bounds(displayDevice->getBounds()); if (displayDevice->isDisplayOn()) { - computeVisibleRegions( - displayDevice->getLayerStack(), dirtyRegion, - opaqueRegion); + computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion); mDrawingState.traverseInZOrder([&](Layer* layer) { - if (layer->getLayerStack() == displayDevice->getLayerStack()) { + if (layer->belongsToDisplay(displayDevice->getLayerStack(), + displayDevice->isPrimary())) { Region drawRegion(tr.transform( layer->visibleNonTransparentRegion)); drawRegion.andSelf(bounds); @@ -1679,9 +1712,25 @@ void SurfaceFlinger::rebuildLayerStacks() { } } +mat4 SurfaceFlinger::computeSaturationMatrix() const { + if (mSaturation == 1.0f) { + return mat4(); + } + + // Rec.709 luma coefficients + float3 luminance{0.213f, 0.715f, 0.072f}; + luminance *= 1.0f - mSaturation; + return mat4( + vec4{luminance.r + mSaturation, luminance.r, luminance.r, 0.0f}, + vec4{luminance.g, luminance.g + mSaturation, luminance.g, 0.0f}, + vec4{luminance.b, luminance.b, luminance.b + mSaturation, 0.0f}, + vec4{0.0f, 0.0f, 0.0f, 1.0f} + ); +} + // pickColorMode translates a given dataspace into the best available color mode. // Currently only support sRGB and Display-P3. -android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) { +android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const { switch (dataSpace) { // treat Unknown as regular SRGB buffer, since that's what the rest of the // system expects. @@ -1704,11 +1753,19 @@ android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) { } } -android_dataspace SurfaceFlinger::bestTargetDataSpace(android_dataspace a, android_dataspace b) { +android_dataspace SurfaceFlinger::bestTargetDataSpace( + android_dataspace a, android_dataspace b) const { // Only support sRGB and Display-P3 right now. if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) { return HAL_DATASPACE_DISPLAY_P3; } + if (a == HAL_DATASPACE_V0_SCRGB_LINEAR || b == HAL_DATASPACE_V0_SCRGB_LINEAR) { + return HAL_DATASPACE_DISPLAY_P3; + } + if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) { + return HAL_DATASPACE_DISPLAY_P3; + } + return HAL_DATASPACE_V0_SRGB; } @@ -1776,7 +1833,7 @@ void SurfaceFlinger::setUpHWComposer() { } - mat4 colorMatrix = mColorMatrix * mDaltonizer(); + mat4 colorMatrix = mColorMatrix * computeSaturationMatrix() * mDaltonizer(); // Set the per-frame data for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) { @@ -2142,7 +2199,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) disp.clear(); for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { sp<const DisplayDevice> hw(mDisplays[dpy]); - if (hw->getLayerStack() == currentlayerStack) { + if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) { if (disp == NULL) { disp = hw; } else { @@ -2191,7 +2248,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // TODO: we could cache the transformed region Region visibleReg; visibleReg.set(layer->computeScreenBounds()); - invalidateLayerStack(layer->getLayerStack(), visibleReg); + invalidateLayerStack(layer, visibleReg); } }); } @@ -2240,7 +2297,7 @@ void SurfaceFlinger::commitTransaction() mTransactionCV.broadcast(); } -void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack, +void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice, Region& outDirtyRegion, Region& outOpaqueRegion) { ATRACE_CALL(); @@ -2257,7 +2314,7 @@ void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack, const Layer::State& s(layer->getDrawingState()); // only consider the layers on the given layer stack - if (layer->getLayerStack() != layerStack) + if (!layer->belongsToDisplay(displayDevice->getLayerStack(), displayDevice->isPrimary())) return; /* @@ -2372,11 +2429,10 @@ void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack, outOpaqueRegion = aboveOpaqueLayers; } -void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack, - const Region& dirty) { +void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) { for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { const sp<DisplayDevice>& hw(mDisplays[dpy]); - if (hw->getLayerStack() == layerStack) { + if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) { hw->dirtyRegion.orSelf(dirty); } } @@ -2417,8 +2473,8 @@ bool SurfaceFlinger::handlePageFlip() for (auto& layer : mLayersWithQueuedFrames) { const Region dirty(layer->latchBuffer(visibleRegions, latchTime)); layer->useSurfaceDamage(); - invalidateLayerStack(layer->getLayerStack(), dirty); - if (!dirty.isEmpty()) { + invalidateLayerStack(layer, dirty); + if (layer->isBufferLatched()) { newDataLatched = true; } } @@ -2428,7 +2484,7 @@ bool SurfaceFlinger::handlePageFlip() // If we will need to wake up at some time in the future to deal with a // queued frame that shouldn't be displayed during this vsync period, wake // up during the next vsync period to check again. - if (frameQueued && mLayersWithQueuedFrames.empty()) { + if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) { signalLayerUpdate(); } @@ -2512,8 +2568,8 @@ bool SurfaceFlinger::doComposeSurfaces( ALOGV("hasClientComposition"); #ifdef USE_HWC2 - mRenderEngine->setColorMode(displayDevice->getActiveColorMode()); mRenderEngine->setWideColor(displayDevice->getWideColorSupport()); + mRenderEngine->setColorMode(displayDevice->getActiveColorMode()); #endif if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) { ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", @@ -2656,6 +2712,8 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, { Mutex::Autolock _l(mStateLock); if (mNumLayers >= MAX_LAYERS) { + ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers, + MAX_LAYERS); return NO_MEMORY; } if (parent == nullptr) { @@ -2792,10 +2850,12 @@ void SurfaceFlinger::setTransactionState( } } - // If a synchronous transaction is explicitly requested without any changes, - // force a transaction anyway. This can be used as a flush mechanism for - // previous async transactions. - if (transactionFlags == 0 && (flags & eSynchronous)) { + // If a synchronous transaction is explicitly requested without any changes, force a transaction + // anyway. This can be used as a flush mechanism for previous async transactions. + // Empty animation transaction can be used to simulate back-pressure, so also force a + // transaction for empty animation transactions. + if (transactionFlags == 0 && + ((flags & eSynchronous) || (flags & eAnimation))) { transactionFlags = eTransactionNeeded; } @@ -3037,6 +3097,13 @@ status_t SurfaceFlinger::createLayer( return result; } + // window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java + // TODO b/64227542 + if (windowType == 441731) { + windowType = 2024; // TYPE_NAVIGATION_BAR_PANEL + layer->setPrimaryDisplayOnly(); + } + layer->setInfo(windowType, ownerUid); result = addClientLayer(client, *handle, *gbp, layer, *parent); @@ -3209,7 +3276,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, if (currentMode == HWC_POWER_MODE_OFF) { // Turn on the display getHwComposer().setPowerMode(type, mode); - if (type == DisplayDevice::DISPLAY_PRIMARY) { + if (type == DisplayDevice::DISPLAY_PRIMARY && + mode != HWC_POWER_MODE_DOZE_SUSPEND) { // FIXME: eventthread only knows about the main display right now mEventThread->onScreenAcquired(); resyncToHardwareVsync(true); @@ -3241,7 +3309,25 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, getHwComposer().setPowerMode(type, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display + } else if (mode == HWC_POWER_MODE_DOZE || + mode == HWC_POWER_MODE_NORMAL) { + // Update display while dozing + getHwComposer().setPowerMode(type, mode); + if (type == DisplayDevice::DISPLAY_PRIMARY) { + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenAcquired(); + resyncToHardwareVsync(true); + } + } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) { + // Leave display going to doze + if (type == DisplayDevice::DISPLAY_PRIMARY) { + disableHardwareVsync(true); // also cancels any in-progress resync + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenReleased(); + } + getHwComposer().setPowerMode(type, mode); } else { + ALOGE("Attempting to set unknown power mode: %d\n", mode); getHwComposer().setPowerMode(type, mode); } } @@ -3710,6 +3796,15 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, */ const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); + + /* + * Dump VrFlinger state if in use. + */ + if (mVrFlingerRequestsDisplay && mVrFlinger) { + result.append("VrFlinger state:\n"); + result.append(mVrFlinger->Dump().c_str()); + result.append("\n"); + } } const Vector< sp<Layer> >& @@ -3808,10 +3903,11 @@ status_t SurfaceFlinger::onTransact( status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { CHECK_INTERFACE(ISurfaceComposer, data, reply); - if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) { - IPCThreadState* ipc = IPCThreadState::self(); + IPCThreadState* ipc = IPCThreadState::self(); + const int uid = ipc->getCallingUid(); + if (CC_UNLIKELY(uid != AID_SYSTEM + && !PermissionCache::checkCallingPermission(sHardwareTest))) { const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); ALOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; @@ -3896,9 +3992,7 @@ status_t SurfaceFlinger::onTransact( // apply a color matrix n = data.readInt32(); if (n) { - // color matrix is sent as mat3 matrix followed by vec3 - // offset, then packed into a mat4 where the last row is - // the offset and extra values are 0 + // color matrix is sent as a column-major mat4 matrix for (size_t i = 0 ; i < 4; i++) { for (size_t j = 0; j < 4; j++) { mColorMatrix[i][j] = data.readFloat(); @@ -3907,6 +4001,14 @@ status_t SurfaceFlinger::onTransact( } else { mColorMatrix = mat4(); } + + // Check that supplied matrix's last row is {0,0,0,1} so we can avoid + // the division by w in the fragment shader + float4 lastRow(transpose(mColorMatrix)[3]); + if (any(greaterThan(abs(lastRow - float4{0, 0, 0, 1}), float4{1e-4f}))) { + ALOGE("The color transform's last row must be (0, 0, 0, 1)"); + } + invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; @@ -3950,6 +4052,13 @@ status_t SurfaceFlinger::onTransact( mUseHwcVirtualDisplays = !n; return NO_ERROR; } + case 1022: { // Set saturation boost + mSaturation = std::max(0.0f, std::min(data.readFloat(), 2.0f)); + + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + } } } return err; @@ -3960,128 +4069,88 @@ void SurfaceFlinger::repaintEverything() { signalTransaction(); } -// --------------------------------------------------------------------------- -// Capture screen into an IGraphiBufferProducer -// --------------------------------------------------------------------------- - -/* The code below is here to handle b/8734824 - * - * We create a IGraphicBufferProducer wrapper that forwards all calls - * from the surfaceflinger thread to the calling binder thread, where they - * are executed. This allows the calling thread in the calling process to be - * reused and not depend on having "enough" binder threads to handle the - * requests. - */ -class GraphicProducerWrapper : public BBinder, public MessageHandler { - /* Parts of GraphicProducerWrapper are run on two different threads, - * communicating by sending messages via Looper but also by shared member - * data. Coherence maintenance is subtle and in places implicit (ugh). - * - * Don't rely on Looper's sendMessage/handleMessage providing - * release/acquire semantics for any data not actually in the Message. - * Data going from surfaceflinger to binder threads needs to be - * synchronized explicitly. - * - * Barrier open/wait do provide release/acquire semantics. This provides - * implicit synchronization for data coming back from binder to - * surfaceflinger threads. - */ +// Checks that the requested width and height are valid and updates them to the display dimensions +// if they are set to 0 +static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice, + Transform::orientation_flags rotation, + uint32_t* requestedWidth, uint32_t* requestedHeight) { + // get screen geometry + uint32_t displayWidth = displayDevice->getWidth(); + uint32_t displayHeight = displayDevice->getHeight(); - sp<IGraphicBufferProducer> impl; - sp<Looper> looper; - status_t result; - bool exitPending; - bool exitRequested; - Barrier barrier; - uint32_t code; - Parcel const* data; - Parcel* reply; - - enum { - MSG_API_CALL, - MSG_EXIT - }; + if (rotation & Transform::ROT_90) { + std::swap(displayWidth, displayHeight); + } - /* - * Called on surfaceflinger thread. This is called by our "fake" - * BpGraphicBufferProducer. We package the data and reply Parcel and - * forward them to the binder thread. - */ - virtual status_t transact(uint32_t code, - const Parcel& data, Parcel* reply, uint32_t /* flags */) { - this->code = code; - this->data = &data; - this->reply = reply; - if (exitPending) { - // if we've exited, we run the message synchronously right here. - // note (JH): as far as I can tell from looking at the code, this - // never actually happens. if it does, i'm not sure if it happens - // on the surfaceflinger or binder thread. - handleMessage(Message(MSG_API_CALL)); - } else { - barrier.close(); - // Prevent stores to this->{code, data, reply} from being - // reordered later than the construction of Message. - atomic_thread_fence(memory_order_release); - looper->sendMessage(this, Message(MSG_API_CALL)); - barrier.wait(); - } - return result; + if ((*requestedWidth > displayWidth) || (*requestedHeight > displayHeight)) { + ALOGE("size mismatch (%d, %d) > (%d, %d)", + *requestedWidth, *requestedHeight, displayWidth, displayHeight); + return BAD_VALUE; } - /* - * here we run on the binder thread. All we've got to do is - * call the real BpGraphicBufferProducer. - */ - virtual void handleMessage(const Message& message) { - int what = message.what; - // Prevent reads below from happening before the read from Message - atomic_thread_fence(memory_order_acquire); - if (what == MSG_API_CALL) { - result = IInterface::asBinder(impl)->transact(code, data[0], reply); - barrier.open(); - } else if (what == MSG_EXIT) { - exitRequested = true; - } + if (*requestedWidth == 0) { + *requestedWidth = displayWidth; + } + if (*requestedHeight == 0) { + *requestedHeight = displayHeight; } + return NO_ERROR; +} + +// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope +class WindowDisconnector { public: - explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl) - : impl(impl), - looper(new Looper(true)), - result(NO_ERROR), - exitPending(false), - exitRequested(false), - code(0), - data(NULL), - reply(NULL) - {} - - // Binder thread - status_t waitForResponse() { - do { - looper->pollOnce(-1); - } while (!exitRequested); - return result; + WindowDisconnector(ANativeWindow* window, int api) : mWindow(window), mApi(api) {} + ~WindowDisconnector() { + native_window_api_disconnect(mWindow, mApi); } - // Client thread - void exit(status_t result) { - this->result = result; - exitPending = true; - // Ensure this->result is visible to the binder thread before it - // handles the message. - atomic_thread_fence(memory_order_release); - looper->sendMessage(this, Message(MSG_EXIT)); - } +private: + ANativeWindow* mWindow; + const int mApi; }; +static status_t getWindowBuffer(ANativeWindow* window, uint32_t requestedWidth, + uint32_t requestedHeight, bool hasWideColorDisplay, + bool renderEngineUsesWideColor, ANativeWindowBuffer** outBuffer) { + const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; + + int err = 0; + err = native_window_set_buffers_dimensions(window, requestedWidth, requestedHeight); + err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); + err |= native_window_set_usage(window, usage); + + if (hasWideColorDisplay) { + err |= native_window_set_buffers_data_space(window, + renderEngineUsesWideColor + ? HAL_DATASPACE_DISPLAY_P3 + : HAL_DATASPACE_V0_SRGB); + } + + if (err != NO_ERROR) { + return BAD_VALUE; + } + + /* TODO: Once we have the sync framework everywhere this can use + * server-side waits on the fence that dequeueBuffer returns. + */ + err = native_window_dequeue_buffer_and_wait(window, outBuffer); + if (err != NO_ERROR) { + return err; + } + + return NO_ERROR; +} status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, const sp<IGraphicBufferProducer>& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { + ATRACE_CALL(); if (CC_UNLIKELY(display == 0)) return BAD_VALUE; @@ -4115,65 +4184,95 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, break; } - class MessageCaptureScreen : public MessageBase { - SurfaceFlinger* flinger; - sp<IBinder> display; - sp<IGraphicBufferProducer> producer; - Rect sourceCrop; - uint32_t reqWidth, reqHeight; - uint32_t minLayerZ,maxLayerZ; - bool useIdentityTransform; - Transform::orientation_flags rotation; - status_t result; - bool isLocalScreenshot; - public: - MessageCaptureScreen(SurfaceFlinger* flinger, - const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - Transform::orientation_flags rotation, - bool isLocalScreenshot) - : flinger(flinger), display(display), producer(producer), - sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight), - minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), - useIdentityTransform(useIdentityTransform), - rotation(rotation), result(PERMISSION_DENIED), - isLocalScreenshot(isLocalScreenshot) - { - } - status_t getResult() const { - return result; + { // Autolock scope + Mutex::Autolock lock(mStateLock); + sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display)); + updateDimensionsLocked(displayDevice, rotationFlags, &reqWidth, &reqHeight); + } + + // create a surface (because we're a producer, and we need to + // dequeue/queue a buffer) + sp<Surface> surface = new Surface(producer, false); + + // Put the screenshot Surface into async mode so that + // Layer::headFenceHasSignaled will always return true and we'll latch the + // first buffer regardless of whether or not its acquire fence has + // signaled. This is needed to avoid a race condition in the rotation + // animation. See b/30209608 + surface->setAsyncMode(true); + + ANativeWindow* window = surface.get(); + + status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); + if (result != NO_ERROR) { + return result; + } + WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL); + + ANativeWindowBuffer* buffer = nullptr; + result = getWindowBuffer(window, reqWidth, reqHeight, hasWideColorDisplay, + getRenderEngine().usesWideColor(), &buffer); + if (result != NO_ERROR) { + return result; + } + + // This mutex protects syncFd and captureResult for communication of the return values from the + // main thread back to this Binder thread + std::mutex captureMutex; + std::condition_variable captureCondition; + std::unique_lock<std::mutex> captureLock(captureMutex); + int syncFd = -1; + std::optional<status_t> captureResult; + + sp<LambdaMessage> message = new LambdaMessage([&]() { + // If there is a refresh pending, bug out early and tell the binder thread to try again + // after the refresh. + if (mRefreshPending) { + ATRACE_NAME("Skipping screenshot for now"); + std::unique_lock<std::mutex> captureLock(captureMutex); + captureResult = std::make_optional<status_t>(EAGAIN); + captureCondition.notify_one(); + return; } - virtual bool handler() { - Mutex::Autolock _l(flinger->mStateLock); - sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display)); - result = flinger->captureScreenImplLocked(hw, producer, - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, rotation, isLocalScreenshot); - static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result); - return true; + + status_t result = NO_ERROR; + int fd = -1; + { + Mutex::Autolock _l(mStateLock); + sp<const DisplayDevice> device(getDisplayDeviceLocked(display)); + result = captureScreenImplLocked(device, buffer, sourceCrop, reqWidth, reqHeight, + minLayerZ, maxLayerZ, useIdentityTransform, + rotationFlags, isLocalScreenshot, &fd); } - }; - // this creates a "fake" BBinder which will serve as a "fake" remote - // binder to receive the marshaled calls and forward them to the - // real remote (a BpGraphicBufferProducer) - sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer); + { + std::unique_lock<std::mutex> captureLock(captureMutex); + syncFd = fd; + captureResult = std::make_optional<status_t>(result); + captureCondition.notify_one(); + } + }); - // the asInterface() call below creates our "fake" BpGraphicBufferProducer - // which does the marshaling work forwards to our "fake remote" above. - sp<MessageBase> msg = new MessageCaptureScreen(this, - display, IGraphicBufferProducer::asInterface( wrapper ), - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, rotationFlags, isLocalScreenshot); + result = postMessageAsync(message); + if (result == NO_ERROR) { + captureCondition.wait(captureLock, [&]() { return captureResult; }); + while (*captureResult == EAGAIN) { + captureResult.reset(); + result = postMessageAsync(message); + if (result != NO_ERROR) { + return result; + } + captureCondition.wait(captureLock, [&]() { return captureResult; }); + } + result = *captureResult; + } - status_t res = postMessageAsync(msg); - if (res == NO_ERROR) { - res = wrapper->waitForResponse(); + if (result == NO_ERROR) { + // queueBuffer takes ownership of syncFd + result = window->queueBuffer(window, buffer, syncFd); } - return res; + + return result; } @@ -4213,6 +4312,11 @@ void SurfaceFlinger::renderScreenImplLocked( ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h); } +#ifdef USE_HWC2 + engine.setWideColor(hw->getWideColorSupport()); + engine.setColorMode(hw->getActiveColorMode()); +#endif + // make sure to clear all GL error flags engine.checkErrors(); @@ -4227,7 +4331,7 @@ void SurfaceFlinger::renderScreenImplLocked( // We loop through the first level of layers without traversing, // as we need to interpret min/max layer Z in the top level Z space. for (const auto& layer : mDrawingState.layersSortedByZ) { - if (layer->getLayerStack() != hw->getLayerStack()) { + if (!layer->belongsToDisplay(hw->getLayerStack(), false)) { continue; } const Layer::State& state(layer->getDrawingState()); @@ -4247,38 +4351,39 @@ void SurfaceFlinger::renderScreenImplLocked( hw->setViewportAndProjection(); } +// A simple RAII class that holds an EGLImage and destroys it either: +// a) When the destroy() method is called +// b) When the object goes out of scope +class ImageHolder { +public: + ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {} + ~ImageHolder() { destroy(); } -status_t SurfaceFlinger::captureScreenImplLocked( - const sp<const DisplayDevice>& hw, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, Transform::orientation_flags rotation, - bool isLocalScreenshot) -{ - ATRACE_CALL(); - - // get screen geometry - uint32_t hw_w = hw->getWidth(); - uint32_t hw_h = hw->getHeight(); - - if (rotation & Transform::ROT_90) { - std::swap(hw_w, hw_h); + void destroy() { + if (mImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mDisplay, mImage); + mImage = EGL_NO_IMAGE_KHR; + } } - if ((reqWidth > hw_w) || (reqHeight > hw_h)) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", - reqWidth, reqHeight, hw_w, hw_h); - return BAD_VALUE; - } +private: + const EGLDisplay mDisplay; + EGLImageKHR mImage; +}; - reqWidth = (!reqWidth) ? hw_w : reqWidth; - reqHeight = (!reqHeight) ? hw_h : reqHeight; +status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& hw, + ANativeWindowBuffer* buffer, Rect sourceCrop, + uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, + Transform::orientation_flags rotation, + bool isLocalScreenshot, int* outSyncFd) { + ATRACE_CALL(); bool secureLayerIsVisible = false; for (const auto& layer : mDrawingState.layersSortedByZ) { const Layer::State& state(layer->getDrawingState()); - if ((layer->getLayerStack() != hw->getLayerStack()) || + if (!layer->belongsToDisplay(hw->getLayerStack(), false) || (state.z < minLayerZ || state.z > maxLayerZ)) { continue; } @@ -4293,123 +4398,84 @@ status_t SurfaceFlinger::captureScreenImplLocked( return PERMISSION_DENIED; } - // create a surface (because we're a producer, and we need to - // dequeue/queue a buffer) - sp<Surface> sur = new Surface(producer, false); + int syncFd = -1; + // create an EGLImage from the buffer so we can later + // turn it into a texture + EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, + EGL_NATIVE_BUFFER_ANDROID, buffer, NULL); + if (image == EGL_NO_IMAGE_KHR) { + return BAD_VALUE; + } - // Put the screenshot Surface into async mode so that - // Layer::headFenceHasSignaled will always return true and we'll latch the - // first buffer regardless of whether or not its acquire fence has - // signaled. This is needed to avoid a race condition in the rotation - // animation. See b/30209608 - sur->setAsyncMode(true); + // This will automatically destroy the image if we return before calling its destroy method + ImageHolder imageHolder(mEGLDisplay, image); + + // this binds the given EGLImage as a framebuffer for the + // duration of this scope. + RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image); + if (imageBond.getStatus() != NO_ERROR) { + ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot"); + return INVALID_OPERATION; + } - ANativeWindow* window = sur.get(); + // this will in fact render into our dequeued buffer + // via an FBO, which means we didn't have to create + // an EGLSurface and therefore we're not + // dependent on the context's EGLConfig. + renderScreenImplLocked( + hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true, + useIdentityTransform, rotation); - status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); - if (result == NO_ERROR) { - uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - - int err = 0; - err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); - err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); - err |= native_window_set_usage(window, usage); - - if (err == NO_ERROR) { - ANativeWindowBuffer* buffer; - /* TODO: Once we have the sync framework everywhere this can use - * server-side waits on the fence that dequeueBuffer returns. - */ - result = native_window_dequeue_buffer_and_wait(window, &buffer); - if (result == NO_ERROR) { - int syncFd = -1; - // create an EGLImage from the buffer so we can later - // turn it into a texture - EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, - EGL_NATIVE_BUFFER_ANDROID, buffer, NULL); - if (image != EGL_NO_IMAGE_KHR) { - // this binds the given EGLImage as a framebuffer for the - // duration of this scope. - RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image); - if (imageBond.getStatus() == NO_ERROR) { - // this will in fact render into our dequeued buffer - // via an FBO, which means we didn't have to create - // an EGLSurface and therefore we're not - // dependent on the context's EGLConfig. - renderScreenImplLocked( - hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true, - useIdentityTransform, rotation); - - // Attempt to create a sync khr object that can produce a sync point. If that - // isn't available, create a non-dupable sync object in the fallback path and - // wait on it directly. - EGLSyncKHR sync; - if (!DEBUG_SCREENSHOTS) { - sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); - // native fence fd will not be populated until flush() is done. - getRenderEngine().flush(); - } else { - sync = EGL_NO_SYNC_KHR; - } - if (sync != EGL_NO_SYNC_KHR) { - // get the sync fd - syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync); - if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - ALOGW("captureScreen: failed to dup sync khr object"); - syncFd = -1; - } - eglDestroySyncKHR(mEGLDisplay, sync); - } else { - // fallback path - sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL); - if (sync != EGL_NO_SYNC_KHR) { - EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, - EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/); - EGLint eglErr = eglGetError(); - if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ALOGW("captureScreen: fence wait timed out"); - } else { - ALOGW_IF(eglErr != EGL_SUCCESS, - "captureScreen: error waiting on EGL fence: %#x", eglErr); - } - eglDestroySyncKHR(mEGLDisplay, sync); - } else { - ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); - } - } - if (DEBUG_SCREENSHOTS) { - uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; - getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); - checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, - hw, minLayerZ, maxLayerZ); - delete [] pixels; - } + // Attempt to create a sync khr object that can produce a sync point. If that + // isn't available, create a non-dupable sync object in the fallback path and + // wait on it directly. + EGLSyncKHR sync = EGL_NO_SYNC_KHR; + if (!DEBUG_SCREENSHOTS) { + sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); + // native fence fd will not be populated until flush() is done. + getRenderEngine().flush(); + } - } else { - ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot"); - result = INVALID_OPERATION; - window->cancelBuffer(window, buffer, syncFd); - buffer = NULL; - } - // destroy our image - eglDestroyImageKHR(mEGLDisplay, image); - } else { - result = BAD_VALUE; - } - if (buffer) { - // queueBuffer takes ownership of syncFd - result = window->queueBuffer(window, buffer, syncFd); - } + if (sync != EGL_NO_SYNC_KHR) { + // get the sync fd + syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync); + if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + ALOGW("captureScreen: failed to dup sync khr object"); + syncFd = -1; + } + eglDestroySyncKHR(mEGLDisplay, sync); + } else { + // fallback path + sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL); + if (sync != EGL_NO_SYNC_KHR) { + EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, + EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/); + EGLint eglErr = eglGetError(); + if (result == EGL_TIMEOUT_EXPIRED_KHR) { + ALOGW("captureScreen: fence wait timed out"); + } else { + ALOGW_IF(eglErr != EGL_SUCCESS, + "captureScreen: error waiting on EGL fence: %#x", eglErr); } + eglDestroySyncKHR(mEGLDisplay, sync); } else { - result = BAD_VALUE; + ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); } - native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } + *outSyncFd = syncFd; - return result; + if (DEBUG_SCREENSHOTS) { + uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; + getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); + checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, + hw, minLayerZ, maxLayerZ); + delete [] pixels; + } + + // destroy our image + imageHolder.destroy(); + + return NO_ERROR; } void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, @@ -4428,7 +4494,7 @@ void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* v size_t i = 0; for (const auto& layer : mDrawingState.layersSortedByZ) { const Layer::State& state(layer->getDrawingState()); - if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ && + if (layer->belongsToDisplay(hw->getLayerStack(), false) && state.z >= minLayerZ && state.z <= maxLayerZ) { layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f", diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9239538932..acfad46526 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -58,7 +58,7 @@ #include "LayerVector.h" #include "MessageQueue.h" #include "SurfaceInterceptor.h" -#include "StartBootAnimThread.h" +#include "StartPropertySetThread.h" #include "DisplayHardware/HWComposer.h" #include "Effects/Daltonizer.h" @@ -227,7 +227,6 @@ private: enum { LOG_FRAME_STATS_PERIOD = 30*60*60 }; static const size_t MAX_LAYERS = 4096; - static constexpr const char* kTimestampProperty = "service.sf.present_timestamp"; // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); @@ -417,6 +416,14 @@ private: int32_t minLayerZ, int32_t maxLayerZ, bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation); +#ifdef USE_HWC2 + status_t captureScreenImplLocked(const sp<const DisplayDevice>& device, + ANativeWindowBuffer* buffer, Rect sourceCrop, + uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ, + int32_t maxLayerZ, bool useIdentityTransform, + Transform::orientation_flags rotation, bool isLocalScreenshot, + int* outSyncFd); +#else status_t captureScreenImplLocked( const sp<const DisplayDevice>& hw, const sp<IGraphicBufferProducer>& producer, @@ -424,8 +431,14 @@ private: int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, Transform::orientation_flags rotation, bool isLocalScreenshot); +#endif - sp<StartBootAnimThread> mStartBootAnimThread = nullptr; + sp<StartPropertySetThread> mStartPropertySetThread = nullptr; + + /* ------------------------------------------------------------------------ + * Properties + */ + void readPersistentProperties(); /* ------------------------------------------------------------------------ * EGL @@ -481,7 +494,7 @@ private: // mark a region of a layer stack dirty. this updates the dirty // region of all screens presenting this layer stack. - void invalidateLayerStack(uint32_t layerStack, const Region& dirty); + void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty); #ifndef USE_HWC2 int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type); @@ -497,7 +510,7 @@ private: * Compositing */ void invalidateHwcGeometry(); - void computeVisibleRegions(uint32_t layerStack, + void computeVisibleRegions(const sp<const DisplayDevice>& displayDevice, Region& dirtyRegion, Region& opaqueRegion); void preComposition(nsecs_t refreshStartTime); @@ -512,8 +525,10 @@ private: // Given a dataSpace, returns the appropriate color_mode to use // to display that dataSpace. - android_color_mode pickColorMode(android_dataspace dataSpace); - android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b); + android_color_mode pickColorMode(android_dataspace dataSpace) const; + android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b) const; + + mat4 computeSaturationMatrix() const; void setUpHWComposer(); void doComposition(); @@ -575,7 +590,12 @@ private: /* ------------------------------------------------------------------------ * VrFlinger */ - void clearHwcLayers(const LayerVector& layers); + template<typename T> + void clearHwcLayers(const T& layers) { + for (size_t i = 0; i < layers.size(); ++i) { + layers[i]->clearHwcLayers(); + } + } void resetHwcLocked(); // Check to see if we should handoff to vr flinger. @@ -693,6 +713,8 @@ private: }; std::queue<CompositePresentTime> mCompositePresentTimes; + std::atomic<bool> mRefreshPending{false}; + /* ------------------------------------------------------------------------ * Feature prototyping */ @@ -748,7 +770,9 @@ private: std::atomic<bool> mVrFlingerRequestsDisplay; static bool useVrFlinger; #endif - }; + + float mSaturation = 1.0f; +}; }; // namespace android #endif // ANDROID_SURFACE_FLINGER_H diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 9babeef87f..abc8fde26b 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -240,10 +240,15 @@ void SurfaceFlingerConsumer::setContentsChangedListener( } void SurfaceFlingerConsumer::onSidebandStreamChanged() { + FrameAvailableListener* unsafeFrameAvailableListener = nullptr; + { + Mutex::Autolock lock(mFrameAvailableMutex); + unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get(); + } sp<ContentsChangedListener> listener; { // scope for the lock Mutex::Autolock lock(mMutex); - ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get()); + ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get()); listener = mContentsChangedListener.promote(); } diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index 0904fab4aa..247d80bc07 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -320,8 +320,8 @@ sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) { void SurfaceFlinger::bootFinished() { - if (mStartBootAnimThread->join() != NO_ERROR) { - ALOGE("Join StartBootAnimThread failed!"); + if (mStartPropertySetThread->join() != NO_ERROR) { + ALOGE("Join StartPropertySetThread failed!"); } const nsecs_t now = systemTime(); const nsecs_t duration = now - mBootTime; @@ -501,6 +501,8 @@ private: sp<VSyncSource::Callback> mCallback; }; +// Do not call property_set on main thread which will be blocked by init +// Use StartPropertySetThread instead. void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); @@ -536,7 +538,8 @@ void SurfaceFlinger::init() { *static_cast<HWComposer::EventHandler *>(this)); // get a RenderEngine for the given display / config (can't fail) - mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID()); + mRenderEngine = RenderEngine::create(mEGLDisplay, + mHwc->getVisualID(), 0); // retrieve the EGL context that was selected/created mEGLContext = mRenderEngine->getEGLContext(); @@ -544,9 +547,6 @@ void SurfaceFlinger::init() { LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, "couldn't create EGLContext"); - // Inform native graphics APIs that the present timestamp is NOT supported: - property_set(kTimestampProperty, "0"); - // initialize our non-virtual displays for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i); @@ -599,9 +599,10 @@ void SurfaceFlinger::init() { mRenderEngine->primeCache(); - mStartBootAnimThread = new StartBootAnimThread(); - if (mStartBootAnimThread->Start() != NO_ERROR) { - ALOGE("Run StartBootAnimThread failed!"); + // Inform native graphics APIs that the present timestamp is NOT supported: + mStartPropertySetThread = new StartPropertySetThread(false); + if (mStartPropertySetThread->Start() != NO_ERROR) { + ALOGE("Run StartPropertySetThread failed!"); } ALOGV("Done initializing"); @@ -615,10 +616,10 @@ int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) { void SurfaceFlinger::startBootAnim() { // Start boot animation service by setting a property mailbox // if property setting thread is already running, Start() will be just a NOP - mStartBootAnimThread->Start(); + mStartPropertySetThread->Start(); // Wait until property was set - if (mStartBootAnimThread->join() != NO_ERROR) { - ALOGE("Join StartBootAnimThread failed!"); + if (mStartPropertySetThread->join() != NO_ERROR) { + ALOGE("Join StartPropertySetThread failed!"); } } @@ -1360,8 +1361,7 @@ void SurfaceFlinger::rebuildLayerStacks() { const Transform& tr(hw->getTransform()); const Rect bounds(hw->getBounds()); if (hw->isDisplayOn()) { - computeVisibleRegions(hw->getLayerStack(), dirtyRegion, - opaqueRegion); + computeVisibleRegions(hw, dirtyRegion, opaqueRegion); mDrawingState.traverseInZOrder([&](Layer* layer) { if (layer->getLayerStack() == hw->getLayerStack()) { @@ -1862,7 +1862,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // TODO: we could cache the transformed region Region visibleReg; visibleReg.set(layer->computeScreenBounds()); - invalidateLayerStack(layer->getLayerStack(), visibleReg); + invalidateLayerStack(layer, visibleReg); } }); } @@ -1923,7 +1923,7 @@ void SurfaceFlinger::commitTransaction() mTransactionCV.broadcast(); } -void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack, +void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice, Region& outDirtyRegion, Region& outOpaqueRegion) { ATRACE_CALL(); @@ -1939,7 +1939,7 @@ void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack, const Layer::State& s(layer->getDrawingState()); // only consider the layers on the given layer stack - if (layer->getLayerStack() != layerStack) + if (layer->getLayerStack() != displayDevice->getLayerStack()) return; /* @@ -2054,8 +2054,8 @@ void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack, outOpaqueRegion = aboveOpaqueLayers; } -void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack, - const Region& dirty) { +void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) { + uint32_t layerStack = layer->getLayerStack(); for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { const sp<DisplayDevice>& hw(mDisplays[dpy]); if (hw->getLayerStack() == layerStack) { @@ -2098,7 +2098,7 @@ bool SurfaceFlinger::handlePageFlip() Layer* layer = layersWithQueuedFrames[i]; const Region dirty(layer->latchBuffer(visibleRegions, latchTime)); layer->useSurfaceDamage(); - invalidateLayerStack(layer->getLayerStack(), dirty); + invalidateLayerStack(layer, dirty); } mVisibleRegionsDirty |= visibleRegions; @@ -2870,7 +2870,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, if (currentMode == HWC_POWER_MODE_OFF) { // Turn on the display getHwComposer().setPowerMode(type, mode); - if (type == DisplayDevice::DISPLAY_PRIMARY) { + if (type == DisplayDevice::DISPLAY_PRIMARY && + mode != HWC_POWER_MODE_DOZE_SUSPEND) { // FIXME: eventthread only knows about the main display right now mEventThread->onScreenAcquired(); resyncToHardwareVsync(true); @@ -2902,7 +2903,25 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, getHwComposer().setPowerMode(type, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display + } else if (mode == HWC_POWER_MODE_DOZE || + mode == HWC_POWER_MODE_NORMAL) { + // Update display while dozing + getHwComposer().setPowerMode(type, mode); + if (type == DisplayDevice::DISPLAY_PRIMARY) { + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenAcquired(); + resyncToHardwareVsync(true); + } + } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) { + // Leave display going to doze + if (type == DisplayDevice::DISPLAY_PRIMARY) { + disableHardwareVsync(true); // also cancels any in-progress resync + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenReleased(); + } + getHwComposer().setPowerMode(type, mode); } else { + ALOGE("Attempting to set unknown power mode: %d\n", mode); getHwComposer().setPowerMode(type, mode); } } diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk index 16041da657..43e22a0bd6 100644 --- a/services/surfaceflinger/tests/Android.mk +++ b/services/surfaceflinger/tests/Android.mk @@ -4,7 +4,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := SurfaceFlinger_test - +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ diff --git a/services/surfaceflinger/tests/AndroidTest.xml b/services/surfaceflinger/tests/AndroidTest.xml new file mode 100644 index 0000000000..8315037b94 --- /dev/null +++ b/services/surfaceflinger/tests/AndroidTest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Config for SurfaceFlinger_test"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="SurfaceFlinger_test->/data/local/tmp/SurfaceFlinger_test" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="SurfaceFlinger_test" /> + </test> +</configuration> diff --git a/services/surfaceflinger/tests/vsync/Android.mk b/services/surfaceflinger/tests/vsync/Android.mk index 9181760453..8e41617f7b 100644 --- a/services/surfaceflinger/tests/vsync/Android.mk +++ b/services/surfaceflinger/tests/vsync/Android.mk @@ -15,4 +15,6 @@ LOCAL_MODULE:= test-vsync-events LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -Werror + include $(BUILD_EXECUTABLE) diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp index aa72c79248..a1b45e6adb 100644 --- a/services/surfaceflinger/tests/vsync/vsync.cpp +++ b/services/surfaceflinger/tests/vsync/vsync.cpp @@ -20,7 +20,7 @@ using namespace android; -int receiver(int fd, int events, void* data) +int receiver(int /*fd*/, int /*events*/, void* data) { DisplayEventReceiver* q = (DisplayEventReceiver*)data; @@ -47,7 +47,7 @@ int receiver(int fd, int events, void* data) return 1; } -int main(int argc, char** argv) +int main(int /*argc*/, char** /*argv*/) { DisplayEventReceiver myDisplayEvent; diff --git a/services/surfaceflinger/tests/waitforvsync/Android.mk b/services/surfaceflinger/tests/waitforvsync/Android.mk index c25f5ab083..932d2be133 100644 --- a/services/surfaceflinger/tests/waitforvsync/Android.mk +++ b/services/surfaceflinger/tests/waitforvsync/Android.mk @@ -11,4 +11,6 @@ LOCAL_MODULE:= test-waitforvsync LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -Werror + include $(BUILD_EXECUTABLE) diff --git a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp index b88b04a897..65eaae58b7 100644 --- a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp +++ b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp @@ -29,7 +29,7 @@ #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) #endif -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { int fd = open("/dev/graphics/fb0", O_RDWR); if (fd >= 0) { do { diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp index d27f274e29..26843c99c8 100644 --- a/services/vr/bufferhubd/buffer_hub.cpp +++ b/services/vr/bufferhubd/buffer_hub.cpp @@ -382,7 +382,7 @@ Status<void> BufferHubService::OnGetPersistentBuffer(Message& message, } Status<QueueInfo> BufferHubService::OnCreateProducerQueue( - pdx::Message& message, size_t meta_size_bytes, + pdx::Message& message, const ProducerQueueConfig& producer_config, const UsagePolicy& usage_policy) { // Use the producer channel id as the global queue id. const int queue_id = message.GetChannelId(); @@ -396,11 +396,11 @@ Status<QueueInfo> BufferHubService::OnCreateProducerQueue( return ErrorStatus(EALREADY); } - auto status = ProducerQueueChannel::Create(this, queue_id, meta_size_bytes, + auto status = ProducerQueueChannel::Create(this, queue_id, producer_config, usage_policy); if (status) { message.SetChannel(status.take()); - return {{meta_size_bytes, queue_id}}; + return {{producer_config, queue_id}}; } else { ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!"); return status.error_status(); diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h index 3bc26354c5..b0df11f2ac 100644 --- a/services/vr/bufferhubd/buffer_hub.h +++ b/services/vr/bufferhubd/buffer_hub.h @@ -166,9 +166,9 @@ class BufferHubService : public pdx::ServiceBase<BufferHubService> { size_t meta_size_bytes); pdx::Status<void> OnGetPersistentBuffer(pdx::Message& message, const std::string& name); - pdx::Status<QueueInfo> OnCreateProducerQueue(pdx::Message& message, - size_t meta_size_bytes, - const UsagePolicy& usage_policy); + pdx::Status<QueueInfo> OnCreateProducerQueue( + pdx::Message& message, const ProducerQueueConfig& producer_config, + const UsagePolicy& usage_policy); BufferHubService(const BufferHubService&) = delete; void operator=(const BufferHubService&) = delete; diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp index 08b27905f7..ac6896ae84 100644 --- a/services/vr/bufferhubd/consumer_channel.cpp +++ b/services/vr/bufferhubd/consumer_channel.cpp @@ -8,9 +8,9 @@ #include <private/dvr/bufferhub_rpc.h> #include "producer_channel.h" -using android::pdx::ErrorStatus; using android::pdx::BorrowedHandle; using android::pdx::Channel; +using android::pdx::ErrorStatus; using android::pdx::Message; using android::pdx::Status; using android::pdx::rpc::DispatchRemoteMethod; @@ -22,8 +22,6 @@ ConsumerChannel::ConsumerChannel(BufferHubService* service, int buffer_id, int channel_id, const std::shared_ptr<Channel> producer) : BufferHubChannel(service, buffer_id, channel_id, kConsumerType), - handled_(true), - ignored_(false), producer_(producer) { GetProducer()->AddConsumer(this); } @@ -34,7 +32,7 @@ ConsumerChannel::~ConsumerChannel() { channel_id(), buffer_id()); if (auto producer = GetProducer()) { - if (!handled_) // Producer is waiting for our Release. + if (!released_) // Producer is waiting for our Release. producer->OnConsumerIgnored(); producer->RemoveConsumer(this); } @@ -108,15 +106,20 @@ ConsumerChannel::OnConsumerAcquire(Message& message, if (!producer) return ErrorStatus(EPIPE); - if (ignored_ || handled_) { + if (acquired_ || released_) { ALOGE( "ConsumerChannel::OnConsumerAcquire: Acquire when not posted: " - "ignored=%d handled=%d channel_id=%d buffer_id=%d", - ignored_, handled_, message.GetChannelId(), producer->buffer_id()); + "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d", + ignored_, acquired_, released_, message.GetChannelId(), + producer->buffer_id()); return ErrorStatus(EBUSY); } else { - ClearAvailable(); - return producer->OnConsumerAcquire(message, metadata_size); + auto status = producer->OnConsumerAcquire(message, metadata_size); + if (status) { + ClearAvailable(); + acquired_ = true; + } + return status; } } @@ -127,17 +130,21 @@ Status<void> ConsumerChannel::OnConsumerRelease(Message& message, if (!producer) return ErrorStatus(EPIPE); - if (ignored_ || handled_) { + if (!acquired_ || released_) { ALOGE( "ConsumerChannel::OnConsumerRelease: Release when not acquired: " - "ignored=%d handled=%d channel_id=%d buffer_id=%d", - ignored_, handled_, message.GetChannelId(), producer->buffer_id()); + "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d", + ignored_, acquired_, released_, message.GetChannelId(), + producer->buffer_id()); return ErrorStatus(EBUSY); } else { - ClearAvailable(); auto status = producer->OnConsumerRelease(message, std::move(release_fence)); - handled_ = !!status; + if (status) { + ClearAvailable(); + acquired_ = false; + released_ = true; + } return status; } } @@ -149,12 +156,13 @@ Status<void> ConsumerChannel::OnConsumerSetIgnore(Message&, bool ignored) { return ErrorStatus(EPIPE); ignored_ = ignored; - if (ignored_ && !handled_) { + if (ignored_ && acquired_) { // Update the producer if ignore is set after the consumer acquires the // buffer. ClearAvailable(); producer->OnConsumerIgnored(); - handled_ = false; + acquired_ = false; + released_ = true; } return {}; @@ -162,10 +170,12 @@ Status<void> ConsumerChannel::OnConsumerSetIgnore(Message&, bool ignored) { bool ConsumerChannel::OnProducerPosted() { if (ignored_) { - handled_ = true; + acquired_ = false; + released_ = true; return false; } else { - handled_ = false; + acquired_ = false; + released_ = false; SignalAvailable(); return true; } diff --git a/services/vr/bufferhubd/consumer_channel.h b/services/vr/bufferhubd/consumer_channel.h index d84055c146..208a002272 100644 --- a/services/vr/bufferhubd/consumer_channel.h +++ b/services/vr/bufferhubd/consumer_channel.h @@ -38,8 +38,9 @@ class ConsumerChannel : public BufferHubChannel { LocalFence release_fence); pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore); - bool handled_; // True if we have processed RELEASE. - bool ignored_; // True if we are ignoring events. + bool acquired_{false}; + bool released_{true}; + bool ignored_{false}; // True if we are ignoring events. std::weak_ptr<Channel> producer_; ConsumerChannel(const ConsumerChannel&) = delete; diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp index b9984a0b08..b2db795717 100644 --- a/services/vr/bufferhubd/producer_channel.cpp +++ b/services/vr/bufferhubd/producer_channel.cpp @@ -122,7 +122,7 @@ bool ProducerChannel::HandleMessage(Message& message) { } Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer( - Message& message) { + Message& /*message*/) { ATRACE_NAME("ProducerChannel::OnGetBuffer"); ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id()); return {NativeBufferHandle<BorrowedHandle>(buffer_, buffer_id())}; @@ -204,7 +204,7 @@ Status<void> ProducerChannel::OnProducerPost( return {}; } -Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) { +Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) { ATRACE_NAME("ProducerChannel::OnGain"); ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id()); if (producer_owns_) { @@ -224,7 +224,7 @@ Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) { } Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>> -ProducerChannel::OnConsumerAcquire(Message& message, +ProducerChannel::OnConsumerAcquire(Message& /*message*/, std::size_t metadata_size) { ATRACE_NAME("ProducerChannel::OnConsumerAcquire"); ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d", diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp index 886e621277..b8bb728b70 100644 --- a/services/vr/bufferhubd/producer_queue_channel.cpp +++ b/services/vr/bufferhubd/producer_queue_channel.cpp @@ -16,11 +16,11 @@ namespace dvr { ProducerQueueChannel::ProducerQueueChannel(BufferHubService* service, int channel_id, - size_t meta_size_bytes, + const ProducerQueueConfig& config, const UsagePolicy& usage_policy, int* error) : BufferHubChannel(service, channel_id, channel_id, kProducerQueueType), - meta_size_bytes_(meta_size_bytes), + config_(config), usage_policy_(usage_policy), capacity_(0) { *error = 0; @@ -35,8 +35,8 @@ ProducerQueueChannel::~ProducerQueueChannel() { /* static */ Status<std::shared_ptr<ProducerQueueChannel>> ProducerQueueChannel::Create( - BufferHubService* service, int channel_id, size_t meta_size_bytes, - const UsagePolicy& usage_policy) { + BufferHubService* service, int channel_id, + const ProducerQueueConfig& config, const UsagePolicy& usage_policy) { // Configuration between |usage_deny_set_mask| and |usage_deny_clear_mask| // should be mutually exclusive. if ((usage_policy.usage_deny_set_mask & usage_policy.usage_deny_clear_mask)) { @@ -50,7 +50,7 @@ Status<std::shared_ptr<ProducerQueueChannel>> ProducerQueueChannel::Create( int error = 0; std::shared_ptr<ProducerQueueChannel> producer(new ProducerQueueChannel( - service, channel_id, meta_size_bytes, usage_policy, &error)); + service, channel_id, config, usage_policy, &error)); if (error < 0) return ErrorStatus(-error); else @@ -76,9 +76,9 @@ bool ProducerQueueChannel::HandleMessage(Message& message) { message); return true; - case BufferHubRPC::ProducerQueueDetachBuffer::Opcode: - DispatchRemoteMethod<BufferHubRPC::ProducerQueueDetachBuffer>( - *this, &ProducerQueueChannel::OnProducerQueueDetachBuffer, message); + case BufferHubRPC::ProducerQueueRemoveBuffer::Opcode: + DispatchRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>( + *this, &ProducerQueueChannel::OnProducerQueueRemoveBuffer, message); return true; default: @@ -134,7 +134,7 @@ Status<RemoteChannelHandle> ProducerQueueChannel::OnCreateConsumerQueue( } Status<QueueInfo> ProducerQueueChannel::OnGetQueueInfo(Message&) { - return {{meta_size_bytes_, buffer_id()}}; + return {{config_, buffer_id()}}; } Status<std::vector<std::pair<RemoteChannelHandle, size_t>>> @@ -222,7 +222,7 @@ ProducerQueueChannel::AllocateBuffer(Message& message, uint32_t width, auto producer_channel_status = ProducerChannel::Create(service(), buffer_id, width, height, layer_count, - format, usage, meta_size_bytes_); + format, usage, config_.meta_size_bytes); if (!producer_channel_status) { ALOGE( "ProducerQueueChannel::AllocateBuffer: Failed to create producer " @@ -276,11 +276,11 @@ ProducerQueueChannel::AllocateBuffer(Message& message, uint32_t width, return {{std::move(buffer_handle), slot}}; } -Status<void> ProducerQueueChannel::OnProducerQueueDetachBuffer( +Status<void> ProducerQueueChannel::OnProducerQueueRemoveBuffer( Message& /*message*/, size_t slot) { if (buffers_[slot].expired()) { ALOGE( - "ProducerQueueChannel::OnProducerQueueDetachBuffer: trying to detach " + "ProducerQueueChannel::OnProducerQueueRemoveBuffer: trying to remove " "an invalid buffer producer at slot %zu", slot); return ErrorStatus(EINVAL); @@ -288,7 +288,7 @@ Status<void> ProducerQueueChannel::OnProducerQueueDetachBuffer( if (capacity_ == 0) { ALOGE( - "ProducerQueueChannel::OnProducerQueueDetachBuffer: trying to detach a " + "ProducerQueueChannel::OnProducerQueueRemoveBuffer: trying to remove a " "buffer producer while the queue's capacity is already zero."); return ErrorStatus(EINVAL); } diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h index 28c74cdf99..fd519c55e0 100644 --- a/services/vr/bufferhubd/producer_queue_channel.h +++ b/services/vr/bufferhubd/producer_queue_channel.h @@ -12,8 +12,8 @@ namespace dvr { class ProducerQueueChannel : public BufferHubChannel { public: static pdx::Status<std::shared_ptr<ProducerQueueChannel>> Create( - BufferHubService* service, int channel_id, size_t meta_size_bytes, - const UsagePolicy& usage_policy); + BufferHubService* service, int channel_id, + const ProducerQueueConfig& config, const UsagePolicy& usage_policy); ~ProducerQueueChannel() override; bool HandleMessage(pdx::Message& message) override; @@ -40,7 +40,7 @@ class ProducerQueueChannel : public BufferHubChannel { // Detach a BufferHubProducer indicated by |slot|. Note that the buffer must // be in Gain'ed state for the producer queue to detach. - pdx::Status<void> OnProducerQueueDetachBuffer(pdx::Message& message, + pdx::Status<void> OnProducerQueueRemoveBuffer(pdx::Message& message, size_t slot); void AddConsumer(ConsumerQueueChannel* channel); @@ -48,8 +48,8 @@ class ProducerQueueChannel : public BufferHubChannel { private: ProducerQueueChannel(BufferHubService* service, int channel_id, - size_t meta_size_bytes, const UsagePolicy& usage_policy, - int* error); + const ProducerQueueConfig& config, + const UsagePolicy& usage_policy, int* error); // Allocate one single producer buffer by |OnProducerQueueAllocateBuffers|. // Note that the newly created buffer's file handle will be pushed to client @@ -60,10 +60,9 @@ class ProducerQueueChannel : public BufferHubChannel { pdx::Message& message, uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage); - // Size of the meta data associated with all the buffers allocated from the - // queue. Now we assume the metadata size is immutable once the queue is - // created. - size_t meta_size_bytes_; + // The producer queue's configuration. Now we assume the configuration is + // immutable once the queue is created. + ProducerQueueConfig config_; // A set of variables to control what |usage| bits can this ProducerQueue // allocate. diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index 5cb201ded3..920152032a 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -7,6 +7,7 @@ cc_library_shared { ], static_libs: [ + "libbroadcastring", "libhwcomposer-client", "libdisplay", "libbufferhubqueue", diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl index 5fd5c3638c..be1ec5b2a3 100644 --- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl +++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl @@ -17,4 +17,9 @@ interface IVrComposer * Registers a callback used to receive frame notifications. */ void registerObserver(in IVrComposerCallback callback); + + /** + * Clears a previously registered frame notification callback. + */ + void clearObserver(); } diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp index ae54e56809..c31417bcc7 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.cpp +++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp @@ -24,26 +24,63 @@ namespace android { namespace dvr { +namespace { using android::hardware::graphics::common::V1_0::PixelFormat; using android::frameworks::vr::composer::V1_0::IVrComposerClient; -VrComposerClient::VrComposerClient(dvr::VrHwc& hal) +class ComposerClientImpl : public ComposerClient { + public: + ComposerClientImpl(android::dvr::VrHwc& hal); + virtual ~ComposerClientImpl(); + + private: + class VrCommandReader : public ComposerClient::CommandReader { + public: + VrCommandReader(ComposerClientImpl& client); + ~VrCommandReader() override; + + bool parseCommand(IComposerClient::Command command, + uint16_t length) override; + + private: + bool parseSetLayerInfo(uint16_t length); + bool parseSetClientTargetMetadata(uint16_t length); + bool parseSetLayerBufferMetadata(uint16_t length); + + IVrComposerClient::BufferMetadata readBufferMetadata(); + + ComposerClientImpl& mVrClient; + android::dvr::VrHwc& mVrHal; + + VrCommandReader(const VrCommandReader&) = delete; + void operator=(const VrCommandReader&) = delete; + }; + + std::unique_ptr<CommandReader> createCommandReader() override; + + dvr::VrHwc& mVrHal; + + ComposerClientImpl(const ComposerClientImpl&) = delete; + void operator=(const ComposerClientImpl&) = delete; +}; + +ComposerClientImpl::ComposerClientImpl(android::dvr::VrHwc& hal) : ComposerClient(hal), mVrHal(hal) {} -VrComposerClient::~VrComposerClient() {} +ComposerClientImpl::~ComposerClientImpl() {} std::unique_ptr<ComposerClient::CommandReader> -VrComposerClient::createCommandReader() { +ComposerClientImpl::createCommandReader() { return std::unique_ptr<CommandReader>(new VrCommandReader(*this)); } -VrComposerClient::VrCommandReader::VrCommandReader(VrComposerClient& client) +ComposerClientImpl::VrCommandReader::VrCommandReader(ComposerClientImpl& client) : CommandReader(client), mVrClient(client), mVrHal(client.mVrHal) {} -VrComposerClient::VrCommandReader::~VrCommandReader() {} +ComposerClientImpl::VrCommandReader::~VrCommandReader() {} -bool VrComposerClient::VrCommandReader::parseCommand( +bool ComposerClientImpl::VrCommandReader::parseCommand( IComposerClient::Command command, uint16_t length) { IVrComposerClient::VrCommand vrCommand = static_cast<IVrComposerClient::VrCommand>(command); @@ -59,7 +96,7 @@ bool VrComposerClient::VrCommandReader::parseCommand( } } -bool VrComposerClient::VrCommandReader::parseSetLayerInfo(uint16_t length) { +bool ComposerClientImpl::VrCommandReader::parseSetLayerInfo(uint16_t length) { if (length != 2) { return false; } @@ -72,7 +109,7 @@ bool VrComposerClient::VrCommandReader::parseSetLayerInfo(uint16_t length) { return true; } -bool VrComposerClient::VrCommandReader::parseSetClientTargetMetadata( +bool ComposerClientImpl::VrCommandReader::parseSetClientTargetMetadata( uint16_t length) { if (length != 7) return false; @@ -84,7 +121,7 @@ bool VrComposerClient::VrCommandReader::parseSetClientTargetMetadata( return true; } -bool VrComposerClient::VrCommandReader::parseSetLayerBufferMetadata( +bool ComposerClientImpl::VrCommandReader::parseSetLayerBufferMetadata( uint16_t length) { if (length != 7) return false; @@ -98,7 +135,7 @@ bool VrComposerClient::VrCommandReader::parseSetLayerBufferMetadata( } IVrComposerClient::BufferMetadata -VrComposerClient::VrCommandReader::readBufferMetadata() { +ComposerClientImpl::VrCommandReader::readBufferMetadata() { IVrComposerClient::BufferMetadata metadata = { .width = read(), .height = read(), @@ -110,5 +147,132 @@ VrComposerClient::VrCommandReader::readBufferMetadata() { return metadata; } +} // namespace + +VrComposerClient::VrComposerClient(dvr::VrHwc& hal) + : client_(new ComposerClientImpl(hal)) { + client_->initialize(); +} + +VrComposerClient::~VrComposerClient() {} + +void VrComposerClient::onHotplug(Display display, + IComposerCallback::Connection connected) { + client_->onHotplug(display, connected); +} + +Return<void> VrComposerClient::registerCallback( + const sp<IComposerCallback>& callback) { + return client_->registerCallback(callback); +} + +Return<uint32_t> VrComposerClient::getMaxVirtualDisplayCount() { + return client_->getMaxVirtualDisplayCount(); +} + +Return<void> VrComposerClient::createVirtualDisplay(uint32_t width, + uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount, + createVirtualDisplay_cb hidl_cb) { + return client_->createVirtualDisplay( + width, height, formatHint, outputBufferSlotCount, hidl_cb); +} + +Return<Error> VrComposerClient::destroyVirtualDisplay(Display display) { + return client_->destroyVirtualDisplay(display); +} + +Return<void> VrComposerClient::createLayer(Display display, + uint32_t bufferSlotCount, createLayer_cb hidl_cb) { + return client_->createLayer(display, bufferSlotCount, hidl_cb); +} + +Return<Error> VrComposerClient::destroyLayer(Display display, Layer layer) { + return client_->destroyLayer(display, layer); +} + +Return<void> VrComposerClient::getActiveConfig(Display display, + getActiveConfig_cb hidl_cb) { + return client_->getActiveConfig(display, hidl_cb); +} + +Return<Error> VrComposerClient::getClientTargetSupport(Display display, + uint32_t width, uint32_t height, PixelFormat format, Dataspace dataspace) { + return client_->getClientTargetSupport(display, width, height, format, + dataspace); +} + +Return<void> VrComposerClient::getColorModes(Display display, + getColorModes_cb hidl_cb) { + return client_->getColorModes(display, hidl_cb); +} + +Return<void> VrComposerClient::getDisplayAttribute(Display display, + Config config, Attribute attribute, getDisplayAttribute_cb hidl_cb) { + return client_->getDisplayAttribute(display, config, attribute, hidl_cb); +} + +Return<void> VrComposerClient::getDisplayConfigs(Display display, + getDisplayConfigs_cb hidl_cb) { + return client_->getDisplayConfigs(display, hidl_cb); +} + +Return<void> VrComposerClient::getDisplayName(Display display, + getDisplayName_cb hidl_cb) { + return client_->getDisplayName(display, hidl_cb); +} + +Return<void> VrComposerClient::getDisplayType(Display display, + getDisplayType_cb hidl_cb) { + return client_->getDisplayType(display, hidl_cb); +} + +Return<void> VrComposerClient::getDozeSupport( + Display display, getDozeSupport_cb hidl_cb) { + return client_->getDozeSupport(display, hidl_cb); +} + +Return<void> VrComposerClient::getHdrCapabilities( + Display display, getHdrCapabilities_cb hidl_cb) { + return client_->getHdrCapabilities(display, hidl_cb); +} + +Return<Error> VrComposerClient::setActiveConfig(Display display, + Config config) { + return client_->setActiveConfig(display, config); +} + +Return<Error> VrComposerClient::setColorMode(Display display, ColorMode mode) { + return client_->setColorMode(display, mode); +} + +Return<Error> VrComposerClient::setPowerMode(Display display, PowerMode mode) { + return client_->setPowerMode(display, mode); +} + +Return<Error> VrComposerClient::setVsyncEnabled(Display display, + Vsync enabled) { + return client_->setVsyncEnabled(display, enabled); +} + +Return<Error> VrComposerClient::setClientTargetSlotCount( + Display display, uint32_t clientTargetSlotCount) { + return client_->setClientTargetSlotCount(display, clientTargetSlotCount); +} + +Return<Error> VrComposerClient::setInputCommandQueue( + const hardware::MQDescriptorSync<uint32_t>& descriptor) { + return client_->setInputCommandQueue(descriptor); +} + +Return<void> VrComposerClient::getOutputCommandQueue( + getOutputCommandQueue_cb hidl_cb) { + return client_->getOutputCommandQueue(hidl_cb); +} + +Return<void> VrComposerClient::executeCommands(uint32_t inLength, + const hidl_vec<hidl_handle>& inHandles, executeCommands_cb hidl_cb) { + return client_->executeCommands(inLength, inHandles, hidl_cb); +} + } // namespace dvr } // namespace android diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h index 1236be96bc..f492230215 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.h +++ b/services/vr/hardware_composer/impl/vr_composer_client.h @@ -29,37 +29,59 @@ class VrHwc; using hardware::graphics::common::V1_0::PixelFormat; using hardware::graphics::composer::V2_1::implementation::ComposerClient; -class VrComposerClient : public ComposerClient { +class VrComposerClient : public IVrComposerClient { public: VrComposerClient(android::dvr::VrHwc& hal); virtual ~VrComposerClient(); - private: - class VrCommandReader : public ComposerClient::CommandReader { - public: - VrCommandReader(VrComposerClient& client); - ~VrCommandReader() override; - - bool parseCommand(IComposerClient::Command command, - uint16_t length) override; - - private: - bool parseSetLayerInfo(uint16_t length); - bool parseSetClientTargetMetadata(uint16_t length); - bool parseSetLayerBufferMetadata(uint16_t length); - - IVrComposerClient::BufferMetadata readBufferMetadata(); + void onHotplug(Display display, IComposerCallback::Connection connected); + + // IComposerClient + Return<void> registerCallback(const sp<IComposerCallback>& callback) override; + Return<uint32_t> getMaxVirtualDisplayCount() override; + Return<void> createVirtualDisplay( + uint32_t width, uint32_t height, PixelFormat formatHint, + uint32_t outputBufferSlotCount, createVirtualDisplay_cb hidl_cb) override; + Return<Error> destroyVirtualDisplay(Display display) override; + Return<void> createLayer(Display display, uint32_t bufferSlotCount, + createLayer_cb hidl_cb) override; + Return<Error> destroyLayer(Display display, Layer layer) override; + Return<void> getActiveConfig(Display display, + getActiveConfig_cb hidl_cb) override; + Return<Error> getClientTargetSupport( + Display display, uint32_t width, uint32_t height, PixelFormat format, + Dataspace dataspace) override; + Return<void> getColorModes(Display display, + getColorModes_cb hidl_cb) override; + Return<void> getDisplayAttribute( + Display display, Config config, Attribute attribute, + getDisplayAttribute_cb hidl_cb) override; + Return<void> getDisplayConfigs(Display display, + getDisplayConfigs_cb hidl_cb) override; + Return<void> getDisplayName(Display display, + getDisplayName_cb hidl_cb) override; + Return<void> getDisplayType(Display display, + getDisplayType_cb hidl_cb) override; + Return<void> getDozeSupport(Display display, + getDozeSupport_cb hidl_cb) override; + Return<void> getHdrCapabilities(Display display, + getHdrCapabilities_cb hidl_cb) override; + Return<Error> setActiveConfig(Display display, Config config) override; + Return<Error> setColorMode(Display display, ColorMode mode) override; + Return<Error> setPowerMode(Display display, PowerMode mode) override; + Return<Error> setVsyncEnabled(Display display, Vsync enabled) override; + Return<Error> setClientTargetSlotCount( + Display display, uint32_t clientTargetSlotCount) override; + Return<Error> setInputCommandQueue( + const hardware::MQDescriptorSync<uint32_t>& descriptor) override; + Return<void> getOutputCommandQueue( + getOutputCommandQueue_cb hidl_cb) override; + Return<void> executeCommands( + uint32_t inLength, const hidl_vec<hidl_handle>& inHandles, + executeCommands_cb hidl_cb) override; - VrComposerClient& mVrClient; - android::dvr::VrHwc& mVrHal; - - VrCommandReader(const VrCommandReader&) = delete; - void operator=(const VrCommandReader&) = delete; - }; - - std::unique_ptr<CommandReader> createCommandReader() override; - - dvr::VrHwc& mVrHal; + private: + std::unique_ptr<ComposerClient> client_; VrComposerClient(const VrComposerClient&) = delete; void operator=(const VrComposerClient&) = delete; diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp index 5d5182775d..861114dbca 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.cpp +++ b/services/vr/hardware_composer/impl/vr_hwc.cpp @@ -15,6 +15,7 @@ */ #include "impl/vr_hwc.h" +#include <cutils/properties.h> #include <private/dvr/display_client.h> #include <ui/Fence.h> @@ -336,11 +337,30 @@ Error VrHwc::getDisplayAttribute(Display display, Config config, *outValue = display_ptr->height(); break; case IComposerClient::Attribute::VSYNC_PERIOD: - *outValue = 1000 * 1000 * 1000 / 30; // 30fps + { + int error = 0; + auto display_client = display::DisplayClient::Create(&error); + if (!display_client) { + ALOGE("Could not connect to display service : %s(%d)", + strerror(error), error); + // Return a default value of 30 fps + *outValue = 1000 * 1000 * 1000 / 30; + } else { + auto metrics = display_client->GetDisplayMetrics(); + *outValue = metrics.get().vsync_period_ns; + } + } break; case IComposerClient::Attribute::DPI_X: case IComposerClient::Attribute::DPI_Y: - *outValue = 300 * 1000; // 300dpi + { + constexpr int32_t kDefaultDPI = 300; + int32_t dpi = property_get_int32("ro.vr.hwc.dpi", kDefaultDPI); + if (dpi <= 0) { + dpi = kDefaultDPI; + } + *outValue = 1000 * dpi; + } break; default: return Error::BAD_PARAMETER; @@ -820,7 +840,6 @@ Return<void> VrHwc::createClient(createClient_cb hidl_cb) { sp<VrComposerClient> client; if (client_ == nullptr) { client = new VrComposerClient(*this); - client->initialize(); } else { ALOGE("Already have a client"); status = Error::NO_RESOURCES; @@ -852,12 +871,5 @@ HwcDisplay* VrHwc::FindDisplay(Display display) { return iter == displays_.end() ? nullptr : iter->second.get(); } -ComposerView* GetComposerViewFromIComposer( - hardware::graphics::composer::V2_1::IComposer* composer) { - return static_cast<VrHwc*>(composer); -} - -IComposer* HIDL_FETCH_IComposer(const char*) { return new VrHwc(); } - } // namespace dvr } // namespace android diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h index df04208fca..523cda3f69 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.h +++ b/services/vr/hardware_composer/impl/vr_hwc.h @@ -309,13 +309,6 @@ class VrHwc : public IComposer, public ComposerBase, public ComposerView { void operator=(const VrHwc&) = delete; }; - -ComposerView* GetComposerViewFromIComposer( - hardware::graphics::composer::V2_1::IComposer* composer); - -hardware::graphics::composer::V2_1::IComposer* HIDL_FETCH_IComposer( - const char* name); - } // namespace dvr } // namespace android diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp index c45fbf4ea6..36a313ae24 100644 --- a/services/vr/hardware_composer/vr_composer.cpp +++ b/services/vr/hardware_composer/vr_composer.cpp @@ -42,6 +42,12 @@ binder::Status VrComposer::registerObserver( return binder::Status::ok(); } +binder::Status VrComposer::clearObserver() { + std::lock_guard<std::mutex> guard(mutex_); + callback_ = nullptr; + return binder::Status::ok(); +} + base::unique_fd VrComposer::OnNewFrame(const ComposerView::Frame& frame) { std::lock_guard<std::mutex> guard(mutex_); diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h index 93d1f2be00..7b580c6cba 100644 --- a/services/vr/hardware_composer/vr_composer.h +++ b/services/vr/hardware_composer/vr_composer.h @@ -27,6 +27,8 @@ class VrComposer binder::Status registerObserver( const sp<IVrComposerCallback>& callback) override; + binder::Status clearObserver() override; + // ComposerView::Observer: base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override; diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp index f9802201da..e36b0ae3f1 100644 --- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp +++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp @@ -26,22 +26,18 @@ int main() { // Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR // mode. - const char instance[] = "vr"; - android::sp<IComposer> service = - android::dvr::HIDL_FETCH_IComposer(instance); + android::sp<android::dvr::VrHwc> service = new android::dvr::VrHwc(); LOG_ALWAYS_FATAL_IF(!service.get(), "Failed to get service"); LOG_ALWAYS_FATAL_IF(service->isRemote(), "Service is remote"); + const char instance[] = "vr"; LOG_ALWAYS_FATAL_IF(service->registerAsService(instance) != android::OK, "Failed to register service"); android::sp<android::dvr::VrComposer> composer = new android::dvr::VrComposer(); - - android::dvr::ComposerView* composer_view = - android::dvr::GetComposerViewFromIComposer(service.get()); - composer_view->RegisterObserver(composer.get()); + service->RegisterObserver(composer.get()); android::sp<android::IServiceManager> sm(android::defaultServiceManager()); @@ -56,7 +52,7 @@ int main() { android::hardware::ProcessState::self()->startThreadPool(); android::hardware::IPCThreadState::self()->joinThreadPool(); - composer_view->UnregisterObserver(composer.get()); + service->UnregisterObserver(composer.get()); return 0; } diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk index 6256e9049d..dbc66f1cb3 100644 --- a/services/vr/performanced/Android.mk +++ b/services/vr/performanced/Android.mk @@ -23,8 +23,10 @@ sourceFiles := \ staticLibraries := \ libperformance \ libpdx_default_transport \ + libvr_manager sharedLibraries := \ + libbinder \ libbase \ libcutils \ liblog \ diff --git a/services/vr/performanced/cpu_set.cpp b/services/vr/performanced/cpu_set.cpp index 1a3723f0b6..1a7264c701 100644 --- a/services/vr/performanced/cpu_set.cpp +++ b/services/vr/performanced/cpu_set.cpp @@ -15,6 +15,9 @@ #include "task.h" #include "unique_file.h" +using android::pdx::ErrorStatus; +using android::pdx::Status; + namespace { constexpr int kDirectoryFlags = O_RDONLY | O_DIRECTORY | O_CLOEXEC; @@ -176,11 +179,11 @@ void CpuSetManager::MoveUnboundTasks(const std::string& target_set) { task_id, task.name().c_str(), target_set.c_str(), task.thread_group_id(), task.parent_process_id()); - const int ret = target->AttachTask(task_id); - ALOGW_IF(ret < 0 && ret != -EINVAL, + auto status = target->AttachTask(task_id); + ALOGW_IF(!status && status.error() != EINVAL, "CpuSetManager::MoveUnboundTasks: Failed to attach task_id=%d " "to cpuset=%s: %s", - task_id, target_set.c_str(), strerror(-ret)); + task_id, target_set.c_str(), status.GetErrorMessage().c_str()); } else { ALOGD_IF(TRACE, "CpuSet::MoveUnboundTasks: Skipping task_id=%d name=%s cpus=%s.", @@ -233,7 +236,7 @@ UniqueFile CpuSet::OpenFilePointer(const std::string& name, int flags) const { return fp; } -int CpuSet::AttachTask(pid_t task_id) const { +Status<void> CpuSet::AttachTask(pid_t task_id) const { auto file = OpenFile("tasks", O_RDWR); if (file.get() >= 0) { std::ostringstream stream; @@ -241,11 +244,15 @@ int CpuSet::AttachTask(pid_t task_id) const { std::string value = stream.str(); const bool ret = base::WriteStringToFd(value, file.get()); - return !ret ? -errno : 0; + if (!ret) + return ErrorStatus(errno); + else + return {}; } else { + const int error = errno; ALOGE("CpuSet::AttachTask: Failed to open %s/tasks: %s", path_.c_str(), - strerror(errno)); - return -errno; + strerror(error)); + return ErrorStatus(error); } } diff --git a/services/vr/performanced/cpu_set.h b/services/vr/performanced/cpu_set.h index fcf280a56f..6879272dc4 100644 --- a/services/vr/performanced/cpu_set.h +++ b/services/vr/performanced/cpu_set.h @@ -11,6 +11,8 @@ #include <android-base/unique_fd.h> +#include <pdx/status.h> + #include "unique_file.h" namespace android { @@ -28,7 +30,7 @@ class CpuSet { std::string GetCpuList() const; - int AttachTask(pid_t task_id) const; + pdx::Status<void> AttachTask(pid_t task_id) const; std::vector<pid_t> GetTasks() const; private: diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp index 955c6610cc..4b9fbe047d 100644 --- a/services/vr/performanced/performance_service.cpp +++ b/services/vr/performanced/performance_service.cpp @@ -8,14 +8,20 @@ #include <pdx/rpc/argument_encoder.h> #include <pdx/rpc/message_buffer.h> #include <pdx/rpc/remote_method.h> +#include <private/android_filesystem_config.h> #include <private/dvr/performance_rpc.h> +#include <private/dvr/trusted_uids.h> #include "task.h" // This prctl is only available in Android kernels. #define PR_SET_TIMERSLACK_PID 41 +using android::dvr::IsTrustedUid; +using android::dvr::Task; +using android::pdx::ErrorStatus; using android::pdx::Message; +using android::pdx::Status; using android::pdx::rpc::DispatchRemoteMethod; using android::pdx::default_transport::Endpoint; @@ -26,6 +32,68 @@ const char kCpuSetBasePath[] = "/dev/cpuset"; constexpr unsigned long kTimerSlackForegroundNs = 50000; constexpr unsigned long kTimerSlackBackgroundNs = 40000000; +// Expands the given parameter pack expression using an initializer list to +// guarantee ordering and a comma expression to guarantee even void expressions +// are valid elements of the initializer list. +#define EXPAND_PACK(...) \ + std::initializer_list<int> { (__VA_ARGS__, 0)... } + +// Returns true if the sender's euid matches any of the uids in |UIDs|. +template <uid_t... UIDs> +struct UserId { + static bool Check(const Message& sender, const Task&) { + const uid_t uid = sender.GetEffectiveUserId(); + bool allow = false; + EXPAND_PACK(allow |= (uid == UIDs)); + return allow; + } +}; + +// Returns true if the sender's egid matches any of the gids in |GIDs|. +template <gid_t... GIDs> +struct GroupId { + static bool Check(const Message& sender, const Task&) { + const gid_t gid = sender.GetEffectiveGroupId(); + bool allow = false; + EXPAND_PACK(allow |= (gid == GIDs)); + return allow; + } +}; + +// Returns true if the sender's euid is trusted according to VR manager service. +struct Trusted { + static bool Check(const Message& sender, const Task&) { + return IsTrustedUid(sender.GetEffectiveUserId()); + } +}; + +// Returns returns true if the task belongs to the sending process. +struct SameProcess { + static bool Check(const Message& sender, const Task& task) { + return sender.GetProcessId() == task.thread_group_id(); + } +}; + +// Returns true if any of the checks in |Allows| pass, false otherwise. +template <typename... Allows> +struct CheckOr { + static bool Check(const Message& sender, const Task& task) { + bool allow = false; + EXPAND_PACK(allow |= Allows::Check(sender, task)); + return allow; + } +}; + +// Returns true if all of the checks in |Allows| pass, false otherwise. +template <typename... Allows> +struct CheckAnd { + static bool Check(const Message& sender, const Task& task) { + bool allow = true; + EXPAND_PACK(allow &= Allows::Check(sender, task)); + return allow; + } +}; + } // anonymous namespace namespace android { @@ -48,43 +116,79 @@ PerformanceService::PerformanceService() const int fifo_low = sched_fifo_min_priority_; const int fifo_medium = sched_fifo_min_priority_ + fifo_range / 5; - // TODO(eieio): Make this configurable on the command line. + // TODO(eieio): Make this configurable on the command line or config file. cpuset_.MoveUnboundTasks("/kernel"); + // TODO(eieio): Replace this witha device-specific config file. This is just a + // hack for now to put some form of permission logic in place while a longer + // term solution is developed. + using AllowRootSystem = + CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM>, + GroupId<AID_SYSTEM>>>; + using AllowRootSystemGraphics = + CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>, + GroupId<AID_SYSTEM, AID_GRAPHICS>>>; + using AllowRootSystemAudio = + CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>, + GroupId<AID_SYSTEM, AID_AUDIO>>>; + using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, + GroupId<AID_SYSTEM>>; + + partition_permission_check_ = AllowRootSystemTrusted::Check; + // Setup the scheduler classes. + // TODO(eieio): Replace this with a device-specific config file. scheduler_classes_ = { {"audio:low", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, - .priority = fifo_medium}}, + .priority = fifo_medium, + .permission_check = AllowRootSystemAudio::Check}}, {"audio:high", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, - .priority = fifo_medium + 3}}, + .priority = fifo_medium + 3, + .permission_check = AllowRootSystemAudio::Check}}, {"graphics", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, - .priority = fifo_medium}}, + .priority = fifo_medium, + .permission_check = AllowRootSystemGraphics::Check}}, {"graphics:low", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, - .priority = fifo_medium}}, + .priority = fifo_medium, + .permission_check = AllowRootSystemGraphics::Check}}, {"graphics:high", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, - .priority = fifo_medium + 2}}, + .priority = fifo_medium + 2, + .permission_check = AllowRootSystemGraphics::Check}}, {"sensors", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, - .priority = fifo_low}}, + .priority = fifo_low, + .permission_check = AllowRootSystem::Check}}, {"sensors:low", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, - .priority = fifo_low}}, + .priority = fifo_low, + .permission_check = AllowRootSystem::Check}}, {"sensors:high", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, - .priority = fifo_low + 1}}, + .priority = fifo_low + 1, + .permission_check = AllowRootSystem::Check}}, + {"vr:system:arp", + {.timer_slack = kTimerSlackForegroundNs, + .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, + .priority = fifo_medium + 2, + .permission_check = AllowRootSystemTrusted::Check}}, + {"vr:app:render", + {.timer_slack = kTimerSlackForegroundNs, + .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, + .priority = fifo_medium + 1, + .permission_check = AllowRootSystemTrusted::Check}}, {"normal", {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_NORMAL, @@ -113,67 +217,94 @@ std::string PerformanceService::DumpState(size_t /*max_length*/) { return cpuset_.DumpState(); } -int PerformanceService::OnSetCpuPartition(Message& message, pid_t task_id, - const std::string& partition) { +Status<void> PerformanceService::OnSetSchedulerPolicy( + Message& message, pid_t task_id, const std::string& scheduler_policy) { + // Forward to scheduler class handler for now. In the future this method will + // subsume the others by unifying both scheduler class and cpu partiton into a + // single policy concept. + ALOGI( + "PerformanceService::OnSetSchedulerPolicy: task_id=%d " + "scheduler_policy=%s", + task_id, scheduler_policy.c_str()); + return OnSetSchedulerClass(message, task_id, scheduler_policy); +} + +Status<void> PerformanceService::OnSetCpuPartition( + Message& message, pid_t task_id, const std::string& partition) { Task task(task_id); if (!task || task.thread_group_id() != message.GetProcessId()) - return -EINVAL; + return ErrorStatus(EINVAL); + + // Temporary permission check. + // TODO(eieio): Replace this with a configuration file. + if (partition_permission_check_ && + !partition_permission_check_(message, task)) { + return ErrorStatus(EINVAL); + } auto target_set = cpuset_.Lookup(partition); if (!target_set) - return -ENOENT; + return ErrorStatus(ENOENT); - const auto attach_error = target_set->AttachTask(task_id); - if (attach_error) - return attach_error; + auto attach_status = target_set->AttachTask(task_id); + if (!attach_status) + return attach_status; - return 0; + return {}; } -int PerformanceService::OnSetSchedulerClass( +Status<void> PerformanceService::OnSetSchedulerClass( Message& message, pid_t task_id, const std::string& scheduler_class) { - // Make sure the task id is valid and belongs to the sending process. Task task(task_id); - if (!task || task.thread_group_id() != message.GetProcessId()) - return -EINVAL; - - struct sched_param param; + if (!task) + return ErrorStatus(EINVAL); - // TODO(eieio): Apply rules based on the requesting process. Applications are - // only allowed one audio thread that runs at SCHED_FIFO. System services can - // have more than one. auto search = scheduler_classes_.find(scheduler_class); if (search != scheduler_classes_.end()) { auto config = search->second; + + // Make sure the sending process is allowed to make the requested change to + // this task. + if (!config.IsAllowed(message, task)) + return ErrorStatus(EINVAL); + + struct sched_param param; param.sched_priority = config.priority; + sched_setscheduler(task_id, config.scheduler_policy, ¶m); prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id); ALOGI("PerformanceService::OnSetSchedulerClass: Set task=%d to class=%s.", task_id, scheduler_class.c_str()); - return 0; + return {}; } else { ALOGE( "PerformanceService::OnSetSchedulerClass: Invalid class=%s requested " "by task=%d.", scheduler_class.c_str(), task_id); - return -EINVAL; + return ErrorStatus(EINVAL); } } -std::string PerformanceService::OnGetCpuPartition(Message& message, - pid_t task_id) { +Status<std::string> PerformanceService::OnGetCpuPartition(Message& message, + pid_t task_id) { // Make sure the task id is valid and belongs to the sending process. Task task(task_id); if (!task || task.thread_group_id() != message.GetProcessId()) - REPLY_ERROR_RETURN(message, EINVAL, ""); + return ErrorStatus(EINVAL); return task.GetCpuSetPath(); } -pdx::Status<void> PerformanceService::HandleMessage(Message& message) { +Status<void> PerformanceService::HandleMessage(Message& message) { + ALOGD_IF(TRACE, "PerformanceService::HandleMessage: op=%d", message.GetOp()); switch (message.GetOp()) { + case PerformanceRPC::SetSchedulerPolicy::Opcode: + DispatchRemoteMethod<PerformanceRPC::SetSchedulerPolicy>( + *this, &PerformanceService::OnSetSchedulerPolicy, message); + return {}; + case PerformanceRPC::SetCpuPartition::Opcode: - DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>( + DispatchRemoteMethod<PerformanceRPC::SetCpuPartition>( *this, &PerformanceService::OnSetCpuPartition, message); return {}; diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h index 34abba7bd9..b28d94addb 100644 --- a/services/vr/performanced/performance_service.h +++ b/services/vr/performanced/performance_service.h @@ -1,12 +1,14 @@ #ifndef ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_ #define ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_ +#include <functional> #include <string> #include <unordered_map> #include <pdx/service.h> #include "cpu_set.h" +#include "task.h" namespace android { namespace dvr { @@ -27,11 +29,15 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { PerformanceService(); - int OnSetCpuPartition(pdx::Message& message, pid_t task_id, - const std::string& partition); - int OnSetSchedulerClass(pdx::Message& message, pid_t task_id, - const std::string& scheduler_class); - std::string OnGetCpuPartition(pdx::Message& message, pid_t task_id); + pdx::Status<void> OnSetSchedulerPolicy(pdx::Message& message, pid_t task_id, + const std::string& scheduler_class); + + pdx::Status<void> OnSetCpuPartition(pdx::Message& message, pid_t task_id, + const std::string& partition); + pdx::Status<void> OnSetSchedulerClass(pdx::Message& message, pid_t task_id, + const std::string& scheduler_class); + pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message, + pid_t task_id); CpuSetManager cpuset_; @@ -43,10 +49,27 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { unsigned long timer_slack; int scheduler_policy; int priority; + std::function<bool(const pdx::Message& message, const Task& task)> + permission_check; + + // Check the permisison of the given task to use this scheduler class. If a + // permission check function is not set then operations are only allowed on + // tasks in the sender's process. + bool IsAllowed(const pdx::Message& sender, const Task& task) const { + if (permission_check) + return permission_check(sender, task); + else if (!task || task.thread_group_id() != sender.GetProcessId()) + return false; + else + return true; + } }; std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_; + std::function<bool(const pdx::Message& message, const Task& task)> + partition_permission_check_; + PerformanceService(const PerformanceService&) = delete; void operator=(const PerformanceService&) = delete; }; diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp index b526082afe..274a1b36d4 100644 --- a/services/vr/performanced/performance_service_tests.cpp +++ b/services/vr/performanced/performance_service_tests.cpp @@ -1,12 +1,22 @@ #include <errno.h> #include <sched.h> +#include <sys/types.h> +#include <unistd.h> #include <condition_variable> +#include <cstdlib> #include <mutex> #include <thread> #include <dvr/performance_client_api.h> #include <gtest/gtest.h> +#include <private/android_filesystem_config.h> + +namespace { + +const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID"; + +} // anonymous namespace TEST(DISABLED_PerformanceTest, SetCpuPartition) { int error; @@ -86,6 +96,27 @@ TEST(PerformanceTest, SetSchedulerClass) { EXPECT_EQ(-EINVAL, error); } +// This API mirrors SetSchedulerClass for now. Replace with with a more specific +// test once the policy API is fully implemented. +TEST(PerformanceTest, SetSchedulerPolicy) { + int error; + + error = dvrSetSchedulerPolicy(0, "background"); + EXPECT_EQ(0, error); + EXPECT_EQ(SCHED_BATCH, sched_getscheduler(0)); + + error = dvrSetSchedulerPolicy(0, "audio:low"); + EXPECT_EQ(0, error); + EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0)); + + error = dvrSetSchedulerPolicy(0, "normal"); + EXPECT_EQ(0, error); + EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0)); + + error = dvrSetSchedulerPolicy(0, "foobar"); + EXPECT_EQ(-EINVAL, error); +} + TEST(PerformanceTest, SchedulerClassResetOnFork) { int error; @@ -135,3 +166,284 @@ TEST(PerformanceTest, GetCpuPartition) { error = dvrGetCpuPartition(0, nullptr, sizeof(partition)); EXPECT_EQ(-EINVAL, error); } + +TEST(PerformanceTest, Permissions) { + int error; + + const int original_uid = getuid(); + const int original_gid = getgid(); + int trusted_uid = -1; + + // See if the environment variable GTEST_TRUSTED_UID is set. If it is enable + // testing the ActivityManager trusted uid permission checks using that uid. + const char* trusted_uid_env = std::getenv(kTrustedUidEnvironmentVariable); + if (trusted_uid_env) + trusted_uid = std::atoi(trusted_uid_env); + + ASSERT_EQ(AID_ROOT, original_uid) + << "This test must run as root to function correctly!"; + + // Test unprivileged policies on a task that does not belong to this process. + // Use the init process (task_id=1) as the target. + error = dvrSetSchedulerPolicy(1, "batch"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(1, "background"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(1, "foreground"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(1, "normal"); + EXPECT_EQ(-EINVAL, error); + + // Switch the uid/gid to an id that should not have permission to access any + // privileged actions. + ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1)) + << "Failed to set gid: " << strerror(errno); + ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1)) + << "Failed to set uid: " << strerror(errno); + + // Unprivileged policies. + error = dvrSetSchedulerPolicy(0, "batch"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "background"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "foreground"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "normal"); + EXPECT_EQ(0, error); + + // Privileged policies. + error = dvrSetSchedulerPolicy(0, "audio:low"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "audio:high"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "graphics"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "graphics:low"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "graphics:high"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "sensors"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "sensors:low"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "sensors:high"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "vr:system:arp"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "vr:app:render"); + EXPECT_EQ(-EINVAL, error); + + // uid=AID_SYSTEM / gid=AID_NOBODY + ASSERT_EQ(0, setresuid(original_uid, original_uid, -1)) + << "Failed to restore uid: " << strerror(errno); + ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_SYSTEM, -1)) + << "Failed to set uid: " << strerror(errno); + + // Unprivileged policies. + error = dvrSetSchedulerPolicy(0, "batch"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "background"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "foreground"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "normal"); + EXPECT_EQ(0, error); + + // Privileged policies. + error = dvrSetSchedulerPolicy(0, "audio:low"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "audio:high"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:low"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:high"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "sensors"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "sensors:low"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "sensors:high"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "vr:system:arp"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "vr:app:render"); + EXPECT_EQ(0, error); + + // uid=AID_NOBODY / gid=AID_SYSTEM + ASSERT_EQ(0, setresuid(original_uid, original_uid, -1)) + << "Failed to restore uid: " << strerror(errno); + ASSERT_EQ(0, setresgid(original_gid, original_gid, -1)) + << "Failed to restore gid: " << strerror(errno); + ASSERT_EQ(0, setresgid(AID_SYSTEM, AID_SYSTEM, -1)) + << "Failed to set gid: " << strerror(errno); + ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_NOBODY, -1)) + << "Failed to set uid: " << strerror(errno); + + // Unprivileged policies. + error = dvrSetSchedulerPolicy(0, "batch"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "background"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "foreground"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "normal"); + EXPECT_EQ(0, error); + + // Privileged policies. + error = dvrSetSchedulerPolicy(0, "audio:low"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "audio:high"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:low"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:high"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "sensors"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "sensors:low"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "sensors:high"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "vr:system:arp"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "vr:app:render"); + EXPECT_EQ(0, error); + + // uid=AID_GRAPHICS / gid=AID_NOBODY + ASSERT_EQ(0, setresuid(original_uid, original_uid, -1)) + << "Failed to restore uid: " << strerror(errno); + ASSERT_EQ(0, setresgid(original_gid, original_gid, -1)) + << "Failed to restore gid: " << strerror(errno); + ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1)) + << "Failed to set gid: " << strerror(errno); + ASSERT_EQ(0, setresuid(AID_GRAPHICS, AID_GRAPHICS, -1)) + << "Failed to set uid: " << strerror(errno); + + // Unprivileged policies. + error = dvrSetSchedulerPolicy(0, "batch"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "background"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "foreground"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "normal"); + EXPECT_EQ(0, error); + + // Privileged policies. + error = dvrSetSchedulerPolicy(0, "audio:low"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "audio:high"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "graphics"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:low"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:high"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "sensors"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "sensors:low"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "sensors:high"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "vr:system:arp"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "vr:app:render"); + EXPECT_EQ(-EINVAL, error); + + // uid=AID_NOBODY / gid=AID_GRAPHICS + ASSERT_EQ(0, setresuid(original_uid, original_uid, -1)) + << "Failed to restore uid: " << strerror(errno); + ASSERT_EQ(0, setresgid(original_gid, original_gid, -1)) + << "Failed to restore gid: " << strerror(errno); + ASSERT_EQ(0, setresgid(AID_GRAPHICS, AID_GRAPHICS, -1)) + << "Failed to set gid: " << strerror(errno); + ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1)) + << "Failed to set uid: " << strerror(errno); + + // Unprivileged policies. + error = dvrSetSchedulerPolicy(0, "batch"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "background"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "foreground"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "normal"); + EXPECT_EQ(0, error); + + // Privileged policies. + error = dvrSetSchedulerPolicy(0, "audio:low"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "audio:high"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "graphics"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:low"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:high"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "sensors"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "sensors:low"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "sensors:high"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "vr:system:arp"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "vr:app:render"); + EXPECT_EQ(-EINVAL, error); + + if (trusted_uid != -1) { + // uid=<trusted uid> / gid=AID_NOBODY + ASSERT_EQ(0, setresuid(original_uid, original_uid, -1)) + << "Failed to restore uid: " << strerror(errno); + ASSERT_EQ(0, setresgid(original_gid, original_gid, -1)) + << "Failed to restore gid: " << strerror(errno); + ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1)) + << "Failed to set gid: " << strerror(errno); + ASSERT_EQ(0, setresuid(trusted_uid, trusted_uid, -1)) + << "Failed to set uid: " << strerror(errno); + + // Unprivileged policies. + error = dvrSetSchedulerPolicy(0, "batch"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "background"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "foreground"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "normal"); + EXPECT_EQ(0, error); + + // Privileged policies. + error = dvrSetSchedulerPolicy(0, "audio:low"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "audio:high"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "graphics"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:low"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "graphics:high"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "sensors"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "sensors:low"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "sensors:high"); + EXPECT_EQ(-EINVAL, error); + error = dvrSetSchedulerPolicy(0, "vr:system:arp"); + EXPECT_EQ(0, error); + error = dvrSetSchedulerPolicy(0, "vr:app:render"); + EXPECT_EQ(0, error); + } + + // Restore original effective uid/gid. + ASSERT_EQ(0, setresgid(original_gid, original_gid, -1)) + << "Failed to restore gid: " << strerror(errno); + ASSERT_EQ(0, setresuid(original_uid, original_uid, -1)) + << "Failed to restore uid: " << strerror(errno); +} diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp index 3d5dfb271a..6b11ce3e25 100644 --- a/services/vr/virtual_touchpad/Android.bp +++ b/services/vr/virtual_touchpad/Android.bp @@ -13,10 +13,15 @@ shared_libs = [ "libutils", ] +header_libraries = [ + "libdvr_headers" +] + cc_library { srcs: src, export_include_dirs: ["include"], shared_libs: shared_libs, + header_libs: header_libraries, cppflags: ["-std=c++11"], cflags: ["-DLOG_TAG=\"VrVirtualTouchpad\""], name: "libvirtualtouchpad", @@ -28,9 +33,6 @@ cc_library { test_static_libs = [ "libcutils", "libvirtualtouchpad", -] - -test_shared_libs = [ "libbase", "liblog", "libutils", @@ -41,7 +43,7 @@ test_src_files = ["tests/VirtualTouchpad_test.cpp"] cc_test { srcs: test_src_files, static_libs: test_static_libs, - shared_libs: test_shared_libs, + header_libs: header_libraries, cppflags = [ "-std=c++11", ], @@ -77,6 +79,7 @@ cc_binary { srcs: service_src, static_libs: service_static_libs, shared_libs: service_shared_libs, + header_libs: header_libraries, cppflags: ["-std=c++11"], cflags: [ "-DLOG_TAG=\"VrVirtualTouchpad\"", @@ -107,6 +110,7 @@ client_shared_libs = [ cc_library { srcs: client_src, shared_libs: client_shared_libs, + header_libs: header_libraries, cppflags: ["-std=c++11"], cflags: ["-DLOG_TAG=\"VirtualTouchpadClient\""], host_ldlibs: ["-llog"], diff --git a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp index eb152edb8b..3ab77a7132 100644 --- a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp +++ b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp @@ -40,6 +40,11 @@ int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad, return FromC(client)->ButtonState(touchpad, buttons); } +int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x, + float y) { + return FromC(client)->Scroll(touchpad, x, y); +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/services/vr/virtual_touchpad/EvdevInjector.cpp b/services/vr/virtual_touchpad/EvdevInjector.cpp index a4ccdd0b6a..7fad37943a 100644 --- a/services/vr/virtual_touchpad/EvdevInjector.cpp +++ b/services/vr/virtual_touchpad/EvdevInjector.cpp @@ -168,6 +168,25 @@ int EvdevInjector::ConfigureAbsSlots(int slots) { return ConfigureAbs(ABS_MT_SLOT, 0, slots, 0, 0); } +int EvdevInjector::ConfigureRel(uint16_t rel_type) { + ALOGV("ConfigureRel 0x%" PRIX16 "", rel_type); + if (rel_type < 0 || rel_type >= REL_CNT) { + ALOGE("EV_REL type 0x%" PRIX16 " out of range [0,0x%X)", rel_type, REL_CNT); + return Error(ERROR_REL_RANGE); + } + if (const int status = RequireState(State::CONFIGURING)) { + return status; + } + if (const int status = EnableEventType(EV_REL)) { + return status; + } + if (const int status = uinput_->IoctlSetInt(UI_SET_RELBIT, rel_type)) { + ALOGE("failed to enable EV_REL 0x%" PRIX16 "", rel_type); + return Error(status); + } + return 0; +} + int EvdevInjector::ConfigureEnd() { ALOGV("ConfigureEnd:"); ALOGV(" name=\"%s\"", uidev_.name); @@ -236,6 +255,10 @@ int EvdevInjector::SendAbs(uint16_t code, int32_t value) { return Send(EV_ABS, code, value); } +int EvdevInjector::SendRel(uint16_t code, int32_t value) { + return Send(EV_REL, code, value); +} + int EvdevInjector::SendMultiTouchSlot(int32_t slot) { if (latest_slot_ != slot) { if (const int status = SendAbs(ABS_MT_SLOT, slot)) { diff --git a/services/vr/virtual_touchpad/EvdevInjector.h b/services/vr/virtual_touchpad/EvdevInjector.h index c69dbefa72..e87c959418 100644 --- a/services/vr/virtual_touchpad/EvdevInjector.h +++ b/services/vr/virtual_touchpad/EvdevInjector.h @@ -30,6 +30,7 @@ class EvdevInjector { ERROR_KEY_RANGE = -3, // |KEY_*|/|BTN_*| code out of range. ERROR_ABS_RANGE = -4, // |ABS_*| code out of range. ERROR_SEQUENCING = -5, // Configure/Send out of order. + ERROR_REL_RANGE = -6, // |REL_*| code out of range. }; // Key event |value| is not defined in <linux/input.h>. @@ -87,6 +88,10 @@ class EvdevInjector { // Configure multitouch coordinate range. int ConfigureMultiTouchXY(int32_t x0, int32_t y0, int32_t x1, int32_t y1); + // Configure a relative axis. + // @param rel_type One of the |REL_*| constants from <linux/input.h>. + int ConfigureRel(uint16_t rel_type); + // Complete configuration and create the input device. int ConfigureEnd(); @@ -96,6 +101,7 @@ class EvdevInjector { int SendSynReport(); int SendKey(uint16_t code, int32_t value); int SendAbs(uint16_t code, int32_t value); + int SendRel(uint16_t code, int32_t value); int SendMultiTouchSlot(int32_t slot); int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y); int SendMultiTouchLift(int32_t slot); diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp index c7c8184c53..00e4ce61f8 100644 --- a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp +++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp @@ -60,6 +60,13 @@ class VirtualTouchpadClientImpl : public VirtualTouchpadClient { return service_->buttonState(touchpad, buttons).transactionError(); } + status_t Scroll(int touchpad, float x, float y) override { + if (service_ == nullptr) { + return NO_INIT; + } + return service_->scroll(touchpad, x, y).transactionError(); + } + void dumpInternal(String8& result) override { result.append("[virtual touchpad]\n"); result.appendFormat("connected = %s\n\n", diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp index f0bdcd9970..bcfdad3ef9 100644 --- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp +++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp @@ -28,6 +28,12 @@ static constexpr int32_t kWidth = 0x10000; static constexpr int32_t kHeight = 0x10000; static constexpr int32_t kSlots = 2; +static constexpr float kScrollScale = 100.0f; + +int32_t scale_relative_scroll(float x) { + return kScrollScale * x; +} + } // anonymous namespace std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() { @@ -66,6 +72,8 @@ status_t VirtualTouchpadEvdev::Attach() { touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT); touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1); touchpad.injector->ConfigureAbsSlots(kSlots); + touchpad.injector->ConfigureRel(REL_WHEEL); + touchpad.injector->ConfigureRel(REL_HWHEEL); touchpad.injector->ConfigureKey(BTN_TOUCH); touchpad.injector->ConfigureKey(BTN_BACK); touchpad.injector->ConfigureEnd(); @@ -86,9 +94,6 @@ int VirtualTouchpadEvdev::Touch(int touchpad_id, float x, float y, if (touchpad_id < 0 || touchpad_id >= kTouchpads) { return EINVAL; } - if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) { - return EINVAL; - } int32_t device_x = x * kWidth; int32_t device_y = y * kHeight; Touchpad& touchpad = touchpad_[touchpad_id]; @@ -162,6 +167,33 @@ int VirtualTouchpadEvdev::ButtonState(int touchpad_id, int buttons) { return touchpad.injector->GetError(); } +int VirtualTouchpadEvdev::Scroll(int touchpad_id, float x, float y) { + if (touchpad_id < 0 || touchpad_id >= kTouchpads) { + return EINVAL; + } + if ((x < -1.0f) || (x > 1.0f) || (y < -1.0f) || (y > 1.0f)) { + return EINVAL; + } + Touchpad& touchpad = touchpad_[touchpad_id]; + if (!touchpad.injector) { + return EvdevInjector::ERROR_SEQUENCING; + } + touchpad.injector->ResetError(); + const int32_t scaled_x = scale_relative_scroll(x); + const int32_t scaled_y = scale_relative_scroll(y); + ALOGV("(%f,%f) -> (%" PRId32 ",%" PRId32 ")", x, y, scaled_x, scaled_y); + if (scaled_x) { + touchpad.injector->SendRel(REL_HWHEEL, scaled_x); + } + if (scaled_y) { + touchpad.injector->SendRel(REL_WHEEL, scaled_y); + } + if (scaled_x || scaled_y) { + touchpad.injector->SendSynReport(); + } + return touchpad.injector->GetError(); +} + void VirtualTouchpadEvdev::dumpInternal(String8& result) { for (int i = 0; i < kTouchpads; ++i) { const auto& touchpad = touchpad_[i]; diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h index 2fb8ff34b0..c9578bf001 100644 --- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h +++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h @@ -21,6 +21,7 @@ class VirtualTouchpadEvdev : public VirtualTouchpad { status_t Detach() override; status_t Touch(int touchpad, float x, float y, float pressure) override; status_t ButtonState(int touchpad, int buttons) override; + status_t Scroll(int touchpad, float x, float y) override; void dumpInternal(String8& result) override; protected: diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp index 81edd32875..523f890ce7 100644 --- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp +++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp @@ -87,6 +87,16 @@ binder::Status VirtualTouchpadService::buttonState(int touchpad, int buttons) { return binder::Status::ok(); } +binder::Status VirtualTouchpadService::scroll(int touchpad, float x, float y) { + if (!CheckPermissions()) { + return binder::Status::fromStatusT(PERMISSION_DENIED); + } + if (const status_t error = touchpad_->Scroll(touchpad, x, y)) { + return binder::Status::fromStatusT(error); + } + return binder::Status::ok(); +} + status_t VirtualTouchpadService::dump( int fd, const Vector<String16>& args[[gnu::unused]]) { String8 result; diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h index cf236f9923..2c46209228 100644 --- a/services/vr/virtual_touchpad/VirtualTouchpadService.h +++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h @@ -23,6 +23,7 @@ class VirtualTouchpadService : public BnVirtualTouchpadService { binder::Status detach() override; binder::Status touch(int touchpad, float x, float y, float pressure) override; binder::Status buttonState(int touchpad, int buttons) override; + binder::Status scroll(int touchpad, float x, float y) override; // Implements BBinder::dump(). status_t dump(int fd, const Vector<String16>& args) override; diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl index 9cfb1868f3..256203ca6d 100644 --- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl +++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl @@ -34,4 +34,15 @@ interface VirtualTouchpadService * @param buttons A union of MotionEvent BUTTON_* values. */ void buttonState(int touchpad, int buttons) = 3; + + /** + * Generate a simulated scroll event. + * + * @param touchpad Selects touchpad. + * @param x Horizontal scroll increment. + * @param y Vertical scroll increment. + * + * Scroll values are in the range [-1.0, 1.0]. + */ + void scroll(int touchpad, float x, float y) = 4; } diff --git a/cmds/surfacereplayer/proto/Android.mk b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc index 3cf1148832..205e8b901f 100644 --- a/cmds/surfacereplayer/proto/Android.mk +++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc @@ -1,5 +1,4 @@ -# -# Copyright (C) 2016 The Android Open Source Project +# 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. @@ -12,17 +11,16 @@ # 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 +# +# Virtual touchpad for the primary display +device.internal = 1 -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +touch.deviceType = touchScreen -include $(BUILD_STATIC_LIBRARY) +# Have input flinger treat injected scroll events like a G1 ball +# rather than the default mouse wheel, because the latter requires +# a visible pointer for targeting. +device.type = rotaryEncoder +device.res = 1.0e+2 +device.scalingFactor = 1.0e-2 diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc new file mode 100644 index 0000000000..d9714e0364 --- /dev/null +++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc @@ -0,0 +1,31 @@ +# Copyright (C) 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Virtual touchpad for the VR virtual display +device.internal = 1 + +touch.deviceType = touchScreen + +# Have input flinger treat injected scroll events like a G1 ball +# rather than the default mouse wheel, because the latter requires +# a visible pointer for targeting. +device.type = rotaryEncoder +device.res = 1.0e+2 +device.scalingFactor = 1.0e-2 + +# This displayID matches the unique ID of the virtual display created for VR. +# This will indicate to input flinger than it should link this input device +# with the virtual display. +touch.displayId = virtual:android:277f1a09-b88d-4d1e-8716-796f114d080b diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h index da3a0b7ee4..99b72fc0d0 100644 --- a/services/vr/virtual_touchpad/include/VirtualTouchpad.h +++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h @@ -61,6 +61,16 @@ class VirtualTouchpad { // virtual status_t ButtonState(int touchpad, int buttons) = 0; + // Generate a simulated scroll event. + // + // @param touchpad Touchpad selector index. + // @param x Horizontal scroll increment. + // @param y Vertical scroll increment. + // Values must be in the range [-1.0, 1.0]. + // @returns OK on success. + // + virtual status_t Scroll(int touchpad, float x, float y) = 0; + // Report state for 'dumpsys'. virtual void dumpInternal(String8& result) = 0; diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h index 23fb9f8321..7d73f06f6b 100644 --- a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h +++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h @@ -17,6 +17,7 @@ class VirtualTouchpadClient : public VirtualTouchpad { status_t Detach() override; status_t Touch(int touchpad, float x, float y, float pressure) override; status_t ButtonState(int touchpad, int buttons) override; + status_t Scroll(int touchpad, float x, float y) override; void dumpInternal(String8& result) override; protected: diff --git a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h index 08cca1b1a7..09fb1cca56 100644 --- a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h +++ b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h @@ -1,17 +1,14 @@ #ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_H #define ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_H +#include <dvr/dvr_api.h> + #ifdef __cplusplus extern "C" { #endif typedef struct DvrVirtualTouchpad DvrVirtualTouchpad; -enum { - DVR_VIRTUAL_TOUCHPAD_PRIMARY = 0, - DVR_VIRTUAL_TOUCHPAD_VIRTUAL = 1, -}; - // Creates a new virtual touchpad client. // // @return Pointer to the created virtual touchpad client; nullptr on failure. @@ -64,6 +61,17 @@ int dvrVirtualTouchpadTouch(DvrVirtualTouchpad* client, int touchpad, float x, int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad, int buttons); +// Generate a simulated scroll event. +// +// @param client Pointer to the virtual touchpad client. +// @param touchpad Selects touchpad. +// @param x Horizontal scroll increment. +// @param y Vertical scroll increment. +// @return Zero on success, status_t-style error code on failure. +// +int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x, + float y); + #ifdef __cplusplus } // extern "C" #endif diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp index 564bcd7bd9..b19b018d49 100644 --- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp +++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp @@ -169,6 +169,11 @@ TEST_F(VirtualTouchpadTest, Goodness) { expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y); // From ConfigureAbsSlots(kSlots): expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT); + // From ConfigureRel(REL_WHEEL): + expect.IoctlSetInt(UI_SET_EVBIT, EV_REL); + expect.IoctlSetInt(UI_SET_RELBIT, REL_WHEEL); + // From ConfigureRel(REL_HWHEEL): + expect.IoctlSetInt(UI_SET_RELBIT, REL_HWHEEL); // From ConfigureKey(BTN_TOUCH): expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY); expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH); diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api index cae1992501..3a2b1efb0b 100644 --- a/vulkan/api/vulkan.api +++ b/vulkan/api/vulkan.api @@ -1424,6 +1424,7 @@ enum VkColorSpaceKHR { VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, + VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, } @extension("VK_EXT_debug_report") // 12 diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h index 43a9a9c20d..d3e5f0f6b1 100644 --- a/vulkan/include/vulkan/vk_android_native_buffer.h +++ b/vulkan/include/vulkan/vk_android_native_buffer.h @@ -17,7 +17,7 @@ #ifndef __VK_ANDROID_NATIVE_BUFFER_H__ #define __VK_ANDROID_NATIVE_BUFFER_H__ -#include <system/window.h> +#include <cutils/native_handle.h> #include <vulkan/vulkan.h> #ifdef __cplusplus diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h index c368ed01c5..0271d38415 100644 --- a/vulkan/include/vulkan/vulkan.h +++ b/vulkan/include/vulkan/vulkan.h @@ -3433,6 +3433,7 @@ typedef enum VkColorSpaceKHR { VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, + VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1), @@ -6203,7 +6204,7 @@ VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT( #endif #define VK_EXT_swapchain_colorspace 1 -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 3 #define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 61498949bb..5f9b357a35 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -75,6 +75,7 @@ cc_library_shared { "libbase", "liblog", "libui", + "libgraphicsenv", "libutils", "libcutils", "libz", diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 6f425f50c1..947a2f7bfe 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -28,9 +28,11 @@ #include <android/dlext.h> #include <cutils/properties.h> -#include <ui/GraphicsEnv.h> +#include <graphicsenv/GraphicsEnv.h> #include <utils/Vector.h> +#include "android-base/properties.h" + #include "driver.h" #include "stubhal.h" @@ -822,9 +824,9 @@ VkResult EnumerateDeviceExtensionProperties( // conditionally add VK_GOOGLE_display_timing if present timestamps are // supported by the driver: - char timestamp_property[PROPERTY_VALUE_MAX]; - property_get("service.sf.present_timestamp", timestamp_property, "1"); - if (strcmp(timestamp_property, "1") == 0) { + const std::string timestamp_property("service.sf.present_timestamp"); + android::base::WaitForPropertyCreation(timestamp_property); + if (android::base::GetBoolProperty(timestamp_property, true)) { loader_extensions.push_back({ VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION}); diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index e2c8c0677c..a346c0ac76 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -22,6 +22,7 @@ #include <sync/sync.h> #include <utils/StrongPointer.h> #include <utils/Vector.h> +#include <system/window.h> #include "driver.h" @@ -429,6 +430,8 @@ android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) { return HAL_DATASPACE_DISPLAY_P3; case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT: return HAL_DATASPACE_V0_SCRGB_LINEAR; + case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT: + return HAL_DATASPACE_V0_SCRGB; case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT: return HAL_DATASPACE_DCI_P3_LINEAR; case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT: @@ -639,6 +642,8 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, const VkSurfaceFormatKHR kWideColorFormats[] = { {VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT}, + {VK_FORMAT_R16G16B16A16_SFLOAT, + VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT}, {VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}, }; @@ -1014,7 +1019,7 @@ VkResult CreateSwapchainKHR(VkDevice device, return VK_ERROR_SURFACE_LOST_KHR; } } - err = native_window_set_usage(surface.window.get(), gralloc_usage); + err = native_window_set_usage(surface.window.get(), uint64_t(gralloc_usage)); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible // errors and translate them to valid Vulkan result codes? @@ -1091,8 +1096,8 @@ VkResult CreateSwapchainKHR(VkDevice device, image_native_buffer.handle = img.buffer->handle; image_native_buffer.stride = img.buffer->stride; image_native_buffer.format = img.buffer->format; - image_native_buffer.usage = img.buffer->usage; - android_convertGralloc0To1Usage(img.buffer->usage, + image_native_buffer.usage = int(img.buffer->usage); + android_convertGralloc0To1Usage(int(img.buffer->usage), &image_native_buffer.usage2.producer, &image_native_buffer.usage2.consumer); |