Merge "Add IPsec tunnel migration feature flag"
diff --git a/Android.bp b/Android.bp
index 615a7a8..3992f82 100644
--- a/Android.bp
+++ b/Android.bp
@@ -56,7 +56,8 @@
cc_library_headers {
name: "libandroid_sensor_headers",
- vendor: true,
+ vendor_available: true,
+ host_supported: true,
export_include_dirs: ["include_sensor"],
}
diff --git a/TEST_MAPPING b/TEST_MAPPING
index f54f132..e66bca0 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -28,9 +28,6 @@
"include-filter": "*CropLatchingTest.*"
},
{
- "include-filter": "*ChildLayerTest.*"
- },
- {
"include-filter": "*ScreenCaptureTest.*"
},
{
@@ -56,9 +53,6 @@
},
{
"include-filter": "*RefreshRateOverlayTest.*"
- },
- {
- "exclude-filter": "*ChildLayerTest#ChildrenSurviveParentDestruction"
}
]
},
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl
index 7e89220..bb3faaf 100644
--- a/aidl/gui/android/view/Surface.aidl
+++ b/aidl/gui/android/view/Surface.aidl
@@ -17,4 +17,4 @@
package android.view;
-parcelable Surface cpp_header "gui/view/Surface.h";
+@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h";
diff --git a/cmds/atrace/README.md b/cmds/atrace/README.md
new file mode 100644
index 0000000..faa43b2
--- /dev/null
+++ b/cmds/atrace/README.md
@@ -0,0 +1,48 @@
+# Atrace categories
+
+The atrace command (and the perfetto configuration) allow listing **categories**
+to select subsets of events to be traced.
+
+Each category can include some userspace events and some ftrace events.
+
+## Vendor categories
+
+It's possible to extend exiting categories (or to define new categories) from
+the /vendor partition in order to add hardware specific ftrace events.
+
+Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt`, atrace
+and perfetto will consider the categories and ftrace events listed there.
+
+The file contains a list of categories, and for each category (on the following
+lines, indented with one or more spaces of time), a list of ftrace events that
+should be enabled when the category is enabled.
+
+Each ftrace event should be a subdirectory in `/sys/kernel/tracing/events/` and
+should be of the form `group/event`. Listing a whole group is not supported,
+each event needs to be listed explicitly.
+
+It is not an error if an ftrace event is listed in the file, but not present on
+the tracing file system.
+
+Example:
+
+```
+gfx
+ mali/gpu_power_state
+ mali/mali_pm_status
+thermal_tj
+ thermal_exynos/thermal_cpu_pressure
+ thermal_exynos/thermal_exynos_arm_update
+```
+
+The file lists two categories (`gfx` and `thermal_tj`). When the `gfx` category
+is enabled, atrace (or perfetto) will enable
+`/sys/kernel/tracing/events/mali/gpu_power_state` and
+`/sys/kernel/tracing/events/mali/mali_pm_status`. When the `thermal_tj` category
+is enabled, atrace (or perfetto) will enable
+`/sys/kernel/tracing/events/thermal_exynos/thermal_cpu_pressure` and
+`/sys/kernel/tracing/events/thermal_exynos/thermal_exynos_arm_update`.
+
+Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt` exists
+on the file system, perfetto and atrace do not query the android.hardware.atrace
+HAL (which is deprecated).
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 48d48ac..8105626 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -49,6 +49,7 @@
#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
+#include <android-base/strings.h>
#include <android-base/stringprintf.h>
using namespace android;
@@ -62,7 +63,7 @@
using std::string;
-#define MAX_SYS_FILES 12
+#define MAX_SYS_FILES 13
const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
@@ -73,7 +74,9 @@
const char* k_pdxServiceCategory = "pdx";
const char* k_coreServicesProp = "ro.atrace.core.services";
-typedef enum { OPT, REQ } requiredness ;
+const char* kVendorCategoriesPath = "/vendor/etc/atrace/atrace_categories.txt";
+
+typedef enum { OPT, REQ } requiredness;
struct TracingCategory {
// The name identifying the category.
@@ -189,6 +192,8 @@
{ OPT, "events/f2fs/f2fs_sync_file_exit/enable" },
{ OPT, "events/f2fs/f2fs_write_begin/enable" },
{ OPT, "events/f2fs/f2fs_write_end/enable" },
+ { OPT, "events/f2fs/f2fs_iostat/enable" },
+ { OPT, "events/f2fs/f2fs_iostat_latency/enable" },
{ OPT, "events/ext4/ext4_da_write_begin/enable" },
{ OPT, "events/ext4/ext4_da_write_end/enable" },
{ OPT, "events/ext4/ext4_sync_file_enter/enable" },
@@ -253,7 +258,20 @@
} },
};
-struct TracingVendorCategory {
+// A category in the vendor categories file.
+struct TracingVendorFileCategory {
+ // The name identifying the category.
+ std::string name;
+
+ // If the category is enabled through command.
+ bool enabled = false;
+
+ // Paths to the ftrace enable files (relative to g_traceFolder).
+ std::vector<std::string> ftrace_enable_paths;
+};
+
+// A category in the vendor HIDL HAL.
+struct TracingVendorHalCategory {
// The name identifying the category.
std::string name;
@@ -263,11 +281,8 @@
// If the category is enabled through command.
bool enabled;
- TracingVendorCategory(string &&name, string &&description, bool enabled)
- : name(std::move(name))
- , description(std::move(description))
- , enabled(enabled)
- {}
+ TracingVendorHalCategory(string&& name, string&& description, bool enabled)
+ : name(std::move(name)), description(std::move(description)), enabled(enabled) {}
};
/* Command line options */
@@ -287,8 +302,9 @@
static bool g_traceAborted = false;
static bool g_categoryEnables[arraysize(k_categories)] = {};
static std::string g_traceFolder;
+static std::vector<TracingVendorFileCategory> g_vendorFileCategories;
static sp<IAtraceDevice> g_atraceHal;
-static std::vector<TracingVendorCategory> g_vendorCategories;
+static std::vector<TracingVendorHalCategory> g_vendorHalCategories;
/* Sys file paths */
static const char* k_traceClockPath =
@@ -645,6 +661,13 @@
}
}
}
+ for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
+ for (const std::string& path : c.ftrace_enable_paths) {
+ if (fileIsWritable(path.c_str())) {
+ ok &= setKernelOptionEnable(path.c_str(), false);
+ }
+ }
+ }
return ok;
}
@@ -724,7 +747,13 @@
static bool setCategoryEnable(const char* name)
{
bool vendor_found = false;
- for (auto &c : g_vendorCategories) {
+ for (auto& c : g_vendorFileCategories) {
+ if (strcmp(name, c.name.c_str()) == 0) {
+ c.enabled = true;
+ vendor_found = true;
+ }
+ }
+ for (auto& c : g_vendorHalCategories) {
if (strcmp(name, c.name.c_str()) == 0) {
c.enabled = true;
vendor_found = true;
@@ -870,6 +899,16 @@
}
}
+ for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
+ if (c.enabled) {
+ for (const std::string& path : c.ftrace_enable_paths) {
+ if (fileIsWritable(path.c_str())) {
+ ok &= setKernelOptionEnable(path.c_str(), true);
+ }
+ }
+ }
+ }
+
return ok;
}
@@ -1055,7 +1094,10 @@
printf(" %10s - %s\n", c.name, c.longname);
}
}
- for (const auto &c : g_vendorCategories) {
+ for (const auto& c : g_vendorFileCategories) {
+ printf(" %10s - (VENDOR)\n", c.name.c_str());
+ }
+ for (const auto& c : g_vendorHalCategories) {
printf(" %10s - %s (HAL)\n", c.name.c_str(), c.description.c_str());
}
}
@@ -1114,8 +1156,38 @@
return true;
}
-void initVendorCategories()
-{
+void initVendorCategoriesFromFile() {
+ std::ifstream is(kVendorCategoriesPath);
+ for (std::string line; std::getline(is, line);) {
+ if (line.empty()) {
+ continue;
+ }
+ if (android::base::StartsWith(line, ' ') || android::base::StartsWith(line, '\t')) {
+ if (g_vendorFileCategories.empty()) {
+ fprintf(stderr, "Malformed vendor categories file\n");
+ exit(1);
+ return;
+ }
+ std::string_view path = std::string_view(line).substr(1);
+ while (android::base::StartsWith(path, ' ') || android::base::StartsWith(path, '\t')) {
+ path.remove_prefix(1);
+ }
+ if (path.empty()) {
+ continue;
+ }
+ std::string enable_path = "events/";
+ enable_path += path;
+ enable_path += "/enable";
+ g_vendorFileCategories.back().ftrace_enable_paths.push_back(std::move(enable_path));
+ } else {
+ TracingVendorFileCategory cat;
+ cat.name = line;
+ g_vendorFileCategories.push_back(std::move(cat));
+ }
+ }
+}
+
+void initVendorCategoriesFromHal() {
g_atraceHal = IAtraceDevice::getService();
if (g_atraceHal == nullptr) {
@@ -1123,27 +1195,34 @@
return;
}
- Return<void> ret = g_atraceHal->listCategories(
- [](const auto& list) {
- g_vendorCategories.reserve(list.size());
- for (const auto& category : list) {
- g_vendorCategories.emplace_back(category.name, category.description, false);
- }
- });
+ Return<void> ret = g_atraceHal->listCategories([](const auto& list) {
+ g_vendorHalCategories.reserve(list.size());
+ for (const auto& category : list) {
+ g_vendorHalCategories.emplace_back(category.name, category.description, false);
+ }
+ });
if (!ret.isOk()) {
fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
}
}
-static bool setUpVendorTracing()
-{
+void initVendorCategories() {
+ // If kVendorCategoriesPath exists on the filesystem, do not use the HAL.
+ if (access(kVendorCategoriesPath, F_OK) != -1) {
+ initVendorCategoriesFromFile();
+ } else {
+ initVendorCategoriesFromHal();
+ }
+}
+
+static bool setUpVendorTracingWithHal() {
if (g_atraceHal == nullptr) {
// No atrace HAL
return true;
}
std::vector<hidl_string> categories;
- for (const auto &c : g_vendorCategories) {
+ for (const auto& c : g_vendorHalCategories) {
if (c.enabled) {
categories.emplace_back(c.name);
}
@@ -1164,15 +1243,14 @@
return true;
}
-static bool cleanUpVendorTracing()
-{
+static bool cleanUpVendorTracingWithHal() {
if (g_atraceHal == nullptr) {
// No atrace HAL
return true;
}
- if (!g_vendorCategories.size()) {
- // No vendor categories
+ if (!g_vendorHalCategories.size()) {
+ // No vendor HAL categories
return true;
}
@@ -1326,7 +1404,7 @@
if (ok && traceStart && !onlyUserspace) {
ok &= setUpKernelTracing();
- ok &= setUpVendorTracing();
+ ok &= setUpVendorTracingWithHal();
ok &= startTrace();
}
@@ -1397,7 +1475,7 @@
if (traceStop) {
cleanUpUserspaceTracing();
if (!onlyUserspace) {
- cleanUpVendorTracing();
+ cleanUpVendorTracingWithHal();
cleanUpKernelTracing();
}
}
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index a60972b..a62bd01 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -126,6 +126,7 @@
],
required: [
"atrace",
+ "bugreport_procdump",
"dmabuf_dump",
"ip",
"iptables",
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index 3091f6b..6f7fea3 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -162,17 +162,16 @@
return 0;
}
bool newline = false;
+ int poll_timeout_ms = 30 * 1000;
while (true) {
- uint64_t start_time = Nanotime();
pollfd fds[] = { { .fd = fd, .events = POLLIN } };
- int ret = TEMP_FAILURE_RETRY(poll(fds, arraysize(fds), 30 * 1000));
+ int ret = TEMP_FAILURE_RETRY(poll(fds, arraysize(fds), poll_timeout_ms));
if (ret == -1) {
dprintf(out_fd, "*** %s: poll failed: %s\n", path, strerror(errno));
newline = true;
break;
- } else if (ret == 0) {
- uint64_t elapsed = Nanotime() - start_time;
- dprintf(out_fd, "*** %s: Timed out after %.3fs\n", path, (float)elapsed / NANOS_PER_SEC);
+ } else if (ret == 0 && poll_timeout_ms != 0) {
+ dprintf(out_fd, "*** %s: Timed out after %ds\n", path, poll_timeout_ms / 1000 );
newline = true;
break;
} else {
@@ -189,6 +188,7 @@
break;
}
}
+ poll_timeout_ms = 0;
}
if (!newline) dprintf(out_fd, "\n");
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 6e9747f..12de33f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -170,6 +170,7 @@
#define RECOVERY_DIR "/cache/recovery"
#define RECOVERY_DATA_DIR "/data/misc/recovery"
#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
+#define UPDATE_ENGINE_PREF_DIR "/data/misc/update_engine/prefs"
#define LOGPERSIST_DATA_DIR "/data/misc/logd"
#define PREREBOOT_DATA_DIR "/data/misc/prereboot"
#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
@@ -193,6 +194,8 @@
static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
static const std::string ANR_DIR = "/data/anr/";
static const std::string ANR_FILE_PREFIX = "anr_";
+static const std::string SHUTDOWN_CHECKPOINTS_DIR = "/data/system/shutdown-checkpoints/";
+static const std::string SHUTDOWN_CHECKPOINTS_FILE_PREFIX = "checkpoints-";
// TODO: temporary variables and functions used during C++ refactoring
@@ -234,6 +237,7 @@
// task and the log title of the duration report.
static const std::string DUMP_TRACES_TASK = "DUMP TRACES";
static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT";
+static const std::string DUMP_NETSTATS_PROTO_TASK = "DUMP NETSTATS PROTO";
static const std::string DUMP_HALS_TASK = "DUMP HALS";
static const std::string DUMP_BOARD_TASK = "dumpstate_board()";
static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS";
@@ -1041,6 +1045,26 @@
}
}
+static void DumpNetstatsProto() {
+ const std::string path = ds.bugreport_internal_dir_ + "/tmp_netstats_proto";
+ auto fd = android::base::unique_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 %s to dump netstats proto.\n", path.c_str());
+ return;
+ }
+ RunCommandToFd(fd, "", {"dumpsys", "netstats", "--proto"},
+ CommandOptions::WithTimeout(120).Build());
+ bool empty = 0 == lseek(fd, 0, SEEK_END);
+ if (!empty) {
+ ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "netstats" + kProtoExt,
+ path);
+ } else {
+ unlink(path.c_str());
+ }
+}
+
static void MaybeAddSystemTraceToZip() {
// This function copies into the .zip the system trace that was snapshotted
// by the early call to MaybeSnapshotSystemTrace(), if any background
@@ -1087,6 +1111,16 @@
RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
}
+static void DumpShutdownCheckpoints() {
+ const bool shutdown_checkpoints_dumped = AddDumps(
+ ds.shutdown_checkpoints_.begin(), ds.shutdown_checkpoints_.end(),
+ "SHUTDOWN CHECKPOINTS", false /* add_to_zip */);
+ if (!shutdown_checkpoints_dumped) {
+ printf("*** NO SHUTDOWN CHECKPOINTS to dump in %s\n\n",
+ SHUTDOWN_CHECKPOINTS_DIR.c_str());
+ }
+}
+
static void DumpDynamicPartitionInfo() {
if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
return;
@@ -1576,7 +1610,8 @@
DurationReporter duration_reporter("DUMPSTATE");
// Enqueue slow functions into the thread pool, if the parallel run is enabled.
- std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins;
+ std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins,
+ dump_netstats_report;
if (ds.dump_pool_) {
// Pool was shutdown in DumpstateDefaultAfterCritical method in order to
// drop root user. Restarts it with two threads for the parallel run.
@@ -1585,6 +1620,8 @@
dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
dump_incident_report = ds.dump_pool_->enqueueTask(
DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
+ dump_netstats_report = ds.dump_pool_->enqueueTask(
+ DUMP_NETSTATS_PROTO_TASK, &DumpNetstatsProto);
dump_board = ds.dump_pool_->enqueueTaskWithFd(
DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
@@ -1600,7 +1637,8 @@
RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
"pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "BUGREPORT_PROCDUMP", {"bugreport_procdump"},
+ CommandOptions::AS_ROOT);
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpVisibleWindowViews);
@@ -1617,9 +1655,6 @@
RunCommand("PROCESSES AND THREADS",
{"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
- CommandOptions::AS_ROOT);
-
if (ds.dump_pool_) {
WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_hals));
} else {
@@ -1649,8 +1684,6 @@
RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
-
for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
@@ -1680,6 +1713,8 @@
DoKmsg();
+ DumpShutdownCheckpoints();
+
DumpIpAddrAndRules();
dump_route_tables();
@@ -1783,6 +1818,13 @@
dump_frozen_cgroupfs();
if (ds.dump_pool_) {
+ WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_netstats_report));
+ } else {
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_NETSTATS_PROTO_TASK,
+ DumpNetstatsProto);
+ }
+
+ if (ds.dump_pool_) {
WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_incident_report));
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK,
@@ -1827,11 +1869,14 @@
if (!PropertiesHelper::IsDryRun()) {
ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX);
ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX);
+ ds.shutdown_checkpoints_ = GetDumpFds(
+ SHUTDOWN_CHECKPOINTS_DIR, SHUTDOWN_CHECKPOINTS_FILE_PREFIX);
}
ds.AddDir(RECOVERY_DIR, true);
ds.AddDir(RECOVERY_DATA_DIR, true);
ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
+ ds.AddDir(UPDATE_ENGINE_PREF_DIR, true);
ds.AddDir(LOGPERSIST_DATA_DIR, false);
if (!PropertiesHelper::IsUserBuild()) {
ds.AddDir(PROFILE_DATA_DIR_CUR, true);
@@ -2878,6 +2923,7 @@
}
tombstone_data_.clear();
anr_data_.clear();
+ shutdown_checkpoints_.clear();
// Instead of shutdown the pool, we delete temporary files directly since
// shutdown blocking the call.
@@ -3161,6 +3207,7 @@
tombstone_data_.clear();
anr_data_.clear();
+ shutdown_checkpoints_.clear();
return (consent_callback_ != nullptr &&
consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
@@ -3891,15 +3938,6 @@
return;
}
-void do_showmap(int pid, const char *name) {
- char title[255];
- char arg[255];
-
- snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
- snprintf(arg, sizeof(arg), "%d", pid);
- RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
-}
-
int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
DurationReporter duration_reporter(title);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index ee6b1ae..7ffe80e 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -499,6 +499,9 @@
// List of open ANR dump files.
std::vector<DumpData> anr_data_;
+ // List of open shutdown checkpoint files.
+ std::vector<DumpData> shutdown_checkpoints_;
+
// A thread pool to execute dump tasks simultaneously if the parallel run is enabled.
std::unique_ptr<android::os::dumpstate::DumpPool> dump_pool_;
@@ -619,9 +622,6 @@
/* Displays a processes times */
void show_showtime(int pid, const char *name);
-/* Runs "showmap" for a process */
-void do_showmap(int pid, const char *name);
-
/* Gets the dmesg output for the kernel */
void do_dmesg();
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index f0c19b9..b8e5ce1 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -60,6 +60,7 @@
MOCK_METHOD1(isDeclared, bool(const String16&));
MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
+ MOCK_METHOD1(getUpdatableNames, Vector<String16>(const String16&));
MOCK_METHOD1(getConnectionInfo, std::optional<ConnectionInfo>(const String16&));
MOCK_METHOD2(registerForNotifications, status_t(const String16&,
const sp<LocalRegistrationCallback>&));
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index faf67fd..bb6639e 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -99,6 +99,8 @@
static constexpr const char* kDataMirrorCePath = "/data_mirror/data_ce";
static constexpr const char* kDataMirrorDePath = "/data_mirror/data_de";
+static constexpr const char* kMiscMirrorCePath = "/data_mirror/misc_ce";
+static constexpr const char* kMiscMirrorDePath = "/data_mirror/misc_de";
static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
@@ -499,10 +501,6 @@
}
static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
- if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
- return true;
- }
-
int32_t uid = multiuser_get_uid(userId, appId);
int shared_app_gid = multiuser_get_shared_gid(userId, appId);
if (shared_app_gid == -1) {
@@ -3558,16 +3556,28 @@
std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
- return error("Failed to create CE mirror");
+ return error("Failed to create CE data mirror");
}
std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
- return error("Failed to create DE mirror");
+ return error("Failed to create DE data mirror");
+ }
+
+ std::string mirrorVolMiscCePath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_));
+ if (fs_prepare_dir(mirrorVolMiscCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+ return error("Failed to create CE misc mirror");
+ }
+
+ std::string mirrorVolMiscDePath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_));
+ if (fs_prepare_dir(mirrorVolMiscDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+ return error("Failed to create DE misc mirror");
}
auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str());
auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
+ auto miscCePath = StringPrintf("%s/misc_ce", create_data_path(uuid_).c_str());
+ auto miscDePath = StringPrintf("%s/misc_de", create_data_path(uuid_).c_str());
if (access(cePath.c_str(), F_OK) != 0) {
return error("Cannot access CE path: " + cePath);
@@ -3575,6 +3585,12 @@
if (access(dePath.c_str(), F_OK) != 0) {
return error("Cannot access DE path: " + dePath);
}
+ if (access(miscCePath.c_str(), F_OK) != 0) {
+ return error("Cannot access misc CE path: " + cePath);
+ }
+ if (access(miscDePath.c_str(), F_OK) != 0) {
+ return error("Cannot access misc DE path: " + dePath);
+ }
struct stat ceStat, mirrorCeStat;
if (stat(cePath.c_str(), &ceStat) != 0) {
@@ -3602,6 +3618,21 @@
MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
return error("Failed to mount " + mirrorVolDePath);
}
+
+ // Mount misc CE mirror
+ if (TEMP_FAILURE_RETRY(mount(miscCePath.c_str(), mirrorVolMiscCePath.c_str(), NULL,
+ MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC,
+ nullptr)) == -1) {
+ return error("Failed to mount " + mirrorVolMiscCePath);
+ }
+
+ // Mount misc DE mirror
+ if (TEMP_FAILURE_RETRY(mount(miscDePath.c_str(), mirrorVolMiscDePath.c_str(), NULL,
+ MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC,
+ nullptr)) == -1) {
+ return error("Failed to mount " + mirrorVolMiscDePath);
+ }
+
return ok();
}
@@ -3624,6 +3655,8 @@
std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+ std::string mirrorMiscCeVolPath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_));
+ std::string mirrorMiscDeVolPath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_));
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
@@ -3648,6 +3681,29 @@
if (delete_dir_contents_and_dir(mirrorDeVolPath, true) != 0) {
res = error("Failed to delete " + mirrorDeVolPath);
}
+
+ // Unmount misc CE storage
+ if (TEMP_FAILURE_RETRY(umount(mirrorMiscCeVolPath.c_str())) != 0) {
+ if (errno != ENOENT) {
+ res = error(StringPrintf("Failed to umount %s %s", mirrorMiscCeVolPath.c_str(),
+ strerror(errno)));
+ }
+ }
+ if (delete_dir_contents_and_dir(mirrorMiscCeVolPath, true) != 0) {
+ res = error("Failed to delete " + mirrorMiscCeVolPath);
+ }
+
+ // Unmount misc DE storage
+ if (TEMP_FAILURE_RETRY(umount(mirrorMiscDeVolPath.c_str())) != 0) {
+ if (errno != ENOENT) {
+ res = error(StringPrintf("Failed to umount %s %s", mirrorMiscDeVolPath.c_str(),
+ strerror(errno)));
+ }
+ }
+ if (delete_dir_contents_and_dir(mirrorMiscDeVolPath, true) != 0) {
+ res = error("Failed to delete " + mirrorMiscDeVolPath);
+ }
+
return res;
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index ebb7891..34ea759 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1956,7 +1956,7 @@
join_fds(context_input_fds), swap_fd.get(), instruction_set, compiler_filter,
debuggable, boot_complete, for_restore, target_sdk_version,
enable_hidden_api_checks, generate_compact_dex, use_jitzygote_image,
- compilation_reason);
+ background_job_compile, compilation_reason);
bool cancelled = false;
pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
diff --git a/cmds/installd/otapreopt.rc b/cmds/installd/otapreopt.rc
index 059ae75..0bad0c5 100644
--- a/cmds/installd/otapreopt.rc
+++ b/cmds/installd/otapreopt.rc
@@ -5,4 +5,4 @@
# The dalvik-cache was not moved itself, so as to restrict the rights of otapreopt_slot.
# But now the relabeling is annoying as there is no force option available here. So
# explicitly list all the ISAs we know.
- restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/mips /data/dalvik-cache/mips64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64
+ restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/riscv64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index 51c4589..4221a3a 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -81,6 +81,7 @@
bool enable_hidden_api_checks,
bool generate_compact_dex,
bool use_jitzygote,
+ bool background_job_compile,
const char* compilation_reason) {
PrepareBootImageFlags(use_jitzygote);
@@ -92,7 +93,8 @@
debuggable, target_sdk_version, enable_hidden_api_checks,
generate_compact_dex, compilation_reason);
- PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore);
+ PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore,
+ background_job_compile);
const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
@@ -296,7 +298,8 @@
}
void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete,
- bool for_restore) {
+ bool for_restore,
+ bool background_job_compile) {
// CPU set
{
std::string cpu_set_format = "--cpu-set=%s";
@@ -306,7 +309,12 @@
"dalvik.vm.restore-dex2oat-cpu-set",
"dalvik.vm.dex2oat-cpu-set",
cpu_set_format)
- : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))
+ : (background_job_compile
+ ? MapPropertyToArgWithBackup(
+ "dalvik.vm.background-dex2oat-cpu-set",
+ "dalvik.vm.dex2oat-cpu-set",
+ cpu_set_format)
+ : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format)))
: MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format);
AddArg(dex2oat_cpu_set_arg);
}
@@ -320,7 +328,12 @@
"dalvik.vm.restore-dex2oat-threads",
"dalvik.vm.dex2oat-threads",
threads_format)
- : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))
+ : (background_job_compile
+ ? MapPropertyToArgWithBackup(
+ "dalvik.vm.background-dex2oat-threads",
+ "dalvik.vm.dex2oat-threads",
+ threads_format)
+ : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format)))
: MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format);
AddArg(dex2oat_threads_arg);
}
diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h
index 559244f..c13e1f1 100644
--- a/cmds/installd/run_dex2oat.h
+++ b/cmds/installd/run_dex2oat.h
@@ -51,6 +51,7 @@
bool enable_hidden_api_checks,
bool generate_compact_dex,
bool use_jitzygote,
+ bool background_job_compile,
const char* compilation_reason);
void Exec(int exit_code);
@@ -76,7 +77,9 @@
bool enable_hidden_api_checks,
bool generate_compact_dex,
const char* compilation_reason);
- void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete, bool for_restore);
+ void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete,
+ bool for_restore,
+ bool background_job_compile);
virtual std::string GetProperty(const std::string& key, const std::string& default_value);
virtual bool GetBoolProperty(const std::string& key, bool default_value);
diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp
index 2a8135a..304ba7b 100644
--- a/cmds/installd/run_dex2oat_test.cpp
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -115,6 +115,7 @@
bool enable_hidden_api_checks = false;
bool generate_compact_dex = true;
bool use_jitzygote = false;
+ bool background_job_compile = false;
const char* compilation_reason = nullptr;
};
@@ -259,6 +260,7 @@
args->enable_hidden_api_checks,
args->generate_compact_dex,
args->use_jitzygote,
+ args->background_job_compile,
args->compilation_reason);
runner.Exec(/*exit_code=*/ 0);
}
@@ -375,6 +377,30 @@
VerifyExpectedFlags();
}
+TEST_F(RunDex2OatTest, CpuSetPostBootCompleteBackground) {
+ setSystemProperty("dalvik.vm.background-dex2oat-cpu-set", "1,3");
+ setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2");
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->post_bootcomplete = true;
+ args->background_job_compile = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("--cpu-set", "=1,3");
+ VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, CpuSetPostBootCompleteBackground_Backup) {
+ setSystemProperty("dalvik.vm.background-dex2oat-cpu-set", "");
+ setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2");
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->post_bootcomplete = true;
+ args->background_job_compile = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("--cpu-set", "=1,2");
+ VerifyExpectedFlags();
+}
+
TEST_F(RunDex2OatTest, CpuSetPostBootCompleteForRestore) {
setSystemProperty("dalvik.vm.restore-dex2oat-cpu-set", "1,2");
setSystemProperty("dalvik.vm.dex2oat-cpu-set", "2,3");
@@ -481,6 +507,30 @@
VerifyExpectedFlags();
}
+TEST_F(RunDex2OatTest, ThreadsPostBootCompleteBackground) {
+ setSystemProperty("dalvik.vm.background-dex2oat-threads", "2");
+ setSystemProperty("dalvik.vm.dex2oat-threads", "3");
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->post_bootcomplete = true;
+ args->background_job_compile = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("-j", "2");
+ VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ThreadsPostBootCompleteBackground_Backup) {
+ setSystemProperty("dalvik.vm.background-dex2oat-threads", "");
+ setSystemProperty("dalvik.vm.dex2oat-threads", "3");
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->post_bootcomplete = true;
+ args->background_job_compile = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("-j", "3");
+ VerifyExpectedFlags();
+}
+
TEST_F(RunDex2OatTest, ThreadsPostBootCompleteForRestore) {
setSystemProperty("dalvik.vm.restore-dex2oat-threads", "4");
setSystemProperty("dalvik.vm.dex2oat-threads", "5");
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 6ef41e3..3b589dc 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -23,6 +23,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
@@ -52,22 +53,7 @@
constexpr int kTimeoutMs = 60000;
-// TODO(calin): try to dedup this code.
-#if defined(__arm__)
-static const std::string kRuntimeIsa = "arm";
-#elif defined(__aarch64__)
-static const std::string kRuntimeIsa = "arm64";
-#elif defined(__mips__) && !defined(__LP64__)
-static const std::string kRuntimeIsa = "mips";
-#elif defined(__mips__) && defined(__LP64__)
-static const std::string kRuntimeIsa = "mips64";
-#elif defined(__i386__)
-static const std::string kRuntimeIsa = "x86";
-#elif defined(__x86_64__)
-static const std::string kRuntimeIsa = "x86_64";
-#else
-static const std::string kRuntimeIsa = "none";
-#endif
+static const std::string kRuntimeIsa = ABI_STRING;
int get_property(const char *key, char *value, const char *default_value) {
return property_get(key, value, default_value);
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index fd879c6..1386660 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -48,14 +48,6 @@
}
cc_binary {
- name: "servicemanager.microdroid",
- defaults: ["servicemanager_defaults"],
- init_rc: ["servicemanager.microdroid.rc"],
- srcs: ["main.cpp"],
- bootstrap: true,
-}
-
-cc_binary {
name: "servicemanager.recovery",
stem: "servicemanager",
recovery: true,
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 3681d5b..cc038ae 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -136,12 +136,33 @@
updatableViaApex = manifestInstance.updatableViaApex();
return false; // break (libvintf uses opposite convention)
});
+ if (updatableViaApex.has_value()) return true; // break (found match)
return false; // continue
});
return updatableViaApex;
}
+static std::vector<std::string> getVintfUpdatableInstances(const std::string& apexName) {
+ std::vector<std::string> instances;
+
+ forEachManifest([&](const ManifestWithDescription& mwd) {
+ mwd.manifest->forEachInstance([&](const auto& manifestInstance) {
+ if (manifestInstance.format() == vintf::HalFormat::AIDL &&
+ manifestInstance.updatableViaApex().has_value() &&
+ manifestInstance.updatableViaApex().value() == apexName) {
+ std::string aname = manifestInstance.package() + "." +
+ manifestInstance.interface() + "/" + manifestInstance.instance();
+ instances.push_back(aname);
+ }
+ return true; // continue (libvintf uses opposite convention)
+ });
+ return false; // continue
+ });
+
+ return instances;
+}
+
static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) {
AidlName aname;
if (!AidlName::fill(name, &aname)) return std::nullopt;
@@ -512,6 +533,30 @@
return Status::ok();
}
+Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& apexName,
+ std::vector<std::string>* outReturn) {
+ auto ctx = mAccess->getCallingContext();
+
+ std::vector<std::string> apexUpdatableInstances;
+#ifndef VENDORSERVICEMANAGER
+ apexUpdatableInstances = getVintfUpdatableInstances(apexName);
+#endif
+
+ outReturn->clear();
+
+ for (const std::string& instance : apexUpdatableInstances) {
+ if (mAccess->canFind(ctx, instance)) {
+ outReturn->push_back(instance);
+ }
+ }
+
+ if (outReturn->size() == 0 && apexUpdatableInstances.size() != 0) {
+ return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denial");
+ }
+
+ return Status::ok();
+}
+
Status ServiceManager::getConnectionInfo(const std::string& name,
std::optional<ConnectionInfo>* outReturn) {
auto ctx = mAccess->getCallingContext();
@@ -568,7 +613,8 @@
}
void ServiceManager::tryStartService(const std::string& name) {
- ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service",
+ ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service. (if it's not "
+ "configured to be a lazy service, it may be stuck starting or still starting).",
name.c_str());
std::thread([=] {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 07b79f8..b24c11c 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -49,6 +49,8 @@
binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override;
binder::Status updatableViaApex(const std::string& name,
std::optional<std::string>* outReturn) override;
+ binder::Status getUpdatableNames(const std::string& apexName,
+ std::vector<std::string>* outReturn) override;
binder::Status getConnectionInfo(const std::string& name,
std::optional<ConnectionInfo>* outReturn) override;
binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index a831d1b..c1a04dd 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -111,9 +111,7 @@
};
int main(int argc, char** argv) {
-#ifdef __ANDROID_RECOVERY__
android::base::InitLogging(argv, android::base::KernelLogger);
-#endif
if (argc > 2) {
LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
diff --git a/cmds/servicemanager/servicemanager.microdroid.rc b/cmds/servicemanager/servicemanager.microdroid.rc
deleted file mode 100644
index c516043..0000000
--- a/cmds/servicemanager/servicemanager.microdroid.rc
+++ /dev/null
@@ -1,9 +0,0 @@
-service servicemanager /system/bin/servicemanager.microdroid
- class core
- user system
- group system readproc
- critical
- onrestart setprop servicemanager.ready false
- onrestart restart apexd
- task_profiles ServiceCapacityLow
- shutdown critical
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 6b35265..3bd6db5 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -3,6 +3,7 @@
user system
group system readproc
critical
+ file /dev/kmsg w
onrestart setprop servicemanager.ready false
onrestart restart apexd
onrestart restart audioserver
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 5d5a75e..0fd8d8e 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -14,13 +14,15 @@
* limitations under the License.
*/
+#include <android-base/properties.h>
+#include <android-base/strings.h>
#include <android/os/BnServiceCallback.h>
#include <binder/Binder.h>
-#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <cutils/android_filesystem_config.h>
-#include <gtest/gtest.h>
#include <gmock/gmock.h>
+#include <gtest/gtest.h>
#include "Access.h"
#include "ServiceManager.h"
@@ -75,6 +77,11 @@
return sm;
}
+static bool isCuttlefish() {
+ return android::base::StartsWith(android::base::GetProperty("ro.product.vendor.device", ""),
+ "vsoc_");
+}
+
TEST(AddService, HappyHappy) {
auto sm = getPermissiveServiceManager();
EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
@@ -306,6 +313,49 @@
EXPECT_THAT(out, ElementsAre("sa"));
}
+TEST(Vintf, UpdatableViaApex) {
+ if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+ auto sm = getPermissiveServiceManager();
+ std::optional<std::string> updatableViaApex;
+ EXPECT_TRUE(sm->updatableViaApex("android.hardware.camera.provider.ICameraProvider/internal/0",
+ &updatableViaApex)
+ .isOk());
+ EXPECT_EQ(std::make_optional<std::string>("com.google.emulated.camera.provider.hal"),
+ updatableViaApex);
+}
+
+TEST(Vintf, UpdatableViaApex_InvalidNameReturnsNullOpt) {
+ if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+ auto sm = getPermissiveServiceManager();
+ std::optional<std::string> updatableViaApex;
+ EXPECT_TRUE(sm->updatableViaApex("android.hardware.camera.provider.ICameraProvider",
+ &updatableViaApex)
+ .isOk()); // missing instance name
+ EXPECT_EQ(std::nullopt, updatableViaApex);
+}
+
+TEST(Vintf, GetUpdatableNames) {
+ if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+ auto sm = getPermissiveServiceManager();
+ std::vector<std::string> names;
+ EXPECT_TRUE(sm->getUpdatableNames("com.google.emulated.camera.provider.hal", &names).isOk());
+ EXPECT_EQ(std::vector<
+ std::string>{"android.hardware.camera.provider.ICameraProvider/internal/0"},
+ names);
+}
+
+TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) {
+ if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+ auto sm = getPermissiveServiceManager();
+ std::vector<std::string> names;
+ EXPECT_TRUE(sm->getUpdatableNames("non.existing.apex.name", &names).isOk());
+ EXPECT_EQ(std::vector<std::string>{}, names);
+}
+
class CallbackHistorian : public BnServiceCallback {
Status onRegistration(const std::string& name, const sp<IBinder>& binder) override {
registrations.push_back(name);
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index c9305a1..80af1d1 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -2,6 +2,7 @@
class core
user system
group system readproc
+ file /dev/kmsg w
task_profiles ServiceCapacityLow
onrestart class_restart main
onrestart class_restart hal
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 63aa7ff..cd8e63d 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -16,6 +16,28 @@
/**
* @addtogroup Choreographer
+ *
+ * Choreographer coordinates the timing of frame rendering. This is the C version of the
+ * android.view.Choreographer object in Java.
+ *
+ * As of API level 33, apps can follow proper frame pacing and even choose a future frame to render.
+ * The API is used as follows:
+ * 1. The app posts an {@link AChoreographer_vsyncCallback} to Choreographer to run on the next
+ * frame.
+ * 2. The callback is called when it is the time to start the frame with an {@link
+ * AChoreographerFrameCallbackData} payload: information about multiple possible frame
+ * timelines.
+ * 3. Apps can choose a frame timeline from the {@link
+ * AChoreographerFrameCallbackData} payload, depending on the frame deadline they can meet when
+ * rendering the frame and their desired presentation time, and subsequently
+ * {@link ASurfaceTransaction_setFrameTimeline notify SurfaceFlinger}
+ * of the choice. Alternatively, for apps that do not choose a frame timeline, their frame would be
+ * presented at the earliest possible timeline.
+ * - The preferred frame timeline is the default frame
+ * timeline that the platform scheduled for the app, based on device configuration.
+ * 4. SurfaceFlinger attempts to follow the chosen frame timeline, by not applying transactions or
+ * latching buffers before the desired presentation time.
+ *
* @{
*/
@@ -47,7 +69,8 @@
struct AChoreographerFrameCallbackData;
/**
- * Opaque type that provides access to an AChoreographerFrameCallbackData object.
+ * Opaque type that provides access to an AChoreographerFrameCallbackData object, which contains
+ * various methods to extract frame information.
*/
typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
@@ -73,8 +96,9 @@
/**
* Prototype of the function that is called when a new frame is being rendered.
- * It's passed the frame data that should not outlive the callback, as well as the data pointer
- * provided by the application that registered a callback.
+ * It is called with \c callbackData describing multiple frame timelines, as well as the \c data
+ * pointer provided by the application that registered a callback. The \c callbackData does not
+ * outlive the callback.
*/
typedef void (*AChoreographer_vsyncCallback)(
const AChoreographerFrameCallbackData* callbackData, void* data);
@@ -110,7 +134,7 @@
__DEPRECATED_IN(29);
/**
- * Power a callback to be run on the next frame. The data pointer provided will
+ * Post a callback to be run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
*
* Available since API level 29.
@@ -131,8 +155,10 @@
uint32_t delayMillis) __INTRODUCED_IN(29);
/**
- * Posts a callback to run on the next frame. The data pointer provided will
+ * Posts a callback to be run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
+ *
+ * Available since API level 33.
*/
void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
AChoreographer_vsyncCallback callback, void* data)
@@ -189,7 +215,10 @@
__INTRODUCED_IN(30);
/**
- * The time in nanoseconds when the frame started being rendered.
+ * The time in nanoseconds at which the frame started being rendered.
+ *
+ * Note that this time should \b not be used to advance animation clocks.
+ * Instead, see AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos().
*/
int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
@@ -201,25 +230,38 @@
const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
/**
- * Get index of the platform-preferred FrameTimeline.
+ * Gets the index of the platform-preferred frame timeline.
+ * The preferred frame timeline is the default
+ * by which the platform scheduled the app, based on the device configuration.
*/
size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
/**
- * The vsync ID token used to map Choreographer data.
+ * Gets the token used by the platform to identify the frame timeline at the given \c index.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
*/
AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
/**
- * The time in nanoseconds which the frame at given index is expected to be presented.
+ * Gets the time in nanoseconds at which the frame described at the given \c index is expected to
+ * be presented. This time should be used to advance any animation clocks.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
*/
int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
/**
- * The time in nanoseconds which the frame at given index needs to be ready by.
+ * Gets the time in nanoseconds at which the frame described at the given \c index needs to be
+ * ready by in order to be presented on time.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
*/
int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
diff --git a/include/android/sensor.h b/include/android/sensor.h
index eef69f4..ba81bc8 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -596,12 +596,15 @@
float accuracy;
} AHeadingEvent;
+// LINT.IfChange
/**
* Information that describes a sensor event, refer to
* <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional
* documentation.
+ *
+ * NOTE: changes to this struct has to be backward compatible and reflected in
+ * sensors_event_t
*/
-/* NOTE: changes to this struct has to be backward compatible */
typedef struct ASensorEvent {
int32_t version; /* sizeof(struct ASensorEvent) */
int32_t sensor; /** The sensor that generates this event */
@@ -646,6 +649,7 @@
uint32_t flags;
int32_t reserved1[3];
} ASensorEvent;
+// LINT.ThenChange (hardware/libhardware/include/hardware/sensors.h)
struct ASensorManager;
/**
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 9a36ecb..6223ef7 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -597,20 +597,20 @@
__INTRODUCED_IN(31);
/**
- * Sets the frame timeline to use in Surface Flinger.
+ * Sets the frame timeline to use in SurfaceFlinger.
*
- * A frame timeline should be chosen based on what frame deadline the application
- * can meet when rendering the frame and the application's desired present time.
- * By setting a frame timeline, Surface Flinger tries to present the frame at the corresponding
- * expected present time.
+ * A frame timeline should be chosen based on the frame deadline the application
+ * can meet when rendering the frame and the application's desired presentation time.
+ * By setting a frame timeline, SurfaceFlinger tries to present the frame at the corresponding
+ * expected presentation time.
*
* To receive frame timelines, a callback must be posted to Choreographer using
- * AChoreographer_postExtendedFrameCallback(). The \a vsnycId can then be extracted from the
+ * AChoreographer_postVsyncCallback(). The \c vsyncId can then be extracted from the
* callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId().
*
- * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to
- * the corresponding expected present time and deadline from the frame to be rendered. A stale or
- * invalid value will be ignored.
+ * \param vsyncId The vsync ID received from AChoreographer, setting the frame's presentation target
+ * to the corresponding expected presentation time and deadline from the frame to be rendered. A
+ * stale or invalid value will be ignored.
*/
void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction,
AVsyncId vsyncId) __INTRODUCED_IN(33);
diff --git a/include/input/Input.h b/include/input/Input.h
index e7d68fc..7ea2970 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -297,6 +297,8 @@
*/
const char* motionClassificationToString(MotionClassification classification);
+const char* motionToolTypeToString(int32_t toolType);
+
/**
* Portion of FrameMetrics timeline of interest to input code.
*/
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
index 0a75278..55f730b 100644
--- a/include/input/PrintTools.h
+++ b/include/input/PrintTools.h
@@ -17,6 +17,7 @@
#pragma once
#include <map>
+#include <optional>
#include <set>
#include <string>
@@ -28,6 +29,15 @@
}
/**
+ * Convert an optional type to string.
+ */
+template <typename T>
+std::string toString(const std::optional<T>& optional,
+ std::string (*toString)(const T&) = constToString) {
+ return optional ? toString(*optional) : "<not set>";
+}
+
+/**
* Convert a set of integral types to string.
*/
template <typename T>
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 76e3e66..5e539f2 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -49,6 +49,9 @@
"com.android.media",
"com.android.media.swcodec",
],
+ llndk: {
+ llndk_headers: true,
+ },
}
cc_library_static {
diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h
index b36728e..d52861a 100644
--- a/libs/arect/include/android/rect.h
+++ b/libs/arect/include/android/rect.h
@@ -57,7 +57,7 @@
} ARect;
#ifdef __cplusplus
-};
+}
#endif
#endif // ANDROID_RECT_H
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index df965ab..28369d6 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -161,7 +161,7 @@
],
header_libs: [
- "libandroid_runtime_vm_headers",
+ "jni_headers",
],
export_header_lib_headers: [
@@ -315,7 +315,7 @@
},
recovery: {
exclude_header_libs: [
- "libandroid_runtime_vm_headers",
+ "jni_headers",
],
},
},
@@ -490,9 +490,6 @@
java: {
enabled: false,
},
- cpp: {
- gen_trace: false,
- },
},
}
@@ -504,6 +501,7 @@
"libbase",
"libbinder",
"libbinder_ndk",
+ "libcutils_sockets",
"liblog",
"libutils",
],
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 54d2445..1c470a1 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -47,6 +47,8 @@
binder_proxy_limit_callback BpBinder::sLimitCallback;
bool BpBinder::sBinderProxyThrottleCreate = false;
+static StaticString16 kDescriptorUninit(u"<uninit descriptor>");
+
// Arbitrarily high value that probably distinguishes a bad behaving app
uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500;
// Another arbitrary value a binder count needs to drop below before another callback will be called
@@ -211,6 +213,7 @@
mAlive(true),
mObitsSent(false),
mObituaries(nullptr),
+ mDescriptorCache(kDescriptorUninit),
mTrackedUid(-1) {
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
}
@@ -258,12 +261,12 @@
bool BpBinder::isDescriptorCached() const {
Mutex::Autolock _l(mLock);
- return mDescriptorCache.size() ? true : false;
+ return mDescriptorCache.string() != kDescriptorUninit.string();
}
const String16& BpBinder::getInterfaceDescriptor() const
{
- if (isDescriptorCached() == false) {
+ if (!isDescriptorCached()) {
sp<BpBinder> thiz = sp<BpBinder>::fromExisting(const_cast<BpBinder*>(this));
Parcel data;
@@ -276,8 +279,7 @@
Mutex::Autolock _l(mLock);
// mDescriptorCache could have been assigned while the lock was
// released.
- if (mDescriptorCache.size() == 0)
- mDescriptorCache = res;
+ if (mDescriptorCache.string() == kDescriptorUninit.string()) mDescriptorCache = res;
}
}
@@ -369,10 +371,7 @@
if (data.dataSize() > LOG_TRANSACTIONS_OVER_SIZE) {
Mutex::Autolock _l(mLock);
ALOGW("Large outgoing transaction of %zu bytes, interface descriptor %s, code %d",
- data.dataSize(),
- mDescriptorCache.size() ? String8(mDescriptorCache).c_str()
- : "<uncached descriptor>",
- code);
+ data.dataSize(), String8(mDescriptorCache).c_str(), code);
}
if (status == DEAD_OBJECT) mAlive = 0;
@@ -647,7 +646,7 @@
if(obits != nullptr) {
if (!obits->isEmpty()) {
ALOGI("onLastStrongRef automatically unlinking death recipients: %s",
- mDescriptorCache.size() ? String8(mDescriptorCache).c_str() : "<uncached descriptor>");
+ String8(mDescriptorCache).c_str());
}
if (ipc) ipc->clearDeathNotification(binderHandle(), this);
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 11c8e5d..6d64e1e 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -45,11 +45,11 @@
#define IF_LOG_TRANSACTIONS() if (false)
#define IF_LOG_COMMANDS() if (false)
-#define LOG_REMOTEREFS(...)
+#define LOG_REMOTEREFS(...)
#define IF_LOG_REMOTEREFS() if (false)
-#define LOG_THREADPOOL(...)
-#define LOG_ONEWAY(...)
+#define LOG_THREADPOOL(...)
+#define LOG_ONEWAY(...)
#else
@@ -132,12 +132,21 @@
} else {
out << "\ttarget.ptr=" << btd->target.ptr;
}
- out << "\t (cookie " << btd->cookie << ")"
- << "\n"
+ out << "\t (cookie " << btd->cookie << ")\n"
<< "\tcode=" << TypeCode(btd->code) << ", flags=" << (void*)(uint64_t)btd->flags << "\n"
- << "\tdata=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)"
- << "\n"
- << "\toffsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size << " bytes)";
+ << "\tdata=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)\n"
+ << "\toffsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size << " bytes)\n";
+ return btd + 1;
+}
+
+static const void* printBinderTransactionDataSecCtx(std::ostream& out, const void* data) {
+ const binder_transaction_data_secctx* btd = (const binder_transaction_data_secctx*)data;
+
+ printBinderTransactionData(out, &btd->transaction_data);
+
+ char* secctx = (char*)btd->secctx;
+ out << "\tsecctx=" << secctx << "\n";
+
return btd+1;
}
@@ -156,6 +165,11 @@
out << "\t" << kReturnStrings[cmdIndex];
switch (code) {
+ case BR_TRANSACTION_SEC_CTX: {
+ out << ": ";
+ cmd = (const int32_t*)printBinderTransactionDataSecCtx(out, cmd);
+ } break;
+
case BR_TRANSACTION:
case BR_REPLY: {
out << ": ";
@@ -394,14 +408,92 @@
// context, so we don't abort
}
+constexpr uint32_t encodeExplicitIdentity(bool hasExplicitIdentity, pid_t callingPid) {
+ uint32_t as_unsigned = static_cast<uint32_t>(callingPid);
+ if (hasExplicitIdentity) {
+ return as_unsigned | (1 << 30);
+ } else {
+ return as_unsigned & ~(1 << 30);
+ }
+}
+
+constexpr int64_t packCallingIdentity(bool hasExplicitIdentity, uid_t callingUid,
+ pid_t callingPid) {
+ // Calling PID is a 32-bit signed integer, but doesn't consume the entire 32 bit space.
+ // To future-proof this and because we have extra capacity, we decided to also support -1,
+ // since this constant is used to represent invalid UID in other places of the system.
+ // Thus, we pack hasExplicitIdentity into the 2nd bit from the left. This allows us to
+ // preserve the (left-most) bit for the sign while also encoding the value of
+ // hasExplicitIdentity.
+ // 32b | 1b | 1b | 30b
+ // token = [ calling uid | calling pid(sign) | has explicit identity | calling pid(rest) ]
+ uint64_t token = (static_cast<uint64_t>(callingUid) << 32) |
+ encodeExplicitIdentity(hasExplicitIdentity, callingPid);
+ return static_cast<int64_t>(token);
+}
+
+constexpr bool unpackHasExplicitIdentity(int64_t token) {
+ return static_cast<int32_t>(token) & (1 << 30);
+}
+
+constexpr uid_t unpackCallingUid(int64_t token) {
+ return static_cast<uid_t>(token >> 32);
+}
+
+constexpr pid_t unpackCallingPid(int64_t token) {
+ int32_t encodedPid = static_cast<int32_t>(token);
+ if (encodedPid & (1 << 31)) {
+ return encodedPid | (1 << 30);
+ } else {
+ return encodedPid & ~(1 << 30);
+ }
+}
+
+static_assert(unpackHasExplicitIdentity(packCallingIdentity(true, 1000, 9999)) == true,
+ "pack true hasExplicit");
+
+static_assert(unpackCallingUid(packCallingIdentity(true, 1000, 9999)) == 1000, "pack true uid");
+
+static_assert(unpackCallingPid(packCallingIdentity(true, 1000, 9999)) == 9999, "pack true pid");
+
+static_assert(unpackHasExplicitIdentity(packCallingIdentity(false, 1000, 9999)) == false,
+ "pack false hasExplicit");
+
+static_assert(unpackCallingUid(packCallingIdentity(false, 1000, 9999)) == 1000, "pack false uid");
+
+static_assert(unpackCallingPid(packCallingIdentity(false, 1000, 9999)) == 9999, "pack false pid");
+
+static_assert(unpackHasExplicitIdentity(packCallingIdentity(true, 1000, -1)) == true,
+ "pack true (negative) hasExplicit");
+
+static_assert(unpackCallingUid(packCallingIdentity(true, 1000, -1)) == 1000,
+ "pack true (negative) uid");
+
+static_assert(unpackCallingPid(packCallingIdentity(true, 1000, -1)) == -1,
+ "pack true (negative) pid");
+
+static_assert(unpackHasExplicitIdentity(packCallingIdentity(false, 1000, -1)) == false,
+ "pack false (negative) hasExplicit");
+
+static_assert(unpackCallingUid(packCallingIdentity(false, 1000, -1)) == 1000,
+ "pack false (negative) uid");
+
+static_assert(unpackCallingPid(packCallingIdentity(false, 1000, -1)) == -1,
+ "pack false (negative) pid");
+
int64_t IPCThreadState::clearCallingIdentity()
{
// ignore mCallingSid for legacy reasons
- int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
+ int64_t token = packCallingIdentity(mHasExplicitIdentity, mCallingUid, mCallingPid);
clearCaller();
+ mHasExplicitIdentity = true;
return token;
}
+bool IPCThreadState::hasExplicitIdentity() {
+ return mHasExplicitIdentity;
+}
+
void IPCThreadState::setStrictModePolicy(int32_t policy)
{
mStrictModePolicy = policy;
@@ -474,9 +566,10 @@
void IPCThreadState::restoreCallingIdentity(int64_t token)
{
- mCallingUid = (int)(token>>32);
+ mCallingUid = unpackCallingUid(token);
mCallingSid = nullptr; // not enough data to restore
- mCallingPid = (int)token;
+ mCallingPid = unpackCallingPid(token);
+ mHasExplicitIdentity = unpackHasExplicitIdentity(token);
}
void IPCThreadState::clearCaller()
@@ -889,6 +982,7 @@
mCallRestriction(mProcess->mCallRestriction) {
pthread_setspecific(gTLS, this);
clearCaller();
+ mHasExplicitIdentity = false;
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
@@ -937,6 +1031,10 @@
if (!reply && !acquireResult) goto finish;
break;
+ case BR_TRANSACTION_PENDING_FROZEN:
+ ALOGW("Sending oneway calls to frozen process.");
+ goto finish;
+
case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish;
@@ -1279,6 +1377,7 @@
const pid_t origPid = mCallingPid;
const char* origSid = mCallingSid;
const uid_t origUid = mCallingUid;
+ const bool origHasExplicitIdentity = mHasExplicitIdentity;
const int32_t origStrictModePolicy = mStrictModePolicy;
const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
const int32_t origWorkSource = mWorkSource;
@@ -1292,6 +1391,7 @@
mCallingPid = tr.sender_pid;
mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
mCallingUid = tr.sender_euid;
+ mHasExplicitIdentity = false;
mLastTransactionBinderFlags = tr.flags;
// ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid,
@@ -1367,6 +1467,7 @@
mCallingPid = origPid;
mCallingSid = origSid;
mCallingUid = origUid;
+ mHasExplicitIdentity = origHasExplicitIdentity;
mStrictModePolicy = origStrictModePolicy;
mLastTransactionBinderFlags = origTransactionBinderFlags;
mWorkSource = origWorkSource;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 05db774..2408307 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -81,6 +81,7 @@
bool isDeclared(const String16& name) override;
Vector<String16> getDeclaredInstances(const String16& interface) override;
std::optional<String16> updatableViaApex(const String16& name) override;
+ Vector<String16> getUpdatableNames(const String16& apexName) override;
std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
class RegistrationWaiter : public android::os::BnServiceCallback {
public:
@@ -443,7 +444,7 @@
bool declared;
if (Status status = mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared);
!status.isOk()) {
- ALOGW("Failed to get isDeclard for %s: %s", String8(name).c_str(),
+ ALOGW("Failed to get isDeclared for %s: %s", String8(name).c_str(),
status.toString8().c_str());
return false;
}
@@ -479,6 +480,23 @@
return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
}
+Vector<String16> ServiceManagerShim::getUpdatableNames(const String16& apexName) {
+ std::vector<std::string> out;
+ if (Status status = mTheRealServiceManager->getUpdatableNames(String8(apexName).c_str(), &out);
+ !status.isOk()) {
+ ALOGW("Failed to getUpdatableNames for %s: %s", String8(apexName).c_str(),
+ status.toString8().c_str());
+ return {};
+ }
+
+ Vector<String16> res;
+ res.setCapacity(out.size());
+ for (const std::string& instance : out) {
+ res.push(String16(instance.c_str()));
+ }
+ return res;
+}
+
std::optional<IServiceManager::ConnectionInfo> ServiceManagerShim::getConnectionInfo(
const String16& name) {
std::optional<os::ConnectionInfo> connectionInfo;
diff --git a/libs/binder/OS.cpp b/libs/binder/OS.cpp
index 77e401f..ce60e33 100644
--- a/libs/binder/OS.cpp
+++ b/libs/binder/OS.cpp
@@ -67,7 +67,7 @@
return RpcTransportCtxFactoryRaw::make();
}
-int sendMessageOnSocket(
+ssize_t sendMessageOnSocket(
const RpcTransportFd& socket, iovec* iovs, int niovs,
const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
if (ancillaryFds != nullptr && !ancillaryFds->empty()) {
@@ -112,7 +112,7 @@
return TEMP_FAILURE_RETRY(sendmsg(socket.fd.get(), &msg, MSG_NOSIGNAL));
}
-int receiveMessageFromSocket(
+ssize_t receiveMessageFromSocket(
const RpcTransportFd& socket, iovec* iovs, int niovs,
std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
if (ancillaryFds != nullptr) {
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
index 0d38968..fecae31 100644
--- a/libs/binder/OS.h
+++ b/libs/binder/OS.h
@@ -33,11 +33,11 @@
std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory();
-int sendMessageOnSocket(
+ssize_t sendMessageOnSocket(
const RpcTransportFd& socket, iovec* iovs, int niovs,
const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds);
-int receiveMessageFromSocket(
+ssize_t receiveMessageFromSocket(
const RpcTransportFd& socket, iovec* iovs, int niovs,
std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 07d0a65..44ff62b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -614,11 +614,14 @@
if (status_t status = readInt32(&fdIndex); status != OK) {
return status;
}
- const auto& oldFd = otherRpcFields->mFds->at(fdIndex);
+ int oldFd = toRawFd(otherRpcFields->mFds->at(fdIndex));
// To match kernel binder behavior, we always dup, even if the
// FD was unowned in the source parcel.
- rpcFields->mFds->emplace_back(
- base::unique_fd(fcntl(toRawFd(oldFd), F_DUPFD_CLOEXEC, 0)));
+ int newFd = -1;
+ if (status_t status = dupFileDescriptor(oldFd, &newFd); status != OK) {
+ ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, strerror(-status));
+ }
+ rpcFields->mFds->emplace_back(base::unique_fd(newFd));
// Fixup the index in the data.
mDataPos = newDataPos + 4;
if (status_t status = writeInt32(rpcFields->mFds->size() - 1); status != OK) {
@@ -966,7 +969,15 @@
}
}
+void Parcel::setEnforceNoDataAvail(bool enforceNoDataAvail) {
+ mEnforceNoDataAvail = enforceNoDataAvail;
+}
+
binder::Status Parcel::enforceNoDataAvail() const {
+ if (!mEnforceNoDataAvail) {
+ return binder::Status::ok();
+ }
+
const auto n = dataAvail();
if (n == 0) {
return binder::Status::ok();
@@ -1464,7 +1475,7 @@
#ifdef BINDER_WITH_KERNEL_IPC
flat_binder_object obj;
obj.hdr.type = BINDER_TYPE_FD;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ obj.flags = 0;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = fd;
obj.cookie = takeOwnership ? 1 : 0;
@@ -3077,6 +3088,7 @@
mAllowFds = true;
mDeallocZero = false;
mOwner = nullptr;
+ mEnforceNoDataAvail = true;
}
void Parcel::scanForFds() const {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 1f311ac..254dda8 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -439,6 +439,10 @@
return mCurrentThreads;
}
+bool ProcessState::isThreadPoolStarted() const {
+ return mThreadPoolStarted;
+}
+
#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
static const char* const names[] = {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 83d0de7..0d06e9e 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -50,7 +50,8 @@
RpcServer::RpcServer(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {}
RpcServer::~RpcServer() {
- (void)shutdown();
+ RpcMutexUniqueLock _l(mLock);
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Must call shutdown() before destructor");
}
sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
@@ -70,11 +71,8 @@
return setupSocketServer(UnixSocketAddress(path));
}
-status_t RpcServer::setupVsockServer(unsigned int port) {
- // realizing value w/ this type at compile time to avoid ubsan abort
- constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
-
- return setupSocketServer(VsockSocketAddress(kAnyCid, port));
+status_t RpcServer::setupVsockServer(unsigned int bindCid, unsigned int port) {
+ return setupSocketServer(VsockSocketAddress(bindCid, port));
}
status_t RpcServer::setupInetServer(const char* address, unsigned int port,
@@ -157,6 +155,12 @@
mRootObjectFactory = std::move(makeObject);
}
+void RpcServer::setConnectionFilter(std::function<bool(const void*, size_t)>&& filter) {
+ RpcMutexLockGuard _l(mLock);
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
+ mConnectionFilter = std::move(filter);
+}
+
sp<IBinder> RpcServer::getRootObject() {
RpcMutexLockGuard _l(mLock);
bool hasWeak = mRootObjectWeak.unsafe_get();
@@ -200,11 +204,15 @@
iovec iov{&zero, sizeof(zero)};
std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds;
- if (receiveMessageFromSocket(server.mServer, &iov, 1, &fds) < 0) {
+ ssize_t num_bytes = receiveMessageFromSocket(server.mServer, &iov, 1, &fds);
+ if (num_bytes < 0) {
int savedErrno = errno;
ALOGE("Failed recvmsg: %s", strerror(savedErrno));
return -savedErrno;
}
+ if (num_bytes == 0) {
+ return DEAD_OBJECT;
+ }
if (fds.size() != 1) {
ALOGE("Expected exactly one fd from recvmsg, got %zu", fds.size());
return -EINVAL;
@@ -239,16 +247,25 @@
socklen_t addrLen = addr.size();
RpcTransportFd clientSocket;
- if (mAcceptFn(*this, &clientSocket) != OK) {
- continue;
+ if ((status = mAcceptFn(*this, &clientSocket)) != OK) {
+ if (status == DEAD_OBJECT)
+ break;
+ else
+ continue;
}
+
+ LOG_RPC_DETAIL("accept on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get());
+
if (getpeername(clientSocket.fd.get(), reinterpret_cast<sockaddr*>(addr.data()),
&addrLen)) {
ALOGE("Could not getpeername socket: %s", strerror(errno));
continue;
}
- LOG_RPC_DETAIL("accept on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get());
+ if (mConnectionFilter != nullptr && !mConnectionFilter(addr.data(), addrLen)) {
+ ALOGE("Dropped client connection fd %d", clientSocket.fd.get());
+ continue;
+ }
{
RpcMutexLockGuard _l(mLock);
@@ -531,33 +548,35 @@
LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
- RpcTransportFd transportFd(unique_fd(TEMP_FAILURE_RETRY(
- socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0))));
- if (!transportFd.fd.ok()) {
+ unique_fd socket_fd(TEMP_FAILURE_RETRY(
+ socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
+ if (!socket_fd.ok()) {
int savedErrno = errno;
ALOGE("Could not create socket: %s", strerror(savedErrno));
return -savedErrno;
}
-
- if (0 != TEMP_FAILURE_RETRY(bind(transportFd.fd.get(), addr.addr(), addr.addrSize()))) {
+ if (0 != TEMP_FAILURE_RETRY(bind(socket_fd.get(), addr.addr(), addr.addrSize()))) {
int savedErrno = errno;
ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
return -savedErrno;
}
+ return setupRawSocketServer(std::move(socket_fd));
+}
+
+status_t RpcServer::setupRawSocketServer(unique_fd socket_fd) {
+ LOG_ALWAYS_FATAL_IF(!socket_fd.ok(), "Socket must be setup to listen.");
+
// Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
// the backlog is increased to a large number.
// TODO(b/189955605): Once we create threads dynamically & lazily, the backlog can be reduced
// to 1.
- if (0 != TEMP_FAILURE_RETRY(listen(transportFd.fd.get(), 50 /*backlog*/))) {
+ if (0 != TEMP_FAILURE_RETRY(listen(socket_fd.get(), 50 /*backlog*/))) {
int savedErrno = errno;
- ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ ALOGE("Could not listen initialized Unix socket: %s", strerror(savedErrno));
return -savedErrno;
}
-
- LOG_RPC_DETAIL("Successfully setup socket server %s", addr.toString().c_str());
-
- if (status_t status = setupExternalServer(std::move(transportFd.fd)); status != OK) {
+ if (status_t status = setupExternalServer(std::move(socket_fd)); status != OK) {
ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
return status;
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 7d6bcfc..ce6ef2b 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -46,8 +46,8 @@
#include "Utils.h"
#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
-#include <android_runtime/vm.h>
#include <jni.h>
+extern "C" JavaVM* AndroidRuntimeGetJavaVM();
#endif
namespace android {
@@ -408,10 +408,11 @@
"Unable to detach thread. No JavaVM, but it was present before!");
LOG_RPC_DETAIL("Detaching current thread from JVM");
- if (vm->DetachCurrentThread() != JNI_OK) {
+ int ret = vm->DetachCurrentThread();
+ if (ret == JNI_OK) {
mAttached = false;
} else {
- ALOGW("Unable to detach current thread from JVM");
+ ALOGW("Unable to detach current thread from JVM (%d)", ret);
}
}
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 1912d14..cd067bf 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -61,7 +61,8 @@
override {
bool sentFds = false;
auto send = [&](iovec* iovs, int niovs) -> ssize_t {
- int ret = sendMessageOnSocket(mSocket, iovs, niovs, sentFds ? nullptr : ancillaryFds);
+ ssize_t ret =
+ sendMessageOnSocket(mSocket, iovs, niovs, sentFds ? nullptr : ancillaryFds);
sentFds |= ret > 0;
return ret;
};
diff --git a/libs/binder/RpcTransportTipcAndroid.cpp b/libs/binder/RpcTransportTipcAndroid.cpp
index 453279c..8b3ddfb 100644
--- a/libs/binder/RpcTransportTipcAndroid.cpp
+++ b/libs/binder/RpcTransportTipcAndroid.cpp
@@ -63,12 +63,14 @@
if (pfd.revents & POLLERR) {
return DEAD_OBJECT;
}
+ if (pfd.revents & POLLIN) {
+ // Copied from FdTrigger.cpp: Even though POLLHUP may also be set,
+ // treat it as a success condition to ensure data is drained.
+ return OK;
+ }
if (pfd.revents & POLLHUP) {
return DEAD_OBJECT;
}
- if (pfd.revents & POLLIN) {
- return OK;
- }
return WOULD_BLOCK;
}
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 5880c0a..0fb1615 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -114,6 +114,12 @@
@nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name);
/**
+ * Returns all instances which are updatable via the APEX. Instance names are fully qualified
+ * like `pack.age.IFoo/default`.
+ */
+ @utf8InCpp String[] getUpdatableNames(@utf8InCpp String apexName);
+
+ /**
* If connection info is available for the given instance, returns the ConnectionInfo
*/
@nullable ConnectionInfo getConnectionInfo(@utf8InCpp String name);
diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h
index 793795e..eef07ae 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -100,4 +100,9 @@
#define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32)
#endif // BINDER_ENABLE_ONEWAY_SPAM_DETECTION
+#ifndef BR_TRANSACTION_PENDING_FROZEN
+// Temporary definition of BR_TRANSACTION_PENDING_FROZEN until UAPI binder.h includes it.
+#define BR_TRANSACTION_PENDING_FROZEN _IO('r', 20)
+#endif // BR_TRANSACTION_PENDING_FROZEN
+
#endif // _BINDER_MODULE_H_
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index c01e92f..d261c21 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -139,12 +139,15 @@
int64_t clearCallingIdentity();
// Restores PID/UID (not SID)
void restoreCallingIdentity(int64_t token);
+ bool hasExplicitIdentity();
+ // For main functions - dangerous for libraries to use
status_t setupPolling(int* fd);
status_t handlePolledCommands();
void flushCommands();
bool flushIfNeeded();
+ // For main functions - dangerous for libraries to use
void joinThreadPool(bool isMain = true);
// Stop the local process.
@@ -241,6 +244,7 @@
bool mPropagateWorkSource;
bool mIsLooper;
bool mIsFlushing;
+ bool mHasExplicitIdentity;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
CallRestriction mCallRestriction;
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 413c97f..2af512e 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -67,7 +67,8 @@
* a system property, or in the case of services in the VINTF manifest, it can be checked
* with isDeclared).
*/
- virtual sp<IBinder> getService( const String16& name) const = 0;
+ [[deprecated("this polls for 5s, prefer waitForService or checkService")]]
+ virtual sp<IBinder> getService(const String16& name) const = 0;
/**
* Retrieve an existing service, non-blocking.
@@ -115,6 +116,12 @@
virtual std::optional<String16> updatableViaApex(const String16& name) = 0;
/**
+ * Returns all instances which are updatable via the APEX. Instance names are fully qualified
+ * like `pack.age.IFoo/default`.
+ */
+ virtual Vector<String16> getUpdatableNames(const String16& apexName) = 0;
+
+ /**
* If this instance has declared remote connection information, returns
* the ConnectionInfo.
*/
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 6de6ce8..f730acb 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -150,6 +150,9 @@
// Returns Status(EX_BAD_PARCELABLE) when the Parcel is not consumed.
binder::Status enforceNoDataAvail() const;
+ // This Api is used by fuzzers to skip dataAvail checks.
+ void setEnforceNoDataAvail(bool enforceNoDataAvail);
+
void freeData();
size_t objectsCount() const;
@@ -1329,6 +1332,9 @@
// data to be overridden with zero when deallocated
mutable bool mDeallocZero;
+ // Set this to false to skip dataAvail checks.
+ bool mEnforceNoDataAvail;
+
release_func mOwner;
size_t mReserved;
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 9679a5f..bad8cb1 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -50,6 +50,7 @@
sp<IBinder> getContextObject(const sp<IBinder>& caller);
+ // For main functions - dangerous for libraries to use
void startThreadPool();
bool becomeContextManager();
@@ -57,8 +58,10 @@
sp<IBinder> getStrongProxyForHandle(int32_t handle);
void expungeHandle(int32_t handle, IBinder* binder);
+ // TODO: deprecate.
void spawnPooledThread(bool isMain);
+ // For main functions - dangerous for libraries to use
status_t setThreadPoolMaxThreadCount(size_t maxThreads);
status_t enableOnewaySpamDetection(bool enable);
void giveThreadPoolName();
@@ -94,6 +97,11 @@
*/
size_t getThreadPoolMaxTotalThreadCount() const;
+ /**
+ * Check to see if the thread pool has started.
+ */
+ bool isThreadPoolStarted() const;
+
enum class DriverFeature {
ONEWAY_SPAM_DETECTION,
EXTENDED_ERROR,
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 81ae26a3..25193a3 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -71,9 +71,19 @@
[[nodiscard]] status_t setupUnixDomainServer(const char* path);
/**
- * Creates an RPC server at the current port.
+ * Sets up an RPC server with a raw socket file descriptor.
+ * The socket should be created and bound to a socket address already, e.g.
+ * the socket can be created in init.rc.
+ *
+ * This method is used in the libbinder_rpc_unstable API
+ * RunInitUnixDomainRpcServer().
*/
- [[nodiscard]] status_t setupVsockServer(unsigned int port);
+ [[nodiscard]] status_t setupRawSocketServer(base::unique_fd socket_fd);
+
+ /**
+ * Creates an RPC server binding to the given CID at the given port.
+ */
+ [[nodiscard]] status_t setupVsockServer(unsigned int bindCid, unsigned int port);
/**
* Creates an RPC server at the current port using IPv4.
@@ -161,6 +171,16 @@
sp<IBinder> getRootObject();
/**
+ * Set optional filter of incoming connections based on the peer's address.
+ *
+ * Takes one argument: a callable that is invoked on each accept()-ed
+ * connection and returns false if the connection should be dropped.
+ * See the description of setPerSessionRootObject() for details about
+ * the callable's arguments.
+ */
+ void setConnectionFilter(std::function<bool(const void*, size_t)>&& filter);
+
+ /**
* See RpcTransportCtx::getCertificate
*/
std::vector<uint8_t> getCertificate(RpcCertificateFormat);
@@ -243,6 +263,7 @@
sp<IBinder> mRootObject;
wp<IBinder> mRootObjectWeak;
std::function<sp<IBinder>(const void*, size_t)> mRootObjectFactory;
+ std::function<bool(const void*, size_t)> mConnectionFilter;
std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
std::unique_ptr<FdTrigger> mShutdownTrigger;
RpcConditionVariable mShutdownCv;
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 5baa4d7..3ebbed6 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -17,38 +17,108 @@
#pragma once
#include <sys/socket.h>
+#include <stdint.h>
extern "C" {
struct AIBinder;
+struct ARpcServer;
+struct ARpcSession;
+
+enum class ARpcSession_FileDescriptorTransportMode {
+ None,
+ Unix,
+ Trusty,
+};
// Starts an RPC server on a given port and a given root IBinder object.
-// This function sets up the server and joins before returning.
-bool RunRpcServer(AIBinder* service, unsigned int port);
+// The server will only accept connections from the given CID.
+// Set `cid` to VMADDR_CID_ANY to accept connections from any client.
+// Set `cid` to VMADDR_CID_LOCAL to only bind to the local vsock interface.
+// Returns an opaque handle to the running server instance, or null if the server
+// could not be started.
+[[nodiscard]] ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid,
+ unsigned int port);
-// Starts an RPC server on a given port and a given root IBinder object.
-// This function sets up the server, calls readyCallback with a given param, and
-// then joins before returning.
-bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
- void* param);
+// Starts a Unix domain RPC server with a given init-managed Unix domain `name`
+// and a given root IBinder object.
+// The socket should be created in init.rc with the same `name`.
+// Returns an opaque handle to the running server instance, or null if the server
+// could not be started.
+[[nodiscard]] ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name);
-// Starts an RPC server on a given port and a given root IBinder factory.
-// RunRpcServerWithFactory acts like RunRpcServerCallback, but instead of
-// assigning single root IBinder object to all connections, factory is called
-// whenever a client connects, making it possible to assign unique IBinder
-// object to each client.
-bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
- void* factoryContext, unsigned int port);
+// Starts an RPC server that bootstraps sessions using an existing Unix domain
+// socket pair, with a given root IBinder object.
+// Callers should create a pair of SOCK_STREAM Unix domain sockets, pass one to
+// this function and the other to UnixDomainBootstrapClient(). Multiple client
+// session can be created from the client end of the pair.
+// Does not take ownership of `service`.
+// Returns an opaque handle to the running server instance, or null if the server
+// could not be started.
+[[nodiscard]] ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
+// Sets the list of supported file descriptor transport modes of this RPC server.
+void ARpcServer_setSupportedFileDescriptorTransportModes(
+ ARpcServer* handle,
+ const ARpcSession_FileDescriptorTransportMode modes[],
+ size_t modes_len);
-// Connect to an RPC server with preconnected file descriptors.
+// Runs ARpcServer_join() in a background thread. Immediately returns.
+void ARpcServer_start(ARpcServer* server);
+
+// Joins the thread of a running RpcServer instance. At any given point, there
+// can only be one thread calling ARpcServer_join().
+// If a client needs to actively terminate join, call ARpcServer_shutdown() in
+// a separate thread.
+void ARpcServer_join(ARpcServer* server);
+
+// Shuts down any running ARpcServer_join().
+[[nodiscard]] bool ARpcServer_shutdown(ARpcServer* server);
+
+// Frees the ARpcServer handle and drops the reference count on the underlying
+// RpcServer instance. The handle must not be reused afterwards.
+// This automatically calls ARpcServer_shutdown().
+void ARpcServer_free(ARpcServer* server);
+
+// Allocates a new RpcSession object and returns an opaque handle to it.
+[[nodiscard]] ARpcSession* ARpcSession_new();
+
+// Connects to an RPC server over vsock at a given CID on a given port.
+// Returns the root Binder object of the server.
+AIBinder* ARpcSession_setupVsockClient(ARpcSession* session, unsigned int cid,
+ unsigned int port);
+
+// Connects to an RPC server over a Unix Domain Socket of the given name.
+// The final Unix Domain Socket path name is /dev/socket/`name`.
+// Returns the root Binder object of the server.
+AIBinder* ARpcSession_setupUnixDomainClient(ARpcSession* session, const char* name);
+
+// Connects to an RPC server over the given bootstrap Unix domain socket.
+// Does NOT take ownership of `bootstrapFd`.
+AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* session,
+ int bootstrapFd);
+
+// Connects to an RPC server with preconnected file descriptors.
//
// requestFd should connect to the server and return a valid file descriptor, or
// -1 if connection fails.
//
// param will be passed to requestFd. Callers can use param to pass contexts to
// the requestFd function.
-AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param);
+AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* session,
+ int (*requestFd)(void* param),
+ void* param);
+// Sets the file descriptor transport mode for this session.
+void ARpcSession_setFileDescriptorTransportMode(ARpcSession* session,
+ ARpcSession_FileDescriptorTransportMode mode);
+
+// Sets the maximum number of incoming threads.
+void ARpcSession_setMaxIncomingThreads(ARpcSession* session, size_t threads);
+
+// Sets the maximum number of outgoing threads.
+void ARpcSession_setMaxOutgoingThreads(ARpcSession* session, size_t threads);
+
+// Decrements the refcount of the underlying RpcSession object.
+void ARpcSession_free(ARpcSession* session);
}
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index a3d42b7..78dae4b 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -14,68 +14,171 @@
* limitations under the License.
*/
+#include <binder_rpc_unstable.hpp>
+
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <android/binder_libbinder.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <cutils/sockets.h>
#include <linux/vm_sockets.h>
using android::OK;
using android::RpcServer;
using android::RpcSession;
+using android::sp;
using android::status_t;
using android::statusToString;
using android::base::unique_fd;
+// Opaque handle for RpcServer.
+struct ARpcServer {};
+
+// Opaque handle for RpcSession.
+struct ARpcSession {};
+
+template <typename A, typename T>
+static A* createObjectHandle(sp<T>& server) {
+ auto ref = server.get();
+ ref->incStrong(ref);
+ return reinterpret_cast<A*>(ref);
+}
+
+template <typename T, typename A>
+static void freeObjectHandle(A* handle) {
+ LOG_ALWAYS_FATAL_IF(handle == nullptr, "Handle cannot be null");
+ auto ref = reinterpret_cast<T*>(handle);
+ ref->decStrong(ref);
+}
+
+template <typename T, typename A>
+static sp<T> handleToStrongPointer(A* handle) {
+ LOG_ALWAYS_FATAL_IF(handle == nullptr, "Handle cannot be null");
+ auto ref = reinterpret_cast<T*>(handle);
+ return sp<T>::fromExisting(ref);
+}
+
+RpcSession::FileDescriptorTransportMode toTransportMode(
+ ARpcSession_FileDescriptorTransportMode mode) {
+ switch (mode) {
+ case ARpcSession_FileDescriptorTransportMode::None:
+ return RpcSession::FileDescriptorTransportMode::NONE;
+ case ARpcSession_FileDescriptorTransportMode::Unix:
+ return RpcSession::FileDescriptorTransportMode::UNIX;
+ case ARpcSession_FileDescriptorTransportMode::Trusty:
+ return RpcSession::FileDescriptorTransportMode::TRUSTY;
+ default:
+ return RpcSession::FileDescriptorTransportMode::NONE;
+ }
+}
+
extern "C" {
-bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
- void* factoryContext, unsigned int port) {
+ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned int port) {
auto server = RpcServer::make();
- if (status_t status = server->setupVsockServer(port); status != OK) {
- LOG(ERROR) << "Failed to set up vsock server with port " << port
- << " error: " << statusToString(status).c_str();
- return false;
+
+ unsigned int bindCid = VMADDR_CID_ANY; // bind to the remote interface
+ if (cid == VMADDR_CID_LOCAL) {
+ bindCid = VMADDR_CID_LOCAL; // bind to the local interface
+ cid = VMADDR_CID_ANY; // no need for a connection filter
}
- server->setPerSessionRootObject([=](const void* addr, size_t addrlen) {
- LOG_ALWAYS_FATAL_IF(addrlen < sizeof(sockaddr_vm), "sockaddr is truncated");
- const sockaddr_vm* vaddr = reinterpret_cast<const sockaddr_vm*>(addr);
- LOG_ALWAYS_FATAL_IF(vaddr->svm_family != AF_VSOCK, "address is not a vsock");
- return AIBinder_toPlatformBinder(factory(vaddr->svm_cid, factoryContext));
- });
- server->join();
-
- // Shutdown any open sessions since server failed.
- (void)server->shutdown();
- return true;
-}
-
-bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
- void* param) {
- auto server = RpcServer::make();
- if (status_t status = server->setupVsockServer(port); status != OK) {
+ if (status_t status = server->setupVsockServer(bindCid, port); status != OK) {
LOG(ERROR) << "Failed to set up vsock server with port " << port
<< " error: " << statusToString(status).c_str();
- return false;
+ return nullptr;
+ }
+ if (cid != VMADDR_CID_ANY) {
+ server->setConnectionFilter([=](const void* addr, size_t addrlen) {
+ LOG_ALWAYS_FATAL_IF(addrlen < sizeof(sockaddr_vm), "sockaddr is truncated");
+ const sockaddr_vm* vaddr = reinterpret_cast<const sockaddr_vm*>(addr);
+ LOG_ALWAYS_FATAL_IF(vaddr->svm_family != AF_VSOCK, "address is not a vsock");
+ if (cid != vaddr->svm_cid) {
+ LOG(ERROR) << "Rejected vsock connection from CID " << vaddr->svm_cid;
+ return false;
+ }
+ return true;
+ });
}
server->setRootObject(AIBinder_toPlatformBinder(service));
-
- if (readyCallback) readyCallback(param);
- server->join();
-
- // Shutdown any open sessions since server failed.
- (void)server->shutdown();
- return true;
+ return createObjectHandle<ARpcServer>(server);
}
-bool RunRpcServer(AIBinder* service, unsigned int port) {
- return RunRpcServerCallback(service, port, nullptr, nullptr);
+ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name) {
+ auto server = RpcServer::make();
+ auto fd = unique_fd(android_get_control_socket(name));
+ if (!fd.ok()) {
+ LOG(ERROR) << "Failed to get fd for the socket:" << name;
+ return nullptr;
+ }
+ if (status_t status = server->setupRawSocketServer(std::move(fd)); status != OK) {
+ LOG(ERROR) << "Failed to set up Unix Domain RPC server with name " << name
+ << " error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ server->setRootObject(AIBinder_toPlatformBinder(service));
+ return createObjectHandle<ARpcServer>(server);
}
-AIBinder* RpcClient(unsigned int cid, unsigned int port) {
+ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd) {
+ auto server = RpcServer::make();
+ auto fd = unique_fd(bootstrapFd);
+ if (!fd.ok()) {
+ LOG(ERROR) << "Invalid bootstrap fd " << bootstrapFd;
+ return nullptr;
+ }
+ if (status_t status = server->setupUnixDomainSocketBootstrapServer(std::move(fd));
+ status != OK) {
+ LOG(ERROR) << "Failed to set up Unix Domain RPC server with bootstrap fd " << bootstrapFd
+ << " error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ server->setRootObject(AIBinder_toPlatformBinder(service));
+ return createObjectHandle<ARpcServer>(server);
+}
+
+void ARpcServer_setSupportedFileDescriptorTransportModes(
+ ARpcServer* handle, const ARpcSession_FileDescriptorTransportMode modes[],
+ size_t modes_len) {
+ auto server = handleToStrongPointer<RpcServer>(handle);
+ std::vector<RpcSession::FileDescriptorTransportMode> modevec;
+ for (size_t i = 0; i < modes_len; i++) {
+ modevec.push_back(toTransportMode(modes[i]));
+ }
+ server->setSupportedFileDescriptorTransportModes(modevec);
+}
+
+void ARpcServer_start(ARpcServer* handle) {
+ handleToStrongPointer<RpcServer>(handle)->start();
+}
+
+void ARpcServer_join(ARpcServer* handle) {
+ handleToStrongPointer<RpcServer>(handle)->join();
+}
+
+bool ARpcServer_shutdown(ARpcServer* handle) {
+ return handleToStrongPointer<RpcServer>(handle)->shutdown();
+}
+
+void ARpcServer_free(ARpcServer* handle) {
+ // Ignore the result of ARpcServer_shutdown - either it had been called
+ // earlier, or the RpcServer destructor will panic.
+ (void)ARpcServer_shutdown(handle);
+ freeObjectHandle<RpcServer>(handle);
+}
+
+ARpcSession* ARpcSession_new() {
auto session = RpcSession::make();
+ return createObjectHandle<ARpcSession>(session);
+}
+
+void ARpcSession_free(ARpcSession* handle) {
+ freeObjectHandle<RpcSession>(handle);
+}
+
+AIBinder* ARpcSession_setupVsockClient(ARpcSession* handle, unsigned int cid, unsigned int port) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
if (status_t status = session->setupVsockClient(cid, port); status != OK) {
LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port
<< " error: " << statusToString(status).c_str();
@@ -84,8 +187,37 @@
return AIBinder_fromPlatformBinder(session->getRootObject());
}
-AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param) {
- auto session = RpcSession::make();
+AIBinder* ARpcSession_setupUnixDomainClient(ARpcSession* handle, const char* name) {
+ std::string pathname(name);
+ pathname = ANDROID_SOCKET_DIR "/" + pathname;
+ auto session = handleToStrongPointer<RpcSession>(handle);
+ if (status_t status = session->setupUnixDomainClient(pathname.c_str()); status != OK) {
+ LOG(ERROR) << "Failed to set up Unix Domain RPC client with path: " << pathname
+ << " error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+
+AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* handle, int bootstrapFd) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
+ auto fd = unique_fd(dup(bootstrapFd));
+ if (!fd.ok()) {
+ LOG(ERROR) << "Invalid bootstrap fd " << bootstrapFd;
+ return nullptr;
+ }
+ if (status_t status = session->setupUnixDomainSocketBootstrapClient(std::move(fd));
+ status != OK) {
+ LOG(ERROR) << "Failed to set up Unix Domain RPC client with bootstrap fd: " << bootstrapFd
+ << " error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+
+AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* handle, int (*requestFd)(void* param),
+ void* param) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
auto request = [=] { return unique_fd{requestFd(param)}; };
if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) {
LOG(ERROR) << "Failed to set up vsock client. error: " << statusToString(status).c_str();
@@ -93,4 +225,20 @@
}
return AIBinder_fromPlatformBinder(session->getRootObject());
}
+
+void ARpcSession_setFileDescriptorTransportMode(ARpcSession* handle,
+ ARpcSession_FileDescriptorTransportMode mode) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
+ session->setFileDescriptorTransportMode(toTransportMode(mode));
+}
+
+void ARpcSession_setMaxIncomingThreads(ARpcSession* handle, size_t threads) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
+ session->setMaxIncomingThreads(threads);
+}
+
+void ARpcSession_setMaxOutgoingThreads(ARpcSession* handle, size_t threads) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
+ session->setMaxOutgoingThreads(threads);
+}
}
diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt
index e856569..1bc2416 100644
--- a/libs/binder/libbinder_rpc_unstable.map.txt
+++ b/libs/binder/libbinder_rpc_unstable.map.txt
@@ -1,8 +1,13 @@
LIBBINDER_RPC_UNSTABLE_SHIM { # platform-only
global:
- RunRpcServer;
- RunRpcServerCallback;
- RpcClient;
+ ARpcServer_free;
+ ARpcServer_join;
+ ARpcServer_newInitUnixDomain;
+ ARpcServer_newVsock;
+ ARpcServer_shutdown;
+ ARpcServer_start;
+ VsockRpcClient;
+ UnixDomainRpcClient;
RpcPreconnectedClient;
local:
*;
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 28d1f16..d0de7b9 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -75,12 +75,48 @@
AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
AIBinder::~AIBinder() {}
-std::optional<bool> AIBinder::associateClassInternal(const AIBinder_Class* clazz,
- const String16& newDescriptor, bool set) {
+// b/175635923 libcxx causes "implicit-conversion" with a string with invalid char
+static std::string SanitizeString(const String16& str) {
+ std::string sanitized{String8(str)};
+ for (auto& c : sanitized) {
+ if (!isprint(c)) {
+ c = '?';
+ }
+ }
+ return sanitized;
+}
+
+bool AIBinder::associateClass(const AIBinder_Class* clazz) {
+ if (clazz == nullptr) return false;
+
+ // If mClazz is non-null, this must have been called and cached
+ // already. So, we can safely call this first. Due to the implementation
+ // of getInterfaceDescriptor (at time of writing), two simultaneous calls
+ // may lead to extra binder transactions, but this is expected to be
+ // exceedingly rare. Once we have a binder, when we get it again later,
+ // we won't make another binder transaction here.
+ const String16& descriptor = getBinder()->getInterfaceDescriptor();
+ const String16& newDescriptor = clazz->getInterfaceDescriptor();
+
std::lock_guard<std::mutex> lock(mClazzMutex);
if (mClazz == clazz) return true;
- if (mClazz != nullptr) {
+ // If this is an ABpBinder, the first class object becomes the canonical one. The implication
+ // of this is that no API can require a proxy information to get information on how to behave.
+ // from the class itself - which should only store the interface descriptor. The functionality
+ // should be implemented by adding AIBinder_* APIs to set values on binders themselves, by
+ // setting things on AIBinder_Class which get transferred along with the binder, so that they
+ // can be read along with the BpBinder, or by modifying APIs directly (e.g. an option in
+ // onTransact).
+ //
+ // While this check is required to support linkernamespaces, one downside of it is that
+ // you may parcel code to communicate between things in the same process. However, comms
+ // between linkernamespaces like this already happen for cross-language calls like Java<->C++
+ // or Rust<->Java, and there are good stability guarantees here. This interacts with
+ // binder Stability checks exactly like any other in-process call. The stability is known
+ // to the IBinder object, so that it doesn't matter if a class object comes from
+ // a different stability level.
+ if (mClazz != nullptr && !asABpBinder()) {
const String16& currentDescriptor = mClazz->getInterfaceDescriptor();
if (newDescriptor == currentDescriptor) {
LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
@@ -97,37 +133,10 @@
return false;
}
- if (set) {
- // if this is a local object, it's not one known to libbinder_ndk
- mClazz = clazz;
- return true;
- }
-
- return {};
-}
-
-// b/175635923 libcxx causes "implicit-conversion" with a string with invalid char
-static std::string SanitizeString(const String16& str) {
- std::string sanitized{String8(str)};
- for (auto& c : sanitized) {
- if (!isprint(c)) {
- c = '?';
- }
- }
- return sanitized;
-}
-
-bool AIBinder::associateClass(const AIBinder_Class* clazz) {
- if (clazz == nullptr) return false;
-
- const String16& newDescriptor = clazz->getInterfaceDescriptor();
-
- auto result = associateClassInternal(clazz, newDescriptor, false);
- if (result.has_value()) return *result;
-
- CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
-
- const String16& descriptor = getBinder()->getInterfaceDescriptor();
+ // This will always be an O(n) comparison, but it's expected to be extremely rare.
+ // since it's an error condition. Do the comparison after we take the lock and
+ // check the pointer equality fast path. By always taking the lock, it's also
+ // more flake-proof. However, the check is not dependent on the lock.
if (descriptor != newDescriptor) {
if (getBinder()->isBinderAlive()) {
LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor
@@ -141,7 +150,14 @@
return false;
}
- return associateClassInternal(clazz, newDescriptor, true).value();
+ // A local binder being set for the first time OR
+ // ignoring a proxy binder which is set multiple time, by considering the first
+ // associated class as the canonical one.
+ if (mClazz == nullptr) {
+ mClazz = clazz;
+ }
+
+ return true;
}
ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
@@ -325,6 +341,10 @@
return lhs->binder < rhs->binder;
}
+// WARNING: When multiple classes exist with the same interface descriptor in different
+// linkernamespaces, the first one to be associated with mClazz becomes the canonical one
+// and the only requirement on this is that the interface descriptors match. If this
+// is an ABpBinder, no other state can be referenced from mClazz.
AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
AIBinder_Class_onDestroy onDestroy,
AIBinder_Class_onTransact onTransact)
@@ -632,6 +652,10 @@
(*in)->get()->markForBinder(binder->getBinder());
status_t status = android::OK;
+
+ // note - this is the only read of a value in clazz, and it comes with a warning
+ // on the API itself. Do not copy this design. Instead, attach data in a new
+ // version of the prepareTransaction function.
if (clazz->writeHeader) {
status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
}
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index d7098e8..67bb092 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -53,12 +53,14 @@
}
private:
- std::optional<bool> associateClassInternal(const AIBinder_Class* clazz,
- const ::android::String16& newDescriptor, bool set);
-
// AIBinder instance is instance of this class for a local object. In order to transact on a
// remote object, this also must be set for simplicity (although right now, only the
// interfaceDescriptor from it is used).
+ //
+ // WARNING: When multiple classes exist with the same interface descriptor in different
+ // linkernamespaces, the first one to be associated with mClazz becomes the canonical one
+ // and the only requirement on this is that the interface descriptors match. If this
+ // is an ABpBinder, no other state can be referenced from mClazz.
const AIBinder_Class* mClazz;
std::mutex mClazzMutex;
};
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index fccc0af..d6937c2 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -30,11 +30,11 @@
#include <android/binder_internal_logging.h>
#include <android/binder_parcel.h>
#include <android/binder_status.h>
-
#include <assert.h>
-
#include <unistd.h>
+
#include <cstddef>
+#include <iostream>
#include <string>
namespace ndk {
@@ -270,14 +270,19 @@
std::string getDescription() const {
#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 30, *)) {
-#else
- if (__ANDROID_API__ >= 30) {
#endif
+
+#if defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 30
const char* cStr = AStatus_getDescription(get());
std::string ret = cStr;
AStatus_deleteDescription(cStr);
return ret;
+#endif
+
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
}
+#endif
+
binder_exception_t exception = getExceptionCode();
std::string desc = std::to_string(exception);
if (exception == EX_SERVICE_SPECIFIC) {
@@ -315,6 +320,11 @@
}
};
+static inline std::ostream& operator<<(std::ostream& os, const ScopedAStatus& status) {
+ return os << status.getDescription();
+ return os;
+}
+
/**
* Convenience wrapper. See AIBinder_DeathRecipient.
*/
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 78bcb43..9949de2 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -196,6 +196,10 @@
bool isRemote() override final { return false; }
+ static std::string makeServiceName(std::string_view instance) {
+ return INTERFACE::descriptor + ("/" + std::string(instance));
+ }
+
protected:
/**
* This function should only be called by asBinder. Otherwise, there is a possibility of
@@ -291,7 +295,10 @@
binder_status_t ICInterface::ICInterfaceData::onDump(AIBinder* binder, int fd, const char** args,
uint32_t numArgs) {
std::shared_ptr<ICInterface> interface = getInterface(binder);
- return interface->dump(fd, args, numArgs);
+ if (interface != nullptr) {
+ return interface->dump(fd, args, numArgs);
+ }
+ return STATUS_DEAD_OBJECT;
}
#ifdef HAS_BINDER_SHELL_COMMAND
@@ -299,7 +306,10 @@
int err, const char** argv,
uint32_t argc) {
std::shared_ptr<ICInterface> interface = getInterface(binder);
- return interface->handleShellCommand(in, out, err, argv, argc);
+ if (interface != nullptr) {
+ return interface->handleShellCommand(in, out, err, argv, argc);
+ }
+ return STATUS_DEAD_OBJECT;
}
#endif
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index c1f2620..caee471 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -41,68 +41,34 @@
if (_status != STATUS_OK) return _status; \
} while (false)
+// AParcelableHolder has been introduced in 31.
+#if __ANDROID_API__ >= 31
class AParcelableHolder {
public:
AParcelableHolder() = delete;
explicit AParcelableHolder(parcelable_stability_t stability)
: mParcel(AParcel_create()), mStability(stability) {}
-#if __ANDROID_API__ >= 31
AParcelableHolder(const AParcelableHolder& other)
: mParcel(AParcel_create()), mStability(other.mStability) {
- // AParcelableHolder has been introduced in 31.
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
- if (__builtin_available(android 31, *)) {
-#else
- if (__ANDROID_API__ >= 31) {
-#endif
- AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
- AParcel_getDataSize(other.mParcel.get()));
- } else {
- syslog(LOG_ERR,
- "sdk_version not compatible, AParcelableHolder need sdk_version >= 31!");
- }
+ AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
+ AParcel_getDataSize(other.mParcel.get()));
}
-#endif
AParcelableHolder(AParcelableHolder&& other) = default;
virtual ~AParcelableHolder() = default;
binder_status_t writeToParcel(AParcel* parcel) const {
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
- if (__builtin_available(android 31, *)) {
-#else
- if (__ANDROID_API__ >= 31) {
-#endif
- int32_t size = AParcel_getDataSize(this->mParcel.get());
- RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
- } else {
- return STATUS_INVALID_OPERATION;
- }
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
- if (__builtin_available(android 31, *)) {
-#else
- if (__ANDROID_API__ >= 31) {
-#endif
- int32_t size = AParcel_getDataSize(this->mParcel.get());
- RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
- } else {
- return STATUS_INVALID_OPERATION;
- }
+ int32_t size = AParcel_getDataSize(this->mParcel.get());
+ RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
+ size = AParcel_getDataSize(this->mParcel.get());
+ RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
return STATUS_OK;
}
binder_status_t readFromParcel(const AParcel* parcel) {
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
- if (__builtin_available(android 31, *)) {
-#else
- if (__ANDROID_API__ >= 31) {
-#endif
- AParcel_reset(mParcel.get());
- } else {
- return STATUS_INVALID_OPERATION;
- }
+ AParcel_reset(mParcel.get());
parcelable_stability_t wireStability;
RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability));
@@ -123,15 +89,7 @@
return STATUS_BAD_VALUE;
}
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
- if (__builtin_available(android 31, *)) {
-#else
- if (__ANDROID_API__ >= 31) {
-#endif
- status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
- } else {
- status = STATUS_INVALID_OPERATION;
- }
+ status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
if (status != STATUS_OK) {
return status;
}
@@ -143,15 +101,7 @@
if (this->mStability > T::_aidl_stability) {
return STATUS_BAD_VALUE;
}
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
- if (__builtin_available(android 31, *)) {
-#else
- if (__ANDROID_API__ >= 31) {
-#endif
- AParcel_reset(mParcel.get());
- } else {
- return STATUS_INVALID_OPERATION;
- }
+ AParcel_reset(mParcel.get());
AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
p.writeToParcel(mParcel.get());
return STATUS_OK;
@@ -161,17 +111,9 @@
binder_status_t getParcelable(std::optional<T>* ret) const {
const std::string parcelableDesc(T::descriptor);
AParcel_setDataPosition(mParcel.get(), 0);
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
- if (__builtin_available(android 31, *)) {
-#else
- if (__ANDROID_API__ >= 31) {
-#endif
- if (AParcel_getDataSize(mParcel.get()) == 0) {
- *ret = std::nullopt;
- return STATUS_OK;
- }
- } else {
- return STATUS_INVALID_OPERATION;
+ if (AParcel_getDataSize(mParcel.get()) == 0) {
+ *ret = std::nullopt;
+ return STATUS_OK;
}
std::string parcelableDescInParcel;
binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
@@ -188,18 +130,7 @@
return STATUS_OK;
}
- void reset() {
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
- if (__builtin_available(android 31, *)) {
-#else
- if (__ANDROID_API__ >= 31) {
-#endif
- AParcel_reset(mParcel.get());
- } else {
- syslog(LOG_ERR,
- "sdk_version not compatible, AParcelableHolder need sdk_version >= 31!");
- }
- }
+ void reset() { AParcel_reset(mParcel.get()); }
inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
@@ -207,34 +138,23 @@
inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; }
inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; }
inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; }
-#if __ANDROID_API__ >= 31
inline AParcelableHolder& operator=(const AParcelableHolder& rhs) {
- // AParcelableHolder has been introduced in 31.
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
- if (__builtin_available(android 31, *)) {
-#else
- if (__ANDROID_API__ >= 31) {
-#endif
- this->reset();
- if (this->mStability != rhs.mStability) {
- syslog(LOG_ERR, "AParcelableHolder stability mismatch: this %d rhs %d!",
- this->mStability, rhs.mStability);
- abort();
- }
- AParcel_appendFrom(rhs.mParcel.get(), this->mParcel.get(), 0,
- AParcel_getDataSize(rhs.mParcel.get()));
- } else {
- syslog(LOG_ERR,
- "sdk_version not compatible, AParcelableHolder need sdk_version >= 31!");
+ this->reset();
+ if (this->mStability != rhs.mStability) {
+ syslog(LOG_ERR, "AParcelableHolder stability mismatch: this %d rhs %d!",
+ this->mStability, rhs.mStability);
+ abort();
}
+ AParcel_appendFrom(rhs.mParcel.get(), this->mParcel.get(), 0,
+ AParcel_getDataSize(rhs.mParcel.get()));
return *this;
}
-#endif
private:
mutable ndk::ScopedAParcel mParcel;
parcelable_stability_t mStability;
};
+#endif // __ANDROID_API__ >= 31
#undef RETURN_ON_FAILURE
} // namespace ndk
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
index d7840ec..2a00736 100644
--- a/libs/binder/ndk/include_cpp/android/binder_to_string.h
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -136,8 +136,10 @@
template <typename _U>
static std::enable_if_t<
#ifdef HAS_NDK_INTERFACE
- std::is_base_of_v<::ndk::ICInterface, _U> ||
- std::is_same_v<::ndk::AParcelableHolder, _U>
+ std::is_base_of_v<::ndk::ICInterface, _U>
+#if __ANDROID_API__ >= 31
+ || std::is_same_v<::ndk::AParcelableHolder, _U>
+#endif
#else
std::is_base_of_v<IInterface, _U> || std::is_same_v<IBinder, _U> ||
std::is_same_v<os::ParcelFileDescriptor, _U> ||
@@ -158,7 +160,7 @@
template <typename _T>
std::string ToString(const _T& t) {
if constexpr (details::ToEmptyString<_T>::value) {
- return "";
+ return "<unimplemented>";
} else if constexpr (std::is_same_v<bool, _T>) {
return t ? "true" : "false";
} else if constexpr (std::is_same_v<char16_t, _T>) {
@@ -174,9 +176,11 @@
return t;
#ifdef HAS_NDK_INTERFACE
} else if constexpr (std::is_same_v<::ndk::SpAIBinder, _T>) {
- return (t.get() == nullptr) ? "(null)" : "";
+ std::stringstream ss;
+ ss << "binder:" << std::hex << t.get();
+ return ss.str();
} else if constexpr (std::is_same_v<::ndk::ScopedFileDescriptor, _T>) {
- return (t.get() == -1) ? "(null)" : "";
+ return "fd:" + std::to_string(t.get());
#endif
#ifdef HAS_STRING16
} else if constexpr (std::is_same_v<String16, _T>) {
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 4163897..05677a8 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -229,6 +229,11 @@
*
* Available since API level 33.
*
+ * WARNING: this API interacts badly with linkernamespaces. For correct behavior, you must
+ * use it on all instances of a class in the same process which share the same interface
+ * descriptor. In general, it is recommended you do not use this API, because it is disabling
+ * type safety.
+ *
* \param clazz class to disable interface header on.
*/
void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) __INTRODUCED_IN(33);
@@ -613,7 +618,8 @@
*
* 1. If the binder died, shortly after the call to onBinderDied.
* 2. If the binder is explicitly unlinked with AIBinder_unlinkToDeath or
- * AIBinder_DeathRecipient_delete.
+ * AIBinder_DeathRecipient_delete, after any pending onBinderDied calls
+ * finish.
* 3. During or shortly after the AIBinder_linkToDeath call if it returns an error.
*
* It is guaranteed that the callback is called exactly once for each call to linkToDeath unless the
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index dfa8ea2..ad4188f 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -68,6 +68,7 @@
*
* \param instance identifier of the service used to lookup the service.
*/
+[[deprecated("this polls 5s, use AServiceManager_waitForService or AServiceManager_checkService")]]
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance)
__INTRODUCED_IN(29);
@@ -108,6 +109,67 @@
__INTRODUCED_IN(31);
/**
+ * Function to call when a service is registered. The instance is passed as well as
+ * ownership of the binder named 'registered'.
+ *
+ * WARNING: a lock is held when this method is called in order to prevent races with
+ * AServiceManager_NotificationRegistration_delete. Do not make synchronous binder calls when
+ * implementing this method to avoid deadlocks.
+ *
+ * \param instance instance name of service registered
+ * \param registered ownership-passed instance of service registered
+ * \param cookie data passed during registration for notifications
+ */
+typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered,
+ void* cookie);
+
+/**
+ * Represents a registration to servicemanager which can be cleared anytime.
+ */
+struct AServiceManager_NotificationRegistration;
+
+/**
+ * Get notifications when a service is registered. If the service is already registered,
+ * you will immediately get a notification.
+ *
+ * WARNING: it is strongly recommended to use AServiceManager_waitForService API instead.
+ * That API will wait synchronously, which is what you usually want in cases, including
+ * using some feature or during boot up. There is a history of bugs where waiting for
+ * notifications like this races with service startup. Also, when this API is used, a service
+ * bug will result in silent failure (rather than a debuggable deadlock). Furthermore, there
+ * is a history of this API being used to know when a service is up as a proxy for whethre
+ * that service should be started. This should only be used if you are intending to get
+ * ahold of the service as a client. For lazy services, whether a service is registered
+ * should not be used as a proxy for when it should be registered, which is only known
+ * by the real client.
+ *
+ * WARNING: if you use this API, you must also ensure that you check missing services are
+ * started and crash otherwise. If service failures are ignored, the system rots.
+ *
+ * \param instance name of service to wait for notifications about
+ * \param onRegister callback for when service is registered
+ * \param cookie data associated with this callback
+ *
+ * \return the token for this registration. Deleting this token will unregister.
+ */
+__attribute__((warn_unused_result)) AServiceManager_NotificationRegistration*
+AServiceManager_registerForServiceNotifications(const char* instance,
+ AServiceManager_onRegister onRegister, void* cookie)
+ __INTRODUCED_IN(34);
+
+/**
+ * Unregister for notifications and delete the object.
+ *
+ * After this method is called, the callback is guaranteed to no longer be invoked. This will block
+ * until any in-progress onRegister callbacks have completed. It is therefore safe to immediately
+ * destroy the void* cookie that was registered when this method returns.
+ *
+ * \param notification object to dismiss
+ */
+void AServiceManager_NotificationRegistration_delete(
+ AServiceManager_NotificationRegistration* notification) __INTRODUCED_IN(34);
+
+/**
* Check if a service is declared (e.g. VINTF manifest).
*
* \param instance identifier of the service.
@@ -143,6 +205,17 @@
bool AServiceManager_isUpdatableViaApex(const char* instance) __INTRODUCED_IN(31);
/**
+ * Returns the APEX name if a service is declared as updatable via an APEX module.
+ *
+ * \param instance identifier of the service
+ * \param context to pass to callback
+ * \param callback taking the APEX name (e.g. 'com.android.foo') and context
+ */
+void AServiceManager_getUpdatableApexName(const char* instance, void* context,
+ void (*callback)(const char*, void*))
+ __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
* Prevent lazy services without client from shutting down their process
*
* This should only be used if it is every eventually set to false. If a
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index f408fad..ffcad55 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -28,17 +28,33 @@
*
* When using this, it is expected that ABinderProcess_setupPolling and
* ABinderProcess_handlePolledCommands are not used.
+ *
+ * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
+ * function should be responsible for configuring the threadpool for the entire application.
*/
void ABinderProcess_startThreadPool();
/**
* This sets the maximum number of threads that can be started in the threadpool. By default, after
* startThreadPool is called, this is 15. If it is called additional times, it will only prevent
* the kernel from starting new threads and will not delete already existing threads.
+ *
+ * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
+ * function should be responsible for configuring the threadpool for the entire application.
*/
bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads);
/**
+ * Check if the threadpool has already been started.
+ * This tells whether someone in the process has called ABinderProcess_startThreadPool. Usually,
+ * you should use this in a library to abort if the threadpool is not started.
+ * Programs should configure binder threadpools once at the beginning.
+ */
+bool ABinderProcess_isThreadPoolStarted();
+/**
* This adds the current thread to the threadpool. This may cause the threadpool to exceed the
* maximum size.
+ *
+ * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
+ * function should be responsible for configuring the threadpool for the entire application.
*/
void ABinderProcess_joinThreadPool();
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index 683a433..c1f62e5 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -50,6 +50,15 @@
* requirements associated with that higher stability level. For instance, a
* VINTF stability binder is required to be in the VINTF manifest. This API
* can be called to use that same interface within the vendor partition.
+ *
+ * WARNING: you must hold on to a binder instance after this is set, while you
+ * are using it. If you get a binder (e.g. `...->asBinder().get()`), you must
+ * save this binder and then
+ * use it. For instance:
+ *
+ * auto binder = ...->asBinder();
+ * AIBinder_forceDowngradeToVendorStability(binder.get());
+ * doSomething(binder);
*/
void AIBinder_forceDowngradeToVendorStability(AIBinder* binder);
@@ -79,6 +88,15 @@
* requirements associated with that higher stability level. For instance, a
* VINTF stability binder is required to be in the VINTF manifest. This API
* can be called to use that same interface within the system partition.
+ *
+ * WARNING: you must hold on to a binder instance after this is set, while you
+ * are using it. If you get a binder (e.g. `...->asBinder().get()`), you must
+ * save this binder and then
+ * use it. For instance:
+ *
+ * auto binder = ...->asBinder();
+ * AIBinder_forceDowngradeToSystemStability(binder.get());
+ * doSomething(binder);
*/
void AIBinder_forceDowngradeToSystemStability(AIBinder* binder);
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 259a736..54e4628 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -152,6 +152,14 @@
AParcel_unmarshal;
};
+LIBBINDER_NDK34 { # introduced=UpsideDownCake
+ global:
+ ABinderProcess_isThreadPoolStarted; # systemapi llndk
+ AServiceManager_getUpdatableApexName; # systemapi
+ AServiceManager_registerForServiceNotifications; # systemapi llndk
+ AServiceManager_NotificationRegistration_delete; # systemapi llndk
+};
+
LIBBINDER_NDK_PLATFORM {
global:
AParcel_getAllowFds;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index c320e8d..8693022 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -129,7 +129,13 @@
}
T* array;
- if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+ if (!allocator(arrayData, length, &array)) {
+ if (length < 0) {
+ return STATUS_UNEXPECTED_NULL;
+ } else {
+ return STATUS_NO_MEMORY;
+ }
+ }
if (length <= 0) return STATUS_OK;
if (array == nullptr) return STATUS_NO_MEMORY;
@@ -157,7 +163,13 @@
}
char16_t* array;
- if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+ if (!allocator(arrayData, length, &array)) {
+ if (length < 0) {
+ return STATUS_UNEXPECTED_NULL;
+ } else {
+ return STATUS_NO_MEMORY;
+ }
+ }
if (length <= 0) return STATUS_OK;
if (array == nullptr) return STATUS_NO_MEMORY;
@@ -204,7 +216,13 @@
return status;
}
- if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+ if (!allocator(arrayData, length)) {
+ if (length < 0) {
+ return STATUS_UNEXPECTED_NULL;
+ } else {
+ return STATUS_NO_MEMORY;
+ }
+ }
if (length <= 0) return STATUS_OK;
diff --git a/libs/binder/ndk/process.cpp b/libs/binder/ndk/process.cpp
index ac582a4..bc6610e 100644
--- a/libs/binder/ndk/process.cpp
+++ b/libs/binder/ndk/process.cpp
@@ -31,6 +31,9 @@
bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads) {
return ProcessState::self()->setThreadPoolMaxThreadCount(numThreads) == 0;
}
+bool ABinderProcess_isThreadPoolStarted() {
+ return ProcessState::self()->isThreadPoolStarted();
+}
void ABinderProcess_joinThreadPool() {
IPCThreadState::self()->joinThreadPool();
}
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 7649a26..e107c83 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -28,6 +28,7 @@
using ::android::IServiceManager;
using ::android::sp;
using ::android::status_t;
+using ::android::statusToString;
using ::android::String16;
using ::android::String8;
@@ -86,6 +87,67 @@
AIBinder_incStrong(ret.get());
return ret.get();
}
+typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered,
+ void* cookie);
+
+struct AServiceManager_NotificationRegistration
+ : public IServiceManager::LocalRegistrationCallback {
+ std::mutex m;
+ const char* instance = nullptr;
+ void* cookie = nullptr;
+ AServiceManager_onRegister onRegister = nullptr;
+
+ virtual void onServiceRegistration(const String16& smInstance, const sp<IBinder>& binder) {
+ std::lock_guard<std::mutex> l(m);
+ if (onRegister == nullptr) return;
+
+ CHECK_EQ(String8(smInstance), instance);
+
+ sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
+ AIBinder_incStrong(ret.get());
+
+ onRegister(instance, ret.get(), cookie);
+ }
+
+ void clear() {
+ std::lock_guard<std::mutex> l(m);
+ instance = nullptr;
+ cookie = nullptr;
+ onRegister = nullptr;
+ }
+};
+
+__attribute__((warn_unused_result)) AServiceManager_NotificationRegistration*
+AServiceManager_registerForServiceNotifications(const char* instance,
+ AServiceManager_onRegister onRegister,
+ void* cookie) {
+ CHECK_NE(instance, nullptr);
+ CHECK_NE(onRegister, nullptr) << instance;
+ // cookie can be nullptr
+
+ auto cb = sp<AServiceManager_NotificationRegistration>::make();
+ cb->instance = instance;
+ cb->onRegister = onRegister;
+ cb->cookie = cookie;
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (status_t res = sm->registerForNotifications(String16(instance), cb); res != STATUS_OK) {
+ LOG(ERROR) << "Failed to register for service notifications for " << instance << ": "
+ << statusToString(res);
+ return nullptr;
+ }
+
+ cb->incStrong(nullptr);
+ return cb.get();
+}
+
+void AServiceManager_NotificationRegistration_delete(
+ AServiceManager_NotificationRegistration* notification) {
+ CHECK_NE(notification, nullptr);
+ notification->clear();
+ notification->decStrong(nullptr);
+}
+
bool AServiceManager_isDeclared(const char* instance) {
if (instance == nullptr) {
return false;
@@ -113,6 +175,18 @@
sp<IServiceManager> sm = defaultServiceManager();
return sm->updatableViaApex(String16(instance)) != std::nullopt;
}
+void AServiceManager_getUpdatableApexName(const char* instance, void* context,
+ void (*callback)(const char*, void*)) {
+ CHECK_NE(instance, nullptr);
+ // context may be nullptr
+ CHECK_NE(callback, nullptr);
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ std::optional<String16> updatableViaApex = sm->updatableViaApex(String16(instance));
+ if (updatableViaApex.has_value()) {
+ callback(String8(updatableViaApex.value()).c_str(), context);
+ }
+}
void AServiceManager_forceLazyServicesPersist(bool persist) {
auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
serviceRegistrar.forcePersist(persist);
diff --git a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
index f3cd218..43b2cb8 100644
--- a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
@@ -106,7 +106,7 @@
std::string outString;
ScopedAStatus status = server->RepeatString("foo", &outString);
EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get()))
- << serviceName << " " << status.getDescription();
+ << serviceName << " " << status;
EXPECT_EQ("foo", outString) << serviceName;
}
}
diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp
index 2afe5d2..76acff5 100644
--- a/libs/binder/ndk/tests/iface.cpp
+++ b/libs/binder/ndk/tests/iface.cpp
@@ -72,6 +72,11 @@
AIBinder_Class* IFoo::kClass = AIBinder_Class_define(kIFooDescriptor, IFoo_Class_onCreate,
IFoo_Class_onDestroy, IFoo_Class_onTransact);
+// Defines the same class. Ordinarly, you would never want to do this, but it's done here
+// to simulate what would happen when multiple linker namespaces interact.
+AIBinder_Class* IFoo::kClassDupe = AIBinder_Class_define(
+ kIFooDescriptor, IFoo_Class_onCreate, IFoo_Class_onDestroy, IFoo_Class_onTransact);
+
class BpFoo : public IFoo {
public:
explicit BpFoo(AIBinder* binder) : mBinder(binder) {}
diff --git a/libs/binder/ndk/tests/include/iface/iface.h b/libs/binder/ndk/tests/include/iface/iface.h
index 7408d0c..0a562f0 100644
--- a/libs/binder/ndk/tests/include/iface/iface.h
+++ b/libs/binder/ndk/tests/include/iface/iface.h
@@ -30,8 +30,13 @@
static const char* kIFooDescriptor;
static AIBinder_Class* kClass;
+ static AIBinder_Class* kClassDupe;
// binder representing this interface with one reference count
+ // NOTE - this will create a new binder if it already exists. If you use
+ // getService for instance, you must pull outBinder. Don't use this without
+ // verifying isRemote or pointer equality. This is not a very good testing API - don't
+ // copy it - consider the AIDL-generated APIs instead.
AIBinder* getBinder();
// Takes ownership of IFoo
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 01b9472..5b2532a 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -33,13 +33,15 @@
#include <binder/IResultReceiver.h>
#include <binder/IServiceManager.h>
#include <binder/IShellCallback.h>
-
#include <sys/prctl.h>
+
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
+#include <optional>
#include <thread>
+
#include "android/binder_ibinder.h"
using namespace android;
@@ -53,6 +55,18 @@
constexpr unsigned int kShutdownWaitTime = 10;
constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715;
+class MyTestFoo : public IFoo {
+ binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+ *out = 2 * in;
+ LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+ return STATUS_OK;
+ }
+ binder_status_t die() override {
+ ADD_FAILURE() << "die called on local instance";
+ return STATUS_OK;
+ }
+};
+
class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
*out = in;
@@ -252,12 +266,52 @@
AIBinder_decStrong(binder);
}
+struct ServiceData {
+ std::string instance;
+ ndk::SpAIBinder binder;
+
+ static void fillOnRegister(const char* instance, AIBinder* binder, void* cookie) {
+ ServiceData* d = reinterpret_cast<ServiceData*>(cookie);
+ d->instance = instance;
+ d->binder = ndk::SpAIBinder(binder);
+ }
+};
+
+TEST(NdkBinder, RegisterForServiceNotificationsNonExisting) {
+ ServiceData data;
+ auto* notif = AServiceManager_registerForServiceNotifications(
+ "DOES_NOT_EXIST", ServiceData::fillOnRegister, (void*)&data);
+ ASSERT_NE(notif, nullptr);
+
+ sleep(1); // give us a chance to fail
+ AServiceManager_NotificationRegistration_delete(notif);
+
+ // checking after deleting to avoid needing a mutex over the data - otherwise
+ // in an environment w/ multiple threads, you would need to guard access
+ EXPECT_EQ(data.instance, "");
+ EXPECT_EQ(data.binder, nullptr);
+}
+
+TEST(NdkBinder, RegisterForServiceNotificationsExisting) {
+ ServiceData data;
+ auto* notif = AServiceManager_registerForServiceNotifications(
+ kExistingNonNdkService, ServiceData::fillOnRegister, (void*)&data);
+ ASSERT_NE(notif, nullptr);
+
+ sleep(1); // give us a chance to fail
+ AServiceManager_NotificationRegistration_delete(notif);
+
+ // checking after deleting to avoid needing a mutex over the data - otherwise
+ // in an environment w/ multiple threads, you would need to guard access
+ EXPECT_EQ(data.instance, kExistingNonNdkService);
+ EXPECT_EQ(data.binder, ndk::SpAIBinder(AServiceManager_checkService(kExistingNonNdkService)));
+}
+
TEST(NdkBinder, UnimplementedDump) {
- sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
+ ndk::SpAIBinder binder;
+ sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName, binder.getR());
ASSERT_NE(foo, nullptr);
- AIBinder* binder = foo->getBinder();
- EXPECT_EQ(OK, AIBinder_dump(binder, STDOUT_FILENO, nullptr, 0));
- AIBinder_decStrong(binder);
+ EXPECT_EQ(OK, AIBinder_dump(binder.get(), STDOUT_FILENO, nullptr, 0));
}
TEST(NdkBinder, UnimplementedShell) {
@@ -281,6 +335,24 @@
EXPECT_EQ(2, out);
}
+TEST(NdkBinder, ReassociateBpBinderWithSameDescriptor) {
+ ndk::SpAIBinder binder;
+ sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName, binder.getR());
+
+ EXPECT_TRUE(AIBinder_isRemote(binder.get()));
+
+ EXPECT_TRUE(AIBinder_associateClass(binder.get(), IFoo::kClassDupe));
+}
+
+TEST(NdkBinder, CantHaveTwoLocalBinderClassesWithSameDescriptor) {
+ sp<IFoo> foo = sp<MyTestFoo>::make();
+ ndk::SpAIBinder binder(foo->getBinder());
+
+ EXPECT_FALSE(AIBinder_isRemote(binder.get()));
+
+ EXPECT_FALSE(AIBinder_associateClass(binder.get(), IFoo::kClassDupe));
+}
+
TEST(NdkBinder, GetTestServiceStressTest) {
// libbinder has some complicated logic to make sure only one instance of
// ABpBinder is associated with each binder.
@@ -337,6 +409,16 @@
EXPECT_EQ(isUpdatable, false);
}
+TEST(NdkBinder, GetUpdatableViaApex) {
+ std::optional<std::string> updatableViaApex;
+ AServiceManager_getUpdatableApexName(
+ "android.hardware.light.ILights/default", &updatableViaApex,
+ [](const char* apexName, void* context) {
+ *static_cast<std::optional<std::string>*>(context) = apexName;
+ });
+ EXPECT_EQ(updatableViaApex, std::nullopt) << *updatableViaApex;
+}
+
// This is too slow
TEST(NdkBinder, CheckLazyServiceShutDown) {
ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
@@ -492,18 +574,6 @@
AIBinder_decStrong(binder);
}
-class MyTestFoo : public IFoo {
- binder_status_t doubleNumber(int32_t in, int32_t* out) override {
- *out = 2 * in;
- LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
- return STATUS_OK;
- }
- binder_status_t die() override {
- ADD_FAILURE() << "die called on local instance";
- return STATUS_OK;
- }
-};
-
TEST(NdkBinder, SetInheritRt) {
// functional test in binderLibTest
sp<IFoo> foo = sp<MyTestFoo>::make();
@@ -544,7 +614,8 @@
sp<IFoo> foo = new MyTestFoo;
EXPECT_EQ(EX_NONE, foo->addService(kInstanceName));
- sp<IFoo> getFoo = IFoo::getService(kInstanceName);
+ ndk::SpAIBinder binder;
+ sp<IFoo> getFoo = IFoo::getService(kInstanceName, binder.getR());
EXPECT_EQ(foo.get(), getFoo.get());
int32_t out;
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index a135796..afd414a 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -17,7 +17,6 @@
rustlibs: [
"libbinder_ndk_sys",
"libdowncast_rs",
- "liblazy_static",
"liblibc",
],
host_supported: true,
@@ -88,6 +87,7 @@
min_sdk_version: "Tiramisu",
lints: "none",
clippy_lints: "none",
+ visibility: [":__subpackages__"],
}
rust_bindgen {
@@ -159,7 +159,6 @@
rustlibs: [
"libbinder_ndk_sys",
"libdowncast_rs",
- "liblazy_static",
"liblibc",
],
}
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 5ebc27f..afb73e9 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -19,7 +19,9 @@
"libbinder_rpc_unstable_bindgen_sys",
"libbinder_rs",
"libdowncast_rs",
+ "libforeign_types",
"liblibc",
+ "liblog_rust",
],
apex_available: [
"com.android.compos",
@@ -66,10 +68,13 @@
visibility: [":__subpackages__"],
source_stem: "bindings",
bindgen_flags: [
+ "--size_t-is-usize",
"--blocklist-type",
"AIBinder",
"--raw-line",
"use binder_ndk_sys::AIBinder;",
+ "--rustified-enum",
+ "ARpcSession_FileDescriptorTransportMode",
],
rustlibs: [
"libbinder_ndk_sys",
diff --git a/libs/binder/rust/rpcbinder/src/client.rs b/libs/binder/rust/rpcbinder/src/client.rs
deleted file mode 100644
index 743800b..0000000
--- a/libs/binder/rust/rpcbinder/src/client.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-use binder::{unstable_api::new_spibinder, FromIBinder, SpIBinder, StatusCode, Strong};
-use std::os::{
- raw::{c_int, c_void},
- unix::io::RawFd,
-};
-
-/// Connects to an RPC Binder server over vsock.
-pub fn get_vsock_rpc_service(cid: u32, port: u32) -> Option<SpIBinder> {
- // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can
- // safely be taken by new_spibinder.
- unsafe { new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, port)) }
-}
-
-/// Connects to an RPC Binder server for a particular interface over vsock.
-pub fn get_vsock_rpc_interface<T: FromIBinder + ?Sized>(
- cid: u32,
- port: u32,
-) -> Result<Strong<T>, StatusCode> {
- interface_cast(get_vsock_rpc_service(cid, port))
-}
-
-/// Connects to an RPC Binder server, using the given callback to get (and take ownership of)
-/// file descriptors already connected to it.
-pub fn get_preconnected_rpc_service(
- mut request_fd: impl FnMut() -> Option<RawFd>,
-) -> Option<SpIBinder> {
- // Double reference the factory because trait objects aren't FFI safe.
- let mut request_fd_ref: RequestFd = &mut request_fd;
- let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;
-
- // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
- // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
- // of param, only passing it to request_fd_wrapper.
- unsafe {
- new_spibinder(binder_rpc_unstable_bindgen::RpcPreconnectedClient(
- Some(request_fd_wrapper),
- param,
- ))
- }
-}
-
-type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
-
-unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
- // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
- // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
- // initialized instance.
- let request_fd_ptr = param as *mut RequestFd;
- let request_fd = request_fd_ptr.as_mut().unwrap();
- if let Some(fd) = request_fd() {
- fd
- } else {
- -1
- }
-}
-
-/// Connects to an RPC Binder server for a particular interface, using the given callback to get
-/// (and take ownership of) file descriptors already connected to it.
-pub fn get_preconnected_rpc_interface<T: FromIBinder + ?Sized>(
- request_fd: impl FnMut() -> Option<RawFd>,
-) -> Result<Strong<T>, StatusCode> {
- interface_cast(get_preconnected_rpc_service(request_fd))
-}
-
-fn interface_cast<T: FromIBinder + ?Sized>(
- service: Option<SpIBinder>,
-) -> Result<Strong<T>, StatusCode> {
- if let Some(service) = service {
- FromIBinder::try_from(service)
- } else {
- Err(StatusCode::NAME_NOT_FOUND)
- }
-}
diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs
index a5eea61..a957385 100644
--- a/libs/binder/rust/rpcbinder/src/lib.rs
+++ b/libs/binder/rust/rpcbinder/src/lib.rs
@@ -16,11 +16,8 @@
//! API for RPC Binder services.
-mod client;
mod server;
+mod session;
-pub use client::{
- get_preconnected_rpc_interface, get_preconnected_rpc_service, get_vsock_rpc_interface,
- get_vsock_rpc_service,
-};
-pub use server::{run_rpc_server, run_rpc_server_with_factory};
+pub use server::{RpcServer, RpcServerRef};
+pub use session::{FileDescriptorTransportMode, RpcSession, RpcSessionRef};
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index aeb23c6..761b306 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -14,111 +14,137 @@
* limitations under the License.
*/
-use binder::{
- unstable_api::{AIBinder, AsNative},
- SpIBinder,
-};
-use std::{os::raw, ptr::null_mut};
+use crate::session::FileDescriptorTransportMode;
+use binder::{unstable_api::AsNative, SpIBinder};
+use binder_rpc_unstable_bindgen::ARpcServer;
+use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
+use std::ffi::CString;
+use std::io::{Error, ErrorKind};
+use std::os::unix::io::{IntoRawFd, OwnedFd};
-/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
-/// port.
-///
-/// If and when the server is ready for connections (it is listening on the port), `on_ready` is
-/// called to allow appropriate action to be taken - e.g. to notify clients that they may now
-/// attempt to connect.
-///
-/// The current thread is joined to the binder thread pool to handle incoming messages.
-///
-/// Returns true if the server has shutdown normally, false if it failed in some way.
-pub fn run_rpc_server<F>(service: SpIBinder, port: u32, on_ready: F) -> bool
-where
- F: FnOnce(),
-{
- let mut ready_notifier = ReadyNotifier(Some(on_ready));
- ready_notifier.run_server(service, port)
+foreign_type! {
+ type CType = binder_rpc_unstable_bindgen::ARpcServer;
+ fn drop = binder_rpc_unstable_bindgen::ARpcServer_free;
+
+ /// A type that represents a foreign instance of RpcServer.
+ #[derive(Debug)]
+ pub struct RpcServer;
+ /// A borrowed RpcServer.
+ pub struct RpcServerRef;
}
-struct ReadyNotifier<F>(Option<F>)
-where
- F: FnOnce();
+/// SAFETY - The opaque handle can be cloned freely.
+unsafe impl Send for RpcServer {}
+/// SAFETY - The underlying C++ RpcServer class is thread-safe.
+unsafe impl Sync for RpcServer {}
-impl<F> ReadyNotifier<F>
-where
- F: FnOnce(),
-{
- fn run_server(&mut self, mut service: SpIBinder, port: u32) -> bool {
+impl RpcServer {
+ /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+ /// vsock port. Only connections from the given CID are accepted.
+ ///
+ // Set `cid` to libc::VMADDR_CID_ANY to accept connections from any client.
+ // Set `cid` to libc::VMADDR_CID_LOCAL to only bind to the local vsock interface.
+ pub fn new_vsock(mut service: SpIBinder, cid: u32, port: u32) -> Result<RpcServer, Error> {
let service = service.as_native_mut();
- let param = self.as_void_ptr();
// SAFETY: Service ownership is transferring to the server and won't be valid afterward.
// Plus the binder objects are threadsafe.
- // RunRpcServerCallback does not retain a reference to `ready_callback` or `param`; it only
- // uses them before it returns, which is during the lifetime of `self`.
unsafe {
- binder_rpc_unstable_bindgen::RunRpcServerCallback(
+ Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(
+ service, cid, port,
+ ))
+ }
+ }
+
+ /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+ /// socket file name. The socket should be initialized in init.rc with the same name.
+ pub fn new_init_unix_domain(
+ mut service: SpIBinder,
+ socket_name: &str,
+ ) -> Result<RpcServer, Error> {
+ let socket_name = match CString::new(socket_name) {
+ Ok(s) => s,
+ Err(e) => {
+ log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+ return Err(Error::from(ErrorKind::InvalidInput));
+ }
+ };
+ let service = service.as_native_mut();
+
+ // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+ // Plus the binder objects are threadsafe.
+ unsafe {
+ Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInitUnixDomain(
service,
- port,
- Some(Self::ready_callback),
- param,
+ socket_name.as_ptr(),
+ ))
+ }
+ }
+
+ /// Creates a binder RPC server that bootstraps sessions using an existing Unix domain socket
+ /// pair, with a given root IBinder object. Callers should create a pair of SOCK_STREAM Unix
+ /// domain sockets, pass one to the server and the other to the client. Multiple client session
+ /// can be created from the client end of the pair.
+ pub fn new_unix_domain_bootstrap(
+ mut service: SpIBinder,
+ bootstrap_fd: OwnedFd,
+ ) -> Result<RpcServer, Error> {
+ let service = service.as_native_mut();
+
+ // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+ // Plus the binder objects are threadsafe.
+ // The server takes ownership of the bootstrap FD.
+ unsafe {
+ Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
+ service,
+ bootstrap_fd.into_raw_fd(),
+ ))
+ }
+ }
+
+ unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> {
+ if ptr.is_null() {
+ return Err(Error::new(ErrorKind::Other, "Failed to start server"));
+ }
+ Ok(RpcServer::from_ptr(ptr))
+ }
+}
+
+impl RpcServerRef {
+ /// Sets the list of file descriptor transport modes supported by this server.
+ pub fn set_supported_file_descriptor_transport_modes(
+ &self,
+ modes: &[FileDescriptorTransportMode],
+ ) {
+ // SAFETY - Does not keep the pointer after returning does, nor does it
+ // read past its boundary. Only passes the 'self' pointer as an opaque handle.
+ unsafe {
+ binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
+ self.as_ptr(),
+ modes.as_ptr(),
+ modes.len(),
)
}
}
- fn as_void_ptr(&mut self) -> *mut raw::c_void {
- self as *mut _ as *mut raw::c_void
+ /// Starts a new background thread and calls join(). Returns immediately.
+ pub fn start(&self) {
+ unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
}
- unsafe extern "C" fn ready_callback(param: *mut raw::c_void) {
- // SAFETY: This is only ever called by `RunRpcServerCallback`, within the lifetime of the
- // `ReadyNotifier`, with `param` taking the value returned by `as_void_ptr` (so a properly
- // aligned non-null pointer to an initialized instance).
- let ready_notifier = param as *mut Self;
- ready_notifier.as_mut().unwrap().notify()
+ /// Joins the RpcServer thread. The call blocks until the server terminates.
+ /// This must be called from exactly one thread.
+ pub fn join(&self) {
+ unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
}
- fn notify(&mut self) {
- if let Some(on_ready) = self.0.take() {
- on_ready();
+ /// Shuts down the running RpcServer. Can be called multiple times and from
+ /// multiple threads. Called automatically during drop().
+ pub fn shutdown(&self) -> Result<(), Error> {
+ if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
+ Ok(())
+ } else {
+ Err(Error::from(ErrorKind::UnexpectedEof))
}
}
}
-
-type RpcServerFactoryRef<'a> = &'a mut (dyn FnMut(u32) -> Option<SpIBinder> + Send + Sync);
-
-/// Runs a binder RPC server, using the given factory function to construct a binder service
-/// implementation for each connection.
-///
-/// The current thread is joined to the binder thread pool to handle incoming messages.
-///
-/// Returns true if the server has shutdown normally, false if it failed in some way.
-pub fn run_rpc_server_with_factory(
- port: u32,
- mut factory: impl FnMut(u32) -> Option<SpIBinder> + Send + Sync,
-) -> bool {
- // Double reference the factory because trait objects aren't FFI safe.
- // NB: The type annotation is necessary to ensure that we have a `dyn` rather than an `impl`.
- let mut factory_ref: RpcServerFactoryRef = &mut factory;
- let context = &mut factory_ref as *mut RpcServerFactoryRef as *mut raw::c_void;
-
- // SAFETY: `factory_wrapper` is only ever called by `RunRpcServerWithFactory`, with context
- // taking the pointer value above (so a properly aligned non-null pointer to an initialized
- // `RpcServerFactoryRef`), within the lifetime of `factory_ref` (i.e. no more calls will be made
- // after `RunRpcServerWithFactory` returns).
- unsafe {
- binder_rpc_unstable_bindgen::RunRpcServerWithFactory(Some(factory_wrapper), context, port)
- }
-}
-
-unsafe extern "C" fn factory_wrapper(cid: u32, context: *mut raw::c_void) -> *mut AIBinder {
- // SAFETY: `context` was created from an `&mut RpcServerFactoryRef` by
- // `run_rpc_server_with_factory`, and we are still within the lifetime of the value it is
- // pointing to.
- let factory_ptr = context as *mut RpcServerFactoryRef;
- let factory = factory_ptr.as_mut().unwrap();
-
- if let Some(mut service) = factory(cid) {
- service.as_native_mut()
- } else {
- null_mut()
- }
-}
diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs
new file mode 100644
index 0000000..62fedb1
--- /dev/null
+++ b/libs/binder/rust/rpcbinder/src/session.rs
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+use binder::unstable_api::new_spibinder;
+use binder::{FromIBinder, SpIBinder, StatusCode, Strong};
+use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
+use std::ffi::CString;
+use std::os::{
+ raw::{c_int, c_void},
+ unix::io::{AsRawFd, BorrowedFd, RawFd},
+};
+
+pub use binder_rpc_unstable_bindgen::ARpcSession_FileDescriptorTransportMode as FileDescriptorTransportMode;
+
+foreign_type! {
+ type CType = binder_rpc_unstable_bindgen::ARpcSession;
+ fn drop = binder_rpc_unstable_bindgen::ARpcSession_free;
+
+ /// A type that represents a foreign instance of RpcSession.
+ #[derive(Debug)]
+ pub struct RpcSession;
+ /// A borrowed RpcSession.
+ pub struct RpcSessionRef;
+}
+
+/// SAFETY - The opaque handle can be cloned freely.
+unsafe impl Send for RpcSession {}
+/// SAFETY - The underlying C++ RpcSession class is thread-safe.
+unsafe impl Sync for RpcSession {}
+
+impl RpcSession {
+ /// Allocates a new RpcSession object.
+ pub fn new() -> RpcSession {
+ // SAFETY - Takes ownership of the returned handle, which has correct refcount.
+ unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) }
+ }
+}
+
+impl Default for RpcSession {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl RpcSessionRef {
+ /// Sets the file descriptor transport mode for this session.
+ pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) {
+ // SAFETY - Only passes the 'self' pointer as an opaque handle.
+ unsafe {
+ binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode(
+ self.as_ptr(),
+ mode,
+ )
+ };
+ }
+
+ /// Sets the maximum number of incoming threads.
+ pub fn set_max_incoming_threads(&self, threads: usize) {
+ // SAFETY - Only passes the 'self' pointer as an opaque handle.
+ unsafe {
+ binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads)
+ };
+ }
+
+ /// Sets the maximum number of outgoing threads.
+ pub fn set_max_outgoing_threads(&self, threads: usize) {
+ // SAFETY - Only passes the 'self' pointer as an opaque handle.
+ unsafe {
+ binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingThreads(self.as_ptr(), threads)
+ };
+ }
+
+ /// Connects to an RPC Binder server over vsock for a particular interface.
+ pub fn setup_vsock_client<T: FromIBinder + ?Sized>(
+ &self,
+ cid: u32,
+ port: u32,
+ ) -> Result<Strong<T>, StatusCode> {
+ // SAFETY: AIBinder returned by ARpcSession_setupVsockClient has correct
+ // reference count, and the ownership can safely be taken by new_spibinder.
+ let service = unsafe {
+ new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupVsockClient(
+ self.as_ptr(),
+ cid,
+ port,
+ ))
+ };
+ Self::get_interface(service)
+ }
+
+ /// Connects to an RPC Binder server over a names Unix Domain Socket for
+ /// a particular interface.
+ pub fn setup_unix_domain_client<T: FromIBinder + ?Sized>(
+ &self,
+ socket_name: &str,
+ ) -> Result<Strong<T>, StatusCode> {
+ let socket_name = match CString::new(socket_name) {
+ Ok(s) => s,
+ Err(e) => {
+ log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+ return Err(StatusCode::NAME_NOT_FOUND);
+ }
+ };
+
+ // SAFETY: AIBinder returned by ARpcSession_setupUnixDomainClient has correct
+ // reference count, and the ownership can safely be taken by new_spibinder.
+ let service = unsafe {
+ new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainClient(
+ self.as_ptr(),
+ socket_name.as_ptr(),
+ ))
+ };
+ Self::get_interface(service)
+ }
+
+ /// Connects to an RPC Binder server over a bootstrap Unix Domain Socket
+ /// for a particular interface.
+ pub fn setup_unix_domain_bootstrap_client<T: FromIBinder + ?Sized>(
+ &self,
+ bootstrap_fd: BorrowedFd,
+ ) -> Result<Strong<T>, StatusCode> {
+ // SAFETY: ARpcSession_setupUnixDomainBootstrapClient does not take
+ // ownership of bootstrap_fd. The returned AIBinder has correct
+ // reference count, and the ownership can safely be taken by new_spibinder.
+ let service = unsafe {
+ new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainBootstrapClient(
+ self.as_ptr(),
+ bootstrap_fd.as_raw_fd(),
+ ))
+ };
+ Self::get_interface(service)
+ }
+
+ /// Connects to an RPC Binder server, using the given callback to get (and
+ /// take ownership of) file descriptors already connected to it.
+ pub fn setup_preconnected_client<T: FromIBinder + ?Sized>(
+ &self,
+ mut request_fd: impl FnMut() -> Option<RawFd>,
+ ) -> Result<Strong<T>, StatusCode> {
+ // Double reference the factory because trait objects aren't FFI safe.
+ let mut request_fd_ref: RequestFd = &mut request_fd;
+ let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;
+
+ // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
+ // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
+ // of param, only passing it to request_fd_wrapper.
+ let service = unsafe {
+ new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupPreconnectedClient(
+ self.as_ptr(),
+ Some(request_fd_wrapper),
+ param,
+ ))
+ };
+ Self::get_interface(service)
+ }
+
+ fn get_interface<T: FromIBinder + ?Sized>(
+ service: Option<SpIBinder>,
+ ) -> Result<Strong<T>, StatusCode> {
+ if let Some(service) = service {
+ FromIBinder::try_from(service)
+ } else {
+ Err(StatusCode::NAME_NOT_FOUND)
+ }
+ }
+}
+
+type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
+
+unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
+ // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
+ // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
+ // initialized instance.
+ let request_fd_ptr = param as *mut RequestFd;
+ let request_fd = request_fd_ptr.as_mut().unwrap();
+ request_fd().unwrap_or(-1)
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 195d9ac..a0e61d9 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -148,4 +148,5 @@
pub use crate::binder::AsNative;
pub use crate::proxy::unstable_api::new_spibinder;
pub use crate::sys::AIBinder;
+ pub use crate::sys::AParcel;
}
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index dee05d0..6f686fb 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -22,7 +22,6 @@
use crate::proxy::SpIBinder;
use crate::sys;
-use lazy_static::lazy_static;
use std::convert::TryFrom;
use std::ffi::{c_void, CStr, CString};
use std::fs::File;
@@ -508,10 +507,8 @@
_private: (),
}
-lazy_static! {
- // Count of how many LazyServiceGuard objects are in existence.
- static ref GUARD_COUNT: Mutex<u64> = Mutex::new(0);
-}
+// Count of how many LazyServiceGuard objects are in existence.
+static GUARD_COUNT: Mutex<u64> = Mutex::new(0);
impl LazyServiceGuard {
/// Create a new LazyServiceGuard to prevent the service manager prematurely killing this
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 4e10fa9..ca2cedc 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -502,7 +502,7 @@
let instances = binder::get_declared_instances("android.hardware.light.ILights")
.expect("Could not get declared instances");
- let expected_defaults = if has_lights { 1 } else { 0 };
+ let expected_defaults = usize::from(has_lights);
assert_eq!(expected_defaults, instances.iter().filter(|i| i.as_str() == "default").count());
}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
new file mode 100644
index 0000000..df8a2af
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
@@ -0,0 +1,27 @@
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+rust_fuzz {
+ name: "parcel_fuzzer_rs",
+ srcs: [
+ "parcel_fuzzer.rs",
+ ],
+ rustlibs: [
+ "libarbitrary",
+ "libnum_traits",
+ "libbinder_rs",
+ "libbinder_random_parcel_rs",
+ "binderReadParcelIface-rust",
+ ],
+
+ fuzz_config: {
+ cc: [
+ "waghpawan@google.com",
+ "smoreland@google.com",
+ ],
+ // hotlist "AIDL fuzzers bugs" on buganizer
+ hotlists: ["4637097"],
+ },
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
new file mode 100644
index 0000000..c5c7719
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+
+#[macro_use]
+extern crate libfuzzer_sys;
+
+mod read_utils;
+
+use crate::read_utils::READ_FUNCS;
+use binder::binder_impl::{
+ Binder, BorrowedParcel, IBinderInternal, Parcel, Stability, TransactionCode,
+};
+use binder::{
+ declare_binder_interface, BinderFeatures, Interface, Parcelable, ParcelableHolder, SpIBinder,
+ StatusCode,
+};
+use binder_random_parcel_rs::create_random_parcel;
+use libfuzzer_sys::arbitrary::Arbitrary;
+
+#[derive(Arbitrary, Debug)]
+enum ReadOperation {
+ SetDataPosition { pos: i32 },
+ GetDataSize,
+ ReadParcelableHolder { is_vintf: bool },
+ ReadBasicTypes { instructions: Vec<usize> },
+}
+
+#[derive(Arbitrary, Debug)]
+enum Operation<'a> {
+ Transact { code: u32, flag: u32, data: &'a [u8] },
+ Append { start: i32, len: i32, data1: &'a [u8], data2: &'a [u8], append_all: bool },
+ Read { read_operations: Vec<ReadOperation>, data: &'a [u8] },
+}
+
+/// Interface to fuzz transact with random parcel
+pub trait BinderTransactTest: Interface {}
+
+declare_binder_interface! {
+ BinderTransactTest["Binder_Transact_Test"] {
+ native: BnBinderTransactTest(on_transact),
+ proxy: BpBinderTransactTest,
+ }
+}
+
+impl BinderTransactTest for Binder<BnBinderTransactTest> {}
+
+impl BinderTransactTest for BpBinderTransactTest {}
+
+impl BinderTransactTest for () {}
+
+fn on_transact(
+ _service: &dyn BinderTransactTest,
+ _code: TransactionCode,
+ _parcel: &BorrowedParcel<'_>,
+ _reply: &mut BorrowedParcel<'_>,
+) -> Result<(), StatusCode> {
+ Err(StatusCode::UNKNOWN_ERROR)
+}
+
+fn do_transact(code: u32, data: &[u8], flag: u32) {
+ let p: Parcel = create_random_parcel(data);
+ let spibinder: Option<SpIBinder> =
+ Some(BnBinderTransactTest::new_binder((), BinderFeatures::default()).as_binder());
+ let _reply = spibinder.submit_transact(code, p, flag);
+}
+
+fn do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all: bool) {
+ let mut p1 = create_random_parcel(data1);
+ let p2 = create_random_parcel(data2);
+
+ // Fuzz both append methods
+ if append_all {
+ match p1.append_all_from(&p2) {
+ Ok(result) => result,
+ Err(e) => {
+ println!("Error occurred while appending a parcel using append_all_from: {:?}", e)
+ }
+ }
+ } else {
+ match p1.append_from(&p2, start, len) {
+ Ok(result) => result,
+ Err(e) => {
+ println!("Error occurred while appending a parcel using append_from: {:?}", e)
+ }
+ }
+ };
+}
+
+fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) {
+ let parcel = create_random_parcel(data);
+
+ for operation in read_operations {
+ match operation {
+ ReadOperation::SetDataPosition { pos } => {
+ unsafe {
+ // Safety: Safe if pos is less than current size of the parcel.
+ // It relies on C++ code for bound checks
+ match parcel.set_data_position(pos) {
+ Ok(result) => result,
+ Err(e) => println!("error occurred while setting data position: {:?}", e),
+ }
+ }
+ }
+
+ ReadOperation::GetDataSize => {
+ let data_size = parcel.get_data_size();
+ println!("data size from parcel: {:?}", data_size);
+ }
+
+ ReadOperation::ReadParcelableHolder { is_vintf } => {
+ let stability = if is_vintf { Stability::Vintf } else { Stability::Local };
+ let mut holder: ParcelableHolder = ParcelableHolder::new(stability);
+ match holder.read_from_parcel(parcel.borrowed_ref()) {
+ Ok(result) => result,
+ Err(err) => {
+ println!("error occurred while reading from parcel: {:?}", err)
+ }
+ }
+ }
+
+ ReadOperation::ReadBasicTypes { instructions } => {
+ for instruction in instructions.iter() {
+ let read_index = instruction % READ_FUNCS.len();
+ READ_FUNCS[read_index](parcel.borrowed_ref());
+ }
+ }
+ }
+ }
+}
+
+fuzz_target!(|operation: Operation| {
+ match operation {
+ Operation::Transact { code, flag, data } => {
+ do_transact(code, data, flag);
+ }
+
+ Operation::Append { start, len, data1, data2, append_all } => {
+ do_append_fuzz(start, len, data1, data2, append_all);
+ }
+
+ Operation::Read { read_operations, data } => {
+ do_read_fuzz(read_operations, data);
+ }
+ }
+});
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp
new file mode 100644
index 0000000..43a3094
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp
@@ -0,0 +1,52 @@
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+rust_bindgen {
+ name: "libbinder_random_parcel_bindgen",
+ crate_name: "binder_random_parcel_bindgen",
+ host_supported: true,
+ wrapper_src: "wrappers/RandomParcelWrapper.hpp",
+ source_stem: "bindings",
+ visibility: [":__subpackages__"],
+ bindgen_flags: [
+ "--size_t-is-usize",
+ "--allowlist-function",
+ "createRandomParcel",
+ "--allowlist-function",
+ "fuzzRustService",
+ ],
+ shared_libs: [
+ "libc++",
+ "libbinder_ndk",
+ ],
+ rustlibs: [
+ "libbinder_rs",
+ ],
+}
+
+rust_library {
+ name: "libbinder_random_parcel_rs",
+ crate_name: "binder_random_parcel_rs",
+ host_supported: true,
+ srcs: [
+ "src/lib.rs",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "libcutils",
+ "libc++",
+ ],
+ static_libs: [
+ "libbinder_create_parcel",
+ "libbinder_random_parcel",
+ ],
+ rustlibs: [
+ "libbinder_rs",
+ "libbinder_random_parcel_bindgen",
+ ],
+ lints: "none",
+ clippy_lints: "none",
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
new file mode 100644
index 0000000..5cb406a
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
@@ -0,0 +1,35 @@
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+aidl_interface {
+ name: "testServiceInterface",
+ srcs: ["ITestService.aidl"],
+ unstable: true,
+ backend: {
+ rust: {
+ enabled: true,
+ },
+ },
+}
+
+rust_fuzz {
+ name: "example_service_fuzzer",
+ srcs: [
+ "service_fuzzer.rs",
+ ],
+ rustlibs: [
+ "libbinder_rs",
+ "libbinder_random_parcel_rs",
+ "testServiceInterface-rust",
+ ],
+ fuzz_config: {
+ cc: [
+ "waghpawan@google.com",
+ "smoreland@google.com",
+ ],
+ // hotlist "AIDL fuzzers bugs" on buganizer
+ hotlists: ["4637097"],
+ },
+}
diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/ITestService.aidl
similarity index 89%
copy from libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
copy to libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/ITestService.aidl
index d62891b..8ce6558 100644
--- a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/ITestService.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-parcelable SingleDataParcelable{
- int data;
+interface ITestService {
+ boolean repeatData(boolean token);
}
\ No newline at end of file
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs
new file mode 100644
index 0000000..a427f28
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+#[macro_use]
+extern crate libfuzzer_sys;
+
+use binder::{self, BinderFeatures, Interface};
+use binder_random_parcel_rs::fuzz_service;
+use testServiceInterface::aidl::ITestService::{self, BnTestService};
+
+struct TestService;
+
+impl Interface for TestService {}
+
+impl ITestService::ITestService for TestService {
+ fn repeatData(&self, token: bool) -> binder::Result<bool> {
+ Ok(token)
+ }
+}
+
+fuzz_target!(|data: &[u8]| {
+ let service = BnTestService::new_binder(TestService, BinderFeatures::default());
+ fuzz_service(&mut service.as_binder(), data);
+});
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
new file mode 100644
index 0000000..1bbd674
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+use binder::binder_impl::Parcel;
+use binder::unstable_api::{AParcel, AsNative};
+use binder::SpIBinder;
+use binder_random_parcel_bindgen::{createRandomParcel, fuzzRustService};
+use std::os::raw::c_void;
+
+/// This API creates a random parcel to be used by fuzzers
+pub fn create_random_parcel(fuzzer_data: &[u8]) -> Parcel {
+ let mut parcel = Parcel::new();
+ let aparcel_ptr: *mut AParcel = parcel.as_native_mut();
+ let ptr = aparcel_ptr as *mut c_void;
+ unsafe {
+ // Safety: `Parcel::as_native_mut` and `slice::as_ptr` always
+ // return valid pointers.
+ createRandomParcel(ptr, fuzzer_data.as_ptr(), fuzzer_data.len());
+ }
+ parcel
+}
+
+/// This API automatically fuzzes provided service
+pub fn fuzz_service(binder: &mut SpIBinder, fuzzer_data: &[u8]) {
+ let ptr = binder.as_native_mut() as *mut c_void;
+ unsafe {
+ // Safety: `SpIBinder::as_native_mut` and `slice::as_ptr` always
+ // return valid pointers.
+ fuzzRustService(ptr, fuzzer_data.as_ptr(), fuzzer_data.len());
+ }
+}
diff --git a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
similarity index 64%
copy from libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
copy to libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
index fc2542b..831bd56 100644
--- a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <cstdint>
+#include <cstddef>
-parcelable GenericDataParcelable {
- int data;
- float majorVersion;
- float minorVersion;
- IBinder binder;
- ParcelFileDescriptor fileDescriptor;
- int[] array;
+extern "C" {
+ // This API is used by rust to fill random parcel.
+ void createRandomParcel(void* aParcel, const uint8_t* data, size_t len);
+
+ // This API is used by fuzzers to automatically fuzz aidl services
+ void fuzzRustService(void* binder, const uint8_t* data, size_t len);
}
\ No newline at end of file
diff --git a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
new file mode 100644
index 0000000..a2d48b6
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+use binder::binder_impl::BorrowedParcel;
+use binder::{ParcelFileDescriptor, Parcelable, SpIBinder};
+use binderReadParcelIface::aidl::parcelables::EmptyParcelable::EmptyParcelable;
+use binderReadParcelIface::aidl::parcelables::GenericDataParcelable::GenericDataParcelable;
+use binderReadParcelIface::aidl::parcelables::SingleDataParcelable::SingleDataParcelable;
+
+macro_rules! read_parcel_interface {
+ ($data_type:ty) => {
+ |parcel: &BorrowedParcel<'_>| {
+ let _res = parcel.read::<$data_type>();
+ }
+ };
+}
+
+#[derive(Debug, Default)]
+pub struct SomeParcelable {
+ pub data: i32,
+}
+
+impl binder::Parcelable for SomeParcelable {
+ fn write_to_parcel(
+ &self,
+ parcel: &mut binder::binder_impl::BorrowedParcel,
+ ) -> std::result::Result<(), binder::StatusCode> {
+ parcel.sized_write(|subparcel| subparcel.write(&self.data))
+ }
+
+ fn read_from_parcel(
+ &mut self,
+ parcel: &binder::binder_impl::BorrowedParcel,
+ ) -> std::result::Result<(), binder::StatusCode> {
+ parcel.sized_read(|subparcel| match subparcel.read() {
+ Ok(result) => {
+ self.data = result;
+ Ok(())
+ }
+ Err(e) => Err(e),
+ })
+ }
+}
+
+binder::impl_deserialize_for_parcelable!(SomeParcelable);
+
+pub const READ_FUNCS: &[fn(&BorrowedParcel<'_>)] = &[
+ //read basic types
+ read_parcel_interface!(bool),
+ read_parcel_interface!(i8),
+ read_parcel_interface!(i32),
+ read_parcel_interface!(i64),
+ read_parcel_interface!(f32),
+ read_parcel_interface!(f64),
+ read_parcel_interface!(u16),
+ read_parcel_interface!(u32),
+ read_parcel_interface!(u64),
+ read_parcel_interface!(String),
+ //read vec of basic types
+ read_parcel_interface!(Vec<i8>),
+ read_parcel_interface!(Vec<i32>),
+ read_parcel_interface!(Vec<i64>),
+ read_parcel_interface!(Vec<f32>),
+ read_parcel_interface!(Vec<f64>),
+ read_parcel_interface!(Vec<u16>),
+ read_parcel_interface!(Vec<u32>),
+ read_parcel_interface!(Vec<u64>),
+ read_parcel_interface!(Vec<String>),
+ read_parcel_interface!(Option<Vec<i8>>),
+ read_parcel_interface!(Option<Vec<i32>>),
+ read_parcel_interface!(Option<Vec<i64>>),
+ read_parcel_interface!(Option<Vec<f32>>),
+ read_parcel_interface!(Option<Vec<f64>>),
+ read_parcel_interface!(Option<Vec<u16>>),
+ read_parcel_interface!(Option<Vec<u32>>),
+ read_parcel_interface!(Option<Vec<u64>>),
+ read_parcel_interface!(Option<Vec<String>>),
+ read_parcel_interface!(ParcelFileDescriptor),
+ read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>),
+ read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>),
+ read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>),
+ read_parcel_interface!(SpIBinder),
+ read_parcel_interface!(Vec<Option<SpIBinder>>),
+ read_parcel_interface!(Option<Vec<SpIBinder>>),
+ read_parcel_interface!(Option<Vec<Option<SpIBinder>>>),
+ read_parcel_interface!(SomeParcelable),
+ read_parcel_interface!(Vec<Option<SomeParcelable>>),
+ read_parcel_interface!(Option<Vec<SomeParcelable>>),
+ read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>),
+ // Fuzz read_from_parcel for AIDL generated parcelables
+ |parcel| {
+ let mut empty_parcelable: EmptyParcelable = EmptyParcelable::default();
+ match empty_parcelable.read_from_parcel(parcel) {
+ Ok(result) => result,
+ Err(e) => {
+ println!("EmptyParcelable: error occurred while reading from a parcel: {:?}", e)
+ }
+ }
+ },
+ |parcel| {
+ let mut single_parcelable: SingleDataParcelable = SingleDataParcelable::default();
+ match single_parcelable.read_from_parcel(parcel) {
+ Ok(result) => result,
+ Err(e) => println!(
+ "SingleDataParcelable: error occurred while reading from a parcel: {:?}",
+ e
+ ),
+ }
+ },
+ |parcel| {
+ let mut generic_parcelable: GenericDataParcelable = GenericDataParcelable::default();
+ match generic_parcelable.read_from_parcel(parcel) {
+ Ok(result) => result,
+ Err(e) => println!(
+ "GenericDataParcelable: error occurred while reading from a parcel: {:?}",
+ e
+ ),
+ }
+ },
+];
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 777f3c9..692cc95 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -156,6 +156,10 @@
std::optional<std::string>* _aidl_return) override {
return mImpl->updatableViaApex(name, _aidl_return);
}
+ android::binder::Status getUpdatableNames(const std::string& apexName,
+ std::vector<std::string>* _aidl_return) override {
+ return mImpl->getUpdatableNames(apexName, _aidl_return);
+ }
android::binder::Status getConnectionInfo(
const std::string& name,
std::optional<android::os::ConnectionInfo>* _aidl_return) override {
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 92d132f..a999d59 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -232,6 +232,7 @@
srcs: [
"binderRpcTest.cpp",
"binderRpcTestCommon.cpp",
+ "binderRpcUniversalTests.cpp",
],
test_suites: ["general-tests"],
@@ -722,5 +723,7 @@
"smoreland@google.com",
"waghpawan@google.com",
],
+ // Adds bugs to hotlist "AIDL fuzzers bugs" on buganizer
+ hotlists: ["4637097"],
},
}
diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
index 4cdeac4..b2e0ef2 100644
--- a/libs/binder/tests/BinderRpcTestServerConfig.aidl
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -21,6 +21,6 @@
int rpcSecurity;
int serverVersion;
int vsockPort;
- int unixBootstrapFd; // Inherited from parent
+ int socketFd; // Inherited from the parent process.
@utf8InCpp String addr;
}
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index 55a3916..6a6e008 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -172,6 +172,24 @@
a_binder->pingBinder();
}
+TEST(BinderAllocation, InterfaceDescriptorTransaction) {
+ sp<IBinder> a_binder = GetRemoteBinder();
+
+ size_t mallocs = 0;
+ const auto on_malloc = OnMalloc([&](size_t bytes) {
+ mallocs++;
+ // Happens to be SM package length. We could switch to forking
+ // and registering our own service if it became an issue.
+ EXPECT_EQ(bytes, 78);
+ });
+
+ a_binder->getInterfaceDescriptor();
+ a_binder->getInterfaceDescriptor();
+ a_binder->getInterfaceDescriptor();
+
+ EXPECT_EQ(mallocs, 1);
+}
+
TEST(BinderAllocation, SmallTransaction) {
String16 empty_descriptor = String16("");
sp<IServiceManager> manager = defaultServiceManager();
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 25b524f..f7498c4 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -120,6 +120,7 @@
BINDER_LIB_TEST_CAN_GET_SID,
BINDER_LIB_TEST_GET_MAX_THREAD_COUNT,
BINDER_LIB_TEST_SET_MAX_THREAD_COUNT,
+ BINDER_LIB_TEST_IS_THREADPOOL_STARTED,
BINDER_LIB_TEST_LOCK_UNLOCK,
BINDER_LIB_TEST_PROCESS_LOCK,
BINDER_LIB_TEST_UNLOCK_AFTER_MS,
@@ -1383,6 +1384,14 @@
EXPECT_EQ(replyi, kKernelThreads + 1);
}
+TEST_F(BinderLibTest, ThreadPoolStarted) {
+ Parcel data, reply;
+ sp<IBinder> server = addServer();
+ ASSERT_TRUE(server != nullptr);
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_IS_THREADPOOL_STARTED, data, &reply), NO_ERROR);
+ EXPECT_TRUE(reply.readBool());
+}
+
size_t epochMillis() {
using std::chrono::duration_cast;
using std::chrono::milliseconds;
@@ -1849,6 +1858,10 @@
reply->writeInt32(ProcessState::self()->getThreadPoolMaxTotalThreadCount());
return NO_ERROR;
}
+ case BINDER_LIB_TEST_IS_THREADPOOL_STARTED: {
+ reply->writeBool(ProcessState::self()->isThreadPoolStarted());
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_PROCESS_LOCK: {
m_blockMutex.lock();
return NO_ERROR;
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 7294305..739c217 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -15,7 +15,6 @@
*/
#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
#include <chrono>
#include <cstdlib>
@@ -29,6 +28,7 @@
#include <sys/socket.h>
#include "binderRpcTestCommon.h"
+#include "binderRpcTestFixture.h"
using namespace std::chrono_literals;
using namespace std::placeholders;
@@ -44,37 +44,6 @@
constexpr bool kEnableSharedLibs = true;
#endif
-static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
- RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
-
-TEST(BinderRpcParcel, EntireParcelFormatted) {
- Parcel p;
- p.writeInt32(3);
-
- EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "format must be set before data is written");
-}
-
-TEST(BinderRpc, CannotUseNextWireVersion) {
- auto session = RpcSession::make();
- EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
- EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
- EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
- EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
-}
-
-TEST(BinderRpc, CanUseExperimentalWireVersion) {
- auto session = RpcSession::make();
- EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
-}
-
-using android::binder::Status;
-
-#define EXPECT_OK(status) \
- do { \
- Status stat = (status); \
- EXPECT_TRUE(stat.isOk()) << stat; \
- } while (false)
-
static std::string WaitStatusToString(int wstatus) {
if (WIFEXITED(wstatus)) {
return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus));
@@ -92,7 +61,15 @@
class Process {
public:
- Process(Process&&) = default;
+ Process(Process&& other)
+ : mCustomExitStatusCheck(std::move(other.mCustomExitStatusCheck)),
+ mReadEnd(std::move(other.mReadEnd)),
+ mWriteEnd(std::move(other.mWriteEnd)) {
+ // The default move constructor doesn't clear mPid after moving it,
+ // which we need to do because the destructor checks for mPid!=0
+ mPid = other.mPid;
+ other.mPid = 0;
+ }
Process(const std::function<void(android::base::borrowed_fd /* writeEnd */,
android::base::borrowed_fd /* readEnd */)>& f) {
android::base::unique_fd childWriteEnd;
@@ -152,21 +129,26 @@
return vsockPort++;
}
-struct ProcessSession {
+static base::unique_fd initUnixSocket(std::string addr) {
+ auto socket_addr = UnixSocketAddress(addr.c_str());
+ base::unique_fd fd(
+ TEMP_FAILURE_RETRY(socket(socket_addr.addr()->sa_family, SOCK_STREAM, AF_UNIX)));
+ CHECK(fd.ok());
+ CHECK_EQ(0, TEMP_FAILURE_RETRY(bind(fd.get(), socket_addr.addr(), socket_addr.addrSize())));
+ return fd;
+}
+
+// Destructors need to be defined, even if pure virtual
+ProcessSession::~ProcessSession() {}
+
+class LinuxProcessSession : public ProcessSession {
+public:
// reference to process hosting a socket server
Process host;
- struct SessionInfo {
- sp<RpcSession> session;
- sp<IBinder> root;
- };
-
- // client session objects associated with other process
- // each one represents a separate session
- std::vector<SessionInfo> sessions;
-
- ProcessSession(ProcessSession&&) = default;
- ~ProcessSession() {
+ LinuxProcessSession(LinuxProcessSession&&) = default;
+ LinuxProcessSession(Process&& host) : host(std::move(host)) {}
+ ~LinuxProcessSession() override {
for (auto& session : sessions) {
session.root = nullptr;
}
@@ -197,46 +179,12 @@
}
}
}
-};
-// Process session where the process hosts IBinderRpcTest, the server used
-// for most testing here
-struct BinderRpcTestProcessSession {
- ProcessSession proc;
-
- // pre-fetched root object (for first session)
- sp<IBinder> rootBinder;
-
- // pre-casted root object (for first session)
- sp<IBinderRpcTest> rootIface;
-
- // whether session should be invalidated by end of run
- bool expectAlreadyShutdown = false;
-
- BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
- ~BinderRpcTestProcessSession() {
- if (!expectAlreadyShutdown) {
- EXPECT_NE(nullptr, rootIface);
- if (rootIface == nullptr) return;
-
- std::vector<int32_t> remoteCounts;
- // calling over any sessions counts across all sessions
- EXPECT_OK(rootIface->countBinders(&remoteCounts));
- EXPECT_EQ(remoteCounts.size(), proc.sessions.size());
- for (auto remoteCount : remoteCounts) {
- EXPECT_EQ(remoteCount, 1);
- }
-
- // even though it is on another thread, shutdown races with
- // the transaction reply being written
- if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
- EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
- }
- }
-
- rootIface = nullptr;
- rootBinder = nullptr;
+ void setCustomExitStatusCheck(std::function<void(int wstatus)> f) override {
+ host.setCustomExitStatusCheck(std::move(f));
}
+
+ void terminate() override { host.terminate(); }
};
static base::unique_fd connectTo(const RpcSocketAddress& addr) {
@@ -273,552 +221,138 @@
return std::move(sockClient);
}
-using RunServiceFn = void (*)(android::base::borrowed_fd writeEnd,
- android::base::borrowed_fd readEnd);
-
-class BinderRpc : public ::testing::TestWithParam<
- std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
-public:
- SocketType socketType() const { return std::get<0>(GetParam()); }
- RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
- uint32_t clientVersion() const { return std::get<2>(GetParam()); }
- uint32_t serverVersion() const { return std::get<3>(GetParam()); }
- bool serverSingleThreaded() const { return std::get<4>(GetParam()); }
- bool noKernel() const { return std::get<5>(GetParam()); }
-
- bool clientOrServerSingleThreaded() const {
- return !kEnableRpcThreads || serverSingleThreaded();
+std::string BinderRpc::PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
+ auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
+ std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
+ if (singleThreaded) {
+ ret += "_single_threaded";
}
-
- // Whether the test params support sending FDs in parcels.
- bool supportsFdTransport() const {
- return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
- (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
- socketType() == SocketType::UNIX_BOOTSTRAP);
+ if (noKernel) {
+ ret += "_no_kernel";
}
+ return ret;
+}
- void SetUp() override {
- if (socketType() == SocketType::UNIX_BOOTSTRAP && rpcSecurity() == RpcSecurity::TLS) {
- GTEST_SKIP() << "Unix bootstrap not supported over a TLS transport";
- }
- }
+// This creates a new process serving an interface on a certain number of
+// threads.
+std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc(
+ const BinderRpcOptions& options) {
+ CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
- static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
- auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
- auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
- std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
- if (singleThreaded) {
- ret += "_single_threaded";
- }
- if (noKernel) {
- ret += "_no_kernel";
- }
- return ret;
- }
+ SocketType socketType = std::get<0>(GetParam());
+ RpcSecurity rpcSecurity = std::get<1>(GetParam());
+ uint32_t clientVersion = std::get<2>(GetParam());
+ uint32_t serverVersion = std::get<3>(GetParam());
+ bool singleThreaded = std::get<4>(GetParam());
+ bool noKernel = std::get<5>(GetParam());
- // This creates a new process serving an interface on a certain number of
- // threads.
- ProcessSession createRpcTestSocketServerProcessEtc(const BinderRpcOptions& options) {
- CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
+ std::string path = android::base::GetExecutableDirectory();
+ auto servicePath = android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
+ singleThreaded ? "_single_threaded" : "",
+ noKernel ? "_no_kernel" : "");
- SocketType socketType = std::get<0>(GetParam());
- RpcSecurity rpcSecurity = std::get<1>(GetParam());
- uint32_t clientVersion = std::get<2>(GetParam());
- uint32_t serverVersion = std::get<3>(GetParam());
- bool singleThreaded = std::get<4>(GetParam());
- bool noKernel = std::get<5>(GetParam());
+ base::unique_fd bootstrapClientFd, socketFd;
- std::string path = android::base::GetExecutableDirectory();
- auto servicePath =
- android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
- singleThreaded ? "_single_threaded" : "",
- noKernel ? "_no_kernel" : "");
-
- base::unique_fd bootstrapClientFd, bootstrapServerFd;
+ auto addr = allocateSocketAddress();
+ // Initializes the socket before the fork/exec.
+ if (socketType == SocketType::UNIX_RAW) {
+ socketFd = initUnixSocket(addr);
+ } else if (socketType == SocketType::UNIX_BOOTSTRAP) {
// Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec.
// This is because we cannot pass ParcelFileDescriptor over a pipe.
- if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &bootstrapServerFd)) {
+ if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &socketFd)) {
int savedErrno = errno;
LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno);
}
+ }
- auto ret = ProcessSession{
- .host = Process([=](android::base::borrowed_fd writeEnd,
- android::base::borrowed_fd readEnd) {
- auto writeFd = std::to_string(writeEnd.get());
- auto readFd = std::to_string(readEnd.get());
- execl(servicePath.c_str(), servicePath.c_str(), writeFd.c_str(), readFd.c_str(),
- NULL);
- }),
- };
+ auto ret = std::make_unique<LinuxProcessSession>(
+ Process([=](android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd) {
+ auto writeFd = std::to_string(writeEnd.get());
+ auto readFd = std::to_string(readEnd.get());
+ execl(servicePath.c_str(), servicePath.c_str(), writeFd.c_str(), readFd.c_str(),
+ NULL);
+ }));
- BinderRpcTestServerConfig serverConfig;
- serverConfig.numThreads = options.numThreads;
- serverConfig.socketType = static_cast<int32_t>(socketType);
- serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
- serverConfig.serverVersion = serverVersion;
- serverConfig.vsockPort = allocateVsockPort();
- serverConfig.addr = allocateSocketAddress();
- serverConfig.unixBootstrapFd = bootstrapServerFd.get();
- for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
- serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
- static_cast<int32_t>(mode));
- }
- writeToFd(ret.host.writeEnd(), serverConfig);
+ BinderRpcTestServerConfig serverConfig;
+ serverConfig.numThreads = options.numThreads;
+ serverConfig.socketType = static_cast<int32_t>(socketType);
+ serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
+ serverConfig.serverVersion = serverVersion;
+ serverConfig.vsockPort = allocateVsockPort();
+ serverConfig.addr = addr;
+ serverConfig.socketFd = socketFd.get();
+ for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
+ serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
+ static_cast<int32_t>(mode));
+ }
+ writeToFd(ret->host.writeEnd(), serverConfig);
- std::vector<sp<RpcSession>> sessions;
- auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
- for (size_t i = 0; i < options.numSessions; i++) {
- sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
- }
+ std::vector<sp<RpcSession>> sessions;
+ auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+ for (size_t i = 0; i < options.numSessions; i++) {
+ sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
+ }
- auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret.host.readEnd());
- BinderRpcTestClientInfo clientInfo;
- for (const auto& session : sessions) {
- auto& parcelableCert = clientInfo.certs.emplace_back();
- parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
- }
- writeToFd(ret.host.writeEnd(), clientInfo);
+ auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret->host.readEnd());
+ BinderRpcTestClientInfo clientInfo;
+ for (const auto& session : sessions) {
+ auto& parcelableCert = clientInfo.certs.emplace_back();
+ parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
+ }
+ writeToFd(ret->host.writeEnd(), clientInfo);
- CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
- if (socketType == SocketType::INET) {
- CHECK_NE(0, serverInfo.port);
- }
+ CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
+ if (socketType == SocketType::INET) {
+ CHECK_NE(0, serverInfo.port);
+ }
- if (rpcSecurity == RpcSecurity::TLS) {
- const auto& serverCert = serverInfo.cert.data;
- CHECK_EQ(OK,
- certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
- serverCert));
- }
+ if (rpcSecurity == RpcSecurity::TLS) {
+ const auto& serverCert = serverInfo.cert.data;
+ CHECK_EQ(OK,
+ certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM, serverCert));
+ }
- status_t status;
+ status_t status;
- for (const auto& session : sessions) {
- CHECK(session->setProtocolVersion(clientVersion));
- session->setMaxIncomingThreads(options.numIncomingConnections);
- session->setMaxOutgoingThreads(options.numOutgoingConnections);
- session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
+ for (const auto& session : sessions) {
+ CHECK(session->setProtocolVersion(clientVersion));
+ session->setMaxIncomingThreads(options.numIncomingConnections);
+ session->setMaxOutgoingThreads(options.numOutgoingConnections);
+ session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
- switch (socketType) {
- case SocketType::PRECONNECTED:
- status = session->setupPreconnectedClient({}, [=]() {
- return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
- });
- break;
- case SocketType::UNIX:
- status = session->setupUnixDomainClient(serverConfig.addr.c_str());
- break;
- case SocketType::UNIX_BOOTSTRAP:
- status = session->setupUnixDomainSocketBootstrapClient(
- base::unique_fd(dup(bootstrapClientFd.get())));
- break;
- case SocketType::VSOCK:
- status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
- break;
- case SocketType::INET:
- status = session->setupInetClient("127.0.0.1", serverInfo.port);
- break;
- default:
- LOG_ALWAYS_FATAL("Unknown socket type");
- }
- if (options.allowConnectFailure && status != OK) {
- ret.sessions.clear();
+ switch (socketType) {
+ case SocketType::PRECONNECTED:
+ status = session->setupPreconnectedClient({}, [=]() {
+ return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
+ });
break;
- }
- CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
- ret.sessions.push_back({session, session->getRootObject()});
+ case SocketType::UNIX_RAW:
+ case SocketType::UNIX:
+ status = session->setupUnixDomainClient(serverConfig.addr.c_str());
+ break;
+ case SocketType::UNIX_BOOTSTRAP:
+ status = session->setupUnixDomainSocketBootstrapClient(
+ base::unique_fd(dup(bootstrapClientFd.get())));
+ break;
+ case SocketType::VSOCK:
+ status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
+ break;
+ case SocketType::INET:
+ status = session->setupInetClient("127.0.0.1", serverInfo.port);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
}
- return ret;
+ if (options.allowConnectFailure && status != OK) {
+ ret->sessions.clear();
+ break;
+ }
+ CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
+ ret->sessions.push_back({session, session->getRootObject()});
}
-
- BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
- BinderRpcTestProcessSession ret{
- .proc = createRpcTestSocketServerProcessEtc(options),
- };
-
- ret.rootBinder = ret.proc.sessions.empty() ? nullptr : ret.proc.sessions.at(0).root;
- ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
-
- return ret;
- }
-
- void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
- size_t sleepMs = 500);
-};
-
-TEST_P(BinderRpc, Ping) {
- auto proc = createRpcTestSocketServerProcess({});
- ASSERT_NE(proc.rootBinder, nullptr);
- EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-}
-
-TEST_P(BinderRpc, GetInterfaceDescriptor) {
- auto proc = createRpcTestSocketServerProcess({});
- ASSERT_NE(proc.rootBinder, nullptr);
- EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
-}
-
-TEST_P(BinderRpc, MultipleSessions) {
- if (serverSingleThreaded()) {
- // Tests with multiple sessions require a multi-threaded service,
- // but work fine on a single-threaded client
- GTEST_SKIP() << "This test requires a multi-threaded service";
- }
-
- auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
- for (auto session : proc.proc.sessions) {
- ASSERT_NE(nullptr, session.root);
- EXPECT_EQ(OK, session.root->pingBinder());
- }
-}
-
-TEST_P(BinderRpc, SeparateRootObject) {
- if (serverSingleThreaded()) {
- GTEST_SKIP() << "This test requires a multi-threaded service";
- }
-
- SocketType type = std::get<0>(GetParam());
- if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
- type == SocketType::UNIX_BOOTSTRAP) {
- // we can't get port numbers for unix sockets
- return;
- }
-
- auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
-
- int port1 = 0;
- EXPECT_OK(proc.rootIface->getClientPort(&port1));
-
- sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
- int port2;
- EXPECT_OK(rootIface2->getClientPort(&port2));
-
- // we should have a different IBinderRpcTest object created for each
- // session, because we use setPerSessionRootObject
- EXPECT_NE(port1, port2);
-}
-
-TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
- auto proc = createRpcTestSocketServerProcess({});
- Parcel data;
- Parcel reply;
- EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
-}
-
-TEST_P(BinderRpc, AppendSeparateFormats) {
- auto proc1 = createRpcTestSocketServerProcess({});
- auto proc2 = createRpcTestSocketServerProcess({});
-
- Parcel pRaw;
-
- Parcel p1;
- p1.markForBinder(proc1.rootBinder);
- p1.writeInt32(3);
-
- EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
- EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
-
- Parcel p2;
- p2.markForBinder(proc2.rootBinder);
- p2.writeInt32(7);
-
- EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
- EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
-}
-
-TEST_P(BinderRpc, UnknownTransaction) {
- auto proc = createRpcTestSocketServerProcess({});
- Parcel data;
- data.markForBinder(proc.rootBinder);
- Parcel reply;
- EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
-}
-
-TEST_P(BinderRpc, SendSomethingOneway) {
- auto proc = createRpcTestSocketServerProcess({});
- EXPECT_OK(proc.rootIface->sendString("asdf"));
-}
-
-TEST_P(BinderRpc, SendAndGetResultBack) {
- auto proc = createRpcTestSocketServerProcess({});
- std::string doubled;
- EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
- EXPECT_EQ("cool cool ", doubled);
-}
-
-TEST_P(BinderRpc, SendAndGetResultBackBig) {
- auto proc = createRpcTestSocketServerProcess({});
- std::string single = std::string(1024, 'a');
- std::string doubled;
- EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
- EXPECT_EQ(single + single, doubled);
-}
-
-TEST_P(BinderRpc, InvalidNullBinderReturn) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> outBinder;
- EXPECT_EQ(proc.rootIface->getNullBinder(&outBinder).transactionError(), UNEXPECTED_NULL);
-}
-
-TEST_P(BinderRpc, CallMeBack) {
- auto proc = createRpcTestSocketServerProcess({});
-
- int32_t pingResult;
- EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
- EXPECT_EQ(OK, pingResult);
-
- EXPECT_EQ(0, MyBinderRpcSession::gNum);
-}
-
-TEST_P(BinderRpc, RepeatBinder) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> inBinder = new MyBinderRpcSession("foo");
- sp<IBinder> outBinder;
- EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
- EXPECT_EQ(inBinder, outBinder);
-
- wp<IBinder> weak = inBinder;
- inBinder = nullptr;
- outBinder = nullptr;
-
- // Force reading a reply, to process any pending dec refs from the other
- // process (the other process will process dec refs there before processing
- // the ping here).
- EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-
- EXPECT_EQ(nullptr, weak.promote());
-
- EXPECT_EQ(0, MyBinderRpcSession::gNum);
-}
-
-TEST_P(BinderRpc, RepeatTheirBinder) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinderRpcSession> session;
- EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
-
- sp<IBinder> inBinder = IInterface::asBinder(session);
- sp<IBinder> outBinder;
- EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
- EXPECT_EQ(inBinder, outBinder);
-
- wp<IBinder> weak = inBinder;
- session = nullptr;
- inBinder = nullptr;
- outBinder = nullptr;
-
- // Force reading a reply, to process any pending dec refs from the other
- // process (the other process will process dec refs there before processing
- // the ping here).
- EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-
- EXPECT_EQ(nullptr, weak.promote());
-}
-
-TEST_P(BinderRpc, RepeatBinderNull) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> outBinder;
- EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
- EXPECT_EQ(nullptr, outBinder);
-}
-
-TEST_P(BinderRpc, HoldBinder) {
- auto proc = createRpcTestSocketServerProcess({});
-
- IBinder* ptr = nullptr;
- {
- sp<IBinder> binder = new BBinder();
- ptr = binder.get();
- EXPECT_OK(proc.rootIface->holdBinder(binder));
- }
-
- sp<IBinder> held;
- EXPECT_OK(proc.rootIface->getHeldBinder(&held));
-
- EXPECT_EQ(held.get(), ptr);
-
- // stop holding binder, because we test to make sure references are cleaned
- // up
- EXPECT_OK(proc.rootIface->holdBinder(nullptr));
- // and flush ref counts
- EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-}
-
-// START TESTS FOR LIMITATIONS OF SOCKET BINDER
-// These are behavioral differences form regular binder, where certain usecases
-// aren't supported.
-
-TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
- auto proc1 = createRpcTestSocketServerProcess({});
- auto proc2 = createRpcTestSocketServerProcess({});
-
- sp<IBinder> outBinder;
- EXPECT_EQ(INVALID_OPERATION,
- proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
-}
-
-TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
- if (serverSingleThreaded()) {
- GTEST_SKIP() << "This test requires a multi-threaded service";
- }
-
- auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
-
- sp<IBinder> outBinder;
- EXPECT_EQ(INVALID_OPERATION,
- proc.rootIface->repeatBinder(proc.proc.sessions.at(1).root, &outBinder)
- .transactionError());
-}
-
-TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
- if (!kEnableKernelIpc || noKernel()) {
- GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
- "at build time.";
- }
-
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
- sp<IBinder> outBinder;
- EXPECT_EQ(INVALID_OPERATION,
- proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
-}
-
-TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
- if (!kEnableKernelIpc || noKernel()) {
- GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
- "at build time.";
- }
-
- auto proc = createRpcTestSocketServerProcess({});
-
- // for historical reasons, IServiceManager interface only returns the
- // exception code
- EXPECT_EQ(binder::Status::EX_TRANSACTION_FAILED,
- defaultServiceManager()->addService(String16("not_suspicious"), proc.rootBinder));
-}
-
-// END TESTS FOR LIMITATIONS OF SOCKET BINDER
-
-TEST_P(BinderRpc, RepeatRootObject) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> outBinder;
- EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
- EXPECT_EQ(proc.rootBinder, outBinder);
-}
-
-TEST_P(BinderRpc, NestedTransactions) {
- auto proc = createRpcTestSocketServerProcess({
- // Enable FD support because it uses more stack space and so represents
- // something closer to a worst case scenario.
- .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
- .serverSupportedFileDescriptorTransportModes =
- {RpcSession::FileDescriptorTransportMode::UNIX},
- });
-
- auto nastyNester = sp<MyBinderRpcTest>::make();
- EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
-
- wp<IBinder> weak = nastyNester;
- nastyNester = nullptr;
- EXPECT_EQ(nullptr, weak.promote());
-}
-
-TEST_P(BinderRpc, SameBinderEquality) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> a;
- EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
-
- sp<IBinder> b;
- EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
-
- EXPECT_EQ(a, b);
-}
-
-TEST_P(BinderRpc, SameBinderEqualityWeak) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinder> a;
- EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
- wp<IBinder> weak = a;
- a = nullptr;
-
- sp<IBinder> b;
- EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
-
- // this is the wrong behavior, since BpBinder
- // doesn't implement onIncStrongAttempted
- // but make sure there is no crash
- EXPECT_EQ(nullptr, weak.promote());
-
- GTEST_SKIP() << "Weak binders aren't currently re-promotable for RPC binder.";
-
- // In order to fix this:
- // - need to have incStrongAttempted reflected across IPC boundary (wait for
- // response to promote - round trip...)
- // - sendOnLastWeakRef, to delete entries out of RpcState table
- EXPECT_EQ(b, weak.promote());
-}
-
-#define expectSessions(expected, iface) \
- do { \
- int session; \
- EXPECT_OK((iface)->getNumOpenSessions(&session)); \
- EXPECT_EQ(expected, session); \
- } while (false)
-
-TEST_P(BinderRpc, SingleSession) {
- auto proc = createRpcTestSocketServerProcess({});
-
- sp<IBinderRpcSession> session;
- EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
- std::string out;
- EXPECT_OK(session->getName(&out));
- EXPECT_EQ("aoeu", out);
-
- expectSessions(1, proc.rootIface);
- session = nullptr;
- expectSessions(0, proc.rootIface);
-}
-
-TEST_P(BinderRpc, ManySessions) {
- auto proc = createRpcTestSocketServerProcess({});
-
- std::vector<sp<IBinderRpcSession>> sessions;
-
- for (size_t i = 0; i < 15; i++) {
- expectSessions(i, proc.rootIface);
- sp<IBinderRpcSession> session;
- EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session));
- sessions.push_back(session);
- }
- expectSessions(sessions.size(), proc.rootIface);
- for (size_t i = 0; i < sessions.size(); i++) {
- std::string out;
- EXPECT_OK(sessions.at(i)->getName(&out));
- EXPECT_EQ(std::to_string(i), out);
- }
- expectSessions(sessions.size(), proc.rootIface);
-
- while (!sessions.empty()) {
- sessions.pop_back();
- expectSessions(sessions.size(), proc.rootIface);
- }
- expectSessions(0, proc.rootIface);
-}
-
-size_t epochMillis() {
- using std::chrono::duration_cast;
- using std::chrono::milliseconds;
- using std::chrono::seconds;
- using std::chrono::system_clock;
- return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+ return ret;
}
TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
@@ -857,8 +391,8 @@
for (auto& t : ts) t.join();
}
-void BinderRpc::testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
- size_t sleepMs) {
+static void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+ size_t sleepMs = 500) {
size_t epochMsBefore = epochMillis();
std::vector<std::thread> ts;
@@ -958,20 +492,6 @@
saturateThreadPool(kNumServerThreads, proc.rootIface);
}
-TEST_P(BinderRpc, OnewayCallDoesNotWait) {
- constexpr size_t kReallyLongTimeMs = 100;
- constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
-
- auto proc = createRpcTestSocketServerProcess({});
-
- size_t epochMsBefore = epochMillis();
-
- EXPECT_OK(proc.rootIface->sleepMsAsync(kSleepMs));
-
- size_t epochMsAfter = epochMillis();
- EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
-}
-
TEST_P(BinderRpc, OnewayCallQueueingWithFds) {
if (!supportsFdTransport()) {
GTEST_SKIP() << "Would fail trivially (which is tested elsewhere)";
@@ -1057,7 +577,7 @@
// Build up oneway calls on the second session to make sure it terminates
// and shuts down. The first session should be unaffected (proc destructor
// checks the first session).
- auto iface = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
+ auto iface = interface_cast<IBinderRpcTest>(proc.proc->sessions.at(1).root);
std::vector<std::thread> threads;
for (size_t i = 0; i < kNumClients; i++) {
@@ -1085,66 +605,7 @@
// any pending commands). We need to erase this session from the record
// here, so that the destructor for our session won't check that this
// session is valid, but we still want it to test the other session.
- proc.proc.sessions.erase(proc.proc.sessions.begin() + 1);
-}
-
-TEST_P(BinderRpc, Callbacks) {
- const static std::string kTestString = "good afternoon!";
-
- for (bool callIsOneway : {true, false}) {
- for (bool callbackIsOneway : {true, false}) {
- for (bool delayed : {true, false}) {
- if (clientOrServerSingleThreaded() &&
- (callIsOneway || callbackIsOneway || delayed)) {
- // we have no incoming connections to receive the callback
- continue;
- }
-
- size_t numIncomingConnections = clientOrServerSingleThreaded() ? 0 : 1;
- auto proc = createRpcTestSocketServerProcess(
- {.numThreads = 1,
- .numSessions = 1,
- .numIncomingConnections = numIncomingConnections});
- auto cb = sp<MyBinderRpcCallback>::make();
-
- if (callIsOneway) {
- EXPECT_OK(proc.rootIface->doCallbackAsync(cb, callbackIsOneway, delayed,
- kTestString));
- } else {
- EXPECT_OK(
- proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
- }
-
- // if both transactions are synchronous and the response is sent back on the
- // same thread, everything should have happened in a nested call. Otherwise,
- // the callback will be processed on another thread.
- if (callIsOneway || callbackIsOneway || delayed) {
- using std::literals::chrono_literals::operator""s;
- RpcMutexUniqueLock _l(cb->mMutex);
- cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
- }
-
- EXPECT_EQ(cb->mValues.size(), 1)
- << "callIsOneway: " << callIsOneway
- << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
- if (cb->mValues.empty()) continue;
- EXPECT_EQ(cb->mValues.at(0), kTestString)
- << "callIsOneway: " << callIsOneway
- << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
-
- // since we are severing the connection, we need to go ahead and
- // tell the server to shutdown and exit so that waitpid won't hang
- if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
- EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
- }
-
- // since this session has an incoming connection w/ a threadpool, we
- // need to manually shut it down
- EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
- proc.expectAlreadyShutdown = true;
- }
- }
- }
+ proc.proc->sessions.erase(proc.proc->sessions.begin() + 1);
}
TEST_P(BinderRpc, SingleDeathRecipient) {
@@ -1177,7 +638,7 @@
ASSERT_TRUE(dr->mCv.wait_for(lock, 100ms, [&]() { return dr->dead; }));
// need to wait for the session to shutdown so we don't "Leak session"
- EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+ EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
proc.expectAlreadyShutdown = true;
}
@@ -1205,7 +666,7 @@
// Explicitly calling shutDownAndWait will cause the death recipients
// to be called.
- EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+ EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
std::unique_lock<std::mutex> lock(dr->mMtx);
if (!dr->dead) {
@@ -1213,8 +674,8 @@
}
EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
- proc.proc.host.terminate();
- proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ proc.proc->terminate();
+ proc.proc->setCustomExitStatusCheck([](int wstatus) {
EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
<< "server process failed incorrectly: " << WaitStatusToString(wstatus);
});
@@ -1259,18 +720,10 @@
}
// need to wait for the session to shutdown so we don't "Leak session"
- EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+ EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
proc.expectAlreadyShutdown = true;
}
-TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
- auto proc = createRpcTestSocketServerProcess({});
- auto cb = sp<MyBinderRpcCallback>::make();
-
- Status status = proc.rootIface->doCallback(cb, true /*oneway*/, false /*delayed*/, "anything");
- EXPECT_EQ(WOULD_BLOCK, status.transactionError());
-}
-
TEST_P(BinderRpc, Die) {
for (bool doDeathCleanup : {true, false}) {
auto proc = createRpcTestSocketServerProcess({});
@@ -1286,7 +739,7 @@
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
<< "Do death cleanup: " << doDeathCleanup;
- proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ proc.proc->setCustomExitStatusCheck([](int wstatus) {
EXPECT_TRUE(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 1)
<< "server process failed incorrectly: " << WaitStatusToString(wstatus);
});
@@ -1316,7 +769,7 @@
// second time! we catch the error :)
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
- proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ proc.proc->setCustomExitStatusCheck([](int wstatus) {
EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)
<< "server process failed incorrectly: " << WaitStatusToString(wstatus);
});
@@ -1330,9 +783,9 @@
{RpcSession::FileDescriptorTransportMode::UNIX},
.allowConnectFailure = true,
});
- EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
- proc.proc.host.terminate();
- proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ EXPECT_TRUE(proc.proc->sessions.empty()) << "session connections should have failed";
+ proc.proc->terminate();
+ proc.proc->setCustomExitStatusCheck([](int wstatus) {
EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
<< "server process failed incorrectly: " << WaitStatusToString(wstatus);
});
@@ -1346,9 +799,9 @@
{RpcSession::FileDescriptorTransportMode::NONE},
.allowConnectFailure = true,
});
- EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
- proc.proc.host.terminate();
- proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ EXPECT_TRUE(proc.proc->sessions.empty()) << "session connections should have failed";
+ proc.proc->terminate();
+ proc.proc->setCustomExitStatusCheck([](int wstatus) {
EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
<< "server process failed incorrectly: " << WaitStatusToString(wstatus);
});
@@ -1460,6 +913,33 @@
EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
}
+TEST_P(BinderRpc, AppendInvalidFd) {
+ auto proc = createRpcTestSocketServerProcess({
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ int badFd = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 0);
+ ASSERT_NE(badFd, -1);
+
+ // Close the file descriptor so it becomes invalid for dup
+ close(badFd);
+
+ Parcel p1;
+ p1.markForBinder(proc.rootBinder);
+ p1.writeInt32(3);
+ EXPECT_EQ(OK, p1.writeFileDescriptor(badFd, false));
+
+ Parcel pRaw;
+ pRaw.markForBinder(proc.rootBinder);
+ EXPECT_EQ(OK, pRaw.appendFrom(&p1, 0, p1.dataSize()));
+
+ pRaw.setDataPosition(0);
+ EXPECT_EQ(3, pRaw.readInt32());
+ ASSERT_EQ(-1, pRaw.readFileDescriptor());
+}
+
TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
if constexpr (!kEnableSharedLibs) {
GTEST_SKIP() << "Test disabled because Binder was built as a static library";
@@ -1516,16 +996,6 @@
ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
}
-TEST_P(BinderRpc, AidlDelegatorTest) {
- auto proc = createRpcTestSocketServerProcess({});
- auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
- ASSERT_NE(nullptr, myDelegator);
-
- std::string doubled;
- EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
- EXPECT_EQ("cool cool ", doubled);
-}
-
static bool testSupportVsockLoopback() {
// We don't need to enable TLS to know if vsock is supported.
unsigned int vsockPort = allocateVsockPort();
@@ -1616,7 +1086,8 @@
}
static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
- std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET};
+ std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET,
+ SocketType::UNIX_RAW};
if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
@@ -1858,9 +1329,20 @@
mAcceptConnection = &Server::recvmsgServerConnection;
mConnectToServer = [this] { return connectToUnixBootstrap(mBootstrapSocket); };
} break;
+ case SocketType::UNIX_RAW: {
+ auto addr = allocateSocketAddress();
+ auto status = rpcServer->setupRawSocketServer(initUnixSocket(addr));
+ if (status != OK) {
+ return AssertionFailure()
+ << "setupRawSocketServer: " << statusToString(status);
+ }
+ mConnectToServer = [addr] {
+ return connectTo(UnixSocketAddress(addr.c_str()));
+ };
+ } break;
case SocketType::VSOCK: {
auto port = allocateVsockPort();
- auto status = rpcServer->setupVsockServer(port);
+ auto status = rpcServer->setupVsockServer(VMADDR_CID_LOCAL, port);
if (status != OK) {
return AssertionFailure() << "setupVsockServer: " << statusToString(status);
}
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index 823bbf6..654e16c 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -69,6 +69,7 @@
PRECONNECTED,
UNIX,
UNIX_BOOTSTRAP,
+ UNIX_RAW,
VSOCK,
INET,
};
@@ -81,6 +82,8 @@
return "unix_domain_socket";
case SocketType::UNIX_BOOTSTRAP:
return "unix_domain_socket_bootstrap";
+ case SocketType::UNIX_RAW:
+ return "raw_uds";
case SocketType::VSOCK:
return "vm_socket";
case SocketType::INET:
@@ -91,6 +94,14 @@
}
}
+static inline size_t epochMillis() {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ using std::chrono::seconds;
+ using std::chrono::system_clock;
+ return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+}
+
struct BinderRpcOptions {
size_t numThreads = 1;
size_t numSessions = 1;
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
new file mode 100644
index 0000000..5a78782
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2022 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 <gtest/gtest.h>
+
+#include "binderRpcTestCommon.h"
+
+#define EXPECT_OK(status) \
+ do { \
+ android::binder::Status stat = (status); \
+ EXPECT_TRUE(stat.isOk()) << stat; \
+ } while (false)
+
+namespace android {
+
+// Abstract base class with a virtual destructor that handles the
+// ownership of a process session for BinderRpcTestSession below
+class ProcessSession {
+public:
+ struct SessionInfo {
+ sp<RpcSession> session;
+ sp<IBinder> root;
+ };
+
+ // client session objects associated with other process
+ // each one represents a separate session
+ std::vector<SessionInfo> sessions;
+
+ virtual ~ProcessSession() = 0;
+
+ // If the process exits with a status, run the given callback on that value.
+ virtual void setCustomExitStatusCheck(std::function<void(int wstatus)> f) = 0;
+
+ // Kill the process. Avoid if possible. Shutdown gracefully via an RPC instead.
+ virtual void terminate() = 0;
+};
+
+// Process session where the process hosts IBinderRpcTest, the server used
+// for most testing here
+struct BinderRpcTestProcessSession {
+ std::unique_ptr<ProcessSession> proc;
+
+ // pre-fetched root object (for first session)
+ sp<IBinder> rootBinder;
+
+ // pre-casted root object (for first session)
+ sp<IBinderRpcTest> rootIface;
+
+ // whether session should be invalidated by end of run
+ bool expectAlreadyShutdown = false;
+
+ BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
+ ~BinderRpcTestProcessSession() {
+ if (!expectAlreadyShutdown) {
+ EXPECT_NE(nullptr, rootIface);
+ if (rootIface == nullptr) return;
+
+ std::vector<int32_t> remoteCounts;
+ // calling over any sessions counts across all sessions
+ EXPECT_OK(rootIface->countBinders(&remoteCounts));
+ EXPECT_EQ(remoteCounts.size(), proc->sessions.size());
+ for (auto remoteCount : remoteCounts) {
+ EXPECT_EQ(remoteCount, 1);
+ }
+
+ // even though it is on another thread, shutdown races with
+ // the transaction reply being written
+ if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
+ EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+ }
+ }
+
+ rootIface = nullptr;
+ rootBinder = nullptr;
+ }
+};
+
+class BinderRpc : public ::testing::TestWithParam<
+ std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
+public:
+ SocketType socketType() const { return std::get<0>(GetParam()); }
+ RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
+ uint32_t clientVersion() const { return std::get<2>(GetParam()); }
+ uint32_t serverVersion() const { return std::get<3>(GetParam()); }
+ bool serverSingleThreaded() const { return std::get<4>(GetParam()); }
+ bool noKernel() const { return std::get<5>(GetParam()); }
+
+ bool clientOrServerSingleThreaded() const {
+ return !kEnableRpcThreads || serverSingleThreaded();
+ }
+
+ // Whether the test params support sending FDs in parcels.
+ bool supportsFdTransport() const {
+ return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
+ (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
+ socketType() == SocketType::UNIX_BOOTSTRAP ||
+ socketType() == SocketType::UNIX_RAW);
+ }
+
+ void SetUp() override {
+ if (socketType() == SocketType::UNIX_BOOTSTRAP && rpcSecurity() == RpcSecurity::TLS) {
+ GTEST_SKIP() << "Unix bootstrap not supported over a TLS transport";
+ }
+ }
+
+ BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
+ BinderRpcTestProcessSession ret{
+ .proc = createRpcTestSocketServerProcessEtc(options),
+ };
+
+ ret.rootBinder = ret.proc->sessions.empty() ? nullptr : ret.proc->sessions.at(0).root;
+ ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
+
+ return ret;
+ }
+
+ static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info);
+
+protected:
+ std::unique_ptr<ProcessSession> createRpcTestSocketServerProcessEtc(
+ const BinderRpcOptions& options);
+};
+
+} // namespace android
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
index a922b21..cc9726b 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -42,7 +42,7 @@
server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes);
unsigned int outPort = 0;
- base::unique_fd unixBootstrapFd(serverConfig.unixBootstrapFd);
+ base::unique_fd socketFd(serverConfig.socketFd);
switch (socketType) {
case SocketType::PRECONNECTED:
@@ -52,10 +52,13 @@
<< serverConfig.addr;
break;
case SocketType::UNIX_BOOTSTRAP:
- CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(unixBootstrapFd)));
+ CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(socketFd)));
+ break;
+ case SocketType::UNIX_RAW:
+ CHECK_EQ(OK, server->setupRawSocketServer(std::move(socketFd)));
break;
case SocketType::VSOCK:
- CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort));
+ CHECK_EQ(OK, server->setupVsockServer(VMADDR_CID_LOCAL, serverConfig.vsockPort));
break;
case SocketType::INET: {
CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
new file mode 100644
index 0000000..f960442
--- /dev/null
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chrono>
+#include <cstdlib>
+#include <type_traits>
+
+#include "binderRpcTestCommon.h"
+#include "binderRpcTestFixture.h"
+
+using namespace std::chrono_literals;
+using namespace std::placeholders;
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
+
+namespace android {
+
+static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
+ RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+
+TEST(BinderRpcParcel, EntireParcelFormatted) {
+ Parcel p;
+ p.writeInt32(3);
+
+ EXPECT_DEATH_IF_SUPPORTED(p.markForBinder(sp<BBinder>::make()),
+ "format must be set before data is written");
+}
+
+TEST(BinderRpc, CannotUseNextWireVersion) {
+ auto session = RpcSession::make();
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
+}
+
+TEST(BinderRpc, CanUseExperimentalWireVersion) {
+ auto session = RpcSession::make();
+ EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
+}
+
+TEST_P(BinderRpc, Ping) {
+ auto proc = createRpcTestSocketServerProcess({});
+ ASSERT_NE(proc.rootBinder, nullptr);
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+TEST_P(BinderRpc, GetInterfaceDescriptor) {
+ auto proc = createRpcTestSocketServerProcess({});
+ ASSERT_NE(proc.rootBinder, nullptr);
+ EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
+}
+
+TEST_P(BinderRpc, MultipleSessions) {
+ if (serverSingleThreaded()) {
+ // Tests with multiple sessions require a multi-threaded service,
+ // but work fine on a single-threaded client
+ GTEST_SKIP() << "This test requires a multi-threaded service";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
+ for (auto session : proc.proc->sessions) {
+ ASSERT_NE(nullptr, session.root);
+ EXPECT_EQ(OK, session.root->pingBinder());
+ }
+}
+
+TEST_P(BinderRpc, SeparateRootObject) {
+ if (serverSingleThreaded()) {
+ GTEST_SKIP() << "This test requires a multi-threaded service";
+ }
+
+ SocketType type = std::get<0>(GetParam());
+ if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
+ type == SocketType::UNIX_BOOTSTRAP || type == SocketType::UNIX_RAW) {
+ // we can't get port numbers for unix sockets
+ return;
+ }
+
+ auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
+
+ int port1 = 0;
+ EXPECT_OK(proc.rootIface->getClientPort(&port1));
+
+ sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc->sessions.at(1).root);
+ int port2;
+ EXPECT_OK(rootIface2->getClientPort(&port2));
+
+ // we should have a different IBinderRpcTest object created for each
+ // session, because we use setPerSessionRootObject
+ EXPECT_NE(port1, port2);
+}
+
+TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
+ auto proc = createRpcTestSocketServerProcess({});
+ Parcel data;
+ Parcel reply;
+ EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
+}
+
+TEST_P(BinderRpc, AppendSeparateFormats) {
+ auto proc1 = createRpcTestSocketServerProcess({});
+ auto proc2 = createRpcTestSocketServerProcess({});
+
+ Parcel pRaw;
+
+ Parcel p1;
+ p1.markForBinder(proc1.rootBinder);
+ p1.writeInt32(3);
+
+ EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
+ EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
+
+ Parcel p2;
+ p2.markForBinder(proc2.rootBinder);
+ p2.writeInt32(7);
+
+ EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
+ EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
+}
+
+TEST_P(BinderRpc, UnknownTransaction) {
+ auto proc = createRpcTestSocketServerProcess({});
+ Parcel data;
+ data.markForBinder(proc.rootBinder);
+ Parcel reply;
+ EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
+}
+
+TEST_P(BinderRpc, SendSomethingOneway) {
+ auto proc = createRpcTestSocketServerProcess({});
+ EXPECT_OK(proc.rootIface->sendString("asdf"));
+}
+
+TEST_P(BinderRpc, SendAndGetResultBack) {
+ auto proc = createRpcTestSocketServerProcess({});
+ std::string doubled;
+ EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
+ EXPECT_EQ("cool cool ", doubled);
+}
+
+TEST_P(BinderRpc, SendAndGetResultBackBig) {
+ auto proc = createRpcTestSocketServerProcess({});
+ std::string single = std::string(1024, 'a');
+ std::string doubled;
+ EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
+ EXPECT_EQ(single + single, doubled);
+}
+
+TEST_P(BinderRpc, InvalidNullBinderReturn) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> outBinder;
+ EXPECT_EQ(proc.rootIface->getNullBinder(&outBinder).transactionError(), UNEXPECTED_NULL);
+}
+
+TEST_P(BinderRpc, CallMeBack) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ int32_t pingResult;
+ EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
+ EXPECT_EQ(OK, pingResult);
+
+ EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST_P(BinderRpc, RepeatBinder) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> inBinder = new MyBinderRpcSession("foo");
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+ EXPECT_EQ(inBinder, outBinder);
+
+ wp<IBinder> weak = inBinder;
+ inBinder = nullptr;
+ outBinder = nullptr;
+
+ // Force reading a reply, to process any pending dec refs from the other
+ // process (the other process will process dec refs there before processing
+ // the ping here).
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ EXPECT_EQ(nullptr, weak.promote());
+
+ EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST_P(BinderRpc, RepeatTheirBinder) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+
+ sp<IBinder> inBinder = IInterface::asBinder(session);
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+ EXPECT_EQ(inBinder, outBinder);
+
+ wp<IBinder> weak = inBinder;
+ session = nullptr;
+ inBinder = nullptr;
+ outBinder = nullptr;
+
+ // Force reading a reply, to process any pending dec refs from the other
+ // process (the other process will process dec refs there before processing
+ // the ping here).
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST_P(BinderRpc, RepeatBinderNull) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
+ EXPECT_EQ(nullptr, outBinder);
+}
+
+TEST_P(BinderRpc, HoldBinder) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ IBinder* ptr = nullptr;
+ {
+ sp<IBinder> binder = new BBinder();
+ ptr = binder.get();
+ EXPECT_OK(proc.rootIface->holdBinder(binder));
+ }
+
+ sp<IBinder> held;
+ EXPECT_OK(proc.rootIface->getHeldBinder(&held));
+
+ EXPECT_EQ(held.get(), ptr);
+
+ // stop holding binder, because we test to make sure references are cleaned
+ // up
+ EXPECT_OK(proc.rootIface->holdBinder(nullptr));
+ // and flush ref counts
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+// START TESTS FOR LIMITATIONS OF SOCKET BINDER
+// These are behavioral differences form regular binder, where certain usecases
+// aren't supported.
+
+TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
+ auto proc1 = createRpcTestSocketServerProcess({});
+ auto proc2 = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> outBinder;
+ EXPECT_EQ(INVALID_OPERATION,
+ proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
+}
+
+TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
+ if (serverSingleThreaded()) {
+ GTEST_SKIP() << "This test requires a multi-threaded service";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
+
+ sp<IBinder> outBinder;
+ EXPECT_EQ(INVALID_OPERATION,
+ proc.rootIface->repeatBinder(proc.proc->sessions.at(1).root, &outBinder)
+ .transactionError());
+}
+
+TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
+ if (!kEnableKernelIpc || noKernel()) {
+ GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+ "at build time.";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
+ sp<IBinder> outBinder;
+ EXPECT_EQ(INVALID_OPERATION,
+ proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
+}
+
+TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
+ if (!kEnableKernelIpc || noKernel()) {
+ GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+ "at build time.";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({});
+
+ // for historical reasons, IServiceManager interface only returns the
+ // exception code
+ EXPECT_EQ(binder::Status::EX_TRANSACTION_FAILED,
+ defaultServiceManager()->addService(String16("not_suspicious"), proc.rootBinder));
+}
+
+// END TESTS FOR LIMITATIONS OF SOCKET BINDER
+
+TEST_P(BinderRpc, RepeatRootObject) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
+ EXPECT_EQ(proc.rootBinder, outBinder);
+}
+
+TEST_P(BinderRpc, NestedTransactions) {
+ auto proc = createRpcTestSocketServerProcess({
+ // Enable FD support because it uses more stack space and so represents
+ // something closer to a worst case scenario.
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ auto nastyNester = sp<MyBinderRpcTest>::make();
+ EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
+
+ wp<IBinder> weak = nastyNester;
+ nastyNester = nullptr;
+ EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST_P(BinderRpc, SameBinderEquality) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> a;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+
+ sp<IBinder> b;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+ EXPECT_EQ(a, b);
+}
+
+TEST_P(BinderRpc, SameBinderEqualityWeak) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> a;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+ wp<IBinder> weak = a;
+ a = nullptr;
+
+ sp<IBinder> b;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+ // this is the wrong behavior, since BpBinder
+ // doesn't implement onIncStrongAttempted
+ // but make sure there is no crash
+ EXPECT_EQ(nullptr, weak.promote());
+
+ GTEST_SKIP() << "Weak binders aren't currently re-promotable for RPC binder.";
+
+ // In order to fix this:
+ // - need to have incStrongAttempted reflected across IPC boundary (wait for
+ // response to promote - round trip...)
+ // - sendOnLastWeakRef, to delete entries out of RpcState table
+ EXPECT_EQ(b, weak.promote());
+}
+
+#define expectSessions(expected, iface) \
+ do { \
+ int session; \
+ EXPECT_OK((iface)->getNumOpenSessions(&session)); \
+ EXPECT_EQ(expected, session); \
+ } while (false)
+
+TEST_P(BinderRpc, SingleSession) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+ std::string out;
+ EXPECT_OK(session->getName(&out));
+ EXPECT_EQ("aoeu", out);
+
+ expectSessions(1, proc.rootIface);
+ session = nullptr;
+ expectSessions(0, proc.rootIface);
+}
+
+TEST_P(BinderRpc, ManySessions) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ std::vector<sp<IBinderRpcSession>> sessions;
+
+ for (size_t i = 0; i < 15; i++) {
+ expectSessions(i, proc.rootIface);
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session));
+ sessions.push_back(session);
+ }
+ expectSessions(sessions.size(), proc.rootIface);
+ for (size_t i = 0; i < sessions.size(); i++) {
+ std::string out;
+ EXPECT_OK(sessions.at(i)->getName(&out));
+ EXPECT_EQ(std::to_string(i), out);
+ }
+ expectSessions(sessions.size(), proc.rootIface);
+
+ while (!sessions.empty()) {
+ sessions.pop_back();
+ expectSessions(sessions.size(), proc.rootIface);
+ }
+ expectSessions(0, proc.rootIface);
+}
+
+TEST_P(BinderRpc, OnewayCallDoesNotWait) {
+ constexpr size_t kReallyLongTimeMs = 100;
+ constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
+
+ auto proc = createRpcTestSocketServerProcess({});
+
+ size_t epochMsBefore = epochMillis();
+
+ EXPECT_OK(proc.rootIface->sleepMsAsync(kSleepMs));
+
+ size_t epochMsAfter = epochMillis();
+ EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
+}
+
+TEST_P(BinderRpc, Callbacks) {
+ const static std::string kTestString = "good afternoon!";
+
+ for (bool callIsOneway : {true, false}) {
+ for (bool callbackIsOneway : {true, false}) {
+ for (bool delayed : {true, false}) {
+ if (clientOrServerSingleThreaded() &&
+ (callIsOneway || callbackIsOneway || delayed)) {
+ // we have no incoming connections to receive the callback
+ continue;
+ }
+
+ size_t numIncomingConnections = clientOrServerSingleThreaded() ? 0 : 1;
+ auto proc = createRpcTestSocketServerProcess(
+ {.numThreads = 1,
+ .numSessions = 1,
+ .numIncomingConnections = numIncomingConnections});
+ auto cb = sp<MyBinderRpcCallback>::make();
+
+ if (callIsOneway) {
+ EXPECT_OK(proc.rootIface->doCallbackAsync(cb, callbackIsOneway, delayed,
+ kTestString));
+ } else {
+ EXPECT_OK(
+ proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
+ }
+
+ // if both transactions are synchronous and the response is sent back on the
+ // same thread, everything should have happened in a nested call. Otherwise,
+ // the callback will be processed on another thread.
+ if (callIsOneway || callbackIsOneway || delayed) {
+ using std::literals::chrono_literals::operator""s;
+ RpcMutexUniqueLock _l(cb->mMutex);
+ cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
+ }
+
+ EXPECT_EQ(cb->mValues.size(), 1)
+ << "callIsOneway: " << callIsOneway
+ << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
+ if (cb->mValues.empty()) continue;
+ EXPECT_EQ(cb->mValues.at(0), kTestString)
+ << "callIsOneway: " << callIsOneway
+ << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
+
+ // since we are severing the connection, we need to go ahead and
+ // tell the server to shutdown and exit so that waitpid won't hang
+ if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
+ EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+ }
+
+ // since this session has an incoming connection w/ a threadpool, we
+ // need to manually shut it down
+ EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
+ proc.expectAlreadyShutdown = true;
+ }
+ }
+ }
+}
+
+TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
+ auto proc = createRpcTestSocketServerProcess({});
+ auto cb = sp<MyBinderRpcCallback>::make();
+
+ Status status = proc.rootIface->doCallback(cb, true /*oneway*/, false /*delayed*/, "anything");
+ EXPECT_EQ(WOULD_BLOCK, status.transactionError());
+}
+
+TEST_P(BinderRpc, AidlDelegatorTest) {
+ auto proc = createRpcTestSocketServerProcess({});
+ auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
+ ASSERT_NE(nullptr, myDelegator);
+
+ std::string doubled;
+ EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
+ EXPECT_EQ("cool cool ", doubled);
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 3904e1d..35866ad 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -12,13 +12,17 @@
host_supported: true,
unstable: true,
srcs: [
- "EmptyParcelable.aidl",
- "SingleDataParcelable.aidl",
- "GenericDataParcelable.aidl",
+ "parcelables/EmptyParcelable.aidl",
+ "parcelables/SingleDataParcelable.aidl",
+ "parcelables/GenericDataParcelable.aidl",
],
backend: {
java: {
- enabled: false,
+ enabled: true,
+ platform_apis: true,
+ },
+ rust: {
+ enabled: true,
},
},
}
diff --git a/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
deleted file mode 100644
index 96d6223..0000000
--- a/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-parcelable EmptyParcelable{
-}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 9dac2c9..768fbe1 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -16,9 +16,9 @@
#define FUZZ_LOG_TAG "binder"
#include "binder.h"
-#include "EmptyParcelable.h"
-#include "GenericDataParcelable.h"
-#include "SingleDataParcelable.h"
+#include "parcelables/EmptyParcelable.h"
+#include "parcelables/GenericDataParcelable.h"
+#include "parcelables/SingleDataParcelable.h"
#include "util.h"
#include <android-base/hex.h>
@@ -359,19 +359,19 @@
},
[] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
FUZZ_LOG() << "about to call readFromParcel() with status for EmptyParcelable";
- EmptyParcelable emptyParcelable{};
+ parcelables::EmptyParcelable emptyParcelable{};
status_t status = emptyParcelable.readFromParcel(&p);
FUZZ_LOG() << " status: " << status;
},
[] (const ::android::Parcel& p , FuzzedDataProvider& /*provider*/) {
FUZZ_LOG() << "about to call readFromParcel() with status for SingleDataParcelable";
- SingleDataParcelable singleDataParcelable;
+ parcelables::SingleDataParcelable singleDataParcelable;
status_t status = singleDataParcelable.readFromParcel(&p);
FUZZ_LOG() <<" status: " << status;
},
[] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
FUZZ_LOG() << "about to call readFromParcel() with status for GenericDataParcelable";
- GenericDataParcelable genericDataParcelable;
+ parcelables::GenericDataParcelable genericDataParcelable;
status_t status = genericDataParcelable.readFromParcel(&p);
FUZZ_LOG() <<" status: " << status;
},
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index af773a0..53e7de4 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -16,9 +16,9 @@
#define FUZZ_LOG_TAG "binder_ndk"
#include "binder_ndk.h"
-#include "aidl/EmptyParcelable.h"
-#include "aidl/GenericDataParcelable.h"
-#include "aidl/SingleDataParcelable.h"
+#include "aidl/parcelables/EmptyParcelable.h"
+#include "aidl/parcelables/GenericDataParcelable.h"
+#include "aidl/parcelables/SingleDataParcelable.h"
#include <android/binder_parcel_utils.h>
#include <android/binder_parcelable_utils.h>
@@ -183,19 +183,19 @@
[](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
FUZZ_LOG() << "about to read parcel using readFromParcel for EmptyParcelable";
- aidl::EmptyParcelable emptyParcelable;
+ aidl::parcelables::EmptyParcelable emptyParcelable;
binder_status_t status = emptyParcelable.readFromParcel(p.aParcel());
FUZZ_LOG() << "status: " << status;
},
[](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
FUZZ_LOG() << "about to read parcel using readFromParcel for SingleDataParcelable";
- aidl::SingleDataParcelable singleDataParcelable;
+ aidl::parcelables::SingleDataParcelable singleDataParcelable;
binder_status_t status = singleDataParcelable.readFromParcel(p.aParcel());
FUZZ_LOG() << "status: " << status;
},
[](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
FUZZ_LOG() << "about to read parcel using readFromParcel for GenericDataParcelable";
- aidl::GenericDataParcelable genericDataParcelable;
+ aidl::parcelables::GenericDataParcelable genericDataParcelable;
binder_status_t status = genericDataParcelable.readFromParcel(p.aParcel());
FUZZ_LOG() << "status: " << status;
},
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index 25f6096..8bef33f 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -18,6 +18,7 @@
#include <fuzzbinder/random_parcel.h>
#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
namespace android {
@@ -30,10 +31,19 @@
.extraFds = {},
};
+ if (provider.ConsumeBool()) {
+ // set calling uid
+ IPCThreadState::self()->restoreCallingIdentity(provider.ConsumeIntegral<int64_t>());
+ }
+
while (provider.remaining_bytes() > 0) {
- uint32_t code = provider.ConsumeIntegral<uint32_t>();
+ // Most of the AIDL services will have small set of transaction codes.
+ uint32_t code = provider.ConsumeBool() ? provider.ConsumeIntegral<uint32_t>()
+ : provider.ConsumeIntegralInRange<uint32_t>(0, 100);
uint32_t flags = provider.ConsumeIntegral<uint32_t>();
Parcel data;
+ // for increased fuzz coverage
+ data.setEnforceNoDataAvail(provider.ConsumeBool());
sp<IBinder> target = options.extraBinders.at(
provider.ConsumeIntegralInRange<size_t>(0, options.extraBinders.size() - 1));
@@ -50,6 +60,8 @@
fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), &options);
Parcel reply;
+ // for increased fuzz coverage
+ reply.setEnforceNoDataAvail(provider.ConsumeBool());
(void)target->transact(code, data, &reply, flags);
// feed back in binders and fds that are returned from the service, so that
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
index 462ef9a..a1fb701 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -29,3 +29,12 @@
}
} // namespace android
+
+extern "C" {
+// This API is used by fuzzers to automatically fuzz aidl services
+void fuzzRustService(void* binder, const uint8_t* data, size_t len) {
+ AIBinder* aiBinder = static_cast<AIBinder*>(binder);
+ FuzzedDataProvider provider(data, len);
+ android::fuzzService(aiBinder, std::move(provider));
+}
+} // extern "C"
diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/parcelables/EmptyParcelable.aidl
similarity index 92%
copy from libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
copy to libs/binder/tests/parcel_fuzzer/parcelables/EmptyParcelable.aidl
index d62891b..1216250 100644
--- a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
+++ b/libs/binder/tests/parcel_fuzzer/parcelables/EmptyParcelable.aidl
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-parcelable SingleDataParcelable{
- int data;
+package parcelables;
+parcelable EmptyParcelable {
}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
similarity index 97%
rename from libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
rename to libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
index fc2542b..f1079e9 100644
--- a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
+++ b/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package parcelables;
parcelable GenericDataParcelable {
int data;
diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/parcelables/SingleDataParcelable.aidl
similarity index 96%
rename from libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
rename to libs/binder/tests/parcel_fuzzer/parcelables/SingleDataParcelable.aidl
index d62891b..0187168 100644
--- a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
+++ b/libs/binder/tests/parcel_fuzzer/parcelables/SingleDataParcelable.aidl
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package parcelables;
parcelable SingleDataParcelable{
int data;
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index edc695f..f0beed2 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -73,6 +73,11 @@
1));
CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
} else {
+ // b/260119717 - Adding more FDs can eventually lead to FD limit exhaustion
+ if (options->extraFds.size() > 1000) {
+ return;
+ }
+
std::vector<base::unique_fd> fds = getRandomFds(&provider);
CHECK(OK ==
p->writeFileDescriptor(fds.begin()->release(),
diff --git a/libs/binder/tests/parcel_fuzzer/rust_interface/Android.bp b/libs/binder/tests/parcel_fuzzer/rust_interface/Android.bp
new file mode 100644
index 0000000..b48dc27
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/rust_interface/Android.bp
@@ -0,0 +1,24 @@
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_static {
+ name: "libbinder_create_parcel",
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ srcs: [
+ "RandomParcelWrapper.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "libbinder_random_parcel",
+ ],
+}
diff --git a/libs/binder/tests/parcel_fuzzer/rust_interface/RandomParcelWrapper.cpp b/libs/binder/tests/parcel_fuzzer/rust_interface/RandomParcelWrapper.cpp
new file mode 100644
index 0000000..2fb7820
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/rust_interface/RandomParcelWrapper.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_libbinder.h>
+#include <android/binder_parcel.h>
+#include <fuzzbinder/random_parcel.h>
+
+extern "C" {
+
+void createRandomParcel(void* aParcel, const uint8_t* data, size_t len) {
+ CHECK_NE(aParcel, nullptr);
+ AParcel* parcel = static_cast<AParcel*>(aParcel);
+ FuzzedDataProvider provider(data, len);
+ android::RandomParcelOptions options;
+
+ android::Parcel* platformParcel = AParcel_viewPlatformParcel(parcel);
+ fillRandomParcel(platformParcel, std::move(provider), &options);
+}
+
+} // extern "C"
\ No newline at end of file
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index 397ff41..8ec9823 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -59,14 +59,14 @@
return RpcTransportCtxFactoryTipcTrusty::make();
}
-int sendMessageOnSocket(
+ssize_t sendMessageOnSocket(
const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */,
const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) {
errno = ENOTSUP;
return -1;
}
-int receiveMessageFromSocket(
+ssize_t receiveMessageFromSocket(
const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */,
std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) {
errno = ENOTSUP;
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
index 58bfe71..d249b2e 100644
--- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -239,6 +239,12 @@
}
if (!(uevt.event & IPC_HANDLE_POLL_MSG)) {
/* No message, terminate here and leave mHaveMessage false */
+ if (uevt.event & IPC_HANDLE_POLL_HUP) {
+ // Peer closed the connection. We need to preserve the order
+ // between MSG and HUP from FdTrigger.cpp, which means that
+ // getting MSG&HUP should return OK instead of DEAD_OBJECT.
+ return DEAD_OBJECT;
+ }
return OK;
}
diff --git a/libs/binder/trusty/include/log/log.h b/libs/binder/trusty/include/log/log.h
index bf877a3..de84617 100644
--- a/libs/binder/trusty/include/log/log.h
+++ b/libs/binder/trusty/include/log/log.h
@@ -120,3 +120,9 @@
do { \
TLOGE("android_errorWriteLog: tag:%x subTag:%s\n", tag, subTag); \
} while (0)
+
+// Override the definition of __assert from binder_status.h
+#ifndef __BIONIC__
+#undef __assert
+#define __assert(file, line, str) LOG_ALWAYS_FATAL("%s:%d: %s", file, line, str)
+#endif // __BIONIC__
diff --git a/libs/binder/trusty/kernel/rules.mk b/libs/binder/trusty/kernel/rules.mk
new file mode 100644
index 0000000..ab7a50d
--- /dev/null
+++ b/libs/binder/trusty/kernel/rules.mk
@@ -0,0 +1,83 @@
+# Copyright (C) 2022 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_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+LIBBINDER_DIR := frameworks/native/libs/binder
+LIBBASE_DIR := system/libbase
+LIBCUTILS_DIR := system/core/libcutils
+LIBUTILS_DIR := system/core/libutils
+FMTLIB_DIR := external/fmtlib
+
+MODULE_SRCS := \
+ $(LOCAL_DIR)/../logging.cpp \
+ $(LOCAL_DIR)/../TrustyStatus.cpp \
+ $(LIBBINDER_DIR)/Binder.cpp \
+ $(LIBBINDER_DIR)/BpBinder.cpp \
+ $(LIBBINDER_DIR)/FdTrigger.cpp \
+ $(LIBBINDER_DIR)/IInterface.cpp \
+ $(LIBBINDER_DIR)/IResultReceiver.cpp \
+ $(LIBBINDER_DIR)/Parcel.cpp \
+ $(LIBBINDER_DIR)/Stability.cpp \
+ $(LIBBINDER_DIR)/Status.cpp \
+ $(LIBBINDER_DIR)/Utils.cpp \
+ $(LIBBASE_DIR)/hex.cpp \
+ $(LIBBASE_DIR)/stringprintf.cpp \
+ $(LIBUTILS_DIR)/Errors.cpp \
+ $(LIBUTILS_DIR)/misc.cpp \
+ $(LIBUTILS_DIR)/RefBase.cpp \
+ $(LIBUTILS_DIR)/StrongPointer.cpp \
+ $(LIBUTILS_DIR)/Unicode.cpp \
+
+# TODO: remove the following when libbinder supports std::string
+# instead of String16 and String8 for Status and descriptors
+MODULE_SRCS += \
+ $(LIBUTILS_DIR)/SharedBuffer.cpp \
+ $(LIBUTILS_DIR)/String16.cpp \
+ $(LIBUTILS_DIR)/String8.cpp \
+
+# TODO: disable dump() transactions to get rid of Vector
+MODULE_SRCS += \
+ $(LIBUTILS_DIR)/VectorImpl.cpp \
+
+MODULE_DEFINES += \
+ LK_DEBUGLEVEL_NO_ALIASES=1 \
+
+MODULE_INCLUDES += \
+ $(LOCAL_DIR)/.. \
+
+GLOBAL_INCLUDES += \
+ $(LOCAL_DIR)/include \
+ $(LOCAL_DIR)/../include \
+ $(LIBBINDER_DIR)/include \
+ $(LIBBINDER_DIR)/ndk/include_cpp \
+ $(LIBBASE_DIR)/include \
+ $(LIBCUTILS_DIR)/include \
+ $(LIBUTILS_DIR)/include \
+ $(FMTLIB_DIR)/include \
+
+GLOBAL_COMPILEFLAGS += \
+ -DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION \
+ -DBINDER_NO_KERNEL_IPC \
+ -DBINDER_RPC_SINGLE_THREADED \
+ -D__ANDROID_VNDK__ \
+
+MODULE_DEPS += \
+ trusty/kernel/lib/libcxx-trusty \
+ trusty/kernel/lib/libcxxabi-trusty \
+
+include make/module.mk
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index a6585c5..067ce17 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -208,5 +208,5 @@
cmdline = std::string(cmdline.c_str());
return cmdline == "zygote" || cmdline == "zygote64" || cmdline == "usap32" ||
- cmdline == "usap64";
+ cmdline == "usap64" || cmdline == "webview_zygote";
}
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 6c6d7f3..1109ad8 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -36,6 +36,9 @@
status_t ServiceManager::addService(const String16& name, const sp<IBinder>& service,
bool /*allowIsolated*/,
int /*dumpsysFlags*/) {
+ if (service == nullptr) {
+ return UNEXPECTED_NULL;
+ }
mNameToService[name] = service;
return NO_ERROR;
}
@@ -78,6 +81,11 @@
return std::nullopt;
}
+Vector<String16> ServiceManager::getUpdatableNames(const String16& apexName) {
+ (void)apexName;
+ return {};
+}
+
std::optional<IServiceManager::ConnectionInfo> ServiceManager::getConnectionInfo(
const String16& name) {
(void)name;
@@ -98,4 +106,8 @@
std::vector<IServiceManager::ServiceDebugInfo> ret;
return ret;
}
+
+void ServiceManager::clear() {
+ mNameToService.clear();
+}
} // namespace android
diff --git a/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h
index e0af5d4..ba6bb7d 100644
--- a/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h
@@ -52,6 +52,8 @@
std::optional<String16> updatableViaApex(const String16& name) override;
+ Vector<String16> getUpdatableNames(const String16& apexName) override;
+
std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
status_t registerForNotifications(const String16& name,
@@ -62,6 +64,9 @@
std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
+ // Clear all of the registered services
+ void clear();
+
private:
std::map<String16, sp<IBinder>> mNameToService;
};
diff --git a/libs/fakeservicemanager/test_sm.cpp b/libs/fakeservicemanager/test_sm.cpp
index 71e5abe..8682c1c 100644
--- a/libs/fakeservicemanager/test_sm.cpp
+++ b/libs/fakeservicemanager/test_sm.cpp
@@ -50,6 +50,12 @@
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
}
+TEST(AddService, SadNullBinder) {
+ auto sm = new ServiceManager();
+ EXPECT_EQ(sm->addService(String16("foo"), nullptr, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), android::UNEXPECTED_NULL);
+}
+
TEST(AddService, HappyOverExistingService) {
auto sm = new ServiceManager();
EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
@@ -58,6 +64,15 @@
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
}
+TEST(AddService, HappyClearAddedService) {
+ auto sm = new ServiceManager();
+ EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+ EXPECT_NE(sm->getService(String16("foo")), nullptr);
+ sm->clear();
+ EXPECT_EQ(sm->getService(String16("foo")), nullptr);
+}
+
TEST(GetService, HappyHappy) {
auto sm = new ServiceManager();
sp<IBinder> service = getBinder();
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index bd21fba..f5af425 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -51,14 +51,14 @@
],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.common-V4-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
"liblog",
],
export_shared_lib_headers: [
- "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.common-V4-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
],
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 7f0cac5..4a0a839 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -364,26 +364,61 @@
return (mUseAngle == YES) ? true : false;
}
+bool GraphicsEnv::angleIsSystemDriver() {
+ // Make sure we are init'ed
+ if (mAngleAppName.empty()) {
+ ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE.");
+ return false;
+ }
+
+ return (mAngleIsSystemDriver == YES) ? true : false;
+}
+
+bool GraphicsEnv::shouldForceLegacyDriver() {
+ // Make sure we are init'ed
+ if (mAngleAppName.empty()) {
+ ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE.");
+ return false;
+ }
+
+ return (mAngleIsSystemDriver == YES && mUseAngle == NO) ? true : false;
+}
+
+std::string GraphicsEnv::getLegacySuffix() {
+ return mLegacyDriverSuffix;
+}
+
void GraphicsEnv::updateUseAngle() {
mUseAngle = NO;
const char* ANGLE_PREFER_ANGLE = "angle";
+ const char* ANGLE_PREFER_LEGACY = "legacy";
+ // The following is a deprecated version of "legacy"
const char* ANGLE_PREFER_NATIVE = "native";
mUseAngle = NO;
if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
- ALOGV("User set \"Developer Options\" to force the use of ANGLE");
+ ALOGI("Using ANGLE, the %s GLES driver for package '%s'",
+ mAngleIsSystemDriver == YES ? "system" : "optional", mAngleAppName.c_str());
mUseAngle = YES;
- } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
- ALOGV("User set \"Developer Options\" to force the use of Native");
+ } else if (mAngleDeveloperOptIn == ANGLE_PREFER_LEGACY ||
+ mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
+ ALOGI("Using the (%s) Legacy GLES driver for package '%s'",
+ mAngleIsSystemDriver == YES ? "optional" : "system", mAngleAppName.c_str());
} else {
ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str());
}
}
void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
- const std::string developerOptIn,
+ const bool angleIsSystemDriver, const std::string developerOptIn,
const std::vector<std::string> eglFeatures) {
+ // Set whether ANGLE is the system driver:
+ mAngleIsSystemDriver = angleIsSystemDriver ? YES : NO;
+
+ // Note: Given the current logic and lack of the old rules file processing,
+ // there seems to be little chance that mUseAngle != UNKNOWN. Leave this
+ // for now, even though it seems outdated.
if (mUseAngle != UNKNOWN) {
// We've already figured out an answer for this app, so just return.
ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(),
@@ -404,6 +439,25 @@
updateUseAngle();
}
+void GraphicsEnv::setLegacyDriverInfo(const std::string appName, const bool angleIsSystemDriver,
+ const std::string legacyDriverName) {
+ ALOGV("setting legacy app name to '%s'", appName.c_str());
+ mAngleAppName = appName;
+
+ // Force the use of the legacy driver instead of ANGLE
+ const char* ANGLE_PREFER_LEGACY = "legacy";
+ mAngleDeveloperOptIn = ANGLE_PREFER_LEGACY;
+ ALOGV("setting ANGLE application opt-in to 'legacy'");
+
+ // Set whether ANGLE is the system driver:
+ mAngleIsSystemDriver = angleIsSystemDriver ? YES : NO;
+
+ mLegacyDriverSuffix = legacyDriverName;
+
+ // Update the current status of whether we should use ANGLE or not
+ updateUseAngle();
+}
+
void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
if (mLayerPaths.empty()) {
mLayerPaths = layerPaths;
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 56d1139..82a6b6c 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -91,17 +91,28 @@
bool shouldUseAngle(std::string appName);
// Check if this app process should use ANGLE.
bool shouldUseAngle();
+ // If ANGLE is the system GLES driver
+ bool angleIsSystemDriver();
+ // If should use legacy driver instead of a system ANGLE driver
+ bool shouldForceLegacyDriver();
// Set a search path for loading ANGLE libraries. The path is a list of
// directories separated by ':'. A directory can be contained in a zip file
// (libraries must be stored uncompressed and page aligned); such elements
// in the search path must have a '!' after the zip filename, e.g.
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
- void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn,
+ void setAngleInfo(const std::string path, const std::string appName,
+ const bool angleIsSystemDriver, std::string devOptIn,
const std::vector<std::string> eglFeatures);
+ // Set the state so that the legacy driver will be used, and in case ANGLE
+ // is the system driver, provide the name of the legacy driver.
+ void setLegacyDriverInfo(const std::string appName, const bool angleIsSystemDriver,
+ const std::string legacyDriverName);
// Get the ANGLE driver namespace.
android_namespace_t* getAngleNamespace();
// Get the app name for ANGLE debug message.
std::string& getAngleAppName();
+ // Get the legacy driver's suffix name.
+ std::string getLegacySuffix();
const std::vector<std::string>& getAngleEglFeatures();
@@ -156,6 +167,10 @@
std::string mAngleDeveloperOptIn;
// ANGLE EGL features;
std::vector<std::string> mAngleEglFeatures;
+ // ANGLE is System Driver flag.
+ UseAngle mAngleIsSystemDriver = UNKNOWN;
+ // Legacy driver name to use when ANGLE is the system driver.
+ std::string mLegacyDriverSuffix;
// Use ANGLE flag.
UseAngle mUseAngle = UNKNOWN;
// Vulkan debug layers libs.
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 56b17ae..2ac1174 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -177,8 +177,6 @@
"BitTube.cpp",
"BLASTBufferQueue.cpp",
- "BufferHubConsumer.cpp",
- "BufferHubProducer.cpp",
"BufferItemConsumer.cpp",
"ConsumerBase.cpp",
"CpuConsumer.cpp",
@@ -216,9 +214,6 @@
shared_libs: [
"libbinder",
- "libbufferhub",
- "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
- "libpdx_default_transport",
],
export_shared_lib_headers: [
@@ -229,24 +224,6 @@
"libgui_aidl_headers",
],
- // bufferhub is not used when building libgui for vendors
- target: {
- vendor: {
- cflags: [
- "-DNO_BUFFERHUB",
- ],
- exclude_srcs: [
- "BufferHubConsumer.cpp",
- "BufferHubProducer.cpp",
- ],
- exclude_shared_libs: [
- "libbufferhub",
- "libbufferhubqueue",
- "libpdx_default_transport",
- ],
- },
- },
-
aidl: {
export_aidl_headers: true,
},
@@ -276,7 +253,6 @@
min_sdk_version: "29",
cflags: [
- "-DNO_BUFFERHUB",
"-DNO_BINDER",
],
@@ -345,7 +321,7 @@
"android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.common-V4-ndk",
"android.hidl.token@1.0-utils",
"libbase",
"libcutils",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dbccf30..a51bbb1 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -287,18 +287,17 @@
// We need to check if we were waiting for a transaction callback in order to
// process any pending buffers and unblock. It's possible to get transaction
- // callbacks for previous requests so we need to ensure the frame from this
- // transaction callback matches the last acquired buffer. Since acquireNextBuffer
- // will stop processing buffers when mWaitForTransactionCallback is set, we know
- // that mLastAcquiredFrameNumber is the frame we're waiting on.
- // We also want to check if mNextTransaction is null because it's possible another
+ // callbacks for previous requests so we need to ensure that there are no pending
+ // frame numbers that were in a sync. We remove the frame from mSyncedFrameNumbers
+ // set and then check if it's empty. If there are no more pending syncs, we can
+ // proceed with flushing the shadow queue.
+ // We also want to check if mSyncTransaction is null because it's possible another
// sync request came in while waiting, but it hasn't started processing yet. In that
// case, we don't actually want to flush the frames in between since they will get
// processed and merged with the sync transaction and released earlier than if they
// were sent to SF
- if (mWaitForTransactionCallback && mSyncTransaction == nullptr &&
- currFrameNumber >= mLastAcquiredFrameNumber) {
- mWaitForTransactionCallback = false;
+ mSyncedFrameNumbers.erase(currFrameNumber);
+ if (mSyncedFrameNumbers.empty() && mSyncTransaction == nullptr) {
flushShadowQueue();
}
} else {
@@ -308,7 +307,6 @@
BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
"empty.");
}
-
decStrong((void*)transactionCommittedCallbackThunk);
}
}
@@ -351,6 +349,20 @@
stat.latchTime,
stat.frameEventStats.dequeueReadyTime);
}
+ auto currFrameNumber = stat.frameEventStats.frameNumber;
+ std::vector<ReleaseCallbackId> staleReleases;
+ for (const auto& [key, value]: mSubmitted) {
+ if (currFrameNumber > key.framenumber) {
+ staleReleases.push_back(key);
+ }
+ }
+ for (const auto& staleRelease : staleReleases) {
+ BQA_LOGE("Faking releaseBufferCallback from transactionCompleteCallback");
+ BBQ_TRACE("FakeReleaseCallback");
+ releaseBufferCallbackLocked(staleRelease,
+ stat.previousReleaseFence ? stat.previousReleaseFence : Fence::NO_FENCE,
+ stat.currentMaxAcquiredBufferCount);
+ }
} else {
BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
}
@@ -391,7 +403,14 @@
const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount) {
BBQ_TRACE();
+
std::unique_lock _lock{mMutex};
+ releaseBufferCallbackLocked(id, releaseFence, currentMaxAcquiredBufferCount);
+}
+
+void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id,
+ const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) {
+ ATRACE_CALL();
BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
// Calculate how many buffers we need to hold before we release them back
@@ -409,16 +428,22 @@
const auto numPendingBuffersToHold =
isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0;
- mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence});
+
+ auto rb = ReleasedBuffer{id, releaseFence};
+ if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) {
+ mPendingRelease.emplace_back(rb);
+ }
// Release all buffers that are beyond the ones that we need to hold
while (mPendingRelease.size() > numPendingBuffersToHold) {
const auto releasedBuffer = mPendingRelease.front();
mPendingRelease.pop_front();
releaseBuffer(releasedBuffer.callbackId, releasedBuffer.releaseFence);
- // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let
- // onFrameAvailable handle processing them since it will merge with the syncTransaction.
- if (!mWaitForTransactionCallback) {
+ // Don't process the transactions here if mSyncedFrameNumbers is not empty. That means
+ // are still transactions that have sync buffers in them that have not been applied or
+ // dropped. Instead, let onFrameAvailable handle processing them since it will merge with
+ // the syncTransaction.
+ if (mSyncedFrameNumbers.empty()) {
acquireNextBufferLocked(std::nullopt);
}
}
@@ -442,6 +467,9 @@
BQA_LOGV("released %s", callbackId.to_string().c_str());
mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
mSubmitted.erase(it);
+ // Remove the frame number from mSyncedFrameNumbers since we can get a release callback
+ // without getting a transaction committed if the buffer was dropped.
+ mSyncedFrameNumbers.erase(callbackId.framenumber);
}
void BLASTBufferQueue::acquireNextBufferLocked(
@@ -608,7 +636,7 @@
}
void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) {
- if (mWaitForTransactionCallback && mNumFrameAvailable > 0) {
+ if (!mSyncedFrameNumbers.empty() && mNumFrameAvailable > 0) {
// We are waiting on a previous sync's transaction callback so allow another sync
// transaction to proceed.
//
@@ -635,6 +663,8 @@
void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr;
SurfaceComposerClient::Transaction* prevTransaction = nullptr;
+ bool waitForTransactionCallback = !mSyncedFrameNumbers.empty();
+
{
BBQ_TRACE();
std::unique_lock _lock{mMutex};
@@ -666,7 +696,7 @@
// add to shadow queue
mNumFrameAvailable++;
- if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) {
+ if (waitForTransactionCallback && mNumFrameAvailable >= 2) {
acquireAndReleaseBuffer();
}
ATRACE_INT(mQueuedBufferTrace.c_str(),
@@ -683,14 +713,14 @@
incStrong((void*)transactionCommittedCallbackThunk);
mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
static_cast<void*>(this));
- mWaitForTransactionCallback = true;
+ mSyncedFrameNumbers.emplace(item.mFrameNumber);
if (mAcquireSingleBuffer) {
prevCallback = mTransactionReadyCallback;
prevTransaction = mSyncTransaction;
mTransactionReadyCallback = nullptr;
mSyncTransaction = nullptr;
}
- } else if (!mWaitForTransactionCallback) {
+ } else if (!waitForTransactionCallback) {
acquireNextBufferLocked(std::nullopt);
}
}
@@ -1097,9 +1127,9 @@
}
// Clear sync states
- if (mWaitForTransactionCallback) {
- BQA_LOGD("mWaitForTransactionCallback cleared");
- mWaitForTransactionCallback = false;
+ if (!mSyncedFrameNumbers.empty()) {
+ BQA_LOGD("mSyncedFrameNumbers cleared");
+ mSyncedFrameNumbers.clear();
}
if (mSyncTransaction != nullptr) {
diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp
deleted file mode 100644
index b5cdeb2..0000000
--- a/libs/gui/BufferHubConsumer.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gui/BufferHubConsumer.h>
-
-namespace android {
-
-using namespace dvr;
-
-/* static */
-sp<BufferHubConsumer> BufferHubConsumer::Create(const std::shared_ptr<ConsumerQueue>& queue) {
- sp<BufferHubConsumer> consumer = new BufferHubConsumer;
- consumer->mQueue = queue;
- return consumer;
-}
-
-/* static */ sp<BufferHubConsumer> BufferHubConsumer::Create(ConsumerQueueParcelable parcelable) {
- if (!parcelable.IsValid()) {
- ALOGE("BufferHubConsumer::Create: Invalid consumer parcelable.");
- return nullptr;
- }
-
- sp<BufferHubConsumer> consumer = new BufferHubConsumer;
- consumer->mQueue = ConsumerQueue::Import(parcelable.TakeChannelHandle());
- return consumer;
-}
-
-status_t BufferHubConsumer::acquireBuffer(BufferItem* /*buffer*/, nsecs_t /*presentWhen*/,
- uint64_t /*maxFrameNumber*/) {
- ALOGE("BufferHubConsumer::acquireBuffer: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::detachBuffer(int /*slot*/) {
- ALOGE("BufferHubConsumer::detachBuffer: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::attachBuffer(int* /*outSlot*/, const sp<GraphicBuffer>& /*buffer*/) {
- ALOGE("BufferHubConsumer::attachBuffer: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::releaseBuffer(int /*buf*/, uint64_t /*frameNumber*/,
- EGLDisplay /*display*/, EGLSyncKHR /*fence*/,
- const sp<Fence>& /*releaseFence*/) {
- ALOGE("BufferHubConsumer::releaseBuffer: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::consumerConnect(const sp<IConsumerListener>& /*consumer*/,
- bool /*controlledByApp*/) {
- ALOGE("BufferHubConsumer::consumerConnect: not implemented.");
-
- // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
- // make IGraphicBufferConsumer_test happy.
- return NO_ERROR;
-}
-
-status_t BufferHubConsumer::consumerDisconnect() {
- ALOGE("BufferHubConsumer::consumerDisconnect: not implemented.");
-
- // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
- // make IGraphicBufferConsumer_test happy.
- return NO_ERROR;
-}
-
-status_t BufferHubConsumer::getReleasedBuffers(uint64_t* /*slotMask*/) {
- ALOGE("BufferHubConsumer::getReleasedBuffers: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {
- ALOGE("BufferHubConsumer::setDefaultBufferSize: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setMaxBufferCount(int /*bufferCount*/) {
- ALOGE("BufferHubConsumer::setMaxBufferCount: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setMaxAcquiredBufferCount(int /*maxAcquiredBuffers*/) {
- ALOGE("BufferHubConsumer::setMaxAcquiredBufferCount: not implemented.");
-
- // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
- // make IGraphicBufferConsumer_test happy.
- return NO_ERROR;
-}
-
-status_t BufferHubConsumer::setConsumerName(const String8& /*name*/) {
- ALOGE("BufferHubConsumer::setConsumerName: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setDefaultBufferFormat(PixelFormat /*defaultFormat*/) {
- ALOGE("BufferHubConsumer::setDefaultBufferFormat: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setDefaultBufferDataSpace(android_dataspace /*defaultDataSpace*/) {
- ALOGE("BufferHubConsumer::setDefaultBufferDataSpace: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setConsumerUsageBits(uint64_t /*usage*/) {
- ALOGE("BufferHubConsumer::setConsumerUsageBits: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setConsumerIsProtected(bool /*isProtected*/) {
- ALOGE("BufferHubConsumer::setConsumerIsProtected: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setTransformHint(uint32_t /*hint*/) {
- ALOGE("BufferHubConsumer::setTransformHint: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::getSidebandStream(sp<NativeHandle>* /*outStream*/) const {
- ALOGE("BufferHubConsumer::getSidebandStream: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::getOccupancyHistory(
- bool /*forceFlush*/, std::vector<OccupancyTracker::Segment>* /*outHistory*/) {
- ALOGE("BufferHubConsumer::getOccupancyHistory: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::discardFreeBuffers() {
- ALOGE("BufferHubConsumer::discardFreeBuffers: not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const {
- ALOGE("BufferHubConsumer::dumpState: not implemented.");
- return INVALID_OPERATION;
-}
-
-IBinder* BufferHubConsumer::onAsBinder() {
- ALOGE("BufferHubConsumer::onAsBinder: BufferHubConsumer should never be used as an Binder "
- "object.");
- return nullptr;
-}
-
-} // namespace android
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
deleted file mode 100644
index 1f71e23..0000000
--- a/libs/gui/BufferHubProducer.cpp
+++ /dev/null
@@ -1,868 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dvr/dvr_api.h>
-#include <gui/BufferHubProducer.h>
-#include <inttypes.h>
-#include <log/log.h>
-#include <system/window.h>
-
-namespace android {
-
-using namespace dvr;
-
-/* static */
-sp<BufferHubProducer> BufferHubProducer::Create(const std::shared_ptr<ProducerQueue>& queue) {
- sp<BufferHubProducer> producer = new BufferHubProducer;
- producer->queue_ = queue;
- return producer;
-}
-
-/* static */
-sp<BufferHubProducer> BufferHubProducer::Create(ProducerQueueParcelable parcelable) {
- if (!parcelable.IsValid()) {
- ALOGE("BufferHubProducer::Create: Invalid producer parcelable.");
- return nullptr;
- }
-
- sp<BufferHubProducer> producer = new BufferHubProducer;
- producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle());
- return producer;
-}
-
-status_t BufferHubProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
- ALOGV("requestBuffer: slot=%d", slot);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("requestBuffer: BufferHubProducer has no connected producer");
- return NO_INIT;
- }
-
- if (slot < 0 || slot >= max_buffer_count_) {
- ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
- return BAD_VALUE;
- } else if (!buffers_[slot].mBufferState.isDequeued()) {
- ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot,
- buffers_[slot].mBufferState.string());
- return BAD_VALUE;
- } else if (buffers_[slot].mGraphicBuffer != nullptr) {
- ALOGE("requestBuffer: slot %d is not empty.", slot);
- return BAD_VALUE;
- } else if (buffers_[slot].mProducerBuffer == nullptr) {
- ALOGE("requestBuffer: slot %d is not dequeued.", slot);
- return BAD_VALUE;
- }
-
- const auto& producer_buffer = buffers_[slot].mProducerBuffer;
- sp<GraphicBuffer> graphic_buffer = producer_buffer->buffer()->buffer();
-
- buffers_[slot].mGraphicBuffer = graphic_buffer;
- buffers_[slot].mRequestBufferCalled = true;
-
- *buf = graphic_buffer;
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::setMaxDequeuedBufferCount(int max_dequeued_buffers) {
- ALOGV("setMaxDequeuedBufferCount: max_dequeued_buffers=%d", max_dequeued_buffers);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (max_dequeued_buffers <= 0 ||
- max_dequeued_buffers >
- int(BufferHubQueue::kMaxQueueCapacity - kDefaultUndequeuedBuffers)) {
- ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", max_dequeued_buffers,
- BufferHubQueue::kMaxQueueCapacity);
- return BAD_VALUE;
- }
-
- // The new dequeued_buffers count should not be violated by the number
- // of currently dequeued buffers.
- int dequeued_count = 0;
- for (const auto& buf : buffers_) {
- if (buf.mBufferState.isDequeued()) {
- dequeued_count++;
- }
- }
- if (dequeued_count > max_dequeued_buffers) {
- ALOGE("setMaxDequeuedBufferCount: the requested dequeued_buffers"
- "count (%d) exceeds the current dequeued buffer count (%d)",
- max_dequeued_buffers, dequeued_count);
- return BAD_VALUE;
- }
-
- max_dequeued_buffer_count_ = max_dequeued_buffers;
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::setAsyncMode(bool async) {
- if (async) {
- // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer
- // automatically and behaves differently from IGraphicBufferConsumer. Thus,
- // android::BufferQueue's async mode (a.k.a. allocating an additional buffer
- // to prevent dequeueBuffer from being blocking) technically does not apply
- // here.
- //
- // In Daydream, non-blocking producer side dequeue is guaranteed by careful
- // buffer consumer implementations. In another word, BufferHubQueue based
- // dequeueBuffer should never block whether setAsyncMode(true) is set or
- // not.
- //
- // See: IGraphicBufferProducer::setAsyncMode and
- // BufferQueueProducer::setAsyncMode for more about original implementation.
- ALOGW("BufferHubProducer::setAsyncMode: BufferHubQueue should always be "
- "asynchronous. This call makes no effact.");
- return NO_ERROR;
- }
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
- uint32_t height, PixelFormat format, uint64_t usage,
- uint64_t* /*outBufferAge*/,
- FrameEventHistoryDelta* /* out_timestamps */) {
- ALOGV("dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, height, format, usage);
-
- status_t ret;
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("dequeueBuffer: BufferQueue has no connected producer");
- return NO_INIT;
- }
-
- const uint32_t kLayerCount = 1;
- if (int32_t(queue_->capacity()) < max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) {
- // Lazy allocation. When the capacity of |queue_| has not reached
- // |max_dequeued_buffer_count_|, allocate new buffer.
- // TODO(jwcai) To save memory, the really reasonable thing to do is to go
- // over existing slots and find first existing one to dequeue.
- ret = AllocateBuffer(width, height, kLayerCount, format, usage);
- if (ret < 0) return ret;
- }
-
- size_t slot = 0;
- std::shared_ptr<ProducerBuffer> producer_buffer;
-
- 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;
-
- producer_buffer = buffer_status.take();
- if (!producer_buffer) return NO_MEMORY;
-
- if (width == producer_buffer->width() && height == producer_buffer->height() &&
- uint32_t(format) == producer_buffer->format()) {
- // The producer queue returns a producer buffer matches the request.
- break;
- }
-
- // Needs reallocation.
- // TODO(jwcai) Consider use VLOG instead if we find this log is not useful.
- ALOGI("dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different "
- "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need "
- "re-allocattion.",
- width, height, format, slot, producer_buffer->width(), producer_buffer->height(),
- producer_buffer->format());
- // Mark the slot as reallocating, so that later we can set
- // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued.
- buffers_[slot].mIsReallocating = true;
-
- // Remove the old buffer once the allocation before allocating its
- // replacement.
- RemoveBuffer(slot);
-
- // Allocate a new producer buffer with new buffer configs. Note that if
- // there are already multiple buffers in the queue, the next one returned
- // from |queue_->Dequeue| may not be the new buffer we just reallocated.
- // Retry up to BufferHubQueue::kMaxQueueCapacity times.
- ret = AllocateBuffer(width, height, kLayerCount, format, usage);
- if (ret < 0) return ret;
- }
-
- // With the BufferHub backed solution. Buffer slot returned from
- // |queue_->Dequeue| is guaranteed to avaiable for producer's use.
- // It's either in free state (if the buffer has never been used before) or
- // in queued state (if the buffer has been dequeued and queued back to
- // BufferHubQueue).
- LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() &&
- !buffers_[slot].mBufferState.isQueued()),
- "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
- buffers_[slot].mBufferState.string());
-
- buffers_[slot].mBufferState.freeQueued();
- buffers_[slot].mBufferState.dequeue();
- ALOGV("dequeueBuffer: slot=%zu", slot);
-
- // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we
- // just need to exopose that through |BufferHubQueue| once we need fence.
- *out_fence = Fence::NO_FENCE;
- *out_slot = int(slot);
- ret = NO_ERROR;
-
- if (buffers_[slot].mIsReallocating) {
- ret |= BUFFER_NEEDS_REALLOCATION;
- buffers_[slot].mIsReallocating = false;
- }
-
- return ret;
-}
-
-status_t BufferHubProducer::detachBuffer(int slot) {
- ALOGV("detachBuffer: slot=%d", slot);
- std::unique_lock<std::mutex> lock(mutex_);
-
- return DetachBufferLocked(static_cast<size_t>(slot));
-}
-
-status_t BufferHubProducer::DetachBufferLocked(size_t slot) {
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("detachBuffer: BufferHubProducer is not connected.");
- return NO_INIT;
- }
-
- if (slot >= static_cast<size_t>(max_buffer_count_)) {
- ALOGE("detachBuffer: slot index %zu out of range [0, %d)", slot, max_buffer_count_);
- return BAD_VALUE;
- } else if (!buffers_[slot].mBufferState.isDequeued()) {
- ALOGE("detachBuffer: slot %zu is not owned by the producer (state = %s)", slot,
- buffers_[slot].mBufferState.string());
- return BAD_VALUE;
- } else if (!buffers_[slot].mRequestBufferCalled) {
- ALOGE("detachBuffer: buffer in slot %zu has not been requested", slot);
- return BAD_VALUE;
- }
- std::shared_ptr<ProducerBuffer> producer_buffer = queue_->GetBuffer(slot);
- if (producer_buffer == nullptr || producer_buffer->buffer() == nullptr) {
- ALOGE("detachBuffer: Invalid ProducerBuffer at slot %zu.", slot);
- return BAD_VALUE;
- }
- sp<GraphicBuffer> graphic_buffer = producer_buffer->buffer()->buffer();
- if (graphic_buffer == nullptr) {
- ALOGE("detachBuffer: Invalid GraphicBuffer at slot %zu.", slot);
- return BAD_VALUE;
- }
-
- // Remove the ProducerBuffer from the ProducerQueue.
- status_t error = RemoveBuffer(slot);
- if (error != NO_ERROR) {
- ALOGE("detachBuffer: Failed to remove buffer, slot=%zu, error=%d.", slot, error);
- return error;
- }
-
- // Here we need to convert the existing ProducerBuffer into a DetachedBufferHandle and inject
- // the handle into the GraphicBuffer object at the requested slot.
- auto status_or_handle = producer_buffer->Detach();
- if (!status_or_handle.ok()) {
- ALOGE("detachBuffer: Failed to detach from a ProducerBuffer at slot %zu, error=%d.", slot,
- status_or_handle.error());
- return BAD_VALUE;
- }
-
- // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
- // be directly backed by BufferHub.
- return INVALID_OPERATION;
-}
-
-status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) {
- ALOGV("detachNextBuffer.");
-
- if (out_buffer == nullptr || out_fence == nullptr) {
- ALOGE("detachNextBuffer: Invalid parameter: out_buffer=%p, out_fence=%p", out_buffer,
- out_fence);
- return BAD_VALUE;
- }
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("detachNextBuffer: BufferHubProducer is not connected.");
- return NO_INIT;
- }
-
- // detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer, and detachBuffer in
- // sequence, except for two things:
- //
- // 1) It is unnecessary to know the dimensions, format, or usage of the next buffer, i.e. the
- // function just returns whatever ProducerBuffer is available from the ProducerQueue and no
- // buffer allocation or re-allocation will happen.
- // 2) It will not block, since if it cannot find an appropriate buffer to return, it will return
- // an error instead.
- size_t slot = 0;
- LocalHandle fence;
-
- // First, dequeue a ProducerBuffer from the ProducerQueue with no timeout. Report error
- // immediately if ProducerQueue::Dequeue() fails.
- auto status_or_buffer = queue_->Dequeue(/*timeout=*/0, &slot, &fence);
- if (!status_or_buffer.ok()) {
- ALOGE("detachNextBuffer: Failed to dequeue buffer, error=%d.", status_or_buffer.error());
- return NO_MEMORY;
- }
-
- std::shared_ptr<ProducerBuffer> producer_buffer = status_or_buffer.take();
- if (producer_buffer == nullptr) {
- ALOGE("detachNextBuffer: Dequeued buffer is null.");
- return NO_MEMORY;
- }
-
- // With the BufferHub backed solution, slot returned from |queue_->Dequeue| is guaranteed to
- // be available for producer's use. It's either in free state (if the buffer has never been used
- // before) or in queued state (if the buffer has been dequeued and queued back to
- // BufferHubQueue).
- if (!buffers_[slot].mBufferState.isFree() && !buffers_[slot].mBufferState.isQueued()) {
- ALOGE("detachNextBuffer: slot %zu is not free or queued, actual state: %s.", slot,
- buffers_[slot].mBufferState.string());
- return BAD_VALUE;
- }
- if (buffers_[slot].mProducerBuffer == nullptr) {
- ALOGE("detachNextBuffer: ProducerBuffer at slot %zu is null.", slot);
- return BAD_VALUE;
- }
- if (buffers_[slot].mProducerBuffer->id() != producer_buffer->id()) {
- ALOGE("detachNextBuffer: ProducerBuffer at slot %zu has mismatched id, actual: "
- "%d, expected: %d.",
- slot, buffers_[slot].mProducerBuffer->id(), producer_buffer->id());
- return BAD_VALUE;
- }
-
- ALOGV("detachNextBuffer: slot=%zu", slot);
- buffers_[slot].mBufferState.freeQueued();
- buffers_[slot].mBufferState.dequeue();
-
- // Second, request the buffer.
- sp<GraphicBuffer> graphic_buffer = producer_buffer->buffer()->buffer();
- buffers_[slot].mGraphicBuffer = producer_buffer->buffer()->buffer();
-
- // Finally, detach the buffer and then return.
- status_t error = DetachBufferLocked(slot);
- if (error == NO_ERROR) {
- *out_fence = new Fence(fence.Release());
- *out_buffer = graphic_buffer;
- }
- return error;
-}
-
-status_t BufferHubProducer::attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) {
- // In the BufferHub design, all buffers are allocated and owned by the BufferHub. Thus only
- // GraphicBuffers that are originated from BufferHub can be attached to a BufferHubProducer.
- ALOGV("queueBuffer: buffer=%p", buffer.get());
-
- if (out_slot == nullptr) {
- ALOGE("attachBuffer: out_slot cannot be NULL.");
- return BAD_VALUE;
- }
- if (buffer == nullptr) {
- ALOGE("attachBuffer: invalid GraphicBuffer.");
- return BAD_VALUE;
- }
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("attachBuffer: BufferQueue has no connected producer");
- return NO_INIT;
- }
-
- // Before attaching the buffer, caller is supposed to call
- // IGraphicBufferProducer::setGenerationNumber to inform the
- // BufferHubProducer the next generation number.
- if (buffer->getGenerationNumber() != generation_number_) {
- ALOGE("attachBuffer: Mismatched generation number, buffer: %u, queue: %u.",
- buffer->getGenerationNumber(), generation_number_);
- return BAD_VALUE;
- }
-
- // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
- // be directly backed by BufferHub.
- return INVALID_OPERATION;
-}
-
-status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
- QueueBufferOutput* output) {
- ALOGV("queueBuffer: slot %d", slot);
-
- if (output == nullptr) {
- return BAD_VALUE;
- }
-
- int64_t timestamp;
- bool is_auto_timestamp;
- android_dataspace dataspace;
- Rect crop(Rect::EMPTY_RECT);
- int scaling_mode;
- uint32_t transform;
- sp<Fence> fence;
-
- input.deflate(×tamp, &is_auto_timestamp, &dataspace, &crop, &scaling_mode, &transform,
- &fence);
-
- // Check input scaling mode is valid.
- switch (scaling_mode) {
- case NATIVE_WINDOW_SCALING_MODE_FREEZE:
- case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
- case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
- case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
- break;
- default:
- ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode);
- return BAD_VALUE;
- }
-
- // Check input fence is valid.
- if (fence == nullptr) {
- ALOGE("queueBuffer: fence is NULL");
- return BAD_VALUE;
- }
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("queueBuffer: BufferQueue has no connected producer");
- return NO_INIT;
- }
-
- if (slot < 0 || slot >= max_buffer_count_) {
- ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
- return BAD_VALUE;
- } else if (!buffers_[slot].mBufferState.isDequeued()) {
- ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot,
- buffers_[slot].mBufferState.string());
- return BAD_VALUE;
- } else if ((!buffers_[slot].mRequestBufferCalled || buffers_[slot].mGraphicBuffer == nullptr)) {
- ALOGE("queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, "
- "mGraphicBuffer=%p)",
- slot, buffers_[slot].mRequestBufferCalled, buffers_[slot].mGraphicBuffer.get());
- return BAD_VALUE;
- }
-
- // Post the producer buffer with timestamp in the metadata.
- const auto& producer_buffer = buffers_[slot].mProducerBuffer;
-
- // Check input crop is not out of boundary of current buffer.
- Rect buffer_rect(producer_buffer->width(), producer_buffer->height());
- Rect cropped_rect(Rect::EMPTY_RECT);
- crop.intersect(buffer_rect, &cropped_rect);
- if (cropped_rect != crop) {
- ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot);
- return BAD_VALUE;
- }
-
- LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
-
- DvrNativeBufferMetadata meta_data;
- meta_data.timestamp = timestamp;
- meta_data.is_auto_timestamp = int32_t(is_auto_timestamp);
- meta_data.dataspace = int32_t(dataspace);
- meta_data.crop_left = crop.left;
- meta_data.crop_top = crop.top;
- meta_data.crop_right = crop.right;
- meta_data.crop_bottom = crop.bottom;
- meta_data.scaling_mode = int32_t(scaling_mode);
- meta_data.transform = int32_t(transform);
-
- producer_buffer->PostAsync(&meta_data, fence_fd);
- buffers_[slot].mBufferState.queue();
-
- output->width = producer_buffer->width();
- output->height = producer_buffer->height();
- output->transformHint = 0; // default value, we don't use it yet.
-
- // |numPendingBuffers| counts of the number of buffers that has been enqueued
- // by the producer but not yet acquired by the consumer. Due to the nature
- // of BufferHubQueue design, this is hard to trace from the producer's client
- // side, but it's safe to assume it's zero.
- output->numPendingBuffers = 0;
-
- // Note that we are not setting nextFrameNumber here as it seems to be only
- // used by surface flinger. See more at b/22802885, ag/791760.
- output->nextFrameNumber = 0;
-
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
- ALOGV(__FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("cancelBuffer: BufferQueue has no connected producer");
- return NO_INIT;
- }
-
- if (slot < 0 || slot >= max_buffer_count_) {
- ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
- return BAD_VALUE;
- } else if (!buffers_[slot].mBufferState.isDequeued()) {
- ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot,
- buffers_[slot].mBufferState.string());
- return BAD_VALUE;
- } else if (fence == nullptr) {
- ALOGE("cancelBuffer: fence is NULL");
- return BAD_VALUE;
- }
-
- auto producer_buffer = buffers_[slot].mProducerBuffer;
- queue_->Enqueue(producer_buffer, size_t(slot), 0U);
- buffers_[slot].mBufferState.cancel();
- buffers_[slot].mFence = fence;
- ALOGV("cancelBuffer: slot %d", slot);
-
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::query(int what, int* out_value) {
- ALOGV(__FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (out_value == nullptr) {
- ALOGE("query: out_value was NULL");
- return BAD_VALUE;
- }
-
- int value = 0;
- switch (what) {
- case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- // TODO(b/36187402) This should be the maximum number of buffers that this
- // producer queue's consumer can acquire. Set to be at least one. Need to
- // find a way to set from the consumer side.
- value = kDefaultUndequeuedBuffers;
- break;
- case NATIVE_WINDOW_BUFFER_AGE:
- value = 0;
- break;
- case NATIVE_WINDOW_WIDTH:
- value = int32_t(queue_->default_width());
- break;
- case NATIVE_WINDOW_HEIGHT:
- value = int32_t(queue_->default_height());
- break;
- case NATIVE_WINDOW_FORMAT:
- value = int32_t(queue_->default_format());
- break;
- case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
- // BufferHubQueue is always operating in async mode, thus semantically
- // consumer can never be running behind. See BufferQueueCore.cpp core
- // for more information about the original meaning of this flag.
- value = 0;
- break;
- case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
- // TODO(jwcai) This is currently not implement as we don't need
- // IGraphicBufferConsumer parity.
- value = 0;
- break;
- case NATIVE_WINDOW_DEFAULT_DATASPACE:
- // TODO(jwcai) Return the default value android::BufferQueue is using as
- // there is no way dvr::ConsumerQueue can set it.
- value = 0; // HAL_DATASPACE_UNKNOWN
- break;
- case NATIVE_WINDOW_STICKY_TRANSFORM:
- // TODO(jwcai) Return the default value android::BufferQueue is using as
- // there is no way dvr::ConsumerQueue can set it.
- value = 0;
- break;
- case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
- // In Daydream's implementation, the consumer end (i.e. VR Compostior)
- // knows how to handle protected buffers.
- value = 1;
- break;
- default:
- return BAD_VALUE;
- }
-
- ALOGV("query: key=%d, v=%d", what, value);
- *out_value = value;
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::connect(const sp<IProducerListener>& /* listener */, int api,
- bool /* producer_controlled_by_app */,
- QueueBufferOutput* output) {
- // Consumer interaction are actually handled by buffer hub, and we need
- // to maintain consumer operations here. We only need to perform basic input
- // parameter checks here.
- ALOGV(__FUNCTION__);
-
- if (output == nullptr) {
- return BAD_VALUE;
- }
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ != kNoConnectedApi) {
- return BAD_VALUE;
- }
-
- if (!queue_->is_connected()) {
- ALOGE("BufferHubProducer::connect: This BufferHubProducer is not "
- "connected to bufferhud. Has it been taken out as a parcelable?");
- return BAD_VALUE;
- }
-
- switch (api) {
- case NATIVE_WINDOW_API_EGL:
- case NATIVE_WINDOW_API_CPU:
- case NATIVE_WINDOW_API_MEDIA:
- case NATIVE_WINDOW_API_CAMERA:
- connected_api_ = api;
-
- output->width = queue_->default_width();
- output->height = queue_->default_height();
-
- // default values, we don't use them yet.
- output->transformHint = 0;
- output->numPendingBuffers = 0;
- output->nextFrameNumber = 0;
- output->bufferReplaced = false;
-
- break;
- default:
- ALOGE("BufferHubProducer::connect: unknow API %d", api);
- return BAD_VALUE;
- }
-
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::disconnect(int api, DisconnectMode /*mode*/) {
- // Consumer interaction are actually handled by buffer hub, and we need
- // to maintain consumer operations here. We only need to perform basic input
- // parameter checks here.
- ALOGV(__FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (kNoConnectedApi == connected_api_) {
- return NO_INIT;
- } else if (api != connected_api_) {
- return BAD_VALUE;
- }
-
- FreeAllBuffers();
- connected_api_ = kNoConnectedApi;
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::setSidebandStream(const sp<NativeHandle>& stream) {
- if (stream != nullptr) {
- // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's
- // metadata.
- ALOGE("SidebandStream is not currently supported.");
- return INVALID_OPERATION;
- }
- return NO_ERROR;
-}
-
-void BufferHubProducer::allocateBuffers(uint32_t /* width */, uint32_t /* height */,
- PixelFormat /* format */, 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_|).
- ALOGE("BufferHubProducer::allocateBuffers not implemented.");
-}
-
-status_t BufferHubProducer::allowAllocation(bool /* allow */) {
- ALOGE("BufferHubProducer::allowAllocation not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubProducer::setGenerationNumber(uint32_t generation_number) {
- ALOGV(__FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
- generation_number_ = generation_number;
- return NO_ERROR;
-}
-
-String8 BufferHubProducer::getConsumerName() const {
- // BufferHub based implementation could have one to many producer/consumer
- // relationship, thus |getConsumerName| from the producer side does not
- // make any sense.
- ALOGE("BufferHubProducer::getConsumerName not supported.");
- return String8("BufferHubQueue::StubConsumer");
-}
-
-status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) {
- if (shared_buffer_mode) {
- ALOGE("BufferHubProducer::setSharedBufferMode(true) is not supported.");
- // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
- return INVALID_OPERATION;
- }
- // Setting to default should just work as a no-op.
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::setAutoRefresh(bool auto_refresh) {
- if (auto_refresh) {
- ALOGE("BufferHubProducer::setAutoRefresh(true) is not supported.");
- return INVALID_OPERATION;
- }
- // Setting to default should just work as a no-op.
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::setDequeueTimeout(nsecs_t timeout) {
- ALOGV(__FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
- dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000));
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::getLastQueuedBuffer(sp<GraphicBuffer>* /* out_buffer */,
- sp<Fence>* /* out_fence */,
- float /*out_transform_matrix*/[16]) {
- ALOGE("BufferHubProducer::getLastQueuedBuffer not implemented.");
- return INVALID_OPERATION;
-}
-
-void BufferHubProducer::getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {
- ALOGE("BufferHubProducer::getFrameTimestamps not implemented.");
-}
-
-status_t BufferHubProducer::getUniqueId(uint64_t* out_id) const {
- ALOGV(__FUNCTION__);
-
- *out_id = unique_id_;
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::getConsumerUsage(uint64_t* out_usage) const {
- ALOGV(__FUNCTION__);
-
- // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
- *out_usage = 0;
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::TakeAsParcelable(ProducerQueueParcelable* out_parcelable) {
- if (!out_parcelable || out_parcelable->IsValid()) return BAD_VALUE;
-
- if (connected_api_ != kNoConnectedApi) {
- ALOGE("BufferHubProducer::TakeAsParcelable: BufferHubProducer has "
- "connected client. Must disconnect first.");
- return BAD_VALUE;
- }
-
- if (!queue_->is_connected()) {
- ALOGE("BufferHubProducer::TakeAsParcelable: This BufferHubProducer "
- "is not connected to bufferhud. Has it been taken out as a "
- "parcelable?");
- return BAD_VALUE;
- }
-
- auto status = queue_->TakeAsParcelable();
- if (!status) {
- ALOGE("BufferHubProducer::TakeAsParcelable: Failed to take out "
- "ProducuerQueueParcelable from the producer queue, error: %s.",
- status.GetErrorMessage().c_str());
- return BAD_VALUE;
- }
-
- *out_parcelable = status.take();
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
- PixelFormat format, uint64_t usage) {
- auto status = queue_->AllocateBuffer(width, height, layer_count, uint32_t(format), usage);
- if (!status) {
- ALOGE("BufferHubProducer::AllocateBuffer: Failed to allocate buffer: %s",
- status.GetErrorMessage().c_str());
- return NO_MEMORY;
- }
-
- size_t slot = status.get();
- auto producer_buffer = queue_->GetBuffer(slot);
-
- LOG_ALWAYS_FATAL_IF(producer_buffer == nullptr,
- "Failed to get the producer buffer at slot: %zu", slot);
-
- buffers_[slot].mProducerBuffer = producer_buffer;
-
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::RemoveBuffer(size_t slot) {
- auto status = queue_->RemoveBuffer(slot);
- if (!status) {
- ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer at slot: %zu, error: %s.",
- slot, status.GetErrorMessage().c_str());
- return INVALID_OPERATION;
- }
-
- // Reset in memory objects related the the buffer.
- buffers_[slot].mProducerBuffer = nullptr;
- buffers_[slot].mBufferState.detachProducer();
- buffers_[slot].mFence = Fence::NO_FENCE;
- buffers_[slot].mGraphicBuffer = nullptr;
- buffers_[slot].mRequestBufferCalled = false;
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::FreeAllBuffers() {
- for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
- // Reset in memory objects related the the buffer.
- buffers_[slot].mProducerBuffer = nullptr;
- buffers_[slot].mBufferState.reset();
- buffers_[slot].mFence = Fence::NO_FENCE;
- buffers_[slot].mGraphicBuffer = nullptr;
- buffers_[slot].mRequestBufferCalled = false;
- }
-
- auto status = queue_->FreeAllBuffers();
- if (!status) {
- ALOGE("BufferHubProducer::FreeAllBuffers: Failed to free all buffers on "
- "the queue: %s",
- status.GetErrorMessage().c_str());
- }
-
- if (queue_->capacity() != 0 || queue_->count() != 0) {
- LOG_ALWAYS_FATAL("BufferHubProducer::FreeAllBuffers: Not all buffers are freed.");
- }
-
- return NO_ERROR;
-}
-
-status_t BufferHubProducer::exportToParcel(Parcel* parcel) {
- status_t res = TakeAsParcelable(&pending_producer_parcelable_);
- if (res != NO_ERROR) return res;
-
- if (!pending_producer_parcelable_.IsValid()) {
- ALOGE("BufferHubProducer::exportToParcel: Invalid parcelable object.");
- return BAD_VALUE;
- }
-
- res = parcel->writeUint32(USE_BUFFER_HUB);
- if (res != NO_ERROR) {
- ALOGE("BufferHubProducer::exportToParcel: Cannot write magic, res=%d.", res);
- return res;
- }
-
- return pending_producer_parcelable_.writeToParcel(parcel);
-}
-
-IBinder* BufferHubProducer::onAsBinder() {
- ALOGE("BufferHubProducer::onAsBinder: BufferHubProducer should never be used as an Binder "
- "object.");
- return nullptr;
-}
-
-} // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index c1d92a2..66cad03 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -18,11 +18,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
-#ifndef NO_BUFFERHUB
-#include <gui/BufferHubConsumer.h>
-#include <gui/BufferHubProducer.h>
-#endif
-
#include <gui/BufferQueue.h>
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueCore.h>
@@ -127,32 +122,4 @@
*outConsumer = consumer;
}
-#ifndef NO_BUFFERHUB
-void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
- sp<IGraphicBufferConsumer>* outConsumer) {
- LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BufferQueue: outProducer must not be NULL");
- LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BufferQueue: outConsumer must not be NULL");
-
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
-
- dvr::ProducerQueueConfigBuilder configBuilder;
- std::shared_ptr<dvr::ProducerQueue> producerQueue =
- dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{});
- LOG_ALWAYS_FATAL_IF(producerQueue == nullptr, "BufferQueue: failed to create ProducerQueue.");
-
- std::shared_ptr<dvr::ConsumerQueue> consumerQueue = producerQueue->CreateConsumerQueue();
- LOG_ALWAYS_FATAL_IF(consumerQueue == nullptr, "BufferQueue: failed to create ConsumerQueue.");
-
- producer = BufferHubProducer::Create(producerQueue);
- consumer = BufferHubConsumer::Create(consumerQueue);
-
- LOG_ALWAYS_FATAL_IF(producer == nullptr, "BufferQueue: failed to create BufferQueueProducer");
- LOG_ALWAYS_FATAL_IF(consumer == nullptr, "BufferQueue: failed to create BufferQueueConsumer");
-
- *outProducer = producer;
- *outConsumer = consumer;
-}
-#endif
-
}; // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 797069c..918ff2d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -27,10 +27,6 @@
#include <binder/Parcel.h>
#include <binder/IInterface.h>
-#ifndef NO_BUFFERHUB
-#include <gui/BufferHubProducer.h>
-#endif
-
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
#include <gui/BufferQueueDefs.h>
@@ -1012,17 +1008,7 @@
}
case USE_BUFFER_HUB: {
ALOGE("createFromParcel: BufferHub not implemented.");
-#ifndef NO_BUFFERHUB
- dvr::ProducerQueueParcelable producerParcelable;
- res = producerParcelable.readFromParcel(parcel);
- if (res != NO_ERROR) {
- ALOGE("createFromParcel: Failed to read from parcel, error=%d", res);
- return nullptr;
- }
- return BufferHubProducer::Create(std::move(producerParcelable));
-#else
return nullptr;
-#endif
}
default: {
ALOGE("createFromParcel: Unexpected mgaic: 0x%x.", outMagic);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 6b544b2..3b13708 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1107,9 +1107,12 @@
ATRACE_CALL();
auto& mapper = GraphicBufferMapper::get();
mapper.setDataspace(buffer->handle, static_cast<ui::Dataspace>(queueBufferInput.dataSpace));
- mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086());
- mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613());
- mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus());
+ if (mHdrMetadataIsSet & HdrMetadata::SMPTE2086)
+ mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086());
+ if (mHdrMetadataIsSet & HdrMetadata::CTA861_3)
+ mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613());
+ if (mHdrMetadataIsSet & HdrMetadata::HDR10PLUS)
+ mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus());
}
void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence,
@@ -2250,6 +2253,7 @@
int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) {
ALOGV("Surface::setBuffersSmpte2086Metadata");
Mutex::Autolock lock(mMutex);
+ mHdrMetadataIsSet |= HdrMetadata::SMPTE2086;
if (metadata) {
mHdrMetadata.smpte2086 = *metadata;
mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086;
@@ -2262,6 +2266,7 @@
int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) {
ALOGV("Surface::setBuffersCta8613Metadata");
Mutex::Autolock lock(mMutex);
+ mHdrMetadataIsSet |= HdrMetadata::CTA861_3;
if (metadata) {
mHdrMetadata.cta8613 = *metadata;
mHdrMetadata.validTypes |= HdrMetadata::CTA861_3;
@@ -2274,6 +2279,7 @@
int Surface::setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata) {
ALOGV("Surface::setBuffersBlobMetadata");
Mutex::Autolock lock(mMutex);
+ mHdrMetadataIsSet |= HdrMetadata::HDR10PLUS;
if (size > 0) {
mHdrMetadata.hdr10plus.assign(metadata, metadata + size);
mHdrMetadata.validTypes |= HdrMetadata::HDR10PLUS;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 47d801a..0f5192d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -352,7 +352,8 @@
transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
- surfaceStats.eventStats);
+ surfaceStats.eventStats,
+ surfaceStats.currentMaxAcquiredBufferCount);
}
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
@@ -377,7 +378,8 @@
transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
- surfaceStats.eventStats);
+ surfaceStats.eventStats,
+ surfaceStats.currentMaxAcquiredBufferCount);
if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl]
@@ -897,6 +899,10 @@
mApplyToken = nullptr;
}
+uint64_t SurfaceComposerClient::Transaction::getId() {
+ return mId;
+}
+
void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 9328a54..f5898d2 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -95,9 +95,12 @@
const std::vector<SurfaceControlStats>& stats);
void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount);
+ void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
+ std::optional<uint32_t> currentMaxAcquiredBufferCount);
void syncNextTransaction(std::function<void(SurfaceComposerClient::Transaction*)> callback,
bool acquireSingleBuffer = true);
void stopContinuousSyncTransaction();
+
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void applyPendingTransactions(uint64_t frameNumber);
SurfaceComposerClient::Transaction* gatherPendingTransactions(uint64_t frameNumber);
@@ -177,6 +180,12 @@
struct ReleasedBuffer {
ReleaseCallbackId callbackId;
sp<Fence> releaseFence;
+ bool operator==(const ReleasedBuffer& rhs) const {
+ // Only compare Id so if we somehow got two callbacks
+ // with different fences we don't decrement mNumAcquired
+ // too far.
+ return rhs.callbackId == callbackId;
+ }
};
std::deque<ReleasedBuffer> mPendingRelease GUARDED_BY(mMutex);
@@ -251,7 +260,6 @@
std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex);
uint32_t mCurrentMaxAcquiredBufferCount;
- bool mWaitForTransactionCallback GUARDED_BY(mMutex) = false;
// Flag to determine if syncTransaction should only acquire a single buffer and then clear or
// continue to acquire buffers until explicitly cleared
@@ -279,6 +287,8 @@
uint64_t mLastAppliedFrameNumber = 0;
std::function<void(bool)> mTransactionHangCallback;
+
+ std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex);
};
} // namespace android
diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h
deleted file mode 100644
index d380770..0000000
--- a/libs/gui/include/gui/BufferHubConsumer.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GUI_BUFFERHUBCONSUMER_H_
-#define ANDROID_GUI_BUFFERHUBCONSUMER_H_
-
-#include <gui/IGraphicBufferConsumer.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/buffer_hub_queue_parcelable.h>
-
-namespace android {
-
-class BufferHubConsumer : public IGraphicBufferConsumer {
-public:
- // Creates a BufferHubConsumer instance by importing an existing producer queue.
- static sp<BufferHubConsumer> Create(const std::shared_ptr<dvr::ConsumerQueue>& queue);
-
- // Creates a BufferHubConsumer instance by importing an existing producer
- // parcelable. Note that this call takes the ownership of the parcelable
- // object and is guaranteed to succeed if parcelable object is valid.
- static sp<BufferHubConsumer> Create(dvr::ConsumerQueueParcelable parcelable);
-
- // See |IGraphicBufferConsumer::acquireBuffer|
- status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
- uint64_t maxFrameNumber = 0) override;
-
- // See |IGraphicBufferConsumer::detachBuffer|
- status_t detachBuffer(int slot) override;
-
- // See |IGraphicBufferConsumer::attachBuffer|
- status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) override;
-
- // See |IGraphicBufferConsumer::releaseBuffer|
- status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence,
- const sp<Fence>& releaseFence) override;
-
- // See |IGraphicBufferConsumer::consumerConnect|
- status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) override;
-
- // See |IGraphicBufferConsumer::consumerDisconnect|
- status_t consumerDisconnect() override;
-
- // See |IGraphicBufferConsumer::getReleasedBuffers|
- status_t getReleasedBuffers(uint64_t* slotMask) override;
-
- // See |IGraphicBufferConsumer::setDefaultBufferSize|
- status_t setDefaultBufferSize(uint32_t w, uint32_t h) override;
-
- // See |IGraphicBufferConsumer::setMaxBufferCount|
- status_t setMaxBufferCount(int bufferCount) override;
-
- // See |IGraphicBufferConsumer::setMaxAcquiredBufferCount|
- status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override;
-
- // See |IGraphicBufferConsumer::setConsumerName|
- status_t setConsumerName(const String8& name) override;
-
- // See |IGraphicBufferConsumer::setDefaultBufferFormat|
- status_t setDefaultBufferFormat(PixelFormat defaultFormat) override;
-
- // See |IGraphicBufferConsumer::setDefaultBufferDataSpace|
- status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) override;
-
- // See |IGraphicBufferConsumer::setConsumerUsageBits|
- status_t setConsumerUsageBits(uint64_t usage) override;
-
- // See |IGraphicBufferConsumer::setConsumerIsProtected|
- status_t setConsumerIsProtected(bool isProtected) override;
-
- // See |IGraphicBufferConsumer::setTransformHint|
- status_t setTransformHint(uint32_t hint) override;
-
- // See |IGraphicBufferConsumer::getSidebandStream|
- status_t getSidebandStream(sp<NativeHandle>* outStream) const override;
-
- // See |IGraphicBufferConsumer::getOccupancyHistory|
- status_t getOccupancyHistory(bool forceFlush,
- std::vector<OccupancyTracker::Segment>* outHistory) override;
-
- // See |IGraphicBufferConsumer::discardFreeBuffers|
- status_t discardFreeBuffers() override;
-
- // See |IGraphicBufferConsumer::dumpState|
- status_t dumpState(const String8& prefix, String8* outResult) const override;
-
- // BufferHubConsumer provides its own logic to cast to a binder object.
- IBinder* onAsBinder() override;
-
-private:
- // Private constructor to force use of |Create|.
- BufferHubConsumer() = default;
-
- // Concrete implementation backed by BufferHubBuffer.
- std::shared_ptr<dvr::ConsumerQueue> mQueue;
-};
-
-} // namespace android
-
-#endif // ANDROID_GUI_BUFFERHUBCONSUMER_H_
diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h
deleted file mode 100644
index 0e925ce..0000000
--- a/libs/gui/include/gui/BufferHubProducer.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GUI_BUFFERHUBPRODUCER_H_
-#define ANDROID_GUI_BUFFERHUBPRODUCER_H_
-
-#include <gui/BufferSlot.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/buffer_hub_queue_parcelable.h>
-
-namespace android {
-
-class BufferHubProducer : public IGraphicBufferProducer {
-public:
- static constexpr int kNoConnectedApi = -1;
-
- // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
- // side logic doesn't limit the number of buffer it can acquire
- // simultaneously. We need a way for consumer logic to configure and enforce
- // that.
- static constexpr int kDefaultUndequeuedBuffers = 1;
-
- // Creates a BufferHubProducer instance by importing an existing prodcuer
- // queue.
- static sp<BufferHubProducer> Create(const std::shared_ptr<dvr::ProducerQueue>& producer);
-
- // Creates a BufferHubProducer instance by importing an existing prodcuer
- // parcelable. Note that this call takes the ownership of the parcelable
- // object and is guaranteed to succeed if parcelable object is valid.
- static sp<BufferHubProducer> Create(dvr::ProducerQueueParcelable parcelable);
-
- // See |IGraphicBufferProducer::requestBuffer|
- status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
-
- // For the BufferHub based implementation. All buffers in the queue are
- // allowed to be dequeued from the consumer side. It call always returns
- // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting
- // |max_dequeued_buffers| here can be considered the same as setting queue
- // capacity.
- //
- // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info
- status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override;
-
- // See |IGraphicBufferProducer::setAsyncMode|
- status_t setAsyncMode(bool async) override;
-
- // See |IGraphicBufferProducer::dequeueBuffer|
- status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
- PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
- FrameEventHistoryDelta* outTimestamps) override;
-
- // See |IGraphicBufferProducer::detachBuffer|
- status_t detachBuffer(int slot) override;
-
- // See |IGraphicBufferProducer::detachNextBuffer|
- status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) override;
-
- // See |IGraphicBufferProducer::attachBuffer|
- status_t attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) override;
-
- // See |IGraphicBufferProducer::queueBuffer|
- status_t queueBuffer(int slot, const QueueBufferInput& input,
- QueueBufferOutput* output) override;
-
- // See |IGraphicBufferProducer::cancelBuffer|
- status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
-
- // See |IGraphicBufferProducer::query|
- status_t query(int what, int* out_value) override;
-
- // See |IGraphicBufferProducer::connect|
- status_t connect(const sp<IProducerListener>& listener, int api,
- bool producer_controlled_by_app, QueueBufferOutput* output) override;
-
- // See |IGraphicBufferProducer::disconnect|
- status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) override;
-
- // See |IGraphicBufferProducer::setSidebandStream|
- status_t setSidebandStream(const sp<NativeHandle>& stream) override;
-
- // See |IGraphicBufferProducer::allocateBuffers|
- void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
- uint64_t usage) override;
-
- // See |IGraphicBufferProducer::allowAllocation|
- status_t allowAllocation(bool allow) override;
-
- // See |IGraphicBufferProducer::setGenerationNumber|
- status_t setGenerationNumber(uint32_t generation_number) override;
-
- // See |IGraphicBufferProducer::getConsumerName|
- String8 getConsumerName() const override;
-
- // See |IGraphicBufferProducer::setSharedBufferMode|
- status_t setSharedBufferMode(bool shared_buffer_mode) override;
-
- // See |IGraphicBufferProducer::setAutoRefresh|
- status_t setAutoRefresh(bool auto_refresh) override;
-
- // See |IGraphicBufferProducer::setDequeueTimeout|
- status_t setDequeueTimeout(nsecs_t timeout) override;
-
- // See |IGraphicBufferProducer::getLastQueuedBuffer|
- status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence,
- float out_transform_matrix[16]) override;
-
- // See |IGraphicBufferProducer::getFrameTimestamps|
- void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override;
-
- // See |IGraphicBufferProducer::getUniqueId|
- status_t getUniqueId(uint64_t* out_id) const override;
-
- // See |IGraphicBufferProducer::getConsumerUsage|
- status_t getConsumerUsage(uint64_t* out_usage) const override;
-
- // Takes out the current producer as a binder parcelable object. Note that the
- // producer must be disconnected to be exportable. After successful export,
- // the producer queue can no longer be connected again. Returns NO_ERROR when
- // takeout is successful and out_parcelable will hold the new parcelable
- // object. Also note that out_parcelable cannot be NULL and must points to an
- // invalid parcelable.
- status_t TakeAsParcelable(dvr::ProducerQueueParcelable* out_parcelable);
-
- IBinder* onAsBinder() override;
-
-protected:
- // See |IGraphicBufferProducer::exportToParcel|
- status_t exportToParcel(Parcel* parcel) override;
-
-private:
- using LocalHandle = pdx::LocalHandle;
-
- // Private constructor to force use of |Create|.
- BufferHubProducer() {}
-
- static uint64_t genUniqueId() {
- static std::atomic<uint32_t> counter{0};
- static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
- return id | counter++;
- }
-
- // Allocate new buffer through BufferHub and add it into |queue_| for
- // bookkeeping.
- status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
- PixelFormat format, uint64_t usage);
-
- // Remove a buffer via BufferHubRPC.
- status_t RemoveBuffer(size_t slot);
-
- // Free all buffers which are owned by the prodcuer. Note that if graphic
- // buffers are acquired by the consumer, we can't .
- status_t FreeAllBuffers();
-
- // Helper function that implements the detachBuffer() call, but assuming |mutex_| has been
- // locked already.
- status_t DetachBufferLocked(size_t slot);
-
- // Concreate implementation backed by BufferHubBuffer.
- std::shared_ptr<dvr::ProducerQueue> queue_;
-
- // Mutex for thread safety.
- std::mutex mutex_;
-
- // Connect client API, should be one of the NATIVE_WINDOW_API_* flags.
- int connected_api_{kNoConnectedApi};
-
- // |max_buffer_count_| sets the capacity of the underlying buffer queue.
- int32_t max_buffer_count_{dvr::BufferHubQueue::kMaxQueueCapacity};
-
- // |max_dequeued_buffer_count_| set the maximum number of buffers that can
- // be dequeued at the same momment.
- int32_t max_dequeued_buffer_count_{1};
-
- // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
- // slot is not yet available. The timeout is stored in milliseconds.
- int dequeue_timeout_ms_{dvr::BufferHubQueue::kNoTimeOut};
-
- // |generation_number_| stores the current generation number of the attached
- // producer. Any attempt to attach a buffer with a different generation
- // number will fail.
- // TOOD(b/38137191) Currently not used as we don't support
- // IGraphicBufferProducer::detachBuffer.
- uint32_t generation_number_{0};
-
- // |buffers_| stores the buffers that have been dequeued from
- // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets
- // filled in with the result of |Dequeue|.
- // TODO(jwcai) The buffer allocated to a slot will also be replaced if the
- // requested buffer usage or geometry differs from that of the buffer
- // allocated to a slot.
- struct BufferHubSlot : public BufferSlot {
- BufferHubSlot() : mProducerBuffer(nullptr), mIsReallocating(false) {}
- // BufferSlot comes from android framework, using m prefix to comply with
- // the name convention with the reset of data fields from BufferSlot.
- std::shared_ptr<dvr::ProducerBuffer> mProducerBuffer;
- bool mIsReallocating;
- };
- BufferHubSlot buffers_[dvr::BufferHubQueue::kMaxQueueCapacity];
-
- // A uniqueId used by IGraphicBufferProducer interface.
- const uint64_t unique_id_{genUniqueId()};
-
- // A pending parcelable object which keeps the bufferhub channel alive.
- dvr::ProducerQueueParcelable pending_producer_parcelable_;
-};
-
-} // namespace android
-
-#endif // ANDROID_GUI_BUFFERHUBPRODUCER_H_
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index 91f80d2..690587f 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -82,12 +82,6 @@
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger = false);
-#ifndef NO_BUFFERHUB
- // Creates an IGraphicBufferProducer and IGraphicBufferConsumer pair backed by BufferHub.
- static void createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
- sp<IGraphicBufferConsumer>* outConsumer);
-#endif
-
BufferQueue() = delete; // Create through createBufferQueue
};
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index ab9ebaa..77615fe 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -111,6 +111,24 @@
return surface != nullptr && surface->getIGraphicBufferProducer() != nullptr;
}
+ static sp<IGraphicBufferProducer> getIGraphicBufferProducer(ANativeWindow* window) {
+ int val;
+ if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &val) >= 0 &&
+ val == NATIVE_WINDOW_SURFACE) {
+ return ((Surface*) window)->mGraphicBufferProducer;
+ }
+ return nullptr;
+ }
+
+ static sp<IBinder> getSurfaceControlHandle(ANativeWindow* window) {
+ int val;
+ if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &val) >= 0 &&
+ val == NATIVE_WINDOW_SURFACE) {
+ return ((Surface*) window)->mSurfaceControlHandle;
+ }
+ return nullptr;
+ }
+
/* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer.
*
* A sideband stream is a device-specific mechanism for passing buffers
@@ -462,6 +480,11 @@
// queue operation. There is no HDR metadata by default.
HdrMetadata mHdrMetadata;
+ // mHdrMetadataIsSet is a bitfield to track which HDR metadata has been set.
+ // Prevent Surface from resetting HDR metadata that was set on a bufer when
+ // HDR metadata is not set on this Surface.
+ uint32_t mHdrMetadataIsSet{0};
+
// mCrop is the crop rectangle that will be used for the next buffer
// that gets queued. It is set by calling setCrop.
Rect mCrop;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index efbdb36..9033e17 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -65,14 +65,16 @@
SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence,
const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
- uint32_t hint, FrameEventHistoryStats eventStats)
+ uint32_t hint, FrameEventHistoryStats eventStats,
+ uint32_t currentMaxAcquiredBufferCount)
: surfaceControl(sc),
latchTime(latchTime),
acquireTimeOrFence(std::move(acquireTimeOrFence)),
presentFence(presentFence),
previousReleaseFence(prevReleaseFence),
transformHint(hint),
- frameEventStats(eventStats) {}
+ frameEventStats(eventStats),
+ currentMaxAcquiredBufferCount(currentMaxAcquiredBufferCount) {}
sp<SurfaceControl> surfaceControl;
nsecs_t latchTime = -1;
@@ -81,6 +83,7 @@
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
FrameEventHistoryStats frameEventStats;
+ uint32_t currentMaxAcquiredBufferCount = 0;
};
using TransactionCompletedCallbackTakesContext =
@@ -461,6 +464,10 @@
// Clears the contents of the transaction without applying it.
void clear();
+ // Returns the current id of the transaction.
+ // The id is updated every time the transaction is applied.
+ uint64_t getId();
+
status_t apply(bool synchronous = false, bool oneWay = false);
// Merge another transaction in to this one, clearing other
// as if it had been applied.
diff --git a/libs/gui/include/gui/test/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h
index 62d1496..08785b4 100644
--- a/libs/gui/include/gui/test/CallbackUtils.h
+++ b/libs/gui/include/gui/test/CallbackUtils.h
@@ -135,7 +135,8 @@
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
const auto& [surfaceControl, latch, acquireTimeOrFence, presentFence,
- previousReleaseFence, transformHint, frameEvents] = surfaceControlStats;
+ previousReleaseFence, transformHint, frameEvents, ignore] =
+ surfaceControlStats;
ASSERT_TRUE(std::holds_alternative<nsecs_t>(acquireTimeOrFence));
ASSERT_EQ(std::get<nsecs_t>(acquireTimeOrFence) > 0,
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index fc68ad2..fa54c7d 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -92,39 +92,6 @@
header_libs: ["libsurfaceflinger_headers"],
}
-// Build a separate binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
-// This test has a main method, and requires a separate binary to be built.
-// To add move tests like this, just add additional cc_test statements,
-// as opposed to adding more source files to this one.
-cc_test {
- name: "SurfaceParcelable_test",
- test_suites: ["device-tests"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- srcs: [
- "SurfaceParcelable_test.cpp",
- ],
-
- shared_libs: [
- "liblog",
- "libbinder",
- "libcutils",
- "libgui",
- "libui",
- "libutils",
- "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
- "libpdx_default_transport",
- ],
-
- header_libs: [
- "libdvr_headers",
- ],
-}
-
cc_test {
name: "SamplingDemo",
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index cb7e94c..b993289 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -161,6 +161,10 @@
ASSERT_EQ(numFramesSubmitted, mBlastBufferQueueAdapter->mSubmitted.size());
}
+ void mergeWithNextTransaction(Transaction* merge, uint64_t frameNumber) {
+ mBlastBufferQueueAdapter->mergeWithNextTransaction(merge, frameNumber);
+ }
+
private:
sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
};
@@ -1111,6 +1115,39 @@
ASSERT_TRUE(receivedCallback);
}
+TEST_F(BLASTBufferQueueTest, SyncNextTransactionDropBuffer) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction sync;
+ adapter.setSyncTransaction(sync);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ // Merge a transaction that has a complete callback into the next frame so we can get notified
+ // when to take a screenshot
+ CallbackHelper transactionCallback;
+ Transaction t;
+ t.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext());
+ adapter.mergeWithNextTransaction(&t, 2);
+ queueBuffer(igbProducer, r, g, b, 0);
+
+ // Drop the buffer, but ensure the next one continues to get processed.
+ sync.setBuffer(mSurfaceControl, nullptr);
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
// This test will currently fail because the old surfacecontrol will steal the last presented buffer
// until the old surface control is destroyed. This is not necessarily a bug but to document a
// limitation with the update API and to test any changes to make the api more robust. The current
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index c6cdeb7..2637f59 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -1184,18 +1184,23 @@
std::vector<sp<IGraphicBufferProducer>> mProducers;
};
-TEST_F(MultiDisplayTests, drop_input_if_layer_on_invalid_display) {
+TEST_F(MultiDisplayTests, drop_touch_if_layer_on_invalid_display) {
ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
// Do not create a display associated with the LayerStack.
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->doTransaction([&](auto &t, auto &sc) { t.setLayerStack(sc, layerStack); });
surface->showAt(100, 100);
+ // Touches should be dropped if the layer is on an invalid display.
injectTapOnDisplay(101, 101, layerStack.id);
- surface->requestFocus(layerStack.id);
- injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
-
EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+ // However, we still let the window be focused and receive keys.
+ surface->requestFocus(layerStack.id);
+ surface->assertFocusChange(true);
+
+ injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
+ surface->expectKey(AKEYCODE_V);
}
TEST_F(MultiDisplayTests, virtual_display_receives_input) {
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 2af2fe1..3427731 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -42,10 +42,6 @@
#define TEST_CONTROLLED_BY_APP false
#define TEST_PRODUCER_USAGE_BITS (0)
-#ifndef USE_BUFFER_HUB_AS_BUFFER_QUEUE
-#define USE_BUFFER_HUB_AS_BUFFER_QUEUE 0
-#endif
-
namespace android {
namespace {
@@ -77,7 +73,6 @@
// Enums to control which IGraphicBufferProducer backend to test.
enum IGraphicBufferProducerTestCode {
USE_BUFFER_QUEUE_PRODUCER = 0,
- USE_BUFFER_HUB_PRODUCER,
};
}; // namespace anonymous
@@ -99,10 +94,6 @@
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
break;
}
- case USE_BUFFER_HUB_PRODUCER: {
- BufferQueue::createBufferHubQueue(&mProducer, &mConsumer);
- break;
- }
default: {
// Should never reach here.
LOG_ALWAYS_FATAL("Invalid test params: %u", GetParam());
@@ -880,11 +871,6 @@
}
TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) {
- if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
- // TODO(b/36724099): Add support for BufferHubProducer::setAsyncMode(true)
- return;
- }
-
ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1;
ASSERT_NO_FATAL_FAILURE(ConnectProducer());
ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true;
@@ -1117,14 +1103,7 @@
}
}
-#if USE_BUFFER_HUB_AS_BUFFER_QUEUE
-INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest,
- ::testing::Values(USE_BUFFER_QUEUE_PRODUCER, USE_BUFFER_HUB_PRODUCER));
-#else
-// TODO(b/70046255): Remove the #ifdef here and always tests both backends once BufferHubQueue can
-// pass all existing libgui tests.
INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest,
::testing::Values(USE_BUFFER_QUEUE_PRODUCER));
-#endif
} // namespace android
diff --git a/libs/gui/tests/SurfaceParcelable_test.cpp b/libs/gui/tests/SurfaceParcelable_test.cpp
deleted file mode 100644
index 686dc82..0000000
--- a/libs/gui/tests/SurfaceParcelable_test.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SurfaceParcelable_test"
-
-#include <gtest/gtest.h>
-
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <gui/BufferHubProducer.h>
-#include <gui/BufferQueue.h>
-#include <gui/view/Surface.h>
-#include <utils/Log.h>
-
-namespace android {
-
-static const String16 kTestServiceName = String16("SurfaceParcelableTestService");
-static const String16 kSurfaceName = String16("TEST_SURFACE");
-static const uint32_t kBufferWidth = 100;
-static const uint32_t kBufferHeight = 1;
-static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-
-enum SurfaceParcelableTestServiceCode {
- CREATE_BUFFER_QUEUE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
- CREATE_BUFFER_HUB_SURFACE,
-};
-
-class SurfaceParcelableTestService : public BBinder {
-public:
- SurfaceParcelableTestService() {
- // BufferQueue
- BufferQueue::createBufferQueue(&mBufferQueueProducer, &mBufferQueueConsumer);
-
- // BufferHub
- dvr::ProducerQueueConfigBuilder configBuilder;
- mProducerQueue = dvr::ProducerQueue::Create(configBuilder.SetDefaultWidth(kBufferWidth)
- .SetDefaultHeight(kBufferHeight)
- .SetDefaultFormat(kBufferFormat)
- .Build(),
- dvr::UsagePolicy{});
- mBufferHubProducer = BufferHubProducer::Create(mProducerQueue);
- }
-
- ~SurfaceParcelableTestService() = default;
-
- virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply,
- uint32_t /*flags*/ = 0) {
- switch (code) {
- case CREATE_BUFFER_QUEUE_SURFACE: {
- view::Surface surfaceShim;
- surfaceShim.name = kSurfaceName;
- surfaceShim.graphicBufferProducer = mBufferQueueProducer;
- return surfaceShim.writeToParcel(reply);
- }
- case CREATE_BUFFER_HUB_SURFACE: {
- view::Surface surfaceShim;
- surfaceShim.name = kSurfaceName;
- surfaceShim.graphicBufferProducer = mBufferHubProducer;
- return surfaceShim.writeToParcel(reply);
- }
- default:
- return UNKNOWN_TRANSACTION;
- };
- }
-
-protected:
- sp<IGraphicBufferProducer> mBufferQueueProducer;
- sp<IGraphicBufferConsumer> mBufferQueueConsumer;
-
- std::shared_ptr<dvr::ProducerQueue> mProducerQueue;
- sp<IGraphicBufferProducer> mBufferHubProducer;
-};
-
-static int runBinderServer() {
- ProcessState::self()->startThreadPool();
-
- sp<IServiceManager> sm = defaultServiceManager();
- sp<SurfaceParcelableTestService> service = new SurfaceParcelableTestService;
- sm->addService(kTestServiceName, service, false);
-
- ALOGI("Binder server running...");
-
- while (true) {
- int stat, retval;
- retval = wait(&stat);
- if (retval == -1 && errno == ECHILD) {
- break;
- }
- }
-
- ALOGI("Binder server exiting...");
- return 0;
-}
-
-class SurfaceParcelableTest : public ::testing::TestWithParam<uint32_t> {
-protected:
- virtual void SetUp() {
- mService = defaultServiceManager()->getService(kTestServiceName);
- if (mService == nullptr) {
- ALOGE("Failed to connect to the test service.");
- return;
- }
-
- ALOGI("Binder service is ready for client.");
- }
-
- status_t GetSurface(view::Surface* surfaceShim) {
- ALOGI("...Test: %d", GetParam());
-
- uint32_t opCode = GetParam();
- Parcel data;
- Parcel reply;
- status_t error = mService->transact(opCode, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("Failed to get surface over binder, error=%d.", error);
- return error;
- }
-
- error = surfaceShim->readFromParcel(&reply);
- if (error != NO_ERROR) {
- ALOGE("Failed to get surface from parcel, error=%d.", error);
- return error;
- }
-
- return NO_ERROR;
- }
-
-private:
- sp<IBinder> mService;
-};
-
-TEST_P(SurfaceParcelableTest, SendOverBinder) {
- view::Surface surfaceShim;
- EXPECT_EQ(GetSurface(&surfaceShim), NO_ERROR);
- EXPECT_EQ(surfaceShim.name, kSurfaceName);
- EXPECT_FALSE(surfaceShim.graphicBufferProducer == nullptr);
-}
-
-INSTANTIATE_TEST_CASE_P(SurfaceBackends, SurfaceParcelableTest,
- ::testing::Values(CREATE_BUFFER_QUEUE_SURFACE, CREATE_BUFFER_HUB_SURFACE));
-
-} // namespace android
-
-int main(int argc, char** argv) {
- pid_t pid = fork();
- if (pid == 0) {
- android::ProcessState::self()->startThreadPool();
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-
- } else {
- ALOGI("Test process pid: %d.", pid);
- return android::runBinderServer();
- }
-}
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 4127f7c..2b7483d 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -64,9 +64,10 @@
}
bool shouldDisregardTransformation(uint32_t source) {
- // Do not apply any transformations to axes from joysticks or touchpads.
+ // Do not apply any transformations to axes from joysticks, touchpads, or relative mice.
return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) ||
- isFromSource(source, AINPUT_SOURCE_CLASS_POSITION);
+ isFromSource(source, AINPUT_SOURCE_CLASS_POSITION) ||
+ isFromSource(source, AINPUT_SOURCE_MOUSE_RELATIVE);
}
bool shouldDisregardOffset(uint32_t source) {
@@ -89,6 +90,25 @@
}
}
+const char* motionToolTypeToString(int32_t toolType) {
+ switch (toolType) {
+ case AMOTION_EVENT_TOOL_TYPE_UNKNOWN:
+ return "UNKNOWN";
+ case AMOTION_EVENT_TOOL_TYPE_FINGER:
+ return "FINGER";
+ case AMOTION_EVENT_TOOL_TYPE_STYLUS:
+ return "STYLUS";
+ case AMOTION_EVENT_TOOL_TYPE_MOUSE:
+ return "MOUSE";
+ case AMOTION_EVENT_TOOL_TYPE_ERASER:
+ return "ERASER";
+ case AMOTION_EVENT_TOOL_TYPE_PALM:
+ return "PALM";
+ default:
+ return "INVALID";
+ }
+}
+
// --- IdGenerator ---
IdGenerator::IdGenerator(Source source) : mSource(source) {}
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index a92016b..4b31246 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -715,10 +715,10 @@
}
TEST_F(MotionEventTest, JoystickAndTouchpadAreNotTransformed) {
- constexpr static std::array kNonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD,
- AMOTION_EVENT_ACTION_DOWN),
- std::pair(AINPUT_SOURCE_JOYSTICK,
- AMOTION_EVENT_ACTION_MOVE)};
+ constexpr static std::array kNonTransformedSources =
+ {std::pair(AINPUT_SOURCE_TOUCHPAD, AMOTION_EVENT_ACTION_DOWN),
+ std::pair(AINPUT_SOURCE_JOYSTICK, AMOTION_EVENT_ACTION_MOVE),
+ std::pair(AINPUT_SOURCE_MOUSE_RELATIVE, AMOTION_EVENT_ACTION_MOVE)};
// Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
ui::Transform transform(ui::Transform::ROT_90, 800, 400);
transform.set(transform.tx() + 20, transform.ty() + 40);
@@ -738,7 +738,7 @@
TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) {
constexpr static std::array kNonPointerSources = {std::pair(AINPUT_SOURCE_TRACKBALL,
AMOTION_EVENT_ACTION_DOWN),
- std::pair(AINPUT_SOURCE_MOUSE_RELATIVE,
+ std::pair(AINPUT_SOURCE_TOUCH_NAVIGATION,
AMOTION_EVENT_ACTION_MOVE)};
// Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
ui::Transform transform(ui::Transform::ROT_90, 800, 400);
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 4a1784e..b2e069c 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "AHardwareBuffer"
+#include <android/hardware_buffer.h>
+#include <android/hardware_buffer_aidl.h>
#include <vndk/hardware_buffer.h>
#include <errno.h>
@@ -32,6 +34,9 @@
#include <android/hardware/graphics/common/1.1/types.h>
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+// TODO: Better way to handle this
+#include "../binder/ndk/parcel_internal.h"
+
static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints
using namespace android;
@@ -412,6 +417,25 @@
return OK;
}
+binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel,
+ AHardwareBuffer* _Nullable* _Nonnull outBuffer) {
+ if (!parcel || !outBuffer) return STATUS_BAD_VALUE;
+ auto buffer = sp<GraphicBuffer>::make();
+ status_t status = parcel->get()->read(*buffer);
+ if (status != STATUS_OK) return status;
+ *outBuffer = AHardwareBuffer_from_GraphicBuffer(buffer.get());
+ AHardwareBuffer_acquire(*outBuffer);
+ return STATUS_OK;
+}
+
+binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer,
+ AParcel* _Nonnull parcel) {
+ const GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer);
+ if (!gb) return STATUS_BAD_VALUE;
+ if (!parcel) return STATUS_BAD_VALUE;
+ return parcel->get()->write(*gb);
+}
+
// ----------------------------------------------------------------------------
// VNDK functions
// ----------------------------------------------------------------------------
@@ -593,15 +617,27 @@
static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_8) ==
AHARDWAREBUFFER_FORMAT_R8_UNORM,
"HAL and AHardwareBuffer pixel format don't match");
+ static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_16_UINT) ==
+ AHARDWAREBUFFER_FORMAT_R16_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RG_1616_UINT) ==
+ AHARDWAREBUFFER_FORMAT_R16G16_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) ==
+ AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
switch (format) {
case AHARDWAREBUFFER_FORMAT_R8_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R16_UINT:
+ case AHARDWAREBUFFER_FORMAT_R16G16_UINT:
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
case AHARDWAREBUFFER_FORMAT_BLOB:
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
@@ -653,6 +689,7 @@
return 1;
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R16_UINT:
return 2;
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
@@ -662,8 +699,10 @@
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+ case AHARDWAREBUFFER_FORMAT_R16G16_UINT:
return 4;
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
return 8;
default:
return 0;
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 18a4b2d..3762e66 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -20,10 +20,15 @@
// from nativewindow/includes/system/window.h
// (not to be confused with the compatibility-only window.h from system/core/includes)
#include <system/window.h>
+#include <android/native_window_aidl.h>
#include <private/android/AHardwareBufferHelpers.h>
+#include <log/log.h>
#include <ui/GraphicBuffer.h>
+#include <gui/Surface.h>
+#include <gui/view/Surface.h>
+#include <android/binder_libbinder.h>
using namespace android;
@@ -59,6 +64,13 @@
return false;
}
}
+static sp<IGraphicBufferProducer> IGraphicBufferProducer_from_ANativeWindow(ANativeWindow* window) {
+ return Surface::getIGraphicBufferProducer(window);
+}
+
+static sp<IBinder> SurfaceControlHandle_from_ANativeWindow(ANativeWindow* window) {
+ return Surface::getSurfaceControlHandle(window);
+}
/**************************************************************************************************
* NDK
@@ -334,6 +346,42 @@
return native_window_set_auto_prerotation(window, autoPrerotation);
}
+binder_status_t ANativeWindow_readFromParcel(
+ const AParcel* _Nonnull parcel, ANativeWindow* _Nullable* _Nonnull outWindow) {
+ const Parcel* nativeParcel = AParcel_viewPlatformParcel(parcel);
+
+ // Use a android::view::Surface to unparcel the window
+ std::shared_ptr<android::view::Surface> shimSurface = std::shared_ptr<android::view::Surface>();
+ status_t ret = shimSurface->readFromParcel(nativeParcel);
+ if (ret != OK) {
+ ALOGE("%s: Error: Failed to create android::view::Surface from AParcel", __FUNCTION__);
+ return STATUS_BAD_VALUE;
+ }
+ sp<Surface> surface = sp<Surface>::make(
+ shimSurface->graphicBufferProducer, false, shimSurface->surfaceControlHandle);
+ ANativeWindow* anw = surface.get();
+ ANativeWindow_acquire(anw);
+ *outWindow = anw;
+ return STATUS_OK;
+}
+
+binder_status_t ANativeWindow_writeToParcel(
+ ANativeWindow* _Nonnull window, AParcel* _Nonnull parcel) {
+ int value;
+ int err = (*window->query)(window, NATIVE_WINDOW_CONCRETE_TYPE, &value);
+ if (err != OK || value != NATIVE_WINDOW_SURFACE) {
+ ALOGE("Error: ANativeWindow is not backed by Surface");
+ return STATUS_BAD_VALUE;
+ }
+ // Use a android::view::Surface to parcelize the window
+ std::shared_ptr<android::view::Surface> shimSurface = std::shared_ptr<android::view::Surface>();
+ shimSurface->graphicBufferProducer = IGraphicBufferProducer_from_ANativeWindow(window);
+ shimSurface->surfaceControlHandle = SurfaceControlHandle_from_ANativeWindow(window);
+
+ Parcel* nativeParcel = AParcel_viewPlatformParcel(parcel);
+ return shimSurface->writeToParcel(nativeParcel);
+}
+
/**************************************************************************************************
* apex-stable
**************************************************************************************************/
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index d7db6bd..bc0bfc5 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -74,6 +74,9 @@
override_export_include_dirs: [
"include",
],
+ export_llndk_headers: [
+ "libarect_headers",
+ ],
},
export_include_dirs: [
"include",
@@ -99,25 +102,27 @@
"liblog",
"libutils",
"libui",
+ "libbinder",
+ "libbinder_ndk",
"android.hardware.graphics.common@1.1",
],
static_libs: [
"libarect",
"libgrallocusage",
+ "libgui_aidl_static",
],
header_libs: [
+ "libgui_headers",
+ "libarect_headers",
"libnativebase_headers",
"libnativewindow_headers",
],
// headers we include in our public headers
- export_static_lib_headers: [
- "libarect",
- ],
-
export_header_lib_headers: [
+ "libarect_headers",
"libnativebase_headers",
],
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index c35507b..b2e8bea 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -173,6 +173,27 @@
* OpenGL ES: GR_GL_R8
*/
AHARDWAREBUFFER_FORMAT_R8_UNORM = 0x38,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R16_UINT
+ * OpenGL ES: GR_GL_R16UI
+ */
+ AHARDWAREBUFFER_FORMAT_R16_UINT = 0x39,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R16G16_UINT
+ * OpenGL ES: GR_GL_RG16UI
+ */
+ AHARDWAREBUFFER_FORMAT_R16G16_UINT = 0x3a,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16
+ * OpenGL ES: N/A
+ */
+ AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM = 0x3b,
};
/**
diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h
new file mode 100644
index 0000000..906d9c6
--- /dev/null
+++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2022 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.
+ */
+
+/**
+ * @file hardware_buffer_aidl.h
+ * @brief HardwareBuffer NDK AIDL glue code
+ */
+
+/**
+ * @addtogroup AHardwareBuffer
+ *
+ * Parcelable support for AHardwareBuffer. Can be used with libbinder_ndk
+ *
+ * @{
+ */
+
+#ifndef ANDROID_HARDWARE_BUFFER_AIDL_H
+#define ANDROID_HARDWARE_BUFFER_AIDL_H
+
+#include <android/binder_parcel.h>
+#include <android/hardware_buffer.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Read an AHardwareBuffer from a AParcel. The output buffer will have an
+ * initial reference acquired and will need to be released with
+ * AHardwareBuffer_release.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success
+ * STATUS_BAD_VALUE if the parcel or outBuffer is null, or if there's an
+ * issue deserializing (eg, corrupted parcel)
+ * STATUS_BAD_TYPE if the parcel's current data position is not that of
+ * an AHardwareBuffer type
+ * STATUS_NO_MEMORY if an allocation fails
+ */
+binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel,
+ AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(34);
+
+/**
+ * Write an AHardwareBuffer to an AParcel.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success.
+ * STATUS_BAD_VALUE if either buffer or parcel is null, or if the AHardwareBuffer*
+ * fails to serialize (eg, internally corrupted)
+ * STATUS_NO_MEMORY if the parcel runs out of space to store the buffer & is
+ * unable to allocate more
+ * STATUS_FDS_NOT_ALLOWED if the parcel does not allow storing FDs
+ */
+binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer,
+ AParcel* _Nonnull parcel) __INTRODUCED_IN(34);
+
+__END_DECLS
+
+// Only enable the AIDL glue helper if this is C++
+#ifdef __cplusplus
+
+namespace aidl::android::hardware {
+
+/**
+ * Wrapper class that enables interop with AIDL NDK generation
+ * Takes ownership of the AHardwareBuffer* given to it in reset() and will automatically
+ * destroy it in the destructor, similar to a smart pointer container
+ */
+class HardwareBuffer {
+public:
+ HardwareBuffer() noexcept {}
+ explicit HardwareBuffer(HardwareBuffer&& other) noexcept : mBuffer(other.release()) {}
+
+ ~HardwareBuffer() {
+ reset();
+ }
+
+ binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
+ reset();
+ return AHardwareBuffer_readFromParcel(parcel, &mBuffer);
+ }
+
+ binder_status_t writeToParcel(AParcel* _Nonnull parcel) const {
+ if (!mBuffer) {
+ return STATUS_BAD_VALUE;
+ }
+ return AHardwareBuffer_writeToParcel(mBuffer, parcel);
+ }
+
+ /**
+ * Destroys any currently owned AHardwareBuffer* and takes ownership of the given
+ * AHardwareBuffer*
+ *
+ * @param buffer The buffer to take ownership of
+ */
+ void reset(AHardwareBuffer* _Nullable buffer = nullptr) noexcept {
+ if (mBuffer) {
+ AHardwareBuffer_release(mBuffer);
+ mBuffer = nullptr;
+ }
+ mBuffer = buffer;
+ }
+
+ inline AHardwareBuffer* _Nullable operator-> () const { return mBuffer; }
+ inline AHardwareBuffer* _Nullable get() const { return mBuffer; }
+ inline explicit operator bool () const { return mBuffer != nullptr; }
+
+ HardwareBuffer& operator=(HardwareBuffer&& other) noexcept {
+ reset(other.release());
+ return *this;
+ }
+
+ /**
+ * Stops managing any contained AHardwareBuffer*, returning it to the caller. Ownership
+ * is released.
+ * @return AHardwareBuffer* or null if this was empty
+ */
+ [[nodiscard]] AHardwareBuffer* _Nullable release() noexcept {
+ AHardwareBuffer* _Nullable ret = mBuffer;
+ mBuffer = nullptr;
+ return ret;
+ }
+
+private:
+ HardwareBuffer(const HardwareBuffer& other) = delete;
+ HardwareBuffer& operator=(const HardwareBuffer& other) = delete;
+
+ AHardwareBuffer* _Nullable mBuffer = nullptr;
+};
+
+} // aidl::android::hardware
+
+#endif // __cplusplus
+
+#endif // ANDROID_HARDWARE_BUFFER_AIDL_H
+
+/** @} */
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index f0e1c4d..a593cd4 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -333,7 +333,7 @@
__INTRODUCED_IN(31);
#ifdef __cplusplus
-};
+}
#endif
#endif // ANDROID_NATIVE_WINDOW_H
diff --git a/libs/nativewindow/include/android/native_window_aidl.h b/libs/nativewindow/include/android/native_window_aidl.h
new file mode 100644
index 0000000..a252245
--- /dev/null
+++ b/libs/nativewindow/include/android/native_window_aidl.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2022 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.
+ */
+
+/**
+ * @file native_window_aidl.h
+ * @brief NativeWindow NDK AIDL glue code
+ */
+
+/**
+ * @addtogroup ANativeWindow
+ *
+ * Parcelable support for ANativeWindow. Can be used with libbinder_ndk
+ *
+ * @{
+ */
+
+#ifndef ANDROID_NATIVE_WINDOW_AIDL_H
+#define ANDROID_NATIVE_WINDOW_AIDL_H
+
+#include <android/binder_parcel.h>
+#include <android/native_window.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Read an ANativeWindow from a AParcel. The output buffer will have an
+ * initial reference acquired and will need to be released with
+ * ANativeWindow_release.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success
+ * STATUS_BAD_VALUE if the parcel or outBuffer is null, or if there's an
+ * issue deserializing (eg, corrupted parcel)
+ * STATUS_BAD_TYPE if the parcel's current data position is not that of
+ * an ANativeWindow type
+ * STATUS_NO_MEMORY if an allocation fails
+ */
+binder_status_t ANativeWindow_readFromParcel(const AParcel* _Nonnull parcel,
+ ANativeWindow* _Nullable* _Nonnull outWindow) __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
+ * Write an ANativeWindow to an AParcel.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success.
+ * STATUS_BAD_VALUE if either buffer or parcel is null, or if the ANativeWindow*
+ * fails to serialize (eg, internally corrupted)
+ * STATUS_NO_MEMORY if the parcel runs out of space to store the buffer & is
+ * unable to allocate more
+ * STATUS_FDS_NOT_ALLOWED if the parcel does not allow storing FDs
+ */
+binder_status_t ANativeWindow_writeToParcel(ANativeWindow* _Nonnull window,
+ AParcel* _Nonnull parcel) __INTRODUCED_IN(__ANDROID_API_U__);
+
+__END_DECLS
+
+// Only enable the AIDL glue helper if this is C++
+#ifdef __cplusplus
+
+namespace aidl::android::hardware {
+
+/**
+ * Wrapper class that enables interop with AIDL NDK generation
+ * Takes ownership of the ANativeWindow* given to it in reset() and will automatically
+ * destroy it in the destructor, similar to a smart pointer container
+ */
+class NativeWindow {
+public:
+ NativeWindow() noexcept {}
+ explicit NativeWindow(ANativeWindow* _Nullable window) {
+ reset(window);
+ }
+
+ explicit NativeWindow(NativeWindow&& other) noexcept {
+ mWindow = other.release(); // steal ownership from r-value
+ }
+
+ ~NativeWindow() {
+ reset();
+ }
+
+ binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
+ reset();
+ return ANativeWindow_readFromParcel(parcel, &mWindow);
+ }
+
+ binder_status_t writeToParcel(AParcel* _Nonnull parcel) const {
+ if (!mWindow) {
+ return STATUS_BAD_VALUE;
+ }
+ return ANativeWindow_writeToParcel(mWindow, parcel);
+ }
+
+ /**
+ * Destroys any currently owned ANativeWindow* and takes ownership of the given
+ * ANativeWindow*
+ *
+ * @param buffer The buffer to take ownership of
+ */
+ void reset(ANativeWindow* _Nullable window = nullptr) noexcept {
+ if (mWindow) {
+ ANativeWindow_release(mWindow);
+ mWindow = nullptr;
+ }
+ if (window != nullptr) {
+ ANativeWindow_acquire(window);
+ }
+ mWindow = window;
+ }
+ inline ANativeWindow* _Nullable operator-> () const { return mWindow; }
+ inline ANativeWindow* _Nullable get() const { return mWindow; }
+ inline explicit operator bool () const { return mWindow != nullptr; }
+
+ NativeWindow& operator=(NativeWindow&& other) noexcept {
+ mWindow = other.release(); // steal ownership from r-value
+ return *this;
+ }
+
+ /**
+ * Stops managing any contained ANativeWindow*, returning it to the caller. Ownership
+ * is released.
+ * @return ANativeWindow* or null if this was empty
+ */
+ [[nodiscard]] ANativeWindow* _Nullable release() noexcept {
+ ANativeWindow* _Nullable ret = mWindow;
+ mWindow = nullptr;
+ return ret;
+ }
+private:
+ ANativeWindow* _Nullable mWindow = nullptr;
+ NativeWindow(const NativeWindow &other) = delete;
+ NativeWindow& operator=(const NativeWindow &other) = delete;
+};
+
+} // aidl::android::hardware
+ //
+namespace aidl::android::view {
+ using Surface = aidl::android::hardware::NativeWindow;
+}
+
+#endif // __cplusplus
+
+#endif // ANDROID_NATIVE_WINDOW_AIDL_H
+
+/** @} */
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index da42a96..d9ac568 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -14,6 +14,8 @@
AHardwareBuffer_release;
AHardwareBuffer_sendHandleToUnixSocket;
AHardwareBuffer_unlock;
+ AHardwareBuffer_readFromParcel; # introduced=34
+ AHardwareBuffer_writeToParcel; # introduced=34
ANativeWindowBuffer_getHardwareBuffer; # llndk
ANativeWindow_OemStorageGet; # llndk
ANativeWindow_OemStorageSet; # llndk
@@ -53,6 +55,8 @@
ANativeWindow_setUsage; # llndk
ANativeWindow_tryAllocateBuffers; # introduced=30
ANativeWindow_unlockAndPost;
+ ANativeWindow_readFromParcel; # introduced=UpsideDownCake
+ ANativeWindow_writeToParcel; # introduced=UpsideDownCake
local:
*;
};
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index 2b93c6e..b6b9cc4 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -21,9 +21,10 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-cc_library_shared {
+cc_library {
name: "libsensor",
+ host_supported: true,
cflags: [
"-Wall",
"-Werror",
diff --git a/libs/shaders/Android.bp b/libs/shaders/Android.bp
index 6b936de..8477479 100644
--- a/libs/shaders/Android.bp
+++ b/libs/shaders/Android.bp
@@ -28,7 +28,7 @@
local_include_dirs: ["include"],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.common-V4-ndk",
"android.hardware.graphics.composer3-V1-ndk",
"android.hardware.graphics.common@1.2",
"libnativewindow",
diff --git a/libs/shaders/tests/Android.bp b/libs/shaders/tests/Android.bp
index cf671bc..718d37b 100644
--- a/libs/shaders/tests/Android.bp
+++ b/libs/shaders/tests/Android.bp
@@ -31,7 +31,7 @@
"libtonemap_headers",
],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.common-V4-ndk",
"android.hardware.graphics.composer3-V1-ndk",
"android.hardware.graphics.common@1.2",
"libnativewindow",
diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp
index 37c9824..eca051d 100644
--- a/libs/tonemap/Android.bp
+++ b/libs/tonemap/Android.bp
@@ -28,7 +28,7 @@
local_include_dirs: ["include"],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.common-V4-ndk",
"android.hardware.graphics.composer3-V1-ndk",
"liblog",
"libnativewindow",
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
index 58851b4..0002d3a 100644
--- a/libs/tonemap/tests/Android.bp
+++ b/libs/tonemap/tests/Android.bp
@@ -31,7 +31,7 @@
"libtonemap_headers",
],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.common-V4-ndk",
"android.hardware.graphics.composer3-V1-ndk",
"libnativewindow",
],
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 0f771a9..98d9b94 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -155,6 +155,8 @@
],
defaults: [
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_shared",
"libui-defaults",
// Uncomment the following line to enable VALIDATE_REGIONS traces
//defaults: ["libui-validate-regions-defaults"],
@@ -164,8 +166,6 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
- "android.hardware.graphics.allocator-V1-ndk",
- "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
@@ -183,7 +183,6 @@
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
"libgralloctypes",
],
diff --git a/libs/ui/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h
index f422ce4..cf5c2e8 100644
--- a/libs/ui/include/ui/PixelFormat.h
+++ b/libs/ui/include/ui/PixelFormat.h
@@ -53,16 +53,19 @@
// real pixel formats supported for rendering -----------------------------
- PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
- PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0
- PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB
- PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB
- PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA
- PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit ARGB
- PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit ARGB
- PIXEL_FORMAT_RGBA_FP16 = HAL_PIXEL_FORMAT_RGBA_FP16, // 64-bit RGBA
- PIXEL_FORMAT_RGBA_1010102 = HAL_PIXEL_FORMAT_RGBA_1010102, // 32-bit RGBA
- PIXEL_FORMAT_R_8 = 0x38,
+ PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
+ PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0
+ PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB
+ PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB
+ PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA
+ PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit ARGB
+ PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit ARGB
+ PIXEL_FORMAT_RGBA_FP16 = HAL_PIXEL_FORMAT_RGBA_FP16, // 64-bit RGBA
+ PIXEL_FORMAT_RGBA_1010102 = HAL_PIXEL_FORMAT_RGBA_1010102, // 32-bit RGBA
+ PIXEL_FORMAT_R_8 = 0x38,
+ PIXEL_FORMAT_R_16_UINT = 0x39,
+ PIXEL_FORMAT_RG_1616_UINT = 0x3a,
+ PIXEL_FORMAT_RGBA_10101010 = 0x3b,
};
typedef int32_t PixelFormat;
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index 83c250a..2af51a7 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -21,31 +21,8 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-cc_library {
- name: "libvibrator",
- vendor_available: true,
- double_loadable: true,
-
- shared_libs: [
- "libbinder",
- "liblog",
- "libutils",
- ],
-
- header_libs: [
- "libaudio_system_headers",
- ],
-
- aidl: {
- include_dirs: ["frameworks/base/core/java"],
- local_include_dirs: ["include/"],
- export_aidl_headers: true,
- },
-
- srcs: [
- ":libvibrator_aidl",
- "*.cpp",
- ],
+cc_defaults {
+ name: "libvibrator_defaults",
cflags: [
"-Wall",
@@ -64,3 +41,54 @@
},
},
}
+
+cc_library {
+ name: "libvibrator",
+ defaults: ["libvibrator_defaults"],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+
+ whole_static_libs: [
+ "libvibratorutils",
+ ],
+
+ header_libs: [
+ "libaudio_system_headers",
+ ],
+
+ aidl: {
+ include_dirs: ["frameworks/base/core/java"],
+ local_include_dirs: ["include/"],
+ export_aidl_headers: true,
+ },
+
+ srcs: [
+ ":libvibrator_aidl",
+ "ExternalVibration.cpp",
+ ],
+}
+
+cc_library {
+ name: "libvibratorutils",
+ defaults: ["libvibrator_defaults"],
+
+ vendor_available: true,
+ double_loadable: true,
+
+ shared_libs: [
+ "libutils",
+ ],
+
+ srcs: [
+ "ExternalVibrationUtils.cpp",
+ ],
+
+ visibility: [
+ "//frameworks/native/libs/vibrator",
+ "//frameworks/av/media/libeffects/hapticgenerator",
+ ],
+}
diff --git a/libs/vibrator/ExternalVibration.cpp b/libs/vibrator/ExternalVibration.cpp
index f6fc19e..ec90645 100644
--- a/libs/vibrator/ExternalVibration.cpp
+++ b/libs/vibrator/ExternalVibration.cpp
@@ -15,11 +15,22 @@
*/
#include <vibrator/ExternalVibration.h>
+#include <vibrator/ExternalVibrationUtils.h>
+#include <android/os/IExternalVibratorService.h>
#include <binder/Parcel.h>
#include <log/log.h>
#include <utils/Errors.h>
+
+// To guarantee if HapticScale enum has the same value as IExternalVibratorService
+static_assert(static_cast<int>(android::os::HapticScale::MUTE) == static_cast<int>(android::os::IExternalVibratorService::SCALE_MUTE));
+static_assert(static_cast<int>(android::os::HapticScale::VERY_LOW) == static_cast<int>(android::os::IExternalVibratorService::SCALE_VERY_LOW));
+static_assert(static_cast<int>(android::os::HapticScale::LOW) == static_cast<int>(android::os::IExternalVibratorService::SCALE_LOW));
+static_assert(static_cast<int>(android::os::HapticScale::NONE) == static_cast<int>(android::os::IExternalVibratorService::SCALE_NONE));
+static_assert(static_cast<int>(android::os::HapticScale::HIGH) == static_cast<int>(android::os::IExternalVibratorService::SCALE_HIGH));
+static_assert(static_cast<int>(android::os::HapticScale::VERY_HIGH) == static_cast<int>(android::os::IExternalVibratorService::SCALE_VERY_HIGH));
+
void writeAudioAttributes(const audio_attributes_t& attrs, android::Parcel* out) {
out->writeInt32(attrs.usage);
out->writeInt32(attrs.content_type);
diff --git a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
index 84357fc..c588bfd 100644
--- a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
+++ b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
@@ -17,17 +17,17 @@
#ifndef ANDROID_EXTERNAL_VIBRATION_UTILS_H
#define ANDROID_EXTERNAL_VIBRATION_UTILS_H
-#include <android/os/IExternalVibratorService.h>
-
namespace android::os {
+// Copied from frameworks/base/core/java/android/os/IExternalVibratorService.aidl
+// The values are checked in ExternalVibration.cpp
enum class HapticScale {
- MUTE = IExternalVibratorService::SCALE_MUTE,
- VERY_LOW = IExternalVibratorService::SCALE_VERY_LOW,
- LOW = IExternalVibratorService::SCALE_LOW,
- NONE = IExternalVibratorService::SCALE_NONE,
- HIGH = IExternalVibratorService::SCALE_HIGH,
- VERY_HIGH = IExternalVibratorService::SCALE_VERY_HIGH,
+ MUTE = -100,
+ VERY_LOW = -2,
+ LOW = -1,
+ NONE = 0,
+ HIGH = 1,
+ VERY_HIGH = 2,
};
bool isValidHapticScale(HapticScale scale);
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
deleted file mode 100644
index 0bda798..0000000
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-sourceFiles = [
- "buffer_hub_queue_client.cpp",
- "buffer_hub_queue_parcelable.cpp",
-]
-
-includeFiles = [
- "include",
-]
-
-staticLibraries = [
- "libbufferhub",
-]
-
-sharedLibraries = [
- "libbinder",
- "libcutils",
- "liblog",
- "libui",
- "libutils",
- "libpdx_default_transport",
-]
-
-headerLibraries = [
- "libdvr_headers",
- "libnativebase_headers",
-]
-
-cc_library_shared {
- name: "libbufferhubqueue",
- cflags: [
- "-DLOG_TAG=\"libbufferhubqueue\"",
- "-DTRACE=0",
- "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
- "-Wall",
- "-Werror",
- "-Wno-format",
- "-Wno-unused-parameter",
- "-Wno-unused-variable",
- ],
- srcs: sourceFiles,
- export_include_dirs: includeFiles,
- export_static_lib_headers: staticLibraries,
- static_libs: staticLibraries,
- shared_libs: sharedLibraries,
- header_libs: headerLibraries,
-}
-
-subdirs = ["benchmarks", "tests"]
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
deleted file mode 100644
index e33e03b..0000000
--- a/libs/vr/libbufferhubqueue/benchmarks/Android.bp
+++ /dev/null
@@ -1,35 +0,0 @@
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_benchmark {
- srcs: ["buffer_transport_benchmark.cpp"],
- shared_libs: [
- "libbase",
- "libbinder",
- "libcutils",
- "libdvr.google",
- "libgui",
- "liblog",
- "libhardware",
- "libui",
- "libutils",
- "libnativewindow",
- "libbufferhubqueue",
- "libpdx_default_transport",
- ],
- cflags: [
- "-DLOG_TAG=\"buffer_transport_benchmark\"",
- "-DTRACE=0",
- "-O2",
- "-Wall",
- "-Werror",
- ],
- name: "buffer_transport_benchmark",
-}
diff --git a/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
deleted file mode 100644
index b6813eb..0000000
--- a/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
+++ /dev/null
@@ -1,589 +0,0 @@
-#include <android-base/logging.h>
-#include <android/native_window.h>
-#include <benchmark/benchmark.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <dvr/dvr_api.h>
-#include <gui/BufferItem.h>
-#include <gui/BufferItemConsumer.h>
-#include <gui/Surface.h>
-#include <private/dvr/epoll_file_descriptor.h>
-#include <utils/Trace.h>
-
-#include <chrono>
-#include <functional>
-#include <iostream>
-#include <thread>
-#include <vector>
-
-#include <dlfcn.h>
-#include <poll.h>
-#include <sys/epoll.h>
-#include <sys/wait.h>
-
-// Use ALWAYS at the tag level. Control is performed manually during command
-// line processing.
-#ifdef ATRACE_TAG
-#undef ATRACE_TAG
-#endif
-#define ATRACE_TAG ATRACE_TAG_ALWAYS
-
-using namespace android;
-using ::benchmark::State;
-
-static const String16 kBinderService = String16("bufferTransport");
-static const uint32_t kBufferWidth = 100;
-static const uint32_t kBufferHeight = 1;
-static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static const uint64_t kBufferUsage =
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
-static const uint32_t kBufferLayer = 1;
-static const int kMaxAcquiredImages = 1;
-static const int kQueueDepth = 2; // We are double buffering for this test.
-static const size_t kMaxQueueCounts = 128;
-static const int kInvalidFence = -1;
-
-enum BufferTransportServiceCode {
- CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION,
-};
-
-// A binder services that minics a compositor that consumes buffers. It provides
-// one Binder interface to create a new Surface for buffer producer to write
-// into; while itself will carry out no-op buffer consuming by acquiring then
-// releasing the buffer immediately.
-class BufferTransportService : public BBinder {
- public:
- BufferTransportService() = default;
- ~BufferTransportService() = default;
-
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0) {
- (void)flags;
- (void)data;
- switch (code) {
- case CREATE_BUFFER_QUEUE: {
- auto new_queue = std::make_shared<BufferQueueHolder>(this);
- reply->writeStrongBinder(
- IGraphicBufferProducer::asBinder(new_queue->producer));
- buffer_queues_.push_back(new_queue);
- return OK;
- }
- default:
- return UNKNOWN_TRANSACTION;
- };
- }
-
- private:
- struct FrameListener : public ConsumerBase::FrameAvailableListener {
- public:
- FrameListener(BufferTransportService* /*service*/,
- sp<BufferItemConsumer> buffer_item_consumer)
- : buffer_item_consumer_(buffer_item_consumer) {}
-
- void onFrameAvailable(const BufferItem& /*item*/) override {
- BufferItem buffer;
- status_t ret = 0;
- {
- ATRACE_NAME("AcquireBuffer");
- ret = buffer_item_consumer_->acquireBuffer(&buffer, /*presentWhen=*/0,
- /*waitForFence=*/false);
- }
-
- if (ret != OK) {
- LOG(ERROR) << "Failed to acquire next buffer.";
- return;
- }
-
- {
- ATRACE_NAME("ReleaseBuffer");
- ret = buffer_item_consumer_->releaseBuffer(buffer);
- }
-
- if (ret != OK) {
- LOG(ERROR) << "Failed to release buffer.";
- return;
- }
- }
-
- private:
- sp<BufferItemConsumer> buffer_item_consumer_;
- };
-
- struct BufferQueueHolder {
- explicit BufferQueueHolder(BufferTransportService* service) {
- BufferQueue::createBufferQueue(&producer, &consumer);
-
- sp<BufferItemConsumer> buffer_item_consumer =
- new BufferItemConsumer(consumer, kBufferUsage, kMaxAcquiredImages,
- /*controlledByApp=*/true);
- buffer_item_consumer->setName(String8("BinderBufferTransport"));
- frame_listener_ = new FrameListener(service, buffer_item_consumer);
- buffer_item_consumer->setFrameAvailableListener(frame_listener_);
- }
-
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
-
- private:
- sp<FrameListener> frame_listener_;
- };
-
- std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
-};
-
-// A virtual interfaces that abstracts the common BufferQueue operations, so
-// that the test suite can use the same test case to drive different types of
-// transport backends.
-class BufferTransport {
- public:
- virtual ~BufferTransport() {}
-
- virtual int Start() = 0;
- virtual sp<Surface> CreateSurface() = 0;
-};
-
-// Binder-based buffer transport backend.
-//
-// On Start() a new process will be swapned to run a Binder server that
-// actually consumes the buffer.
-// On CreateSurface() a new Binder BufferQueue will be created, which the
-// service holds the concrete binder node of the IGraphicBufferProducer while
-// sending the binder proxy to the client. In another word, the producer side
-// operations are carried out process while the consumer side operations are
-// carried out within the BufferTransportService's own process.
-class BinderBufferTransport : public BufferTransport {
- public:
- BinderBufferTransport() {}
-
- int Start() override {
- sp<IServiceManager> sm = defaultServiceManager();
- service_ = sm->getService(kBinderService);
- if (service_ == nullptr) {
- LOG(ERROR) << "Failed to get the benchmark service.";
- return -EIO;
- }
-
- LOG(INFO) << "Binder server is ready for client.";
- return 0;
- }
-
- sp<Surface> CreateSurface() override {
- Parcel data;
- Parcel reply;
- int error = service_->transact(CREATE_BUFFER_QUEUE, data, &reply);
- if (error != OK) {
- LOG(ERROR) << "Failed to get buffer queue over binder.";
- return nullptr;
- }
-
- sp<IBinder> binder;
- error = reply.readNullableStrongBinder(&binder);
- if (error != OK) {
- LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
- return nullptr;
- }
-
- auto producer = interface_cast<IGraphicBufferProducer>(binder);
- if (producer == nullptr) {
- LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
- return nullptr;
- }
-
- sp<Surface> surface = new Surface(producer, /*controlledByApp=*/true);
-
- // Set buffer dimension.
- ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
- ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight,
- kBufferFormat);
-
- return surface;
- }
-
- private:
- sp<IBinder> service_;
-};
-
-class DvrApi {
- public:
- DvrApi() {
- handle_ = dlopen("libdvr.google.so", RTLD_NOW | RTLD_LOCAL);
- CHECK(handle_);
-
- auto dvr_get_api =
- reinterpret_cast<decltype(&dvrGetApi)>(dlsym(handle_, "dvrGetApi"));
- int ret = dvr_get_api(&api_, sizeof(api_), /*version=*/1);
-
- CHECK(ret == 0);
- }
-
- ~DvrApi() { dlclose(handle_); }
-
- const DvrApi_v1& Api() { return api_; }
-
- private:
- void* handle_ = nullptr;
- DvrApi_v1 api_;
-};
-
-// BufferHub/PDX-based buffer transport.
-//
-// On Start() a new thread will be swapned to run an epoll polling thread which
-// minics the behavior of a compositor. Similar to Binder-based backend, the
-// buffer available handler is also a no-op: Buffer gets acquired and released
-// immediately.
-// On CreateSurface() a pair of dvr::ProducerQueue and dvr::ConsumerQueue will
-// be created. The epoll thread holds on the consumer queue and dequeues buffer
-// from it; while the producer queue will be wrapped in a Surface and returned
-// to test suite.
-class BufferHubTransport : public BufferTransport {
- public:
- virtual ~BufferHubTransport() {
- stopped_.store(true);
- if (reader_thread_.joinable()) {
- reader_thread_.join();
- }
- }
-
- int Start() override {
- int ret = epoll_fd_.Create();
- if (ret < 0) {
- LOG(ERROR) << "Failed to create epoll fd: %s", strerror(-ret);
- return -1;
- }
-
- // Create the reader thread.
- reader_thread_ = std::thread([this]() {
- int ret = dvr_.Api().PerformanceSetSchedulerPolicy(0, "graphics");
- if (ret < 0) {
- LOG(ERROR) << "Failed to set scheduler policy, ret=" << ret;
- return;
- }
-
- stopped_.store(false);
- LOG(INFO) << "Reader Thread Running...";
-
- while (!stopped_.load()) {
- std::array<epoll_event, kMaxQueueCounts> events;
-
- // Don't sleep forever so that we will have a chance to wake up.
- const int ret = epoll_fd_.Wait(events.data(), events.size(),
- /*timeout=*/100);
- if (ret < 0) {
- LOG(ERROR) << "Error polling consumer queues.";
- continue;
- }
- if (ret == 0) {
- continue;
- }
-
- const int num_events = ret;
- for (int i = 0; i < num_events; i++) {
- uint32_t index = events[i].data.u32;
- dvr_.Api().ReadBufferQueueHandleEvents(
- buffer_queues_[index]->GetReadQueue());
- }
- }
-
- LOG(INFO) << "Reader Thread Exiting...";
- });
-
- return 0;
- }
-
- sp<Surface> CreateSurface() override {
- auto new_queue = std::make_shared<BufferQueueHolder>();
- if (!new_queue->IsReady()) {
- LOG(ERROR) << "Failed to create BufferHub-based BufferQueue.";
- return nullptr;
- }
-
- // Set buffer dimension.
- ANativeWindow_setBuffersGeometry(new_queue->GetSurface(), kBufferWidth,
- kBufferHeight, kBufferFormat);
-
- // Use the next position as buffer_queue index.
- uint32_t index = buffer_queues_.size();
- epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u32 = index}};
- int queue_fd =
- dvr_.Api().ReadBufferQueueGetEventFd(new_queue->GetReadQueue());
- const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, queue_fd, &event);
- if (ret < 0) {
- LOG(ERROR) << "Failed to track consumer queue: " << strerror(-ret)
- << ", consumer queue fd: " << queue_fd;
- return nullptr;
- }
-
- buffer_queues_.push_back(new_queue);
- ANativeWindow_acquire(new_queue->GetSurface());
- return static_cast<Surface*>(new_queue->GetSurface());
- }
-
- private:
- struct BufferQueueHolder {
- BufferQueueHolder() {
- int ret = 0;
- ret = dvr_.Api().WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kBufferLayer,
- kBufferUsage, 0, sizeof(DvrNativeBufferMetadata), &write_queue_);
- if (ret < 0) {
- LOG(ERROR) << "Failed to create write buffer queue, ret=" << ret;
- return;
- }
-
- ret = dvr_.Api().WriteBufferQueueCreateReadQueue(write_queue_,
- &read_queue_);
- if (ret < 0) {
- LOG(ERROR) << "Failed to create read buffer queue, ret=" << ret;
- return;
- }
-
- ret = dvr_.Api().ReadBufferQueueSetBufferAvailableCallback(
- read_queue_, BufferAvailableCallback, this);
- if (ret < 0) {
- LOG(ERROR) << "Failed to create buffer available callback, ret=" << ret;
- return;
- }
-
- ret =
- dvr_.Api().WriteBufferQueueGetANativeWindow(write_queue_, &surface_);
- if (ret < 0) {
- LOG(ERROR) << "Failed to create surface, ret=" << ret;
- return;
- }
- }
-
- static void BufferAvailableCallback(void* context) {
- BufferQueueHolder* thiz = static_cast<BufferQueueHolder*>(context);
- thiz->HandleBufferAvailable();
- }
-
- DvrReadBufferQueue* GetReadQueue() { return read_queue_; }
-
- ANativeWindow* GetSurface() { return surface_; }
-
- bool IsReady() {
- return write_queue_ != nullptr && read_queue_ != nullptr &&
- surface_ != nullptr;
- }
-
- void HandleBufferAvailable() {
- int ret = 0;
- DvrNativeBufferMetadata meta;
- DvrReadBuffer* buffer = nullptr;
- DvrNativeBufferMetadata metadata;
- int acquire_fence = kInvalidFence;
-
- {
- ATRACE_NAME("AcquireBuffer");
- ret = dvr_.Api().ReadBufferQueueAcquireBuffer(
- read_queue_, 0, &buffer, &metadata, &acquire_fence);
- }
- if (ret < 0) {
- LOG(ERROR) << "Failed to acquire consumer buffer, error: " << ret;
- return;
- }
-
- if (buffer != nullptr) {
- ATRACE_NAME("ReleaseBuffer");
- ret = dvr_.Api().ReadBufferQueueReleaseBuffer(read_queue_, buffer,
- &meta, kInvalidFence);
- }
- if (ret < 0) {
- LOG(ERROR) << "Failed to release consumer buffer, error: " << ret;
- }
- }
-
- private:
- DvrWriteBufferQueue* write_queue_ = nullptr;
- DvrReadBufferQueue* read_queue_ = nullptr;
- ANativeWindow* surface_ = nullptr;
- };
-
- static DvrApi dvr_;
- std::atomic<bool> stopped_;
- std::thread reader_thread_;
-
- dvr::EpollFileDescriptor epoll_fd_;
- std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
-};
-
-DvrApi BufferHubTransport::dvr_ = {};
-
-enum TransportType {
- kBinderBufferTransport,
- kBufferHubTransport,
-};
-
-// Main test suite, which supports two transport backend: 1) BinderBufferQueue,
-// 2) BufferHubQueue. The test case drives the producer end of both transport
-// backend by queuing buffers into the buffer queue by using ANativeWindow API.
-class BufferTransportBenchmark : public ::benchmark::Fixture {
- public:
- void SetUp(State& state) override {
- if (state.thread_index == 0) {
- const int transport = state.range(0);
- switch (transport) {
- case kBinderBufferTransport:
- transport_.reset(new BinderBufferTransport);
- break;
- case kBufferHubTransport:
- transport_.reset(new BufferHubTransport);
- break;
- default:
- CHECK(false) << "Unknown test case.";
- break;
- }
-
- CHECK(transport_);
- const int ret = transport_->Start();
- CHECK_EQ(ret, 0);
-
- LOG(INFO) << "Transport backend running, transport=" << transport << ".";
-
- // Create surfaces for each thread.
- surfaces_.resize(state.threads);
- for (int i = 0; i < state.threads; i++) {
- // Common setup every thread needs.
- surfaces_[i] = transport_->CreateSurface();
- CHECK(surfaces_[i]);
-
- LOG(INFO) << "Surface initialized on thread " << i << ".";
- }
- }
- }
-
- void TearDown(State& state) override {
- if (state.thread_index == 0) {
- surfaces_.clear();
- transport_.reset();
- LOG(INFO) << "Tear down benchmark.";
- }
- }
-
- protected:
- std::unique_ptr<BufferTransport> transport_;
- std::vector<sp<Surface>> surfaces_;
-};
-
-BENCHMARK_DEFINE_F(BufferTransportBenchmark, Producers)(State& state) {
- ANativeWindow* window = nullptr;
- ANativeWindow_Buffer buffer;
- int32_t error = 0;
- double total_gain_buffer_us = 0;
- double total_post_buffer_us = 0;
- int iterations = 0;
-
- while (state.KeepRunning()) {
- if (window == nullptr) {
- CHECK(surfaces_[state.thread_index]);
- window = static_cast<ANativeWindow*>(surfaces_[state.thread_index].get());
-
- // Lock buffers a couple time from the queue, so that we have the buffer
- // allocated.
- for (int i = 0; i < kQueueDepth; i++) {
- error = ANativeWindow_lock(window, &buffer,
- /*inOutDirtyBounds=*/nullptr);
- CHECK_EQ(error, 0);
- error = ANativeWindow_unlockAndPost(window);
- CHECK_EQ(error, 0);
- }
- }
-
- {
- ATRACE_NAME("GainBuffer");
- auto t1 = std::chrono::high_resolution_clock::now();
- error = ANativeWindow_lock(window, &buffer,
- /*inOutDirtyBounds=*/nullptr);
- auto t2 = std::chrono::high_resolution_clock::now();
- std::chrono::duration<double, std::micro> delta_us = t2 - t1;
- total_gain_buffer_us += delta_us.count();
- }
- CHECK_EQ(error, 0);
-
- {
- ATRACE_NAME("PostBuffer");
- auto t1 = std::chrono::high_resolution_clock::now();
- error = ANativeWindow_unlockAndPost(window);
- auto t2 = std::chrono::high_resolution_clock::now();
- std::chrono::duration<double, std::micro> delta_us = t2 - t1;
- total_post_buffer_us += delta_us.count();
- }
- CHECK_EQ(error, 0);
-
- iterations++;
- }
-
- state.counters["gain_buffer_us"] = ::benchmark::Counter(
- total_gain_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
- state.counters["post_buffer_us"] = ::benchmark::Counter(
- total_post_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
- state.counters["producer_us"] = ::benchmark::Counter(
- (total_gain_buffer_us + total_post_buffer_us) / iterations,
- ::benchmark::Counter::kAvgThreads);
-}
-
-BENCHMARK_REGISTER_F(BufferTransportBenchmark, Producers)
- ->Unit(::benchmark::kMicrosecond)
- ->Ranges({{kBinderBufferTransport, kBufferHubTransport}})
- ->ThreadRange(1, 32);
-
-static void runBinderServer() {
- ProcessState::self()->setThreadPoolMaxThreadCount(0);
- ProcessState::self()->startThreadPool();
-
- sp<IServiceManager> sm = defaultServiceManager();
- sp<BufferTransportService> service = new BufferTransportService;
- sm->addService(kBinderService, service, false);
-
- LOG(INFO) << "Binder server running...";
-
- while (true) {
- int stat, retval;
- retval = wait(&stat);
- if (retval == -1 && errno == ECHILD) {
- break;
- }
- }
-
- LOG(INFO) << "Service Exiting...";
-}
-
-// To run binder-based benchmark, use:
-// adb shell buffer_transport_benchmark \
-// --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/0/"
-//
-// To run bufferhub-based benchmark, use:
-// adb shell buffer_transport_benchmark \
-// --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/1/"
-int main(int argc, char** argv) {
- bool tracing_enabled = false;
-
- // Parse arguments in addition to "--benchmark_filter" paramters.
- for (int i = 1; i < argc; i++) {
- if (std::string(argv[i]) == "--help") {
- std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl;
- std::cout << "\t--trace: Enable systrace logging." << std::endl;
- return 0;
- }
- if (std::string(argv[i]) == "--trace") {
- tracing_enabled = true;
- continue;
- }
- }
-
- // Setup ATRACE/systrace based on command line.
- atrace_setup();
- atrace_set_tracing_enabled(tracing_enabled);
-
- pid_t pid = fork();
- if (pid == 0) {
- // Child, i.e. the client side.
- ProcessState::self()->startThreadPool();
-
- ::benchmark::Initialize(&argc, argv);
- ::benchmark::RunSpecifiedBenchmarks();
- } else {
- LOG(INFO) << "Benchmark process pid: " << pid;
- runBinderServer();
- }
-}
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
deleted file mode 100644
index 2d3fa4a..0000000
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ /dev/null
@@ -1,823 +0,0 @@
-#include "include/private/dvr/buffer_hub_queue_client.h"
-
-#include <inttypes.h>
-#include <log/log.h>
-#include <poll.h>
-#include <sys/epoll.h>
-
-#include <array>
-
-#include <pdx/default_transport/client_channel.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <pdx/file_handle.h>
-#include <pdx/trace.h>
-
-#define RETRY_EINTR(fnc_call) \
- ([&]() -> decltype(fnc_call) { \
- decltype(fnc_call) result; \
- do { \
- result = (fnc_call); \
- } while (result == -1 && errno == EINTR); \
- return result; \
- })()
-
-using android::pdx::ErrorStatus;
-using android::pdx::LocalChannelHandle;
-using android::pdx::LocalHandle;
-using android::pdx::Status;
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-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))} {
- Initialize();
-}
-
-BufferHubQueue::BufferHubQueue(const std::string& endpoint_path)
- : Client{
- pdx::default_transport::ClientChannelFactory::Create(endpoint_path)} {
- Initialize();
-}
-
-void BufferHubQueue::Initialize() {
- int ret = epoll_fd_.Create();
- if (ret < 0) {
- ALOGE("BufferHubQueue::BufferHubQueue: Failed to create epoll fd: %s",
- strerror(-ret));
- return;
- }
-
- 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("%s: Failed to add event fd to epoll set: %s", __FUNCTION__,
- strerror(-ret));
- }
-}
-
-Status<void> BufferHubQueue::ImportQueue() {
- auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>();
- if (!status) {
- ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
- status.GetErrorMessage().c_str());
- return ErrorStatus(status.error());
- } else {
- SetupQueue(status.get());
- return {};
- }
-}
-
-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;
- user_metadata_size_ = queue_info.producer_config.user_metadata_size;
- id_ = queue_info.id;
-}
-
-std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
- if (auto status = CreateConsumerQueueHandle(/*silent*/ false))
- return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
- else
- return nullptr;
-}
-
-std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateSilentConsumerQueue() {
- if (auto status = CreateConsumerQueueHandle(/*silent*/ true))
- return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
- else
- return nullptr;
-}
-
-Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle(
- bool silent) {
- auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>(silent);
- if (!status) {
- ALOGE(
- "BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: "
- "%s",
- status.GetErrorMessage().c_str());
- return ErrorStatus(status.error());
- }
-
- return status;
-}
-
-pdx::Status<ConsumerQueueParcelable>
-BufferHubQueue::CreateConsumerQueueParcelable(bool silent) {
- auto status = CreateConsumerQueueHandle(silent);
- if (!status)
- return status.error_status();
-
- // A temporary consumer queue client to pull its channel parcelable.
- auto consumer_queue =
- std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
- ConsumerQueueParcelable queue_parcelable(
- consumer_queue->GetChannel()->TakeChannelParcelable());
-
- if (!queue_parcelable.IsValid()) {
- ALOGE("%s: Failed to create consumer queue parcelable.", __FUNCTION__);
- return ErrorStatus(EINVAL);
- }
-
- return {std::move(queue_parcelable)};
-}
-
-bool BufferHubQueue::WaitForBuffers(int timeout) {
- ATRACE_NAME("BufferHubQueue::WaitForBuffers");
- std::array<epoll_event, kMaxEvents> events;
-
- // Loop at least once to check for hangups.
- do {
- ALOGD_IF(
- TRACE,
- "BufferHubQueue::WaitForBuffers: queue_id=%d count=%zu capacity=%zu",
- id(), count(), capacity());
-
- // If there is already a buffer then just check for hangup without waiting.
- const int ret = epoll_fd_.Wait(events.data(), events.size(),
- count() == 0 ? timeout : 0);
-
- if (ret == 0) {
- ALOGI_IF(TRACE,
- "BufferHubQueue::WaitForBuffers: No events before timeout: "
- "queue_id=%d",
- id());
- return count() != 0;
- }
-
- if (ret < 0 && ret != -EINTR) {
- ALOGE("%s: Failed to wait for buffers: %s", __FUNCTION__, strerror(-ret));
- return false;
- }
-
- const int num_events = ret;
-
- // A BufferQueue's epoll fd tracks N+1 events, where there are N events,
- // one for each buffer in the queue, and one extra event for the queue
- // client itself.
- for (int i = 0; i < num_events; i++) {
- int32_t event_fd;
- int32_t index;
- std::tie(event_fd, index) = Unstuff(events[i].data.u64);
-
- PDX_TRACE_FORMAT(
- "epoll_event|queue_id=%d;num_events=%d;event_index=%d;event_fd=%d;"
- "slot=%d|",
- id(), num_events, i, event_fd, index);
-
- ALOGD_IF(TRACE,
- "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), event_fd,
- events[i].events);
- } else if (is_queue_event_index(index)) {
- HandleQueueEvent(events[i].events);
- } else {
- ALOGW(
- "BufferHubQueue::WaitForBuffers: Unknown event type event_fd=%d "
- "index=%d",
- event_fd, index);
- }
- }
- } while (count() == 0 && capacity() > 0 && !hung_up());
-
- return count() != 0;
-}
-
-Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd,
- int poll_events) {
- ATRACE_NAME("BufferHubQueue::HandleBufferEvent");
- if (!buffers_[slot]) {
- ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
- return ErrorStatus(ENOENT);
- }
-
- auto status = buffers_[slot]->GetEventMask(poll_events);
- if (!status) {
- ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- const int events = status.get();
- PDX_TRACE_FORMAT(
- "buffer|queue_id=%d;buffer_id=%d;slot=%zu;event_fd=%d;poll_events=%x;"
- "events=%d|",
- id(), buffers_[slot]->id(), slot, event_fd, poll_events, events);
-
- if (events & EPOLLIN) {
- return Enqueue({buffers_[slot], slot, buffers_[slot]->GetQueueIndex()});
- } else if (events & EPOLLHUP) {
- ALOGW(
- "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu "
- "event_fd=%d buffer_id=%d",
- slot, buffers_[slot]->event_fd(), buffers_[slot]->id());
- return RemoveBuffer(slot);
- } else {
- ALOGW(
- "BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll "
- "events=%d",
- slot, events);
- }
-
- return {};
-}
-
-Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) {
- ATRACE_NAME("BufferHubQueue::HandleQueueEvent");
- auto status = GetEventMask(poll_event);
- if (!status) {
- ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- const int events = status.get();
- if (events & EPOLLIN) {
- // Note that after buffer imports, if |count()| still returns 0, epoll
- // wait will be tried again to acquire the newly imported buffer.
- auto buffer_status = OnBufferAllocated();
- if (!buffer_status) {
- ALOGE("%s: Failed to import buffer: %s", __FUNCTION__,
- buffer_status.GetErrorMessage().c_str());
- }
- } else if (events & EPOLLHUP) {
- ALOGD_IF(TRACE, "%s: hang up event!", __FUNCTION__);
- hung_up_ = true;
- } else {
- ALOGW("%s: Unknown epoll events=%x", __FUNCTION__, events);
- }
-
- return {};
-}
-
-Status<void> BufferHubQueue::AddBuffer(
- const std::shared_ptr<BufferHubBase>& buffer, size_t slot) {
- ALOGD_IF(TRACE, "%s: buffer_id=%d slot=%zu", __FUNCTION__, buffer->id(),
- slot);
-
- if (is_full()) {
- ALOGE("%s: queue is at maximum capacity: %zu", __FUNCTION__, capacity_);
- return ErrorStatus(E2BIG);
- }
-
- 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.
- auto remove_status = RemoveBuffer(slot);
- if (!remove_status)
- return remove_status.error_status();
- }
-
- for (const auto& event_source : buffer->GetEventSources()) {
- epoll_event event = {.events = event_source.event_mask | EPOLLET,
- .data = {.u64 = Stuff(buffer->event_fd(), slot)}};
- const int ret =
- epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event);
- if (ret < 0) {
- ALOGE("%s: Failed to add buffer to epoll set: %s", __FUNCTION__,
- strerror(-ret));
- return ErrorStatus(-ret);
- }
- }
-
- buffers_[slot] = buffer;
- capacity_++;
- return {};
-}
-
-Status<void> BufferHubQueue::RemoveBuffer(size_t slot) {
- ALOGD_IF(TRACE, "%s: slot=%zu", __FUNCTION__, slot);
-
- if (buffers_[slot]) {
- for (const auto& event_source : buffers_[slot]->GetEventSources()) {
- const int ret =
- epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr);
- if (ret < 0) {
- ALOGE("%s: Failed to remove buffer from epoll set: %s", __FUNCTION__,
- strerror(-ret));
- return ErrorStatus(-ret);
- }
- }
-
- // Trigger OnBufferRemoved callback if registered.
- if (on_buffer_removed_)
- on_buffer_removed_(buffers_[slot]);
-
- buffers_[slot] = nullptr;
- capacity_--;
- }
-
- return {};
-}
-
-Status<void> BufferHubQueue::Enqueue(Entry entry) {
- if (!is_full()) {
- // Find and remove the enqueued buffer from unavailable_buffers_slot if
- // exist.
- auto enqueued_buffer_iter = std::find_if(
- unavailable_buffers_slot_.begin(), unavailable_buffers_slot_.end(),
- [&entry](size_t slot) -> bool { return slot == entry.slot; });
- if (enqueued_buffer_iter != unavailable_buffers_slot_.end()) {
- unavailable_buffers_slot_.erase(enqueued_buffer_iter);
- }
-
- available_buffers_.push(std::move(entry));
-
- // Trigger OnBufferAvailable callback if registered.
- if (on_buffer_available_)
- on_buffer_available_();
-
- return {};
- } else {
- ALOGE("%s: Buffer queue is full!", __FUNCTION__);
- return ErrorStatus(E2BIG);
- }
-}
-
-Status<std::shared_ptr<BufferHubBase>> BufferHubQueue::Dequeue(int timeout,
- size_t* slot) {
- ALOGD_IF(TRACE, "%s: count=%zu, timeout=%d", __FUNCTION__, count(), timeout);
-
- PDX_TRACE_FORMAT("%s|count=%zu|", __FUNCTION__, count());
-
- if (count() == 0) {
- if (!WaitForBuffers(timeout))
- return ErrorStatus(ETIMEDOUT);
- }
-
- auto& entry = available_buffers_.top();
- PDX_TRACE_FORMAT("buffer|buffer_id=%d;slot=%zu|", entry.buffer->id(),
- entry.slot);
-
- std::shared_ptr<BufferHubBase> buffer = std::move(entry.buffer);
- *slot = entry.slot;
-
- available_buffers_.pop();
- unavailable_buffers_slot_.push_back(*slot);
-
- return {std::move(buffer)};
-}
-
-void BufferHubQueue::SetBufferAvailableCallback(
- BufferAvailableCallback callback) {
- on_buffer_available_ = callback;
-}
-
-void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) {
- on_buffer_removed_ = callback;
-}
-
-pdx::Status<void> BufferHubQueue::FreeAllBuffers() {
- // Clear all available buffers.
- while (!available_buffers_.empty())
- available_buffers_.pop();
-
- pdx::Status<void> last_error; // No error.
- // Clear all buffers this producer queue is tracking.
- for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
- if (buffers_[slot] != nullptr) {
- auto status = RemoveBuffer(slot);
- if (!status) {
- ALOGE(
- "ProducerQueue::FreeAllBuffers: Failed to remove buffer at "
- "slot=%zu.",
- slot);
- last_error = status.error_status();
- }
- }
- }
-
- return last_error;
-}
-
-ProducerQueue::ProducerQueue(LocalChannelHandle handle)
- : BASE(std::move(handle)) {
- auto status = ImportQueue();
- if (!status) {
- ALOGE("ProducerQueue::ProducerQueue: Failed to import queue: %s",
- status.GetErrorMessage().c_str());
- Close(-status.error());
- }
-}
-
-ProducerQueue::ProducerQueue(const ProducerQueueConfig& config,
- const UsagePolicy& usage)
- : BASE(BufferHubRPC::kClientPath) {
- auto status =
- InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(config, usage);
- if (!status) {
- ALOGE("ProducerQueue::ProducerQueue: Failed to create producer queue: %s",
- status.GetErrorMessage().c_str());
- Close(-status.error());
- return;
- }
-
- SetupQueue(status.get());
-}
-
-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 (buffer_count == 0) {
- return {std::vector<size_t>()};
- }
-
- 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);
- }
-
- Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
- InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
- width, height, layer_count, format, usage, buffer_count);
- if (!status) {
- ALOGE("ProducerQueue::AllocateBuffers: failed to allocate buffers: %s",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- auto buffer_handle_slots = status.take();
- LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != buffer_count,
- "BufferHubRPC::ProducerQueueAllocateBuffers should "
- "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(ProducerBuffer::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() != buffer_count) {
- // Error out if the count of imported buffer(s) is not correct.
- ALOGE(
- "ProducerQueue::AllocateBuffers: requested to import %zu "
- "buffers, but actually imported %zu buffers.",
- buffer_count, buffer_slots.size());
- return ErrorStatus(ENOMEM);
- }
-
- return {std::move(buffer_slots)};
-}
-
-Status<size_t> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
- uint32_t layer_count,
- uint32_t format, uint64_t usage) {
- // We only allocate one buffer at a time.
- constexpr size_t buffer_count = 1;
- auto status =
- AllocateBuffers(width, height, layer_count, format, usage, buffer_count);
- if (!status) {
- ALOGE("ProducerQueue::AllocateBuffer: Failed to allocate buffer: %s",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- return {status.get()[0]};
-}
-
-Status<void> ProducerQueue::AddBuffer(
- const std::shared_ptr<ProducerBuffer>& buffer, size_t slot) {
- ALOGD_IF(TRACE, "ProducerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
- id(), buffer->id(), slot);
- // For producer buffer, we need to enqueue the newly added buffer
- // immediately. Producer queue starts with all buffers in available state.
- auto status = BufferHubQueue::AddBuffer(buffer, slot);
- if (!status)
- return status;
-
- return BufferHubQueue::Enqueue({buffer, slot, 0ULL});
-}
-
-Status<size_t> ProducerQueue::InsertBuffer(
- const std::shared_ptr<ProducerBuffer>& buffer) {
- if (buffer == nullptr ||
- !BufferHubDefs::isClientGained(buffer->buffer_state(),
- buffer->client_state_mask())) {
- ALOGE(
- "ProducerQueue::InsertBuffer: Can only insert a buffer when it's in "
- "gained state.");
- return ErrorStatus(EINVAL);
- }
-
- auto status_or_slot =
- InvokeRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>(
- buffer->cid());
- if (!status_or_slot) {
- ALOGE(
- "ProducerQueue::InsertBuffer: Failed to insert producer buffer: "
- "buffer_cid=%d, error: %s.",
- buffer->cid(), status_or_slot.GetErrorMessage().c_str());
- return status_or_slot.error_status();
- }
-
- size_t slot = status_or_slot.get();
-
- // Note that we are calling AddBuffer() from the base class to explicitly
- // avoid Enqueue() the ProducerBuffer.
- auto status = BufferHubQueue::AddBuffer(buffer, slot);
- if (!status) {
- ALOGE("ProducerQueue::InsertBuffer: Failed to add buffer: %s.",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
- return {slot};
-}
-
-Status<void> ProducerQueue::RemoveBuffer(size_t slot) {
- auto status =
- InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
- if (!status) {
- ALOGE("%s: Failed to remove producer buffer: %s", __FUNCTION__,
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- return BufferHubQueue::RemoveBuffer(slot);
-}
-
-Status<std::shared_ptr<ProducerBuffer>> ProducerQueue::Dequeue(
- int timeout, size_t* slot, LocalHandle* release_fence) {
- DvrNativeBufferMetadata canonical_meta;
- return Dequeue(timeout, slot, &canonical_meta, release_fence);
-}
-
-pdx::Status<std::shared_ptr<ProducerBuffer>> ProducerQueue::Dequeue(
- int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* release_fence, bool gain_posted_buffer) {
- ATRACE_NAME("ProducerQueue::Dequeue");
- if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) {
- ALOGE("%s: Invalid parameter.", __FUNCTION__);
- return ErrorStatus(EINVAL);
- }
-
- std::shared_ptr<ProducerBuffer> buffer;
- Status<std::shared_ptr<BufferHubBase>> dequeue_status =
- BufferHubQueue::Dequeue(timeout, slot);
- if (dequeue_status.ok()) {
- buffer = std::static_pointer_cast<ProducerBuffer>(dequeue_status.take());
- } else {
- if (gain_posted_buffer) {
- Status<std::shared_ptr<ProducerBuffer>> dequeue_unacquired_status =
- ProducerQueue::DequeueUnacquiredBuffer(slot);
- if (!dequeue_unacquired_status.ok()) {
- ALOGE("%s: DequeueUnacquiredBuffer returned error: %d", __FUNCTION__,
- dequeue_unacquired_status.error());
- return dequeue_unacquired_status.error_status();
- }
- buffer = dequeue_unacquired_status.take();
- } else {
- return dequeue_status.error_status();
- }
- }
- const int ret =
- buffer->GainAsync(out_meta, release_fence, gain_posted_buffer);
- if (ret < 0 && ret != -EALREADY)
- return ErrorStatus(-ret);
-
- return {std::move(buffer)};
-}
-
-Status<std::shared_ptr<ProducerBuffer>> ProducerQueue::DequeueUnacquiredBuffer(
- size_t* slot) {
- if (unavailable_buffers_slot_.size() < 1) {
- ALOGE(
- "%s: Failed to dequeue un-acquired buffer. All buffer(s) are in "
- "acquired state if exist.",
- __FUNCTION__);
- return ErrorStatus(ENOMEM);
- }
-
- // Find the first buffer that is not in acquired state from
- // unavailable_buffers_slot_.
- for (auto iter = unavailable_buffers_slot_.begin();
- iter != unavailable_buffers_slot_.end(); iter++) {
- std::shared_ptr<ProducerBuffer> buffer = ProducerQueue::GetBuffer(*iter);
- if (buffer == nullptr) {
- ALOGE("%s failed. Buffer slot %d is null.", __FUNCTION__,
- static_cast<int>(*slot));
- return ErrorStatus(EIO);
- }
- if (!BufferHubDefs::isAnyClientAcquired(buffer->buffer_state())) {
- *slot = *iter;
- unavailable_buffers_slot_.erase(iter);
- unavailable_buffers_slot_.push_back(*slot);
- ALOGD("%s: Producer queue dequeue unacquired buffer in slot %d",
- __FUNCTION__, static_cast<int>(*slot));
- return {std::move(buffer)};
- }
- }
- ALOGE(
- "%s: Failed to dequeue un-acquired buffer. No un-acquired buffer exist.",
- __FUNCTION__);
- return ErrorStatus(EBUSY);
-}
-
-pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
- if (capacity() != 0) {
- ALOGE(
- "%s: producer queue can only be taken out as a parcelable when empty. "
- "Current queue capacity: %zu",
- __FUNCTION__, capacity());
- return ErrorStatus(EINVAL);
- }
-
- std::unique_ptr<pdx::ClientChannel> channel = TakeChannel();
- ProducerQueueParcelable queue_parcelable(channel->TakeChannelParcelable());
-
- // Here the queue parcelable is returned and holds the underlying system
- // resources backing the queue; while the original client channel of this
- // producer queue is destroyed in place so that this client can no longer
- // provide producer operations.
- return {std::move(queue_parcelable)};
-}
-
-/*static */
-std::unique_ptr<ConsumerQueue> ConsumerQueue::Import(
- LocalChannelHandle handle) {
- return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(std::move(handle)));
-}
-
-ConsumerQueue::ConsumerQueue(LocalChannelHandle handle)
- : BufferHubQueue(std::move(handle)) {
- auto status = ImportQueue();
- if (!status) {
- ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
- status.GetErrorMessage().c_str());
- Close(-status.error());
- }
-
- auto import_status = ImportBuffers();
- if (import_status) {
- ALOGI("%s: Imported %zu buffers.", __FUNCTION__, import_status.get());
- } else {
- ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
- import_status.GetErrorMessage().c_str());
- }
-}
-
-Status<size_t> ConsumerQueue::ImportBuffers() {
- auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
- if (!status) {
- if (status.error() == EBADR) {
- ALOGI("%s: Queue is silent, no buffers imported.", __FUNCTION__);
- return {0};
- } else {
- ALOGE("%s: Failed to import consumer buffer: %s", __FUNCTION__,
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
- }
-
- int ret;
- Status<void> last_error;
- size_t imported_buffers_count = 0;
-
- auto buffer_handle_slots = status.take();
- for (auto& buffer_handle_slot : buffer_handle_slots) {
- ALOGD_IF(TRACE, ": buffer_handle=%d", __FUNCTION__,
- buffer_handle_slot.first.value());
-
- std::unique_ptr<ConsumerBuffer> consumer_buffer =
- ConsumerBuffer::Import(std::move(buffer_handle_slot.first));
- if (!consumer_buffer) {
- ALOGE("%s: Failed to import buffer: slot=%zu", __FUNCTION__,
- buffer_handle_slot.second);
- last_error = ErrorStatus(EPIPE);
- continue;
- }
-
- auto add_status =
- AddBuffer(std::move(consumer_buffer), buffer_handle_slot.second);
- if (!add_status) {
- ALOGE("%s: Failed to add buffer: %s", __FUNCTION__,
- add_status.GetErrorMessage().c_str());
- last_error = add_status;
- } else {
- imported_buffers_count++;
- }
- }
-
- if (imported_buffers_count > 0)
- return {imported_buffers_count};
- else
- return last_error.error_status();
-}
-
-Status<void> ConsumerQueue::AddBuffer(
- const std::shared_ptr<ConsumerBuffer>& buffer, size_t slot) {
- ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu", __FUNCTION__, id(),
- buffer->id(), slot);
- return BufferHubQueue::AddBuffer(buffer, slot);
-}
-
-Status<std::shared_ptr<ConsumerBuffer>> ConsumerQueue::Dequeue(
- int timeout, size_t* slot, void* meta, size_t user_metadata_size,
- LocalHandle* acquire_fence) {
- if (user_metadata_size != user_metadata_size_) {
- ALOGE(
- "%s: Metadata size (%zu) for the dequeuing buffer does not match "
- "metadata size (%zu) for the queue.",
- __FUNCTION__, user_metadata_size, user_metadata_size_);
- return ErrorStatus(EINVAL);
- }
-
- DvrNativeBufferMetadata canonical_meta;
- auto status = Dequeue(timeout, slot, &canonical_meta, acquire_fence);
- if (!status)
- return status.error_status();
-
- if (meta && user_metadata_size) {
- void* metadata_src =
- reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
- if (metadata_src) {
- memcpy(meta, metadata_src, user_metadata_size);
- } else {
- ALOGW("%s: no user-defined metadata.", __FUNCTION__);
- }
- }
-
- return status;
-}
-
-Status<std::shared_ptr<ConsumerBuffer>> ConsumerQueue::Dequeue(
- int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* acquire_fence) {
- ATRACE_NAME("ConsumerQueue::Dequeue");
- if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) {
- ALOGE("%s: Invalid parameter.", __FUNCTION__);
- return ErrorStatus(EINVAL);
- }
-
- auto status = BufferHubQueue::Dequeue(timeout, slot);
- if (!status)
- return status.error_status();
-
- auto buffer = std::static_pointer_cast<ConsumerBuffer>(status.take());
- const int ret = buffer->AcquireAsync(out_meta, acquire_fence);
- if (ret < 0)
- return ErrorStatus(-ret);
-
- return {std::move(buffer)};
-}
-
-Status<void> ConsumerQueue::OnBufferAllocated() {
- ALOGD_IF(TRACE, "%s: queue_id=%d", __FUNCTION__, id());
-
- auto status = ImportBuffers();
- if (!status) {
- ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
- status.GetErrorMessage().c_str());
- return ErrorStatus(status.error());
- } else if (status.get() == 0) {
- ALOGW("%s: No new buffers allocated!", __FUNCTION__);
- return ErrorStatus(ENOBUFS);
- } else {
- ALOGD_IF(TRACE, "%s: Imported %zu consumer buffers.", __FUNCTION__,
- status.get());
- return {};
- }
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
deleted file mode 100644
index f705749..0000000
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#include "include/private/dvr/buffer_hub_queue_parcelable.h"
-
-#include <binder/Parcel.h>
-#include <pdx/default_transport/channel_parcelable.h>
-
-namespace android {
-namespace dvr {
-
-template <BufferHubQueueParcelableMagic Magic>
-bool BufferHubQueueParcelable<Magic>::IsValid() const {
- return !!channel_parcelable_ && channel_parcelable_->IsValid();
-}
-
-template <BufferHubQueueParcelableMagic Magic>
-pdx::LocalChannelHandle BufferHubQueueParcelable<Magic>::TakeChannelHandle() {
- if (!IsValid()) {
- ALOGE(
- "BufferHubQueueParcelable::TakeChannelHandle: Invalid channel parcel.");
- return {}; // Returns an empty channel handle.
- }
-
- // Take channel handle out of the parcelable and reset the parcelable.
- pdx::LocalChannelHandle handle = channel_parcelable_->TakeChannelHandle();
- // Now channel_parcelable_ should already be invalid, but reset it to release
- // the invalid parcelable object from unique_ptr.
- channel_parcelable_ = nullptr;
- return handle;
-}
-
-template <BufferHubQueueParcelableMagic Magic>
-status_t BufferHubQueueParcelable<Magic>::writeToParcel(Parcel* parcel) const {
- if (!IsValid()) {
- ALOGE("BufferHubQueueParcelable::writeToParcel: Invalid channel.");
- return -EINVAL;
- }
-
- status_t res = parcel->writeUint32(Magic);
- if (res != OK) {
- ALOGE("BufferHubQueueParcelable::writeToParcel: Cannot write magic.");
- return res;
- }
-
- return channel_parcelable_->writeToParcel(parcel);
-}
-
-template <BufferHubQueueParcelableMagic Magic>
-status_t BufferHubQueueParcelable<Magic>::readFromParcel(const Parcel* parcel) {
- if (IsValid()) {
- ALOGE(
- "BufferHubQueueParcelable::readFromParcel: This parcelable object has "
- "been initialized already.");
- return -EINVAL;
- }
-
- uint32_t out_magic = 0;
- status_t res = OK;
-
- res = parcel->readUint32(&out_magic);
- if (res != OK)
- return res;
-
- if (out_magic != Magic) {
- ALOGE(
- "BufferHubQueueParcelable::readFromParcel: Unexpected magic: 0x%x, "
- "epxected: 0x%x",
- out_magic, Magic);
- return -EINVAL;
- }
-
- // (Re)Alocate channel parcelable object.
- channel_parcelable_ =
- std::make_unique<pdx::default_transport::ChannelParcelable>();
- return channel_parcelable_->readFromParcel(parcel);
-}
-
-template class BufferHubQueueParcelable<
- BufferHubQueueParcelableMagic::Producer>;
-template class BufferHubQueueParcelable<
- BufferHubQueueParcelableMagic::Consumer>;
-
-} // namespace dvr
-} // namespace android
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
deleted file mode 100644
index 74b4b3d..0000000
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ /dev/null
@@ -1,476 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
-#define ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
-
-#include <ui/BufferQueueDefs.h>
-
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Weverything"
-#endif
-
-// The following headers are included without checking every warning.
-// TODO(b/72172820): Remove the workaround once we have enforced -Weverything
-// in these headers and their dependencies.
-#include <pdx/client.h>
-#include <pdx/status.h>
-#include <private/dvr/buffer_hub_queue_parcelable.h>
-#include <private/dvr/bufferhub_rpc.h>
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/epoll_file_descriptor.h>
-#include <private/dvr/producer_buffer.h>
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-#include <memory>
-#include <queue>
-#include <vector>
-
-namespace android {
-namespace dvr {
-
-class ConsumerQueue;
-
-// |BufferHubQueue| manages a queue of |BufferHubBase|s. Buffers are
-// automatically re-requeued when released by the remote side.
-class BufferHubQueue : public pdx::Client {
- public:
- using BufferAvailableCallback = std::function<void()>;
- using BufferRemovedCallback =
- std::function<void(const std::shared_ptr<BufferHubBase>&)>;
-
- virtual ~BufferHubQueue() {}
-
- // 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();
-
- // 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();
-
- // 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_; }
-
- // Returns the default buffer height of this buffer queue.
- uint32_t default_height() const { return default_height_; }
-
- // Returns the default buffer format of this buffer queue.
- uint32_t default_format() const { return default_format_; }
-
- // Creates a new consumer in handle form for immediate transport over RPC.
- pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
- bool silent = false);
-
- // Creates a new consumer in parcelable form for immediate transport over
- // Binder.
- pdx::Status<ConsumerQueueParcelable> CreateConsumerQueueParcelable(
- bool silent = false);
-
- // Returns the number of buffers avaiable for dequeue.
- size_t count() const { return available_buffers_.size(); }
-
- // Returns the total number of buffers that the queue is tracking.
- size_t capacity() const { return capacity_; }
-
- // Returns the size of metadata structure associated with this queue.
- size_t metadata_size() const { return user_metadata_size_; }
-
- // Returns whether the buffer queue is full.
- bool is_full() const {
- return available_buffers_.size() >= kMaxQueueCapacity;
- }
-
- // Returns whether the buffer queue is connected to bufferhubd.
- bool is_connected() const { return !!GetChannel(); }
-
- int GetBufferId(size_t slot) const {
- return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
- : -1;
- }
-
- std::shared_ptr<BufferHubBase> GetBuffer(size_t slot) const {
- return buffers_[slot];
- }
-
- pdx::Status<int> GetEventMask(int events) {
- if (auto* client_channel = GetChannel()) {
- return client_channel->GetEventMask(events);
- } else {
- return pdx::ErrorStatus(EINVAL);
- }
- }
-
- // Returns an fd that signals pending queue events using
- // EPOLLIN/POLLIN/readible. Either HandleQueueEvents or WaitForBuffers may be
- // called to handle pending queue events.
- int queue_fd() const { return epoll_fd_.Get(); }
-
- // Handles any pending events, returning available buffers to the queue and
- // reaping disconnected buffers. Returns true if successful, false if an error
- // occurred.
- bool HandleQueueEvents() { return WaitForBuffers(0); }
-
- // 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);
-
- // The queue tracks at most this many buffers.
- static constexpr size_t kMaxQueueCapacity =
- android::BufferQueueDefs::NUM_BUFFER_SLOTS;
-
- static constexpr int kNoTimeOut = -1;
-
- int id() const { return id_; }
- bool hung_up() const { return hung_up_; }
-
- protected:
- explicit BufferHubQueue(pdx::LocalChannelHandle channel);
- explicit BufferHubQueue(const std::string& endpoint_path);
-
- // Imports the queue parameters by querying BufferHub for the parameters for
- // this channel.
- pdx::Status<void> ImportQueue();
-
- // Sets up the queue with the given parameters.
- void SetupQueue(const QueueInfo& queue_info);
-
- // 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<BufferHubBase>& buffer,
- size_t slot);
-
- // Called by ProducerQueue::RemoveBuffer and ConsumerQueue::RemoveBuffer only
- // to deregister a buffer for epoll and internal bookkeeping.
- virtual pdx::Status<void> RemoveBuffer(size_t slot);
-
- // Free all buffers that belongs to this queue. Can only be called from
- // producer side.
- virtual pdx::Status<void> FreeAllBuffers();
-
- // 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
- // immediately, even if no buffers are available.
- pdx::Status<std::shared_ptr<BufferHubBase>> Dequeue(int timeout,
- size_t* slot);
-
- // Waits for buffers to become available and adds them to the available queue.
- bool WaitForBuffers(int timeout);
-
- pdx::Status<void> HandleBufferEvent(size_t slot, int event_fd,
- int poll_events);
- pdx::Status<void> HandleQueueEvent(int poll_events);
-
- // Entry in the priority queue of available buffers that stores related
- // per-buffer data.
- struct Entry {
- Entry() : slot(0) {}
- Entry(const std::shared_ptr<BufferHubBase>& in_buffer, size_t in_slot,
- uint64_t in_index)
- : buffer(in_buffer), slot(in_slot), index(in_index) {}
- Entry(const std::shared_ptr<BufferHubBase>& in_buffer,
- std::unique_ptr<uint8_t[]> in_metadata, pdx::LocalHandle in_fence,
- size_t in_slot)
- : buffer(in_buffer),
- metadata(std::move(in_metadata)),
- fence(std::move(in_fence)),
- slot(in_slot) {}
- Entry(Entry&&) = default;
- Entry& operator=(Entry&&) = default;
-
- std::shared_ptr<BufferHubBase> buffer;
- std::unique_ptr<uint8_t[]> metadata;
- pdx::LocalHandle fence;
- size_t slot;
- uint64_t index;
- };
-
- struct EntryComparator {
- bool operator()(const Entry& lhs, const Entry& rhs) {
- return lhs.index > rhs.index;
- }
- };
-
- // Enqueues a buffer to the available list (Gained for producer or Acquireed
- // for consumer).
- pdx::Status<void> Enqueue(Entry entry);
-
- // 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 user_metadata_size_{0};
-
- // Buffers and related data that are available for dequeue.
- std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
- available_buffers_;
-
- // Slot of the buffers that are not available for normal dequeue. For example,
- // the slot of posted or acquired buffers in the perspective of a producer.
- std::vector<size_t> unavailable_buffers_slot_;
-
- 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:
- // 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) {
- return index >= 0 &&
- index < static_cast<int64_t>(BufferHubQueue::kMaxQueueCapacity);
- }
-
- // When |index| == kEpollQueueEventIndex it refers to the queue itself.
- static bool is_queue_event_index(int64_t index) {
- return index == BufferHubQueue::kEpollQueueEventIndex;
- }
-
- // 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};
-
- // Default buffer width that is set during ProducerQueue's creation.
- uint32_t default_width_{1};
-
- // Default buffer height that is set during ProducerQueue's creation.
- uint32_t default_height_{1};
-
- // Default buffer format that is set during ProducerQueue's creation.
- uint32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888
-
- // 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::array<std::shared_ptr<BufferHubBase>, kMaxQueueCapacity> buffers_;
-
- // Keeps track with how many buffers have been added into the queue.
- size_t capacity_{0};
-
- // Epoll fd used to manage buffer events.
- EpollFileDescriptor epoll_fd_;
-
- // Flag indicating that the other side hung up. For ProducerQueues this
- // triggers when BufferHub dies or explicitly closes the queue channel. For
- // ConsumerQueues this can either mean the same or that the ProducerQueue on
- // the other end hung up.
- bool hung_up_{false};
-
- // Global id for the queue that is consistent across processes.
- int id_{-1};
-
- // Buffer event callbacks
- BufferAvailableCallback on_buffer_available_;
- BufferRemovedCallback on_buffer_removed_;
-
- BufferHubQueue(const BufferHubQueue&) = delete;
- void operator=(BufferHubQueue&) = delete;
-};
-
-class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> {
- public:
- // 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
- // |usage_set_mask| takes precedence over |usage_clear_mask|. All buffer
- // allocation through this producer queue shall not have any of the usage bits
- // in |usage_deny_set_mask| set. Allocation calls violating this will be
- // rejected. All buffer allocation through this producer queue must have all
- // the usage bits in |usage_deny_clear_mask| set. Allocation calls violating
- // 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.
- 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(pdx::LocalChannelHandle handle) {
- return BASE::Create(std::move(handle));
- }
-
- // Get a producer buffer. 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 ProducerBuffer.
- std::shared_ptr<ProducerBuffer> GetBuffer(size_t slot) const {
- return std::static_pointer_cast<ProducerBuffer>(
- 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 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 GAINED state).
- pdx::Status<void> AddBuffer(const std::shared_ptr<ProducerBuffer>& buffer,
- size_t slot);
-
- // Inserts a ProducerBuffer into the queue. On success, the method returns the
- // |slot| number where the new buffer gets inserted. Note that the buffer
- // being inserted should be in Gain'ed state prior to the call and it's
- // considered as already Dequeued when the function returns.
- pdx::Status<size_t> InsertBuffer(
- const std::shared_ptr<ProducerBuffer>& buffer);
-
- // Remove producer buffer from the queue.
- pdx::Status<void> RemoveBuffer(size_t slot) override;
-
- // Free all buffers on this producer queue.
- pdx::Status<void> FreeAllBuffers() override {
- return BufferHubQueue::FreeAllBuffers();
- }
-
- // 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.
- // @return a buffer in gained state, which was originally in released state.
- pdx::Status<std::shared_ptr<ProducerBuffer>> Dequeue(
- int timeout, size_t* slot, pdx::LocalHandle* release_fence);
-
- // 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.
- //
- // @param timeout to dequeue a buffer.
- // @param slot is the slot of the output ProducerBuffer.
- // @param release_fence for gaining a buffer.
- // @param out_meta metadata of the output buffer.
- // @param gain_posted_buffer whether to gain posted buffer if no released
- // buffer is available to gain.
- // @return a buffer in gained state, which was originally in released state if
- // gain_posted_buffer is false, or in posted/released state if
- // gain_posted_buffer is true.
- // TODO(b/112007999): gain_posted_buffer true is only used to prevent
- // libdvrtracking from starving when there are non-responding clients. This
- // gain_posted_buffer param can be removed once libdvrtracking start to use
- // the new AHardwareBuffer API.
- pdx::Status<std::shared_ptr<ProducerBuffer>> Dequeue(
- int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* release_fence, bool gain_posted_buffer = false);
-
- // Enqueues a producer buffer in the queue.
- pdx::Status<void> Enqueue(const std::shared_ptr<ProducerBuffer>& buffer,
- size_t slot, uint64_t index) {
- return BufferHubQueue::Enqueue({buffer, slot, index});
- }
-
- // Takes out the current producer queue as a binder parcelable object. Note
- // that the queue must be empty to be exportable. After successful export, the
- // producer queue client should no longer be used.
- pdx::Status<ProducerQueueParcelable> TakeAsParcelable();
-
- private:
- friend BASE;
-
- // Constructors are automatically exposed through ProducerQueue::Create(...)
- // static template methods inherited from ClientBase, which take the same
- // arguments as the constructors.
- explicit ProducerQueue(pdx::LocalChannelHandle handle);
- ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
-
- // 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.
- //
- // @param slot the slot of the returned buffer.
- // @return a buffer in gained state, which was originally in posted state or
- // released state.
- pdx::Status<std::shared_ptr<ProducerBuffer>> DequeueUnacquiredBuffer(
- size_t* slot);
-};
-
-class ConsumerQueue : public BufferHubQueue {
- public:
- // Get a consumer buffer. Note that the method doesn't check whether the
- // buffer slot has a valid buffer that has been imported already. When no
- // buffer has been imported before it returns nullptr; otherwise returns a
- // shared pointer to a ConsumerBuffer.
- std::shared_ptr<ConsumerBuffer> GetBuffer(size_t slot) const {
- return std::static_pointer_cast<ConsumerBuffer>(
- BufferHubQueue::GetBuffer(slot));
- }
-
- // Import a ConsumerQueue from a channel handle. |ignore_on_import| controls
- // whether or not buffers are set to be ignored when imported. This may be
- // 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(pdx::LocalChannelHandle handle);
-
- // Import newly created buffers from the service side.
- // Returns number of buffers successfully imported or an error.
- 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
- // the buffer to the producer side. |meta| is passed along from BufferHub,
- // The user of ProducerBuffer is responsible with making sure that the
- // Dequeue() is done with the corect metadata type and size with those used
- // when the buffer is orignally created.
- template <typename Meta>
- pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue(
- 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<ConsumerBuffer>> Dequeue(
- int timeout, size_t* slot, pdx::LocalHandle* acquire_fence) {
- return Dequeue(timeout, slot, nullptr, 0, acquire_fence);
- }
-
- pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue(
- int timeout, size_t* slot, void* meta, size_t user_metadata_size,
- pdx::LocalHandle* acquire_fence);
- pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue(
- int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* acquire_fence);
-
- private:
- friend BufferHubQueue;
-
- explicit ConsumerQueue(pdx::LocalChannelHandle handle);
-
- // 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.
- pdx::Status<void> AddBuffer(const std::shared_ptr<ConsumerBuffer>& buffer,
- size_t slot);
-
- pdx::Status<void> OnBufferAllocated() override;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
deleted file mode 100644
index 36ab5f6..0000000
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
-#define ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
-
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Weverything"
-#endif
-
-// The following headers are included without checking every warning.
-// TODO(b/72172820): Remove the workaround once we have enforced -Weverything
-// in these headers and their dependencies.
-#include <pdx/channel_parcelable.h>
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-namespace android {
-namespace dvr {
-
-enum BufferHubQueueParcelableMagic : uint32_t {
- Producer = 0x62687170, // 'bhqp'
- Consumer = 0x62687163, // 'bhqc'
-};
-
-template <BufferHubQueueParcelableMagic Magic>
-class BufferHubQueueParcelable : public Parcelable {
- public:
- BufferHubQueueParcelable() = default;
-
- BufferHubQueueParcelable(BufferHubQueueParcelable&& other) noexcept = default;
- BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) noexcept {
- channel_parcelable_ = std::move(other.channel_parcelable_);
- return *this;
- }
-
- // Constructs an parcelable contains the channel parcelable.
- explicit BufferHubQueueParcelable(
- std::unique_ptr<pdx::ChannelParcelable> channel_parcelable)
- : channel_parcelable_(std::move(channel_parcelable)) {}
-
- BufferHubQueueParcelable(const BufferHubQueueParcelable&) = delete;
- void operator=(const BufferHubQueueParcelable&) = delete;
-
- bool IsValid() const;
-
- // Returns a channel handle constructed from this parcelable object and takes
- // the ownership of all resources from the parcelable object.
- pdx::LocalChannelHandle TakeChannelHandle();
-
- // Serializes the queue parcelable into the given parcel. Note that no system
- // resources are getting duplicated, nor did the parcel takes ownership of the
- // queue parcelable. Thus, the parcelable object must remain valid for the
- // lifetime of the parcel.
- status_t writeToParcel(Parcel* parcel) const override;
-
- // Deserialize the queue parcelable from the given parcel. Note that system
- // resources are duplicated from the parcel into the queue parcelable. Returns
- // error if the targeting parcelable object is already valid.
- status_t readFromParcel(const Parcel* parcel) override;
-
- private:
- std::unique_ptr<pdx::ChannelParcelable> channel_parcelable_;
-};
-
-using ProducerQueueParcelable =
- BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Producer>;
-using ConsumerQueueParcelable =
- BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Consumer>;
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
deleted file mode 100644
index 2f14f7c..0000000
--- a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
-#define ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
-
-#include <android-base/unique_fd.h>
-#include <log/log.h>
-#include <sys/epoll.h>
-
-namespace android {
-namespace dvr {
-
-class EpollFileDescriptor {
- public:
- static const int CTL_ADD = EPOLL_CTL_ADD;
- static const int CTL_MOD = EPOLL_CTL_MOD;
- static const int CTL_DEL = EPOLL_CTL_DEL;
-
- EpollFileDescriptor() : fd_(-1) {}
-
- // Constructs an EpollFileDescriptor from an integer file descriptor and
- // takes ownership.
- explicit EpollFileDescriptor(int fd) : fd_(fd) {}
-
- bool IsValid() const { return fd_.get() >= 0; }
-
- int Create() {
- if (IsValid()) {
- ALOGW("epoll fd has already been created.");
- return -EALREADY;
- }
-
- fd_.reset(epoll_create1(EPOLL_CLOEXEC));
-
- if (fd_.get() < 0)
- return -errno;
- else
- return 0;
- }
-
- int Control(int op, int target_fd, epoll_event* ev) {
- if (epoll_ctl(fd_.get(), op, target_fd, ev) < 0)
- return -errno;
- else
- return 0;
- }
-
- int Wait(epoll_event* events, int maxevents, int timeout) {
- int ret = epoll_wait(fd_.get(), events, maxevents, timeout);
-
- if (ret < 0)
- return -errno;
- else
- return ret;
- }
-
- int Get() const { return fd_.get(); }
-
- private:
- base::unique_fd fd_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
deleted file mode 100644
index 33a0d75..0000000
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ /dev/null
@@ -1,66 +0,0 @@
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-header_libraries = [
- "libdvr_headers",
-]
-
-shared_libraries = [
- "libbase",
- "libbinder",
- "libbufferhubqueue",
- "libcutils",
- "libgui",
- "liblog",
- "libhardware",
- "libui",
- "libutils",
- "libnativewindow",
- "libpdx_default_transport",
-]
-
-static_libraries = [
- "libchrome",
- "libdvrcommon",
- "libperformance",
-]
-
-cc_test {
- srcs: ["buffer_hub_queue-test.cpp"],
- header_libs: header_libraries,
- static_libs: static_libraries,
- shared_libs: shared_libraries,
- cflags: [
- "-DLOG_TAG=\"buffer_hub_queue-test\"",
- "-DTRACE=0",
- "-O0",
- "-g",
- "-Wall",
- "-Werror",
- "-Wno-error=sign-compare", // to fix later
- ],
- name: "buffer_hub_queue-test",
-}
-
-cc_test {
- srcs: ["buffer_hub_queue_producer-test.cpp"],
- header_libs: header_libraries,
- static_libs: static_libraries,
- shared_libs: shared_libraries,
- cflags: [
- "-DLOG_TAG=\"buffer_hub_queue_producer-test\"",
- "-DTRACE=0",
- "-O0",
- "-g",
- "-Wall",
- "-Werror",
- ],
- name: "buffer_hub_queue_producer-test",
-}
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
deleted file mode 100644
index 6ae603b..0000000
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ /dev/null
@@ -1,1083 +0,0 @@
-#include <base/logging.h>
-#include <binder/Parcel.h>
-#include <dvr/dvr_api.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/producer_buffer.h>
-
-#include <gtest/gtest.h>
-#include <poll.h>
-#include <sys/eventfd.h>
-
-#include <vector>
-
-// Enable/disable debug logging.
-#define TRACE 0
-
-namespace android {
-namespace dvr {
-
-using pdx::LocalChannelHandle;
-using pdx::LocalHandle;
-
-namespace {
-
-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;
-constexpr int kTimeoutMs = 100;
-constexpr int kNoTimeout = 0;
-
-class BufferHubQueueTest : public ::testing::Test {
- public:
- bool CreateProducerQueue(const ProducerQueueConfig& config,
- const UsagePolicy& usage) {
- producer_queue_ = ProducerQueue::Create(config, usage);
- return producer_queue_ != nullptr;
- }
-
- bool CreateConsumerQueue() {
- if (producer_queue_) {
- consumer_queue_ = producer_queue_->CreateConsumerQueue();
- return consumer_queue_ != nullptr;
- } else {
- return false;
- }
- }
-
- bool CreateQueues(const ProducerQueueConfig& config,
- const UsagePolicy& usage) {
- return CreateProducerQueue(config, usage) && CreateConsumerQueue();
- }
-
- void AllocateBuffer(size_t* slot_out = nullptr) {
- // Create producer buffer.
- 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;
- }
-
- bool WaitAndHandleOnce(BufferHubQueue* queue, int timeout_ms) {
- pollfd pfd{queue->queue_fd(), POLLIN, 0};
- int ret;
- do {
- ret = poll(&pfd, 1, timeout_ms);
- } while (ret == -1 && errno == EINTR);
-
- if (ret < 0) {
- ALOGW("Failed to poll queue %d's event fd, error: %s.", queue->id(),
- strerror(errno));
- return false;
- } else if (ret == 0) {
- return false;
- }
- return queue->HandleQueueEvents();
- }
-
- protected:
- ProducerQueueConfigBuilder config_builder_;
- std::unique_ptr<ProducerQueue> producer_queue_;
- std::unique_ptr<ConsumerQueue> consumer_queue_;
-};
-
-TEST_F(BufferHubQueueTest, TestDequeue) {
- const int64_t nb_dequeue_times = 16;
-
- ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
- // Allocate only one buffer.
- AllocateBuffer();
-
- // But dequeue multiple times.
- for (int64_t i = 0; i < nb_dequeue_times; i++) {
- size_t slot;
- LocalHandle fence;
- DvrNativeBufferMetadata mi, mo;
-
- // Producer gains a buffer.
- auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- EXPECT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(p1, nullptr);
-
- // Producer posts the buffer.
- mi.index = i;
- EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
-
- // Consumer acquires a buffer.
- auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- EXPECT_TRUE(c1_status.ok()) << c1_status.GetErrorMessage();
- auto c1 = c1_status.take();
- ASSERT_NE(c1, nullptr);
- EXPECT_EQ(mi.index, i);
- EXPECT_EQ(mo.index, i);
-
- // Consumer releases the buffer.
- EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
- }
-}
-
-TEST_F(BufferHubQueueTest,
- TestDequeuePostedBufferIfNoAvailableReleasedBuffer_withConsumerBuffer) {
- ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
- // Allocate 3 buffers to use.
- const size_t test_queue_capacity = 3;
- for (int64_t i = 0; i < test_queue_capacity; i++) {
- AllocateBuffer();
- }
- EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
-
- size_t producer_slot, consumer_slot;
- LocalHandle fence;
- DvrNativeBufferMetadata mi, mo;
-
- // Producer posts 2 buffers and remember their posted sequence.
- std::deque<size_t> posted_slots;
- for (int64_t i = 0; i < 2; i++) {
- auto p1_status =
- producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
- EXPECT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(p1, nullptr);
-
- // Producer should not be gaining posted buffer when there are still
- // available buffers to gain.
- auto found_iter =
- std::find(posted_slots.begin(), posted_slots.end(), producer_slot);
- EXPECT_EQ(found_iter, posted_slots.end());
- posted_slots.push_back(producer_slot);
-
- // Producer posts the buffer.
- mi.index = i;
- EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
- }
-
- // Consumer acquires one buffer.
- auto c1_status =
- consumer_queue_->Dequeue(kTimeoutMs, &consumer_slot, &mo, &fence);
- EXPECT_TRUE(c1_status.ok());
- auto c1 = c1_status.take();
- ASSERT_NE(c1, nullptr);
- // Consumer should get the oldest posted buffer. No checks here.
- // posted_slots[0] should be in acquired state now.
- EXPECT_EQ(mo.index, 0);
- // Consumer releases the buffer.
- EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
- // posted_slots[0] should be in released state now.
-
- // Producer gain and post 2 buffers.
- for (int64_t i = 0; i < 2; i++) {
- auto p1_status =
- producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
- EXPECT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(p1, nullptr);
-
- // The gained buffer should be the one in released state or the one haven't
- // been use.
- EXPECT_NE(posted_slots[1], producer_slot);
-
- mi.index = i + 2;
- EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
- }
-
- // Producer gains a buffer.
- auto p1_status =
- producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
- EXPECT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(p1, nullptr);
-
- // The gained buffer should be the oldest posted buffer.
- EXPECT_EQ(posted_slots[1], producer_slot);
-
- // Producer posts the buffer.
- mi.index = 4;
- EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
-}
-
-TEST_F(BufferHubQueueTest,
- TestDequeuePostedBufferIfNoAvailableReleasedBuffer_noConsumerBuffer) {
- ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
- // Allocate 4 buffers to use.
- const size_t test_queue_capacity = 4;
- for (int64_t i = 0; i < test_queue_capacity; i++) {
- AllocateBuffer();
- }
- EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
-
- // Post all allowed buffers and remember their posted sequence.
- std::deque<size_t> posted_slots;
- for (int64_t i = 0; i < test_queue_capacity; i++) {
- size_t slot;
- LocalHandle fence;
- DvrNativeBufferMetadata mi, mo;
-
- // Producer gains a buffer.
- auto p1_status =
- producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
- EXPECT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(p1, nullptr);
-
- // Producer should not be gaining posted buffer when there are still
- // available buffers to gain.
- auto found_iter = std::find(posted_slots.begin(), posted_slots.end(), slot);
- EXPECT_EQ(found_iter, posted_slots.end());
- posted_slots.push_back(slot);
-
- // Producer posts the buffer.
- mi.index = i;
- EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
- }
-
- // Gain posted buffers in sequence.
- const int64_t nb_dequeue_all_times = 2;
- for (int j = 0; j < nb_dequeue_all_times; ++j) {
- for (int i = 0; i < test_queue_capacity; ++i) {
- size_t slot;
- LocalHandle fence;
- DvrNativeBufferMetadata mi, mo;
-
- // Producer gains a buffer.
- auto p1_status =
- producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
- EXPECT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(p1, nullptr);
-
- // The gained buffer should be the oldest posted buffer.
- EXPECT_EQ(posted_slots[i], slot);
-
- // Producer posts the buffer.
- mi.index = i + test_queue_capacity * (j + 1);
- EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
- }
- }
-}
-
-TEST_F(BufferHubQueueTest, TestProducerConsumer) {
- const size_t kBufferCount = 16;
- size_t slot;
- DvrNativeBufferMetadata mi, mo;
- LocalHandle fence;
-
- ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
- for (size_t i = 0; i < kBufferCount; i++) {
- AllocateBuffer();
-
- // Producer queue has all the available buffers on initialize.
- ASSERT_EQ(producer_queue_->count(), i + 1);
- ASSERT_EQ(producer_queue_->capacity(), i + 1);
-
- // Consumer queue has no avaiable buffer on initialize.
- ASSERT_EQ(consumer_queue_->count(), 0U);
- // Consumer queue does not import buffers until a dequeue is issued.
- ASSERT_EQ(consumer_queue_->capacity(), i);
- // Dequeue returns timeout since no buffer is ready to consumer, but
- // this implicitly triggers buffer import and bump up |capacity|.
- auto status = consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence);
- ASSERT_FALSE(status.ok());
- ASSERT_EQ(ETIMEDOUT, status.error());
- ASSERT_EQ(consumer_queue_->capacity(), i + 1);
- }
-
- // Use eventfd as a stand-in for a fence.
- LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-
- for (size_t i = 0; i < kBufferCount; i++) {
- // First time there is no buffer available to dequeue.
- auto consumer_status =
- consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence);
- ASSERT_FALSE(consumer_status.ok());
- ASSERT_EQ(consumer_status.error(), ETIMEDOUT);
-
- // 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(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(producer_status.ok());
- auto producer = producer_status.take();
- ASSERT_NE(nullptr, producer);
-
- mi.index = static_cast<int64_t>(i);
- ASSERT_EQ(producer->PostAsync(&mi, post_fence), 0);
-
- // Second time the just the POSTED buffer should be dequeued.
- consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(consumer_status.ok());
- EXPECT_TRUE(fence.IsValid());
-
- auto consumer = consumer_status.take();
- ASSERT_NE(nullptr, consumer);
- ASSERT_EQ(mi.index, mo.index);
- }
-}
-
-TEST_F(BufferHubQueueTest, TestInsertBuffer) {
- ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
-
- consumer_queue_ = producer_queue_->CreateConsumerQueue();
- ASSERT_TRUE(consumer_queue_ != nullptr);
- EXPECT_EQ(producer_queue_->capacity(), 0);
- EXPECT_EQ(consumer_queue_->capacity(), 0);
-
- std::shared_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
- kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage, 0);
- ASSERT_TRUE(p1 != nullptr);
- ASSERT_EQ(p1->GainAsync(), 0);
-
- // Inserting a posted buffer will fail.
- DvrNativeBufferMetadata meta;
- EXPECT_EQ(p1->PostAsync(&meta, LocalHandle()), 0);
- auto status_or_slot = producer_queue_->InsertBuffer(p1);
- EXPECT_FALSE(status_or_slot.ok());
- EXPECT_EQ(status_or_slot.error(), EINVAL);
-
- // Inserting a gained buffer will succeed.
- std::shared_ptr<ProducerBuffer> p2 = ProducerBuffer::Create(
- kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage);
- ASSERT_EQ(p2->GainAsync(), 0);
- ASSERT_TRUE(p2 != nullptr);
- status_or_slot = producer_queue_->InsertBuffer(p2);
- EXPECT_TRUE(status_or_slot.ok()) << status_or_slot.GetErrorMessage();
- // This is the first buffer inserted, should take slot 0.
- size_t slot = status_or_slot.get();
- EXPECT_EQ(slot, 0);
-
- // Wait and expect the consumer to kick up the newly inserted buffer.
- WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs);
- EXPECT_EQ(consumer_queue_->capacity(), 1ULL);
-}
-
-TEST_F(BufferHubQueueTest, TestRemoveBuffer) {
- ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
- DvrNativeBufferMetadata mo;
-
- // 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<ProducerBuffer> 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(kTimeoutMs, &entry->slot, &mo, &entry->fence);
- ASSERT_TRUE(producer_status.ok());
- entry->buffer = producer_status.take();
- ASSERT_NE(nullptr, entry->buffer);
- }
-
- // 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(WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs));
- ASSERT_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) {
- // 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;
- for (size_t i = 0; i < kBufferCount; i++) {
- AllocateBuffer();
- }
- ASSERT_EQ(kBufferCount, producer_queue_->count());
-
- // Build a silent consumer queue to test multi-consumer queue features.
- auto silent_queue = producer_queue_->CreateSilentConsumerQueue();
- ASSERT_NE(nullptr, silent_queue);
-
- // Check that silent queue doesn't import buffers on creation.
- EXPECT_EQ(silent_queue->capacity(), 0U);
-
- // Dequeue and post a buffer.
- size_t slot;
- LocalHandle fence;
- DvrNativeBufferMetadata mi, mo;
- auto producer_status =
- producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- EXPECT_TRUE(producer_status.ok());
- auto producer_buffer = producer_status.take();
- ASSERT_NE(producer_buffer, nullptr);
- EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0);
- // After post, check the number of remaining available buffers.
- EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
-
- // Currently we expect no buffer to be available prior to calling
- // WaitForBuffers/HandleQueueEvents.
- // TODO(eieio): Note this behavior may change in the future.
- EXPECT_EQ(silent_queue->count(), 0U);
- EXPECT_FALSE(silent_queue->HandleQueueEvents());
- EXPECT_EQ(silent_queue->count(), 0U);
-
- // Build a new consumer queue to test multi-consumer queue features.
- consumer_queue_ = silent_queue->CreateConsumerQueue();
- ASSERT_NE(consumer_queue_, nullptr);
-
- // Check that buffers are correctly imported on construction.
- EXPECT_EQ(consumer_queue_->capacity(), kBufferCount);
- // Buffers are only imported, but their availability is not checked until
- // first call to Dequeue().
- EXPECT_EQ(consumer_queue_->count(), 0U);
-
- // Reclaim released/ignored buffers.
- EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
-
- usleep(10000);
- WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs);
- EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
-
- // Post another buffer.
- producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- EXPECT_TRUE(producer_status.ok());
- producer_buffer = producer_status.take();
- ASSERT_NE(producer_buffer, nullptr);
- EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0);
-
- // Verify that the consumer queue receives it.
- size_t consumer_queue_count = consumer_queue_->count();
- WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs);
- EXPECT_GT(consumer_queue_->count(), consumer_queue_count);
-
- // Save the current consumer queue buffer count to compare after the dequeue.
- consumer_queue_count = consumer_queue_->count();
-
- // Dequeue and acquire/release (discard) buffers on the consumer end.
- auto consumer_status =
- consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- EXPECT_TRUE(consumer_status.ok());
- auto consumer_buffer = consumer_status.take();
- ASSERT_NE(consumer_buffer, nullptr);
- consumer_buffer->Discard();
-
- // Buffer should be returned to the producer queue without being handled by
- // the silent consumer queue.
- EXPECT_LT(consumer_queue_->count(), consumer_queue_count);
- EXPECT_EQ(producer_queue_->count(), kBufferCount - 2);
-
- WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs);
- EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
-}
-
-struct TestUserMetadata {
- char a;
- int32_t b;
- int64_t c;
-};
-
-constexpr uint64_t kUserMetadataSize =
- static_cast<uint64_t>(sizeof(TestUserMetadata));
-
-TEST_F(BufferHubQueueTest, TestUserMetadata) {
- ASSERT_TRUE(CreateQueues(
- config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{}));
-
- AllocateBuffer();
-
- std::vector<TestUserMetadata> user_metadata_list = {
- {'0', 0, 0}, {'1', 10, 3333}, {'@', 123, 1000000000}};
-
- for (auto user_metadata : user_metadata_list) {
- size_t slot;
- LocalHandle fence;
- DvrNativeBufferMetadata mi, mo;
-
- auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- EXPECT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(p1, nullptr);
-
- // TODO(b/69469185): Test against metadata from consumer once we implement
- // release metadata properly.
- // EXPECT_EQ(mo.user_metadata_ptr, 0U);
- // EXPECT_EQ(mo.user_metadata_size, 0U);
-
- mi.user_metadata_size = kUserMetadataSize;
- mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
- EXPECT_EQ(p1->PostAsync(&mi, {}), 0);
- auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- EXPECT_TRUE(c1_status.ok()) << c1_status.GetErrorMessage();
- auto c1 = c1_status.take();
- ASSERT_NE(c1, nullptr);
-
- EXPECT_EQ(mo.user_metadata_size, kUserMetadataSize);
- auto out_user_metadata =
- reinterpret_cast<TestUserMetadata*>(mo.user_metadata_ptr);
- EXPECT_EQ(user_metadata.a, out_user_metadata->a);
- EXPECT_EQ(user_metadata.b, out_user_metadata->b);
- EXPECT_EQ(user_metadata.c, out_user_metadata->c);
-
- // When release, empty metadata is also legit.
- mi.user_metadata_size = 0U;
- mi.user_metadata_ptr = 0U;
- c1->ReleaseAsync(&mi, {});
- }
-}
-
-TEST_F(BufferHubQueueTest, TestUserMetadataMismatch) {
- ASSERT_TRUE(CreateQueues(
- config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{}));
-
- AllocateBuffer();
-
- TestUserMetadata user_metadata;
- size_t slot;
- LocalHandle fence;
- DvrNativeBufferMetadata mi, mo;
- auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- EXPECT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(p1, nullptr);
-
- // Post with mismatched user metadata size will fail. But the producer buffer
- // itself should stay untouched.
- mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
- mi.user_metadata_size = kUserMetadataSize + 1;
- EXPECT_EQ(p1->PostAsync(&mi, {}), -E2BIG);
- // Post with the exact same user metdata size can success.
- mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
- mi.user_metadata_size = kUserMetadataSize;
- EXPECT_EQ(p1->PostAsync(&mi, {}), 0);
-}
-
-TEST_F(BufferHubQueueTest, TestEnqueue) {
- ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
- UsagePolicy{}));
- AllocateBuffer();
-
- size_t slot;
- LocalHandle fence;
- DvrNativeBufferMetadata mo;
- auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(nullptr, p1);
-
- producer_queue_->Enqueue(p1, slot, 0ULL);
- auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_FALSE(c1_status.ok());
-}
-
-TEST_F(BufferHubQueueTest, TestAllocateBuffer) {
- ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
- size_t ps1;
- AllocateBuffer();
- LocalHandle fence;
- DvrNativeBufferMetadata mi, mo;
- auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &ps1, &mo, &fence);
- ASSERT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_NE(p1, nullptr);
-
- // producer queue is exhausted
- size_t ps2;
- auto p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence);
- ASSERT_FALSE(p2_status.ok());
- ASSERT_EQ(ETIMEDOUT, p2_status.error());
-
- // dynamically add buffer.
- AllocateBuffer();
- ASSERT_EQ(producer_queue_->count(), 1U);
- ASSERT_EQ(producer_queue_->capacity(), 2U);
-
- // now we can dequeue again
- p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence);
- ASSERT_TRUE(p2_status.ok());
- auto p2 = p2_status.take();
- ASSERT_NE(p2, nullptr);
- ASSERT_EQ(producer_queue_->count(), 0U);
- // p1 and p2 should have different slot number
- ASSERT_NE(ps1, ps2);
-
- // Consumer queue does not import buffers until |Dequeue| or |ImportBuffers|
- // are called. So far consumer_queue_ should be empty.
- ASSERT_EQ(consumer_queue_->count(), 0U);
-
- int64_t seq = 1;
- mi.index = seq;
- ASSERT_EQ(p1->PostAsync(&mi, {}), 0);
-
- size_t cs1, cs2;
- auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &cs1, &mo, &fence);
- ASSERT_TRUE(c1_status.ok()) << c1_status.GetErrorMessage();
- auto c1 = c1_status.take();
- ASSERT_NE(c1, nullptr);
- ASSERT_EQ(consumer_queue_->count(), 0U);
- ASSERT_EQ(consumer_queue_->capacity(), 2U);
- ASSERT_EQ(cs1, ps1);
-
- ASSERT_EQ(p2->PostAsync(&mi, {}), 0);
- auto c2_status = consumer_queue_->Dequeue(kTimeoutMs, &cs2, &mo, &fence);
- ASSERT_TRUE(c2_status.ok());
- auto c2 = c2_status.take();
- ASSERT_NE(c2, nullptr);
- ASSERT_EQ(cs2, ps2);
-}
-
-TEST_F(BufferHubQueueTest, TestAllocateTwoBuffers) {
- ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
- ASSERT_EQ(producer_queue_->capacity(), 0);
- auto status = producer_queue_->AllocateBuffers(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage, /*buffer_count=*/2);
- ASSERT_TRUE(status.ok());
- std::vector<size_t> buffer_slots = status.take();
- ASSERT_EQ(buffer_slots.size(), 2);
- ASSERT_EQ(producer_queue_->capacity(), 2);
-}
-
-TEST_F(BufferHubQueueTest, TestAllocateZeroBuffers) {
- ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
- ASSERT_EQ(producer_queue_->capacity(), 0);
- auto status = producer_queue_->AllocateBuffers(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage, /*buffer_count=*/0);
- ASSERT_TRUE(status.ok());
- std::vector<size_t> buffer_slots = status.take();
- ASSERT_EQ(buffer_slots.size(), 0);
- ASSERT_EQ(producer_queue_->capacity(), 0);
-}
-
-TEST_F(BufferHubQueueTest, TestUsageSetMask) {
- const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
- ASSERT_TRUE(
- CreateQueues(config_builder_.Build(), UsagePolicy{set_mask, 0, 0, 0}));
-
- // When allocation, leave out |set_mask| from usage bits on purpose.
- auto status = producer_queue_->AllocateBuffer(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~set_mask);
- ASSERT_TRUE(status.ok());
-
- LocalHandle fence;
- size_t slot;
- DvrNativeBufferMetadata mo;
- auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_EQ(p1->usage() & set_mask, set_mask);
-}
-
-TEST_F(BufferHubQueueTest, TestUsageClearMask) {
- const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
- ASSERT_TRUE(
- CreateQueues(config_builder_.Build(), UsagePolicy{0, clear_mask, 0, 0}));
-
- // When allocation, add |clear_mask| into usage bits on purpose.
- auto status = producer_queue_->AllocateBuffer(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage | clear_mask);
- ASSERT_TRUE(status.ok());
-
- LocalHandle fence;
- size_t slot;
- DvrNativeBufferMetadata mo;
- auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(p1_status.ok());
- auto p1 = p1_status.take();
- ASSERT_EQ(p1->usage() & clear_mask, 0U);
-}
-
-TEST_F(BufferHubQueueTest, TestUsageDenySetMask) {
- const uint32_t deny_set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
- 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.
- auto status = producer_queue_->AllocateBuffer(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~deny_set_mask);
- ASSERT_TRUE(status.ok());
-
- // While allocation with those bits should fail.
- 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(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.
- auto status = producer_queue_->AllocateBuffer(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage | deny_clear_mask);
- ASSERT_TRUE(status.ok());
-
- // While allocation without those bits should fail.
- 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);
-}
-
-TEST_F(BufferHubQueueTest, TestFreeAllBuffers) {
- constexpr size_t kBufferCount = 2;
-
-#define CHECK_NO_BUFFER_THEN_ALLOCATE(num_buffers) \
- EXPECT_EQ(consumer_queue_->count(), 0U); \
- EXPECT_EQ(consumer_queue_->capacity(), 0U); \
- EXPECT_EQ(producer_queue_->count(), 0U); \
- EXPECT_EQ(producer_queue_->capacity(), 0U); \
- for (size_t i = 0; i < num_buffers; i++) { \
- AllocateBuffer(); \
- } \
- EXPECT_EQ(producer_queue_->count(), num_buffers); \
- EXPECT_EQ(producer_queue_->capacity(), num_buffers);
-
- size_t slot;
- LocalHandle fence;
- pdx::Status<void> status;
- pdx::Status<std::shared_ptr<ConsumerBuffer>> consumer_status;
- pdx::Status<std::shared_ptr<ProducerBuffer>> producer_status;
- std::shared_ptr<ConsumerBuffer> consumer_buffer;
- std::shared_ptr<ProducerBuffer> producer_buffer;
- DvrNativeBufferMetadata mi, mo;
-
- ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
- // Free all buffers when buffers are avaible for dequeue.
- CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
- status = producer_queue_->FreeAllBuffers();
- EXPECT_TRUE(status.ok());
-
- // Free all buffers when one buffer is dequeued.
- CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
- producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(producer_status.ok());
- status = producer_queue_->FreeAllBuffers();
- EXPECT_TRUE(status.ok());
-
- // Free all buffers when all buffers are dequeued.
- CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
- for (size_t i = 0; i < kBufferCount; i++) {
- producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(producer_status.ok());
- }
- status = producer_queue_->FreeAllBuffers();
- EXPECT_TRUE(status.ok());
-
- // Free all buffers when one buffer is posted.
- CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
- producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(producer_status.ok());
- producer_buffer = producer_status.take();
- ASSERT_NE(nullptr, producer_buffer);
- ASSERT_EQ(0, producer_buffer->PostAsync(&mi, fence));
- status = producer_queue_->FreeAllBuffers();
- EXPECT_TRUE(status.ok());
-
- // Free all buffers when all buffers are posted.
- CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
- for (size_t i = 0; i < kBufferCount; i++) {
- producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(producer_status.ok());
- producer_buffer = producer_status.take();
- ASSERT_NE(producer_buffer, nullptr);
- ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0);
- }
- status = producer_queue_->FreeAllBuffers();
- EXPECT_TRUE(status.ok());
-
- // Free all buffers when all buffers are acquired.
- CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
- for (size_t i = 0; i < kBufferCount; i++) {
- producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(producer_status.ok());
- producer_buffer = producer_status.take();
- ASSERT_NE(producer_buffer, nullptr);
- ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0);
- consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
- ASSERT_TRUE(consumer_status.ok()) << consumer_status.GetErrorMessage();
- }
-
- status = producer_queue_->FreeAllBuffers();
- EXPECT_TRUE(status.ok());
-
- // In addition to FreeAllBuffers() from the queue, it is also required to
- // delete all references to the ProducerBuffer (i.e. the PDX client).
- producer_buffer = nullptr;
-
- // Crank consumer queue events to pickup EPOLLHUP events on the queue.
- consumer_queue_->HandleQueueEvents();
-
- // One last check.
- CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-
-#undef CHECK_NO_BUFFER_THEN_ALLOCATE
-}
-
-TEST_F(BufferHubQueueTest, TestProducerToParcelableNotEmpty) {
- ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
- UsagePolicy{}));
-
- // Allocate only one buffer.
- AllocateBuffer();
-
- // Export should fail as the queue is not empty.
- auto status = producer_queue_->TakeAsParcelable();
- EXPECT_FALSE(status.ok());
-}
-
-TEST_F(BufferHubQueueTest, TestProducerExportToParcelable) {
- ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
- auto s1 = producer_queue_->TakeAsParcelable();
- EXPECT_TRUE(s1.ok());
-
- ProducerQueueParcelable output_parcelable = s1.take();
- EXPECT_TRUE(output_parcelable.IsValid());
-
- Parcel parcel;
- status_t res;
- res = output_parcelable.writeToParcel(&parcel);
- EXPECT_EQ(res, OK);
-
- // After written into parcelable, the output_parcelable is still valid has
- // keeps the producer channel alive.
- EXPECT_TRUE(output_parcelable.IsValid());
-
- // Creating producer buffer should fail.
- auto s2 = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
- kBufferLayerCount, kBufferFormat,
- kBufferUsage);
- ASSERT_FALSE(s2.ok());
-
- // Reset the data position so that we can read back from the same parcel
- // without doing actually Binder IPC.
- parcel.setDataPosition(0);
- producer_queue_ = nullptr;
-
- // Recreate the producer queue from the parcel.
- ProducerQueueParcelable input_parcelable;
- EXPECT_FALSE(input_parcelable.IsValid());
-
- res = input_parcelable.readFromParcel(&parcel);
- EXPECT_EQ(res, OK);
- EXPECT_TRUE(input_parcelable.IsValid());
-
- EXPECT_EQ(producer_queue_, nullptr);
- producer_queue_ = ProducerQueue::Import(input_parcelable.TakeChannelHandle());
- EXPECT_FALSE(input_parcelable.IsValid());
- ASSERT_NE(producer_queue_, nullptr);
-
- // Newly created queue from the parcel can allocate buffer, post buffer to
- // consumer.
- EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
- EXPECT_EQ(producer_queue_->count(), 1U);
- EXPECT_EQ(producer_queue_->capacity(), 1U);
-
- size_t slot;
- DvrNativeBufferMetadata producer_meta;
- DvrNativeBufferMetadata consumer_meta;
- LocalHandle fence;
- auto s3 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
- EXPECT_TRUE(s3.ok());
-
- std::shared_ptr<ProducerBuffer> p1 = s3.take();
- ASSERT_NE(p1, nullptr);
-
- producer_meta.timestamp = 42;
- EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
-
- // Make sure the buffer can be dequeued from consumer side.
- auto s4 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence);
- EXPECT_TRUE(s4.ok()) << s4.GetErrorMessage();
- EXPECT_EQ(consumer_queue_->capacity(), 1U);
-
- auto consumer = s4.take();
- ASSERT_NE(consumer, nullptr);
- EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
-}
-
-TEST_F(BufferHubQueueTest, TestCreateConsumerParcelable) {
- ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
-
- auto s1 = producer_queue_->CreateConsumerQueueParcelable();
- EXPECT_TRUE(s1.ok());
- ConsumerQueueParcelable output_parcelable = s1.take();
- EXPECT_TRUE(output_parcelable.IsValid());
-
- // Write to a Parcel new object.
- Parcel parcel;
- status_t res;
- res = output_parcelable.writeToParcel(&parcel);
-
- // Reset the data position so that we can read back from the same parcel
- // without doing actually Binder IPC.
- parcel.setDataPosition(0);
-
- // No consumer queue created yet.
- EXPECT_EQ(consumer_queue_, nullptr);
-
- // If the parcel contains a consumer queue, read into a
- // ProducerQueueParcelable should fail.
- ProducerQueueParcelable wrongly_typed_parcelable;
- EXPECT_FALSE(wrongly_typed_parcelable.IsValid());
- res = wrongly_typed_parcelable.readFromParcel(&parcel);
- EXPECT_EQ(res, -EINVAL);
- parcel.setDataPosition(0);
-
- // Create the consumer queue from the parcel.
- ConsumerQueueParcelable input_parcelable;
- EXPECT_FALSE(input_parcelable.IsValid());
-
- res = input_parcelable.readFromParcel(&parcel);
- EXPECT_EQ(res, OK);
- EXPECT_TRUE(input_parcelable.IsValid());
-
- consumer_queue_ = ConsumerQueue::Import(input_parcelable.TakeChannelHandle());
- EXPECT_FALSE(input_parcelable.IsValid());
- ASSERT_NE(consumer_queue_, nullptr);
-
- EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
- EXPECT_EQ(producer_queue_->count(), 1U);
- EXPECT_EQ(producer_queue_->capacity(), 1U);
-
- size_t slot;
- DvrNativeBufferMetadata producer_meta;
- DvrNativeBufferMetadata consumer_meta;
- LocalHandle fence;
- auto s2 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
- EXPECT_TRUE(s2.ok());
-
- std::shared_ptr<ProducerBuffer> p1 = s2.take();
- ASSERT_NE(p1, nullptr);
-
- producer_meta.timestamp = 42;
- EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
-
- // Make sure the buffer can be dequeued from consumer side.
- auto s3 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence);
- EXPECT_TRUE(s3.ok()) << s3.GetErrorMessage();
- EXPECT_EQ(consumer_queue_->capacity(), 1U);
-
- auto consumer = s3.take();
- ASSERT_NE(consumer, nullptr);
- EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
-}
-
-} // namespace
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
deleted file mode 100644
index fab1097..0000000
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ /dev/null
@@ -1,603 +0,0 @@
-#include <base/logging.h>
-#include <gui/BufferHubProducer.h>
-#include <gui/IProducerListener.h>
-#include <gui/Surface.h>
-#include <pdx/default_transport/channel_parcelable.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace dvr {
-
-using pdx::LocalHandle;
-
-namespace {
-
-// Default dimensions before setDefaultBufferSize is called by the consumer.
-constexpr uint32_t kDefaultWidth = 1;
-constexpr uint32_t kDefaultHeight = 1;
-
-// Default format before setDefaultBufferFormat is called by the consumer.
-constexpr PixelFormat kDefaultFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-constexpr int kDefaultConsumerUsageBits = 0;
-
-// Default transform hint before setTransformHint is called by the consumer.
-constexpr uint32_t kDefaultTransformHint = 0;
-
-constexpr int kTestApi = NATIVE_WINDOW_API_CPU;
-constexpr int kTestApiOther = NATIVE_WINDOW_API_EGL;
-constexpr int kTestApiInvalid = 0xDEADBEEF;
-constexpr int kTestProducerUsageBits = 0;
-constexpr bool kTestControlledByApp = true;
-
-// Builder pattern to slightly vary *almost* correct input
-// -- avoids copying and pasting
-struct QueueBufferInputBuilder {
- IGraphicBufferProducer::QueueBufferInput build() {
- return IGraphicBufferProducer::QueueBufferInput(
- mTimestamp, mIsAutoTimestamp, mDataSpace, mCrop, mScalingMode,
- mTransform, mFence);
- }
-
- QueueBufferInputBuilder& setTimestamp(int64_t timestamp) {
- this->mTimestamp = timestamp;
- return *this;
- }
-
- QueueBufferInputBuilder& setIsAutoTimestamp(bool isAutoTimestamp) {
- this->mIsAutoTimestamp = isAutoTimestamp;
- return *this;
- }
-
- QueueBufferInputBuilder& setDataSpace(android_dataspace dataSpace) {
- this->mDataSpace = dataSpace;
- return *this;
- }
-
- QueueBufferInputBuilder& setCrop(Rect crop) {
- this->mCrop = crop;
- return *this;
- }
-
- QueueBufferInputBuilder& setScalingMode(int scalingMode) {
- this->mScalingMode = scalingMode;
- return *this;
- }
-
- QueueBufferInputBuilder& setTransform(uint32_t transform) {
- this->mTransform = transform;
- return *this;
- }
-
- QueueBufferInputBuilder& setFence(sp<Fence> fence) {
- this->mFence = fence;
- return *this;
- }
-
- private:
- int64_t mTimestamp{1384888611};
- bool mIsAutoTimestamp{false};
- android_dataspace mDataSpace{HAL_DATASPACE_UNKNOWN};
- Rect mCrop{Rect(kDefaultWidth, kDefaultHeight)};
- int mScalingMode{0};
- uint32_t mTransform{0};
- sp<Fence> mFence{Fence::NO_FENCE};
-};
-
-// This is a test that covers our implementation of bufferhubqueue-based
-// IGraphicBufferProducer.
-class BufferHubQueueProducerTest : public ::testing::Test {
- protected:
- virtual void SetUp() {
- const ::testing::TestInfo* const testInfo =
- ::testing::UnitTest::GetInstance()->current_test_info();
- ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(),
- testInfo->name());
-
- auto config = ProducerQueueConfigBuilder().Build();
- auto queue = ProducerQueue::Create(config, UsagePolicy{});
- ASSERT_TRUE(queue != nullptr);
-
- mProducer = BufferHubProducer::Create(std::move(queue));
- ASSERT_TRUE(mProducer != nullptr);
- mSurface = new Surface(mProducer, true);
- ASSERT_TRUE(mSurface != nullptr);
- }
-
- // Connect to a producer in a 'correct' fashion.
- void ConnectProducer() {
- IGraphicBufferProducer::QueueBufferOutput output;
- // Can connect the first time.
- ASSERT_EQ(OK, mProducer->connect(kStubListener, kTestApi,
- kTestControlledByApp, &output));
- }
-
- // Dequeue a buffer in a 'correct' fashion.
- // Precondition: Producer is connected.
- void DequeueBuffer(int* outSlot) {
- sp<Fence> fence;
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(outSlot, &fence));
- }
-
- void DequeueBuffer(int* outSlot, sp<Fence>* outFence) {
- ASSERT_NE(nullptr, outSlot);
- ASSERT_NE(nullptr, outFence);
-
- int ret = mProducer->dequeueBuffer(
- outSlot, outFence, kDefaultWidth, kDefaultHeight, kDefaultFormat,
- kTestProducerUsageBits, nullptr, nullptr);
- // BUFFER_NEEDS_REALLOCATION can be either on or off.
- ASSERT_EQ(0, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & ret);
-
- // Slot number should be in boundary.
- ASSERT_LE(0, *outSlot);
- ASSERT_GT(BufferQueueDefs::NUM_BUFFER_SLOTS, *outSlot);
- }
-
- // Create a generic "valid" input for queueBuffer
- // -- uses the default buffer format, width, etc.
- static IGraphicBufferProducer::QueueBufferInput CreateBufferInput() {
- return QueueBufferInputBuilder().build();
- }
-
- const sp<IProducerListener> kStubListener{new StubProducerListener};
-
- sp<BufferHubProducer> mProducer;
- sp<Surface> mSurface;
-};
-
-TEST_F(BufferHubQueueProducerTest, ConnectFirst_ReturnsError) {
- IGraphicBufferProducer::QueueBufferOutput output;
-
- // NULL output returns BAD_VALUE
- EXPECT_EQ(BAD_VALUE, mProducer->connect(kStubListener, kTestApi,
- kTestControlledByApp, nullptr));
-
- // Invalid API returns bad value
- EXPECT_EQ(BAD_VALUE, mProducer->connect(kStubListener, kTestApiInvalid,
- kTestControlledByApp, &output));
-}
-
-TEST_F(BufferHubQueueProducerTest, ConnectAgain_ReturnsError) {
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
- // Can't connect when there is already a producer connected.
- IGraphicBufferProducer::QueueBufferOutput output;
- EXPECT_EQ(BAD_VALUE, mProducer->connect(kStubListener, kTestApi,
- kTestControlledByApp, &output));
-}
-
-TEST_F(BufferHubQueueProducerTest, Disconnect_Succeeds) {
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
- ASSERT_EQ(OK, mProducer->disconnect(kTestApi));
-}
-
-TEST_F(BufferHubQueueProducerTest, Disconnect_ReturnsError) {
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
- // Must disconnect with same API number
- EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiOther));
- // API must not be out of range
- EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiInvalid));
-}
-
-TEST_F(BufferHubQueueProducerTest, Query_Succeeds) {
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
- int32_t value = -1;
- EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_WIDTH, &value));
- EXPECT_EQ(kDefaultWidth, static_cast<uint32_t>(value));
-
- EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_HEIGHT, &value));
- EXPECT_EQ(kDefaultHeight, static_cast<uint32_t>(value));
-
- EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_FORMAT, &value));
- EXPECT_EQ(kDefaultFormat, value);
-
- EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value));
- EXPECT_LE(0, value);
- EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, value);
-
- EXPECT_EQ(OK,
- mProducer->query(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value));
- EXPECT_FALSE(value); // Can't run behind when we haven't touched the queue
-
- EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &value));
- EXPECT_EQ(kDefaultConsumerUsageBits, value);
-}
-
-TEST_F(BufferHubQueueProducerTest, Query_ReturnsError) {
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
- // One past the end of the last 'query' enum value. Update this if we add more
- // enums.
- const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1;
-
- int value;
- // What was out of range
- EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ -1, &value));
- EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ 0xDEADBEEF, &value));
- EXPECT_EQ(BAD_VALUE,
- mProducer->query(NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE, &value));
-
- // Some enums from window.h are 'invalid'
- EXPECT_EQ(BAD_VALUE,
- mProducer->query(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &value));
- EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_CONCRETE_TYPE, &value));
- EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_WIDTH, &value));
- EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_HEIGHT, &value));
- EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_TRANSFORM_HINT, &value));
-
- // Value was NULL
- EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/ NULL));
-}
-
-TEST_F(BufferHubQueueProducerTest, Queue_Succeeds) {
- int slot = -1;
-
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
- // Request the buffer (pre-requisite for queueing)
- sp<GraphicBuffer> buffer;
- ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
- // A generic "valid" input
- IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
- IGraphicBufferProducer::QueueBufferOutput output;
-
- // Queue the buffer back into the BQ
- ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-
- EXPECT_EQ(kDefaultWidth, output.width);
- EXPECT_EQ(kDefaultHeight, output.height);
- EXPECT_EQ(kDefaultTransformHint, output.transformHint);
-
- // BufferHubQueue delivers buffers to consumer immediately.
- EXPECT_EQ(0u, output.numPendingBuffers);
-
- // Note that BufferHubQueue doesn't support nextFrameNumber as it seems to
- // be a SurfaceFlinger specific optimization.
- EXPECT_EQ(0u, output.nextFrameNumber);
-
- // Buffer was not in the dequeued state
- EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-// Test invalid slot number
-TEST_F(BufferHubQueueProducerTest, QueueInvalidSlot_ReturnsError) {
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
- // A generic "valid" input
- IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
- IGraphicBufferProducer::QueueBufferOutput output;
-
- EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ -1, input, &output));
- EXPECT_EQ(BAD_VALUE,
- mProducer->queueBuffer(/*slot*/ 0xDEADBEEF, input, &output));
- EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(BufferQueueDefs::NUM_BUFFER_SLOTS,
- input, &output));
-}
-
-// Slot was not in the dequeued state (all slots start out in Free state)
-TEST_F(BufferHubQueueProducerTest, QueueNotDequeued_ReturnsError) {
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
- IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
- IGraphicBufferProducer::QueueBufferOutput output;
-
- EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ 0, input, &output));
-}
-
-// Slot was enqueued without requesting a buffer
-TEST_F(BufferHubQueueProducerTest, QueueNotRequested_ReturnsError) {
- int slot = -1;
-
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
- IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
- IGraphicBufferProducer::QueueBufferOutput output;
-
- EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-// Test when fence was NULL
-TEST_F(BufferHubQueueProducerTest, QueueNoFence_ReturnsError) {
- int slot = -1;
-
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
- sp<GraphicBuffer> buffer;
- ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
- sp<Fence> nullFence = NULL;
-
- IGraphicBufferProducer::QueueBufferInput input =
- QueueBufferInputBuilder().setFence(nullFence).build();
- IGraphicBufferProducer::QueueBufferOutput output;
-
- EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-// Test scaling mode was invalid
-TEST_F(BufferHubQueueProducerTest, QueueTestInvalidScalingMode_ReturnsError) {
- int slot = -1;
-
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
- sp<GraphicBuffer> buffer;
- ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
- IGraphicBufferProducer::QueueBufferInput input =
- QueueBufferInputBuilder().setScalingMode(-1).build();
- IGraphicBufferProducer::QueueBufferOutput output;
-
- EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-
- input = QueueBufferInputBuilder().setScalingMode(0xDEADBEEF).build();
-
- EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-// Test crop rect is out of bounds of the buffer dimensions
-TEST_F(BufferHubQueueProducerTest, QueueCropOutOfBounds_ReturnsError) {
- int slot = -1;
-
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
- sp<GraphicBuffer> buffer;
- ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
- IGraphicBufferProducer::QueueBufferInput input =
- QueueBufferInputBuilder()
- .setCrop(Rect(kDefaultWidth + 1, kDefaultHeight + 1))
- .build();
- IGraphicBufferProducer::QueueBufferOutput output;
-
- EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-TEST_F(BufferHubQueueProducerTest, CancelBuffer_Succeeds) {
- int slot = -1;
- sp<Fence> fence;
-
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence));
-
- // Should be able to cancel buffer after a dequeue.
- EXPECT_EQ(OK, mProducer->cancelBuffer(slot, fence));
-}
-
-TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
- return;
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
- int minUndequeuedBuffers;
- ASSERT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
- &minUndequeuedBuffers));
-
- const int minBuffers = 1;
- const int maxBuffers =
- BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
-
- ASSERT_EQ(OK, mProducer->setAsyncMode(false)) << "async mode: " << false;
- ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(minBuffers))
- << "bufferCount: " << minBuffers;
-
- // Should now be able to dequeue up to minBuffers times
- // Should now be able to dequeue up to maxBuffers times
- int slot = -1;
- for (int i = 0; i < minBuffers; ++i) {
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
- }
-
- ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(maxBuffers));
-
- // queue the first buffer to enable max dequeued buffer count checking
- IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
- IGraphicBufferProducer::QueueBufferOutput output;
- sp<GraphicBuffer> buffer;
- ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
- ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-
- sp<Fence> fence;
- for (int i = 0; i < maxBuffers; ++i) {
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence));
- }
-
- // Cancel a buffer, so we can decrease the buffer count
- ASSERT_EQ(OK, mProducer->cancelBuffer(slot, fence));
-
- // Should now be able to decrease the max dequeued count by 1
- ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(maxBuffers - 1));
-}
-
-TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Fails) {
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
- int minUndequeuedBuffers;
- ASSERT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
- &minUndequeuedBuffers));
-
- const int minBuffers = 1;
- const int maxBuffers =
- BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
-
- ASSERT_EQ(OK, mProducer->setAsyncMode(false)) << "async mode: " << false;
- // Buffer count was out of range
- EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0))
- << "bufferCount: " << 0;
- EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1))
- << "bufferCount: " << maxBuffers + 1;
-
- // Set max dequeue count to 2
- ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(2));
- // Dequeue 2 buffers
- int slot = -1;
- sp<Fence> fence;
- for (int i = 0; i < 2; i++) {
- ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth,
- kDefaultHeight, kDefaultFormat,
- kTestProducerUsageBits,
- nullptr, nullptr)))
- << "slot: " << slot;
- }
-
- // Client has too many buffers dequeued
- EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(1))
- << "bufferCount: " << minBuffers;
-}
-
-TEST_F(BufferHubQueueProducerTest,
- DisconnectedProducerReturnsError_dequeueBuffer) {
- int slot = -1;
- sp<Fence> fence;
-
- ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth,
- kDefaultHeight, kDefaultFormat,
- kTestProducerUsageBits,
- nullptr, nullptr));
-}
-
-TEST_F(BufferHubQueueProducerTest,
- DisconnectedProducerReturnsError_requestBuffer) {
- int slot = -1;
- sp<GraphicBuffer> buffer;
-
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
- // Shouldn't be able to request buffer after disconnect.
- ASSERT_EQ(OK, mProducer->disconnect(kTestApi));
- ASSERT_EQ(NO_INIT, mProducer->requestBuffer(slot, &buffer));
-}
-
-TEST_F(BufferHubQueueProducerTest,
- DisconnectedProducerReturnsError_queueBuffer) {
- int slot = -1;
- sp<GraphicBuffer> buffer;
-
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
- ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
- // A generic "valid" input
- IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
- IGraphicBufferProducer::QueueBufferOutput output;
-
- // Shouldn't be able to queue buffer after disconnect.
- ASSERT_EQ(OK, mProducer->disconnect(kTestApi));
- ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output));
-}
-
-TEST_F(BufferHubQueueProducerTest,
- DisconnectedProducerReturnsError_cancelBuffer) {
- int slot = -1;
- sp<GraphicBuffer> buffer;
-
- ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
- ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
- // Shouldn't be able to cancel buffer after disconnect.
- ASSERT_EQ(OK, mProducer->disconnect(kTestApi));
- ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE));
-}
-
-TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) {
- int slot = -1;
- sp<GraphicBuffer> buffer;
- IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
- IGraphicBufferProducer::QueueBufferOutput output;
-
- EXPECT_NO_FATAL_FAILURE(ConnectProducer());
-
- constexpr int maxDequeuedBuffers = 1;
- int minUndequeuedBuffers;
- EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
- &minUndequeuedBuffers));
- EXPECT_EQ(OK, mProducer->setAsyncMode(false));
- EXPECT_EQ(OK, mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers));
-
- int maxCapacity = maxDequeuedBuffers + minUndequeuedBuffers;
-
- // Dequeue, request, and queue all buffers.
- for (int i = 0; i < maxCapacity; i++) {
- EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
- EXPECT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
- EXPECT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
- }
-
- // Disconnect then reconnect.
- EXPECT_EQ(OK, mProducer->disconnect(kTestApi));
- EXPECT_NO_FATAL_FAILURE(ConnectProducer());
-
- // Dequeue, request, and queue all buffers.
- for (int i = 0; i < maxCapacity; i++) {
- EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
- EXPECT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
- EXPECT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
- }
-
- EXPECT_EQ(OK, mProducer->disconnect(kTestApi));
-}
-
-TEST_F(BufferHubQueueProducerTest, TakeAsParcelable) {
- // Connected producer cannot be taken out as a parcelable.
- EXPECT_NO_FATAL_FAILURE(ConnectProducer());
- ProducerQueueParcelable producer_parcelable;
- EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), BAD_VALUE);
-
- // Create a valid fake producer parcelable.
- auto fake_channel_parcelable =
- std::make_unique<pdx::default_transport::ChannelParcelable>(
- LocalHandle(0), LocalHandle(0), LocalHandle(0));
- EXPECT_TRUE(fake_channel_parcelable->IsValid());
- ProducerQueueParcelable fake_producer_parcelable(
- std::move(fake_channel_parcelable));
- EXPECT_TRUE(fake_producer_parcelable.IsValid());
-
- // Disconnect producer can be taken out, but only to an invalid parcelable.
- ASSERT_EQ(mProducer->disconnect(kTestApi), OK);
- EXPECT_EQ(mProducer->TakeAsParcelable(&fake_producer_parcelable), BAD_VALUE);
- EXPECT_FALSE(producer_parcelable.IsValid());
- EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), OK);
- EXPECT_TRUE(producer_parcelable.IsValid());
-
- // Should still be able to query buffer dimension after disconnect.
- int32_t value = -1;
- EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_WIDTH, &value));
- EXPECT_EQ(static_cast<uint32_t>(value), kDefaultWidth);
-
- EXPECT_EQ(mProducer->query(NATIVE_WINDOW_HEIGHT, &value), OK);
- EXPECT_EQ(static_cast<uint32_t>(value), kDefaultHeight);
-
- EXPECT_EQ(mProducer->query(NATIVE_WINDOW_FORMAT, &value), OK);
- EXPECT_EQ(value, kDefaultFormat);
-
- // But connect to API will fail.
- IGraphicBufferProducer::QueueBufferOutput output;
- EXPECT_EQ(mProducer->connect(kStubListener, kTestApi, kTestControlledByApp,
- &output),
- BAD_VALUE);
-
- // Create a new producer from the parcelable and connect to kTestApi should
- // succeed.
- sp<BufferHubProducer> new_producer =
- BufferHubProducer::Create(std::move(producer_parcelable));
- ASSERT_TRUE(new_producer != nullptr);
- EXPECT_EQ(new_producer->connect(kStubListener, kTestApi, kTestControlledByApp,
- &output),
- OK);
-}
-
-} // namespace
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
deleted file mode 100644
index b0ed950..0000000
--- a/libs/vr/libdisplay/Android.bp
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-sourceFiles = [
- "display_client.cpp",
- "display_manager_client.cpp",
- "display_protocol.cpp",
- "shared_buffer_helpers.cpp",
- "vsync_service.cpp",
-]
-
-localIncludeFiles = [
- "include",
-]
-
-sharedLibraries = [
- "libbase",
- "libbinder",
- "libbufferhubqueue",
- "libcutils",
- "liblog",
- "libutils",
- "libui",
- "libgui",
- "libhardware",
- "libsync",
- "libnativewindow",
- "libpdx_default_transport",
-]
-
-staticLibraries = [
- "libdvrcommon",
- "libbroadcastring",
-]
-
-headerLibraries = [
- "vulkan_headers",
- "libdvr_headers",
-]
-
-cc_library {
- srcs: sourceFiles,
- cflags: ["-DLOG_TAG=\"libdisplay\"",
- "-DTRACE=0",
- "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
- "-DGL_GLEXT_PROTOTYPES",
- "-DEGL_EGLEXT_PROTOTYPES",
- "-Wall",
- "-Werror",
- ], // + [ "-UNDEBUG", "-DDEBUG", "-O0", "-g" ],
- export_include_dirs: localIncludeFiles,
- shared_libs: sharedLibraries,
- static_libs: staticLibraries,
- header_libs: headerLibraries,
- export_header_lib_headers: headerLibraries,
-
- name: "libdisplay",
-}
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
deleted file mode 100644
index 62856df..0000000
--- a/libs/vr/libdisplay/display_client.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-#include "include/private/dvr/display_client.h"
-
-#include <cutils/native_handle.h>
-#include <log/log.h>
-#include <pdx/default_transport/client_channel.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <pdx/status.h>
-
-#include <mutex>
-
-#include <private/dvr/display_protocol.h>
-
-using android::pdx::ErrorStatus;
-using android::pdx::LocalHandle;
-using android::pdx::LocalChannelHandle;
-using android::pdx::Status;
-using android::pdx::Transaction;
-using android::pdx::rpc::IfAnyOf;
-
-namespace android {
-namespace dvr {
-namespace display {
-
-Surface::Surface(LocalChannelHandle channel_handle, int* error)
- : BASE{pdx::default_transport::ClientChannel::Create(
- std::move(channel_handle))} {
- auto status = InvokeRemoteMethod<DisplayProtocol::GetSurfaceInfo>();
- if (!status) {
- ALOGE("Surface::Surface: Failed to get surface info: %s",
- status.GetErrorMessage().c_str());
- Close(status.error());
- if (error)
- *error = status.error();
- }
-
- surface_id_ = status.get().surface_id;
- z_order_ = status.get().z_order;
- visible_ = status.get().visible;
-}
-
-Surface::Surface(const SurfaceAttributes& attributes, int* error)
- : BASE{pdx::default_transport::ClientChannelFactory::Create(
- DisplayProtocol::kClientPath),
- kInfiniteTimeout} {
- auto status = InvokeRemoteMethod<DisplayProtocol::CreateSurface>(attributes);
- if (!status) {
- ALOGE("Surface::Surface: Failed to create display surface: %s",
- status.GetErrorMessage().c_str());
- Close(status.error());
- if (error)
- *error = status.error();
- }
-
- surface_id_ = status.get().surface_id;
- z_order_ = status.get().z_order;
- visible_ = status.get().visible;
-}
-
-Status<void> Surface::SetVisible(bool visible) {
- return SetAttributes(
- {{SurfaceAttribute::Visible, SurfaceAttributeValue{visible}}});
-}
-
-Status<void> Surface::SetZOrder(int z_order) {
- return SetAttributes(
- {{SurfaceAttribute::ZOrder, SurfaceAttributeValue{z_order}}});
-}
-
-Status<void> Surface::SetAttributes(const SurfaceAttributes& attributes) {
- auto status = InvokeRemoteMethod<DisplayProtocol::SetAttributes>(attributes);
- if (!status) {
- ALOGE(
- "Surface::SetAttributes: Failed to set display surface "
- "attributes: %s",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- // Set the local cached copies of the attributes we care about from the full
- // set of attributes sent to the display service.
- for (const auto& attribute : attributes) {
- const auto& key = attribute.first;
- const auto* variant = &attribute.second;
- bool invalid_value = false;
- switch (key) {
- case SurfaceAttribute::Visible:
- invalid_value =
- !IfAnyOf<int32_t, int64_t, bool>::Get(variant, &visible_);
- break;
- case SurfaceAttribute::ZOrder:
- invalid_value = !IfAnyOf<int32_t>::Get(variant, &z_order_);
- break;
- }
-
- if (invalid_value) {
- ALOGW(
- "Surface::SetAttributes: Failed to set display surface "
- "attribute %d because of incompatible type: %d",
- key, variant->index());
- }
- }
-
- return {};
-}
-
-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>(
- 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());
- return status.error_status();
- }
-
- auto producer_queue = ProducerQueue::Import(status.take());
- if (!producer_queue) {
- ALOGE("Surface::CreateQueue: Failed to import producer queue!");
- return ErrorStatus(ENOMEM);
- }
-
- return {std::move(producer_queue)};
-}
-
-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, 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(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);
- 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)};
-}
-
-DisplayClient::DisplayClient(int* error)
- : BASE(pdx::default_transport::ClientChannelFactory::Create(
- DisplayProtocol::kClientPath),
- kInfiniteTimeout) {
- if (error)
- *error = Client::error();
-}
-
-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<uint8_t> DisplayClient::GetDisplayIdentificationPort() {
- return InvokeRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>();
-}
-
-Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface(
- const SurfaceAttributes& attributes) {
- int error;
- if (auto client = Surface::Create(attributes, &error))
- return {std::move(client)};
- else
- return ErrorStatus(error);
-}
-
-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::GetGlobalBuffer: Failed to get named buffer: key=%d; "
- "error=%s",
- key, status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- auto ion_buffer = std::make_unique<IonBuffer>();
- auto native_buffer_handle = status.take();
- const int ret = native_buffer_handle.Import(ion_buffer.get());
- if (ret < 0) {
- ALOGE(
- "DisplayClient::GetGlobalBuffer: Failed to import global buffer: "
- "key=%d; error=%s",
- key, strerror(-ret));
- return ErrorStatus(-ret);
- }
-
- return {std::move(ion_buffer)};
-}
-
-Status<bool> DisplayClient::IsVrAppRunning() {
- return InvokeRemoteMethod<DisplayProtocol::IsVrAppRunning>();
-}
-
-} // namespace display
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
deleted file mode 100644
index fdeeb70..0000000
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "include/private/dvr/display_manager_client.h"
-
-#include <pdx/default_transport/client_channel_factory.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/display_protocol.h>
-#include <utils/Log.h>
-
-using android::pdx::ErrorStatus;
-using android::pdx::LocalChannelHandle;
-using android::pdx::Transaction;
-
-namespace android {
-namespace dvr {
-namespace display {
-
-DisplayManagerClient::DisplayManagerClient()
- : BASE(pdx::default_transport::ClientChannelFactory::Create(
- DisplayManagerProtocol::kClientPath)) {}
-
-DisplayManagerClient::~DisplayManagerClient() {}
-
-pdx::Status<std::vector<display::SurfaceState>>
-DisplayManagerClient::GetSurfaceState() {
- auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceState>();
- if (!status) {
- ALOGE(
- "DisplayManagerClient::GetSurfaceState: Failed to get surface info: %s",
- status.GetErrorMessage().c_str());
- }
-
- return status;
-}
-
-pdx::Status<std::unique_ptr<ConsumerQueue>>
-DisplayManagerClient::GetSurfaceQueue(int surface_id, int queue_id) {
- auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>(
- surface_id, queue_id);
- if (!status) {
- ALOGE(
- "DisplayManagerClient::GetSurfaceQueue: Failed to get queue for "
- "surface_id=%d queue_id=%d: %s",
- surface_id, queue_id, status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- return {ConsumerQueue::Import(status.take())};
-}
-
-} // namespace display
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libdisplay/display_protocol.cpp b/libs/vr/libdisplay/display_protocol.cpp
deleted file mode 100644
index 773f9a5..0000000
--- a/libs/vr/libdisplay/display_protocol.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "include/private/dvr/display_protocol.h"
-
-namespace android {
-namespace dvr {
-namespace display {
-
-constexpr char DisplayProtocol::kClientPath[];
-constexpr char DisplayManagerProtocol::kClientPath[];
-constexpr char VSyncProtocol::kClientPath[];
-
-} // namespace display
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libdisplay/include/CPPLINT.cfg b/libs/vr/libdisplay/include/CPPLINT.cfg
deleted file mode 100644
index 2f8a3c0..0000000
--- a/libs/vr/libdisplay/include/CPPLINT.cfg
+++ /dev/null
@@ -1 +0,0 @@
-filter=-build/header_guard
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
deleted file mode 100644
index 81546ac..0000000
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ /dev/null
@@ -1,100 +0,0 @@
-#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>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/display_protocol.h>
-
-namespace android {
-namespace dvr {
-namespace display {
-
-class Surface : public pdx::ClientBase<Surface> {
- public:
- // Utility named constructor. This can be removed once ClientBase::Create is
- // refactored to return Status<T> types.
- static pdx::Status<std::unique_ptr<Surface>> CreateSurface(
- const SurfaceAttributes& attributes) {
- int error;
- pdx::Status<std::unique_ptr<Surface>> status;
- if (auto surface = Create(attributes, &error))
- status.SetValue(std::move(surface));
- else
- status.SetError(error);
- return status;
- }
-
- int surface_id() const { return surface_id_; }
- int z_order() const { return z_order_; }
- bool visible() const { return visible_; }
-
- pdx::Status<void> SetVisible(bool visible);
- pdx::Status<void> SetZOrder(int z_order);
- pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes);
-
- // Creates an empty queue.
- 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.
- pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width,
- uint32_t height,
- uint32_t layer_count,
- uint32_t format,
- uint64_t usage,
- size_t capacity,
- size_t metadata_size);
-
- private:
- friend BASE;
-
- int surface_id_ = -1;
- int z_order_ = 0;
- bool visible_ = false;
-
- // TODO(eieio,avakulenko): Remove error param once pdx::ClientBase::Create()
- // returns Status<T>.
- explicit Surface(const SurfaceAttributes& attributes, int* error = nullptr);
- explicit Surface(pdx::LocalChannelHandle channel_handle,
- int* error = nullptr);
-
- Surface(const Surface&) = delete;
- void operator=(const Surface&) = delete;
-};
-
-class DisplayClient : public pdx::ClientBase<DisplayClient> {
- public:
- pdx::Status<Metrics> GetDisplayMetrics();
- pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type);
- pdx::Status<uint8_t> GetDisplayIdentificationPort();
- 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);
-
- // Temporary query for current VR status. Will be removed later.
- pdx::Status<bool> IsVrAppRunning();
-
- private:
- friend BASE;
-
- explicit DisplayClient(int* error = nullptr);
-
- DisplayClient(const DisplayClient&) = delete;
- void operator=(const DisplayClient&) = delete;
-};
-
-} // namespace display
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_DISPLAY_CLIENT_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
deleted file mode 100644
index 45aef51..0000000
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef ANDROID_DVR_DISPLAY_MANAGER_CLIENT_H_
-#define ANDROID_DVR_DISPLAY_MANAGER_CLIENT_H_
-
-#include <string>
-#include <vector>
-
-#include <pdx/client.h>
-#include <pdx/status.h>
-#include <private/dvr/display_protocol.h>
-
-namespace android {
-namespace dvr {
-
-class IonBuffer;
-class ConsumerQueue;
-
-namespace display {
-
-class DisplayManagerClient : public pdx::ClientBase<DisplayManagerClient> {
- public:
- ~DisplayManagerClient() override;
-
- pdx::Status<std::vector<SurfaceState>> GetSurfaceState();
- pdx::Status<std::unique_ptr<ConsumerQueue>> GetSurfaceQueue(int surface_id,
- int queue_id);
-
- using Client::event_fd;
-
- pdx::Status<int> GetEventMask(int events) {
- if (auto* client_channel = GetChannel())
- return client_channel->GetEventMask(events);
- else
- return pdx::ErrorStatus(EINVAL);
- }
-
- private:
- friend BASE;
-
- DisplayManagerClient();
-
- DisplayManagerClient(const DisplayManagerClient&) = delete;
- void operator=(const DisplayManagerClient&) = delete;
-};
-
-} // namespace display
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_DISPLAY_MANAGER_CLIENT_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
deleted file mode 100644
index 9f4cc4a..0000000
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ /dev/null
@@ -1,304 +0,0 @@
-#ifndef ANDROID_DVR_DISPLAY_PROTOCOL_H_
-#define ANDROID_DVR_DISPLAY_PROTOCOL_H_
-
-#include <sys/types.h>
-
-#include <array>
-#include <map>
-
-#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>
-#include <private/dvr/bufferhub_rpc.h>
-
-// RPC protocol definitions for DVR display services (VrFlinger).
-
-namespace android {
-namespace dvr {
-namespace display {
-
-// Native display metrics.
-struct Metrics {
- // Basic display properties.
- uint32_t display_width;
- uint32_t display_height;
- uint32_t display_x_dpi;
- uint32_t display_y_dpi;
- uint32_t vsync_period_ns;
-
- // HMD metrics.
- // TODO(eieio): Determine how these fields should be populated. On phones
- // these values are determined at runtime by VrCore based on which headset the
- // phone is in. On dedicated hardware this needs to come from somewhere else.
- // Perhaps these should be moved to a separate structure that is returned by a
- // separate runtime call.
- uint32_t distorted_width;
- uint32_t distorted_height;
- uint32_t hmd_ipd_mm;
- float inter_lens_distance_m;
- std::array<float, 4> left_fov_lrbt;
- std::array<float, 4> right_fov_lrbt;
-
- private:
- PDX_SERIALIZABLE_MEMBERS(Metrics, display_width, display_height,
- display_x_dpi, display_y_dpi, vsync_period_ns,
- distorted_width, distorted_height, hmd_ipd_mm,
- inter_lens_distance_m, left_fov_lrbt,
- right_fov_lrbt);
-};
-
-// Serializable base type for enum structs. Enum structs are easier to use than
-// enum classes, especially for bitmasks. This base type provides common
-// utilities for flags types.
-template <typename Integer>
-class Flags {
- public:
- using Base = Flags<Integer>;
- using Type = Integer;
-
- // NOLINTNEXTLINE(google-explicit-constructor)
- Flags(const Integer& value) : value_{value} {}
- Flags(const Flags&) = default;
- Flags& operator=(const Flags&) = default;
-
- Integer value() const { return value_; }
- // NOLINTNEXTLINE(google-explicit-constructor)
- operator Integer() const { return value_; }
-
- bool IsSet(Integer bits) const { return (value_ & bits) == bits; }
- bool IsClear(Integer bits) const { return (value_ & bits) == 0; }
-
- void Set(Integer bits) { value_ |= bits; }
- void Clear(Integer bits) { value_ &= ~bits; }
-
- Integer operator|(Integer bits) const { return value_ | bits; }
- Integer operator&(Integer bits) const { return value_ & bits; }
-
- Flags& operator|=(Integer bits) {
- value_ |= bits;
- return *this;
- }
- Flags& operator&=(Integer bits) {
- value_ &= bits;
- return *this;
- }
-
- private:
- Integer value_;
-
- PDX_SERIALIZABLE_MEMBERS(Flags<Integer>, value_);
-};
-
-// Flags indicating what changed since last update.
-struct SurfaceUpdateFlags : public Flags<uint32_t> {
- enum : Type {
- None = DVR_SURFACE_UPDATE_FLAGS_NONE,
- NewSurface = DVR_SURFACE_UPDATE_FLAGS_NEW_SURFACE,
- BuffersChanged = DVR_SURFACE_UPDATE_FLAGS_BUFFERS_CHANGED,
- VisibilityChanged = DVR_SURFACE_UPDATE_FLAGS_VISIBILITY_CHANGED,
- AttributesChanged = DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED,
- };
-
- SurfaceUpdateFlags() : Base{None} {}
- using Base::Base;
-};
-
-// Surface attribute key/value types.
-using SurfaceAttributeKey = int32_t;
-using SurfaceAttributeValue =
- pdx::rpc::Variant<int32_t, int64_t, bool, float, std::array<float, 2>,
- std::array<float, 3>, std::array<float, 4>,
- std::array<float, 8>, std::array<float, 16>>;
-
-// Defined surface attribute keys.
-struct SurfaceAttribute : public Flags<SurfaceAttributeKey> {
- enum : Type {
- // Keys in the negative integer space are interpreted by VrFlinger for
- // direct surfaces.
- Direct = DVR_SURFACE_ATTRIBUTE_DIRECT,
- ZOrder = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
- Visible = DVR_SURFACE_ATTRIBUTE_VISIBLE,
-
- // Invalid key. May be used to terminate C style lists in public API code.
- Invalid = DVR_SURFACE_ATTRIBUTE_INVALID,
-
- // Positive keys are interpreted by the compositor only.
- FirstUserKey = DVR_SURFACE_ATTRIBUTE_FIRST_USER_KEY,
- };
-
- SurfaceAttribute() : Base{Invalid} {}
- using Base::Base;
-};
-
-// Collection of surface attribute key/value pairs.
-using SurfaceAttributes = std::map<SurfaceAttributeKey, SurfaceAttributeValue>;
-
-struct SurfaceState {
- int32_t surface_id;
- int32_t process_id;
- int32_t user_id;
-
- SurfaceAttributes surface_attributes;
- SurfaceUpdateFlags update_flags;
- std::vector<int32_t> queue_ids;
-
- // Convenience accessors.
- bool GetVisible() const {
- bool bool_value = false;
- GetAttribute(SurfaceAttribute::Visible, &bool_value,
- ValidTypes<int32_t, int64_t, bool, float>{});
- return bool_value;
- }
-
- int GetZOrder() const {
- int int_value = 0;
- GetAttribute(SurfaceAttribute::ZOrder, &int_value,
- ValidTypes<int32_t, int64_t, float>{});
- return int_value;
- }
-
- private:
- template <typename... Types>
- struct ValidTypes {};
-
- template <typename ReturnType, typename... Types>
- bool GetAttribute(SurfaceAttributeKey key, ReturnType* out_value,
- ValidTypes<Types...>) const {
- auto search = surface_attributes.find(key);
- if (search != surface_attributes.end())
- return pdx::rpc::IfAnyOf<Types...>::Get(&search->second, out_value);
- else
- return false;
- }
-
- PDX_SERIALIZABLE_MEMBERS(SurfaceState, surface_id, process_id,
- surface_attributes, update_flags, queue_ids);
-};
-
-struct SurfaceInfo {
- int surface_id;
- bool visible;
- int z_order;
-
- private:
- PDX_SERIALIZABLE_MEMBERS(SurfaceInfo, surface_id, visible, z_order);
-};
-
-enum class ConfigFileType : uint32_t {
- kLensMetrics,
- kDeviceMetrics,
- kDeviceConfiguration,
- kDeviceEdid
-};
-
-struct DisplayProtocol {
- // Service path.
- static constexpr char kClientPath[] = "system/vr/display/client";
-
- // Op codes.
- enum {
- kOpGetMetrics = 0,
- kOpGetConfigurationData,
- kOpSetupGlobalBuffer,
- kOpDeleteGlobalBuffer,
- kOpGetGlobalBuffer,
- kOpIsVrAppRunning,
- kOpCreateSurface,
- kOpGetSurfaceInfo,
- kOpCreateQueue,
- kOpSetAttributes,
- kOpGetDisplayIdentificationPort,
- };
-
- // Aliases.
- using LocalChannelHandle = pdx::LocalChannelHandle;
- using Void = pdx::rpc::Void;
-
- // Methods.
- PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void));
- PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData,
- std::string(ConfigFileType config_type));
- PDX_REMOTE_METHOD(GetDisplayIdentificationPort,
- kOpGetDisplayIdentificationPort, uint8_t(Void));
- 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(const ProducerQueueConfig& producer_config));
- PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes,
- void(const SurfaceAttributes& attributes));
-};
-
-struct DisplayManagerProtocol {
- // Service path.
- static constexpr char kClientPath[] = "system/vr/display/manager";
-
- // Op codes.
- enum {
- kOpGetSurfaceState = 0,
- kOpGetSurfaceQueue,
- };
-
- // Aliases.
- using LocalChannelHandle = pdx::LocalChannelHandle;
- using Void = pdx::rpc::Void;
-
- // Methods.
- PDX_REMOTE_METHOD(GetSurfaceState, kOpGetSurfaceState,
- std::vector<SurfaceState>(Void));
- PDX_REMOTE_METHOD(GetSurfaceQueue, kOpGetSurfaceQueue,
- LocalChannelHandle(int surface_id, int queue_id));
-};
-
-struct VSyncSchedInfo {
- int64_t vsync_period_ns;
- int64_t timestamp_ns;
- uint32_t next_vsync_count;
-
- private:
- PDX_SERIALIZABLE_MEMBERS(VSyncSchedInfo, vsync_period_ns, timestamp_ns,
- next_vsync_count);
-};
-
-struct VSyncProtocol {
- // Service path.
- static constexpr char kClientPath[] = "system/vr/display/vsync";
-
- // Op codes.
- enum {
- kOpWait = 0,
- kOpAck,
- kOpGetLastTimestamp,
- kOpGetSchedInfo,
- kOpAcknowledge,
- };
-
- // Aliases.
- using Void = pdx::rpc::Void;
- using Timestamp = int64_t;
-
- // Methods.
- PDX_REMOTE_METHOD(Wait, kOpWait, Timestamp(Void));
- PDX_REMOTE_METHOD(GetLastTimestamp, kOpGetLastTimestamp, Timestamp(Void));
- PDX_REMOTE_METHOD(GetSchedInfo, kOpGetSchedInfo, VSyncSchedInfo(Void));
- PDX_REMOTE_METHOD(Acknowledge, kOpAcknowledge, void(Void));
-};
-
-} // namespace display
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_DISPLAY_PROTOCOL_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
deleted file mode 100644
index 20541a6..0000000
--- a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
+++ /dev/null
@@ -1,146 +0,0 @@
-#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/include/private/dvr/vsync_service.h b/libs/vr/libdisplay/include/private/dvr/vsync_service.h
deleted file mode 100644
index 152464a..0000000
--- a/libs/vr/libdisplay/include/private/dvr/vsync_service.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef ANDROID_DVR_VSYNC_SERVICE_H_
-#define ANDROID_DVR_VSYNC_SERVICE_H_
-
-#include <binder/IInterface.h>
-
-namespace android {
-namespace dvr {
-
-class IVsyncCallback : public IInterface {
- public:
- DECLARE_META_INTERFACE(VsyncCallback)
-
- enum {
- ON_VSYNC = IBinder::FIRST_CALL_TRANSACTION
- };
-
- virtual status_t onVsync(int64_t vsync_timestamp) = 0;
-};
-
-class BnVsyncCallback : public BnInterface<IVsyncCallback> {
- public:
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags = 0);
-};
-
-// Register a callback with IVsyncService to be notified of vsync events and
-// timestamps. There's also a shared memory vsync buffer defined in
-// dvr_shared_buffers.h. IVsyncService has advantages over the vsync shared
-// memory buffer that make it preferable in certain situations:
-//
-// 1. The shared memory buffer lifetime is controlled by VrCore. IVsyncService
-// is always available as long as surface flinger is running.
-//
-// 2. IVsyncService will make a binder callback when a vsync event occurs. This
-// allows the client to not write code to implement periodic "get the latest
-// vsync" calls, which is necessary with the vsync shared memory buffer.
-//
-// 3. The IVsyncService provides the real vsync timestamp reported by hardware
-// composer, whereas the vsync shared memory buffer only has predicted vsync
-// times.
-class IVsyncService : public IInterface {
-public:
- DECLARE_META_INTERFACE(VsyncService)
-
- static const char* GetServiceName() { return "vrflinger_vsync"; }
-
- enum {
- REGISTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
- UNREGISTER_CALLBACK
- };
-
- virtual status_t registerCallback(const sp<IVsyncCallback> callback) = 0;
- virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) = 0;
-};
-
-class BnVsyncService : public BnInterface<IVsyncService> {
- public:
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags = 0);
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_VSYNC_SERVICE_H_
diff --git a/libs/vr/libdisplay/shared_buffer_helpers.cpp b/libs/vr/libdisplay/shared_buffer_helpers.cpp
deleted file mode 100644
index 6ebf487..0000000
--- a/libs/vr/libdisplay/shared_buffer_helpers.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-#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/libdisplay/system/CPPLINT.cfg b/libs/vr/libdisplay/system/CPPLINT.cfg
deleted file mode 100644
index 2f8a3c0..0000000
--- a/libs/vr/libdisplay/system/CPPLINT.cfg
+++ /dev/null
@@ -1 +0,0 @@
-filter=-build/header_guard
diff --git a/libs/vr/libdisplay/vsync_service.cpp b/libs/vr/libdisplay/vsync_service.cpp
deleted file mode 100644
index 04d4f30..0000000
--- a/libs/vr/libdisplay/vsync_service.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-#include "include/private/dvr/vsync_service.h"
-
-#include <binder/Parcel.h>
-#include <log/log.h>
-
-namespace android {
-namespace dvr {
-
-status_t BnVsyncCallback::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- switch (code) {
- case ON_VSYNC: {
- CHECK_INTERFACE(IVsyncCallback, data, reply);
- int64_t vsync_timestamp = 0;
- status_t result = data.readInt64(&vsync_timestamp);
- if (result != OK) {
- ALOGE("onVsync failed to readInt64: %d", result);
- return result;
- }
- onVsync(vsync_timestamp);
- return OK;
- }
- default: {
- return BBinder::onTransact(code, data, reply, flags);
- }
- }
-}
-
-class BpVsyncCallback : public BpInterface<IVsyncCallback> {
-public:
- explicit BpVsyncCallback(const sp<IBinder>& impl)
- : BpInterface<IVsyncCallback>(impl) {}
- virtual ~BpVsyncCallback() {}
-
- virtual status_t onVsync(int64_t vsync_timestamp) {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(
- IVsyncCallback::getInterfaceDescriptor());
- if (result != OK) {
- ALOGE("onVsync failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeInt64(vsync_timestamp);
- if (result != OK) {
- ALOGE("onVsync failed to writeInt64: %d", result);
- return result;
- }
- result = remote()->transact(BnVsyncCallback::ON_VSYNC, data, &reply,
- IBinder::FLAG_ONEWAY);
- if (result != OK) {
- ALOGE("onVsync failed to transact: %d", result);
- return result;
- }
- return result;
- }
-};
-
-IMPLEMENT_META_INTERFACE(VsyncCallback, "android.dvr.IVsyncCallback");
-
-
-status_t BnVsyncService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- switch (code) {
- case REGISTER_CALLBACK: {
- CHECK_INTERFACE(IVsyncService, data, reply);
- sp<IBinder> callback;
- status_t result = data.readStrongBinder(&callback);
- if (result != OK) {
- ALOGE("registerCallback failed to readStrongBinder: %d", result);
- return result;
- }
- registerCallback(interface_cast<IVsyncCallback>(callback));
- return OK;
- }
- case UNREGISTER_CALLBACK: {
- CHECK_INTERFACE(IVsyncService, data, reply);
- sp<IBinder> callback;
- status_t result = data.readStrongBinder(&callback);
- if (result != OK) {
- ALOGE("unregisterCallback failed to readStrongBinder: %d", result);
- return result;
- }
- unregisterCallback(interface_cast<IVsyncCallback>(callback));
- return OK;
- }
- default: {
- return BBinder::onTransact(code, data, reply, flags);
- }
- }
-}
-
-class BpVsyncService : public BpInterface<IVsyncService> {
-public:
- explicit BpVsyncService(const sp<IBinder>& impl)
- : BpInterface<IVsyncService>(impl) {}
- virtual ~BpVsyncService() {}
-
- virtual status_t registerCallback(const sp<IVsyncCallback> callback) {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(
- IVsyncService::getInterfaceDescriptor());
- if (result != OK) {
- ALOGE("registerCallback failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(IInterface::asBinder(callback));
- if (result != OK) {
- ALOGE("registerCallback failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(
- BnVsyncService::REGISTER_CALLBACK, data, &reply);
- if (result != OK) {
- ALOGE("registerCallback failed to transact: %d", result);
- return result;
- }
- return result;
- }
-
- virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(
- IVsyncService::getInterfaceDescriptor());
- if (result != OK) {
- ALOGE("unregisterCallback failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(IInterface::asBinder(callback));
- if (result != OK) {
- ALOGE("unregisterCallback failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(
- BnVsyncService::UNREGISTER_CALLBACK, data, &reply);
- if (result != OK) {
- ALOGE("unregisterCallback failed to transact: %d", result);
- return result;
- }
- return result;
- }
-};
-
-IMPLEMENT_META_INTERFACE(VsyncService, "android.dvr.IVsyncService");
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 96023dd..9dbeacb 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -33,87 +33,3 @@
],
min_sdk_version: "29",
}
-
-cc_library_headers {
- name: "libdvr_private_headers",
- export_include_dirs: ["."],
- vendor_available: false,
-}
-
-cflags = [
- "-DDVR_TRACKING_IMPLEMENTED=0",
- "-DLOG_TAG=\"libdvr\"",
- "-DTRACE=0",
- "-Wall",
- "-Werror",
-]
-
-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_pose.cpp",
- "dvr_surface.cpp",
- "dvr_tracking.cpp",
-]
-
-static_libs = [
- "libbroadcastring",
- "libvrsensor",
- "libdisplay",
- "libvirtualtouchpadclient",
- "libvr_hwc-impl",
- "libvr_hwc-binder",
- "libgrallocusage",
- "libperformance",
-]
-
-shared_libs = [
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hidl.token@1.0-utils",
- "libbase",
- "libbufferhubqueue",
- "libbinder",
- "liblog",
- "libcutils",
- "libutils",
- "libnativewindow",
- "libgui",
- "libui",
- "libpdx_default_transport",
-]
-
-cc_library_shared {
- name: "libdvr.google",
- system_ext_specific: true,
- owner: "google",
- cflags: cflags,
- header_libs: ["libdvr_headers"],
- export_header_lib_headers: ["libdvr_headers"],
- srcs: srcs,
- static_libs: static_libs,
- shared_libs: shared_libs,
- version_script: "exported_apis.lds",
-}
-
-// Also build a static libdvr for linking into tests. The linker script
-// restricting function access in the shared lib makes it inconvenient to use in
-// test code.
-cc_library_static {
- name: "libdvr_static.google",
- owner: "google",
- cflags: cflags,
- header_libs: ["libdvr_headers"],
- export_header_lib_headers: ["libdvr_headers"],
- srcs: srcs,
- static_libs: static_libs,
- shared_libs: shared_libs,
-}
-
-subdirs = [
- "tests",
-]
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
deleted file mode 100644
index e099f6a..0000000
--- a/libs/vr/libdvr/dvr_api.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "include/dvr/dvr_api.h"
-
-#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_tracking.h>
-#include <dvr/dvr_vsync.h>
-
-// Headers not yet moved into libdvr.
-// TODO(jwcai) Move these once their callers are moved into Google3.
-#include <dvr/dvr_hardware_composer_client.h>
-#include <dvr/pose_client.h>
-#include <dvr/virtual_touchpad_client.h>
-
-extern "C" {
-
-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) {
- // 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) \
- do { \
- if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
- clamped_struct_size) { \
- dvr_api->name = dvr##name; \
- } \
- } while (0)
-
-#define DVR_V1_API_ENTRY_DEPRECATED(name) \
- do { \
- if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
- clamped_struct_size) { \
- dvr_api->name = nullptr; \
- } \
- } while (0)
-
-#include "include/dvr/dvr_api_entries.h"
-
-// Undefine macro definitions to play nice with Google3 style rules.
-#undef DVR_V1_API_ENTRY
-#undef DVR_V1_API_ENTRY_DEPRECATED
-
- return 0;
- }
-
- ALOGE("dvrGetApi: Unknown API version=%d", version);
- return -EINVAL;
-}
-
-} // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
deleted file mode 100644
index c11706f..0000000
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-#include "include/dvr/dvr_buffer.h"
-
-#include <android/hardware_buffer.h>
-#include <dvr/dvr_shared_buffers.h>
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/producer_buffer.h>
-#include <ui/GraphicBuffer.h>
-
-#include "dvr_internal.h"
-
-using namespace android;
-
-namespace android {
-namespace dvr {
-
-DvrBuffer* CreateDvrBufferFromIonBuffer(
- const std::shared_ptr<IonBuffer>& ion_buffer) {
- if (!ion_buffer)
- return nullptr;
- return new DvrBuffer{std::move(ion_buffer)};
-}
-
-} // namespace dvr
-} // namespace android
-
-namespace {
-
-int ConvertToAHardwareBuffer(GraphicBuffer* graphic_buffer,
- AHardwareBuffer** hardware_buffer) {
- if (!hardware_buffer || !graphic_buffer) {
- return -EINVAL;
- }
- *hardware_buffer = reinterpret_cast<AHardwareBuffer*>(graphic_buffer);
- AHardwareBuffer_acquire(*hardware_buffer);
- return 0;
-}
-
-} // anonymous namespace
-
-extern "C" {
-
-void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) {
- if (write_buffer != nullptr) {
- ALOGW_IF(
- write_buffer->slot != -1,
- "dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
- "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
- dvrWriteBufferGetId(write_buffer));
- delete write_buffer;
- }
-}
-
-int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer) {
- return write_buffer && write_buffer->write_buffer;
-}
-
-int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer) {
- if (!write_buffer || !write_buffer->write_buffer)
- return -EINVAL;
-
- return write_buffer->write_buffer->id();
-}
-
-int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* write_buffer,
- AHardwareBuffer** hardware_buffer) {
- if (!write_buffer || !write_buffer->write_buffer)
- return -EINVAL;
-
- return ConvertToAHardwareBuffer(
- write_buffer->write_buffer->buffer()->buffer().get(), hardware_buffer);
-}
-
-void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) {
- if (read_buffer != nullptr) {
- ALOGW_IF(
- read_buffer->slot != -1,
- "dvrReadBufferDestroy: Destroying a buffer associated with a valid "
- "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
- dvrReadBufferGetId(read_buffer));
- delete read_buffer;
- }
-}
-
-int dvrReadBufferIsValid(DvrReadBuffer* read_buffer) {
- return read_buffer && read_buffer->read_buffer;
-}
-
-int dvrReadBufferGetId(DvrReadBuffer* read_buffer) {
- if (!read_buffer || !read_buffer->read_buffer)
- return -EINVAL;
-
- return read_buffer->read_buffer->id();
-}
-
-int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* read_buffer,
- AHardwareBuffer** hardware_buffer) {
- if (!read_buffer || !read_buffer->read_buffer)
- return -EINVAL;
-
- return ConvertToAHardwareBuffer(
- read_buffer->read_buffer->buffer()->buffer().get(), hardware_buffer);
-}
-
-void dvrBufferDestroy(DvrBuffer* buffer) { delete buffer; }
-
-int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer,
- AHardwareBuffer** hardware_buffer) {
- if (!buffer || !buffer->buffer || !hardware_buffer) {
- return -EINVAL;
- }
-
- return ConvertToAHardwareBuffer(buffer->buffer->buffer().get(),
- hardware_buffer);
-}
-
-// Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
-int dvrBufferGlobalLayoutVersionGet() {
- return android::dvr::kSharedBufferLayoutVersion;
-}
-
-} // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
deleted file mode 100644
index 1ca653c..0000000
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ /dev/null
@@ -1,552 +0,0 @@
-#include "include/dvr/dvr_api.h"
-#include "include/dvr/dvr_buffer_queue.h"
-
-#include <android/native_window.h>
-#include <gui/BufferHubProducer.h>
-
-#include "dvr_internal.h"
-#include "dvr_buffer_queue_internal.h"
-
-using namespace android;
-using android::dvr::BufferHubBase;
-using android::dvr::ConsumerBuffer;
-using android::dvr::ConsumerQueue;
-using android::dvr::ProducerBuffer;
-using android::dvr::ProducerQueue;
-using android::dvr::ProducerQueueConfigBuilder;
-using android::dvr::UsagePolicy;
-
-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()) {}
-
-int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
- if (native_window_ == nullptr) {
- // Lazy creation of |native_window|, as not everyone is using
- // DvrWriteBufferQueue as an external surface.
- sp<IGraphicBufferProducer> gbp = BufferHubProducer::Create(producer_queue_);
- native_window_ = new Surface(gbp, true);
- }
-
- *out_window = static_cast<ANativeWindow*>(native_window_.get());
- return 0;
-}
-
-int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
- std::unique_ptr<ConsumerQueue> consumer_queue =
- producer_queue_->CreateConsumerQueue();
- if (consumer_queue == nullptr) {
- ALOGE(
- "DvrWriteBufferQueue::CreateReadQueue: Failed to create consumer queue "
- "from producer queue: queue_id=%d.", producer_queue_->id());
- return -ENOMEM;
- }
-
- *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
- return 0;
-}
-
-int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
- int* out_fence_fd) {
- DvrNativeBufferMetadata meta;
- DvrWriteBuffer* buffer = nullptr;
- int fence_fd = -1;
- if (const int ret = GainBuffer(timeout, &buffer, &meta, &fence_fd))
- return ret;
- if (!buffer)
- return -ENOMEM;
-
- write_buffers_[buffer->slot].reset(buffer);
- write_buffer->write_buffer = std::move(buffer->write_buffer);
- *out_fence_fd = fence_fd;
- return 0;
-}
-
-int DvrWriteBufferQueue::GainBuffer(int timeout,
- DvrWriteBuffer** out_write_buffer,
- DvrNativeBufferMetadata* out_meta,
- int* out_fence_fd) {
- size_t slot;
- pdx::LocalHandle release_fence;
-
- // 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, out_meta, &release_fence);
- if (!buffer_status) {
- ALOGE_IF(buffer_status.error() != ETIMEDOUT,
- "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer: %s",
- buffer_status.GetErrorMessage().c_str());
- return -buffer_status.error();
- }
-
- if (write_buffers_[slot] == nullptr) {
- // Lazy initialization of a write_buffers_ slot. Note that a slot will
- // only be dynamically allocated once during the entire cycle life of a
- // queue.
- write_buffers_[slot] = std::make_unique<DvrWriteBuffer>();
- write_buffers_[slot]->slot = slot;
- }
-
- LOG_ALWAYS_FATAL_IF(
- write_buffers_[slot]->write_buffer,
- "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot);
- write_buffers_[slot]->write_buffer = std::move(buffer_status.take());
-
- const auto& producer_buffer = write_buffers_[slot]->write_buffer;
- if (!producer_buffer)
- return -ENOMEM;
-
- if (width_ == producer_buffer->width() &&
- height_ == producer_buffer->height() &&
- format_ == producer_buffer->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_, producer_buffer->width(),
- producer_buffer->height(), producer_buffer->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 = producer_buffer->layer_count();
- uint64_t old_usage = producer_buffer->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();
- }
- // Make sure that the previously allocated buffer is dereferenced from
- // write_buffers_ array.
- write_buffers_[slot]->write_buffer = nullptr;
-
- 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;
- }
-
- *out_write_buffer = write_buffers_[slot].release();
- *out_fence_fd = release_fence.Release();
-
- return 0;
-}
-
-int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer,
- const DvrNativeBufferMetadata* meta,
- int ready_fence_fd) {
- // Some basic sanity checks before we put the buffer back into a slot.
- size_t slot = static_cast<size_t>(write_buffer->slot);
- LOG_FATAL_IF(
- (write_buffers->slot < 0 || write_buffers->slot >= write_buffers_.size()),
- "DvrWriteBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
-
- if (write_buffers_[slot] != nullptr) {
- ALOGE("DvrWriteBufferQueue::PostBuffer: Slot is not empty: %zu", slot);
- return -EINVAL;
- }
- if (write_buffer->write_buffer == nullptr) {
- ALOGE("DvrWriteBufferQueue::PostBuffer: Invalid write buffer.");
- return -EINVAL;
- }
- if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) {
- ALOGE(
- "DvrWriteBufferQueue::PostBuffer: Buffer to be posted does not "
- "belong to this buffer queue. Posting buffer: id=%d, buffer in "
- "queue: id=%d",
- write_buffer->write_buffer->id(), producer_queue_->GetBufferId(slot));
- return -EINVAL;
- }
-
- write_buffer->write_buffer->SetQueueIndex(next_post_index_++);
- pdx::LocalHandle fence(ready_fence_fd);
- const int ret = write_buffer->write_buffer->PostAsync(meta, fence);
- if (ret < 0) {
- ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d",
- ret);
- return ret;
- }
-
- // Put the DvrWriteBuffer pointer back into its slot for reuse.
- write_buffers_[slot].reset(write_buffer);
- // It's import to reset the write buffer client now. It should stay invalid
- // until next GainBuffer on the same slot.
- write_buffers_[slot]->write_buffer = nullptr;
- return 0;
-}
-
-int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) {
- if (width == 0 || height == 0) {
- ALOGE(
- "DvrWriteBufferQueue::ResizeBuffer: invalid buffer dimension: w=%u, "
- "h=%u.",
- width, height);
- return -EINVAL;
- }
-
- width_ = width;
- height_ = height;
- return 0;
-}
-
-int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
- uint32_t layer_count, uint64_t usage,
- size_t capacity, size_t metadata_size,
- DvrWriteBufferQueue** out_write_queue) {
- if (!out_write_queue)
- return -EINVAL;
-
- auto config_builder = ProducerQueueConfigBuilder()
- .SetDefaultWidth(width)
- .SetDefaultHeight(height)
- .SetDefaultFormat(format)
- .SetMetadataSize(metadata_size);
- std::unique_ptr<ProducerQueue> producer_queue =
- ProducerQueue::Create(config_builder.Build(), UsagePolicy{});
- if (!producer_queue) {
- ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue.");
- return -ENOMEM;
- }
-
- auto status = producer_queue->AllocateBuffers(width, height, layer_count,
- format, usage, capacity);
- if (!status.ok()) {
- ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers.");
- return -ENOMEM;
- }
-
- *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue));
- return 0;
-}
-
-void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
- delete write_queue;
-}
-
-ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
- if (!write_queue)
- return -EINVAL;
-
- return write_queue->capacity();
-}
-
-int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
- if (!write_queue)
- return -EINVAL;
-
- return write_queue->id();
-}
-
-int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
- ANativeWindow** out_window) {
- if (!write_queue || !out_window)
- return -EINVAL;
-
- return write_queue->GetNativeWindow(out_window);
-}
-
-int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
- DvrReadBufferQueue** out_read_queue) {
- if (!write_queue || !out_read_queue)
- return -EINVAL;
-
- return write_queue->CreateReadQueue(out_read_queue);
-}
-
-int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
- DvrWriteBuffer** out_write_buffer,
- DvrNativeBufferMetadata* out_meta,
- int* out_fence_fd) {
- if (!write_queue || !out_write_buffer || !out_meta || !out_fence_fd)
- return -EINVAL;
-
- return write_queue->GainBuffer(timeout, out_write_buffer, out_meta,
- out_fence_fd);
-}
-
-int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
- DvrWriteBuffer* write_buffer,
- const DvrNativeBufferMetadata* meta,
- int ready_fence_fd) {
- if (!write_queue || !write_buffer || !write_buffer->write_buffer || !meta)
- return -EINVAL;
-
- return write_queue->PostBuffer(write_buffer, meta, ready_fence_fd);
-}
-
-int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
- uint32_t width, uint32_t height) {
- if (!write_queue)
- return -EINVAL;
-
- 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(
- "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue "
- "from producer queue: queue_id=%d.", consumer_queue_->id());
- return -ENOMEM;
- }
-
- *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
- return 0;
-}
-
-int DvrReadBufferQueue::AcquireBuffer(int timeout,
- DvrReadBuffer** out_read_buffer,
- DvrNativeBufferMetadata* out_meta,
- int* out_fence_fd) {
- size_t slot;
- pdx::LocalHandle acquire_fence;
- auto buffer_status =
- consumer_queue_->Dequeue(timeout, &slot, out_meta, &acquire_fence);
- if (!buffer_status) {
- ALOGE_IF(buffer_status.error() != ETIMEDOUT,
- "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer: %s",
- buffer_status.GetErrorMessage().c_str());
- return -buffer_status.error();
- }
-
- if (read_buffers_[slot] == nullptr) {
- // Lazy initialization of a read_buffers_ slot. Note that a slot will only
- // be dynamically allocated once during the entire cycle life of a queue.
- read_buffers_[slot] = std::make_unique<DvrReadBuffer>();
- read_buffers_[slot]->slot = slot;
- }
-
- LOG_FATAL_IF(
- read_buffers_[slot]->read_buffer,
- "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot);
- read_buffers_[slot]->read_buffer = std::move(buffer_status.take());
-
- *out_read_buffer = read_buffers_[slot].release();
- *out_fence_fd = acquire_fence.Release();
-
- return 0;
-}
-
-int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer,
- const DvrNativeBufferMetadata* meta,
- int release_fence_fd) {
- // Some basic sanity checks before we put the buffer back into a slot.
- size_t slot = static_cast<size_t>(read_buffer->slot);
- LOG_FATAL_IF(
- (read_buffers->slot < 0 || read_buffers->slot >= read_buffers_size()),
- "DvrReadBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
-
- if (read_buffers_[slot] != nullptr) {
- ALOGE("DvrReadBufferQueue::ReleaseBuffer: Slot is not empty: %zu", slot);
- return -EINVAL;
- }
- if (read_buffer->read_buffer == nullptr) {
- ALOGE("DvrReadBufferQueue::ReleaseBuffer: Invalid read buffer.");
- return -EINVAL;
- }
- if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
- if (consumer_queue_->GetBufferId(slot) > 0) {
- ALOGE(
- "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
- "belong to this queue (queue_id=%d): attempting to release buffer "
- "(buffer_id=%d) at slot %d which holds a different buffer "
- "(buffer_id=%d).",
- consumer_queue_->id(), read_buffer->read_buffer->id(),
- static_cast<int>(slot), consumer_queue_->GetBufferId(slot));
- } else {
- ALOGI(
- "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
- "belong to this queue (queue_id=%d): attempting to release buffer "
- "(buffer_id=%d) at slot %d which is empty.",
- consumer_queue_->id(), read_buffer->read_buffer->id(),
- static_cast<int>(slot));
- }
- }
-
- pdx::LocalHandle fence(release_fence_fd);
- int ret = read_buffer->read_buffer->ReleaseAsync(meta, fence);
- if (ret < 0) {
- ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d",
- ret);
- return ret;
- }
-
- // Put the DvrReadBuffer pointer back into its slot for reuse.
- read_buffers_[slot].reset(read_buffer);
- // It's import to reset the read buffer client now. It should stay invalid
- // until next AcquireBuffer on the same slot.
- read_buffers_[slot]->read_buffer = nullptr;
- 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<BufferHubBase>& buffer) {
- // When buffer is removed from the queue, the slot is already invalid.
- auto read_buffer = std::make_unique<DvrReadBuffer>();
- read_buffer->read_buffer =
- std::static_pointer_cast<ConsumerBuffer>(buffer);
- callback(read_buffer.release(), context);
- });
- }
-}
-
-int DvrReadBufferQueue::HandleEvents() {
- // TODO(jwcai) Probably should change HandleQueueEvents to return Status.
- consumer_queue_->HandleQueueEvents();
- return 0;
-}
-
-void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
- delete read_queue;
-}
-
-ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
- if (!read_queue)
- return -EINVAL;
-
- return read_queue->capacity();
-}
-
-int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
- if (!read_queue)
- return -EINVAL;
-
- return read_queue->id();
-}
-
-int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue) {
- if (!read_queue)
- return -EINVAL;
-
- return read_queue->event_fd();
-}
-
-int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
- DvrReadBufferQueue** out_read_queue) {
- if (!read_queue || !out_read_queue)
- return -EINVAL;
-
- return read_queue->CreateReadQueue(out_read_queue);
-}
-
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
- DvrReadBuffer* read_buffer, int* out_fence_fd,
- void* out_meta, size_t meta_size_bytes) {
- if (!read_queue || !read_buffer || !out_fence_fd)
- return -EINVAL;
-
- if (meta_size_bytes != 0 && !out_meta)
- return -EINVAL;
-
- return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
- meta_size_bytes);
-}
-
-int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
- DvrReadBuffer** out_read_buffer,
- DvrNativeBufferMetadata* out_meta,
- int* out_fence_fd) {
- if (!read_queue || !out_read_buffer || !out_meta || !out_fence_fd)
- return -EINVAL;
-
- return read_queue->AcquireBuffer(timeout, out_read_buffer, out_meta,
- out_fence_fd);
-}
-
-int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
- DvrReadBuffer* read_buffer,
- const DvrNativeBufferMetadata* meta,
- int release_fence_fd) {
- if (!read_queue || !read_buffer || !read_buffer->read_buffer || !meta)
- return -EINVAL;
-
- return read_queue->ReleaseBuffer(read_buffer, meta, release_fence_fd);
-}
-
-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
deleted file mode 100644
index e53a686..0000000
--- a/libs/vr/libdvr/dvr_buffer_queue_internal.h
+++ /dev/null
@@ -1,95 +0,0 @@
-#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 <array>
-#include <memory>
-
-#include "dvr_internal.h"
-
-struct ANativeWindow;
-
-typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata;
-typedef struct DvrReadBuffer DvrReadBuffer;
-typedef struct DvrReadBufferQueue DvrReadBufferQueue;
-typedef struct DvrWriteBuffer DvrWriteBuffer;
-typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
-typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer,
- void* context);
-
-struct DvrWriteBufferQueue {
- using BufferHubQueue = android::dvr::BufferHubQueue;
- 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 GainBuffer(int timeout, DvrWriteBuffer** out_write_buffer,
- DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
- int PostBuffer(DvrWriteBuffer* write_buffer,
- const DvrNativeBufferMetadata* meta, int ready_fence_fd);
- int ResizeBuffer(uint32_t width, uint32_t height);
-
- private:
- std::shared_ptr<ProducerQueue> producer_queue_;
- std::array<std::unique_ptr<DvrWriteBuffer>, BufferHubQueue::kMaxQueueCapacity>
- write_buffers_;
-
- int64_t next_post_index_ = 0;
- uint32_t width_;
- uint32_t height_;
- uint32_t format_;
-
- android::sp<android::Surface> native_window_;
-};
-
-struct DvrReadBufferQueue {
- using BufferHubQueue = android::dvr::BufferHubQueue;
- 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 user_metadata_size);
- int AcquireBuffer(int timeout, DvrReadBuffer** out_read_buffer,
- DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
- int ReleaseBuffer(DvrReadBuffer* read_buffer,
- const DvrNativeBufferMetadata* meta, int release_fence_fd);
- void SetBufferAvailableCallback(
- DvrReadBufferQueueBufferAvailableCallback callback, void* context);
- void SetBufferRemovedCallback(
- DvrReadBufferQueueBufferRemovedCallback callback, void* context);
- int HandleEvents();
-
- private:
- std::shared_ptr<ConsumerQueue> consumer_queue_;
- std::array<std::unique_ptr<DvrReadBuffer>, BufferHubQueue::kMaxQueueCapacity>
- read_buffers_;
-};
-
-#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
deleted file mode 100644
index df0d54e..0000000
--- a/libs/vr/libdvr/dvr_configuration_data.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#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
deleted file mode 100644
index 7f631e3..0000000
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-#include "include/dvr/dvr_display_manager.h"
-
-#include <dvr/dvr_buffer.h>
-#include <pdx/rpc/variant.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/consumer_buffer.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::dvr::ConsumerBuffer;
-using android::dvr::display::DisplayManagerClient;
-using android::dvr::display::SurfaceAttribute;
-using android::dvr::display::SurfaceAttributes;
-using android::dvr::display::SurfaceState;
-using android::pdx::rpc::EmptyVariant;
-
-namespace {
-
-// Extracts type and value from the attribute Variant and writes them into the
-// respective fields of DvrSurfaceAttribute.
-struct AttributeVisitor {
- DvrSurfaceAttribute* attribute;
-
- void operator()(int32_t value) {
- attribute->value.int32_value = value;
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
- }
- void operator()(int64_t value) {
- attribute->value.int64_value = value;
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64;
- }
- void operator()(bool value) {
- attribute->value.bool_value = value;
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
- }
- void operator()(float value) {
- attribute->value.float_value = value;
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT;
- }
- void operator()(const std::array<float, 2>& value) {
- std::copy(value.cbegin(), value.cend(), attribute->value.float2_value);
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2;
- }
- void operator()(const std::array<float, 3>& value) {
- std::copy(value.cbegin(), value.cend(), attribute->value.float3_value);
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3;
- }
- void operator()(const std::array<float, 4>& value) {
- std::copy(value.cbegin(), value.cend(), attribute->value.float4_value);
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4;
- }
- void operator()(const std::array<float, 8>& value) {
- std::copy(value.cbegin(), value.cend(), attribute->value.float8_value);
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8;
- }
- void operator()(const std::array<float, 16>& value) {
- std::copy(value.cbegin(), value.cend(), attribute->value.float16_value);
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16;
- }
- void operator()(EmptyVariant) {
- attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
- }
-};
-
-size_t ConvertSurfaceAttributes(const SurfaceAttributes& surface_attributes,
- DvrSurfaceAttribute* attributes,
- size_t max_count) {
- size_t count = 0;
- for (const auto& attribute : surface_attributes) {
- if (count >= max_count)
- break;
-
- // Copy the key and extract the Variant value using a visitor.
- attributes[count].key = attribute.first;
- attribute.second.Visit(AttributeVisitor{&attributes[count]});
- count++;
- }
-
- return count;
-}
-
-} // anonymous namespace
-
-extern "C" {
-
-struct DvrDisplayManager {
- std::unique_ptr<DisplayManagerClient> client;
-};
-
-struct DvrSurfaceState {
- std::vector<SurfaceState> state;
-};
-
-int dvrDisplayManagerCreate(DvrDisplayManager** client_out) {
- if (!client_out)
- return -EINVAL;
-
- auto client = DisplayManagerClient::Create();
- if (!client) {
- ALOGE("dvrDisplayManagerCreate: Failed to create display manager client!");
- return -EIO;
- }
-
- *client_out = new DvrDisplayManager{std::move(client)};
- return 0;
-}
-
-void dvrDisplayManagerDestroy(DvrDisplayManager* client) { delete client; }
-
-int dvrDisplayManagerGetEventFd(DvrDisplayManager* client) {
- if (!client)
- return -EINVAL;
-
- return client->client->event_fd();
-}
-
-int dvrDisplayManagerTranslateEpollEventMask(DvrDisplayManager* client,
- int in_events, int* out_events) {
- if (!client || !out_events)
- return -EINVAL;
-
- auto status = client->client->GetEventMask(in_events);
- if (!status)
- return -status.error();
-
- *out_events = status.get();
- return 0;
-}
-
-int dvrDisplayManagerGetSurfaceState(DvrDisplayManager* client,
- DvrSurfaceState* state) {
- if (!client || !state)
- return -EINVAL;
-
- auto status = client->client->GetSurfaceState();
- if (!status)
- return -status.error();
-
- state->state = status.take();
- return 0;
-}
-
-int dvrDisplayManagerGetReadBufferQueue(DvrDisplayManager* client,
- int surface_id, int queue_id,
- DvrReadBufferQueue** queue_out) {
- if (!client || !queue_out)
- return -EINVAL;
-
- auto status = client->client->GetSurfaceQueue(surface_id, queue_id);
- if (!status) {
- ALOGE("dvrDisplayManagerGetReadBufferQueue: Failed to get queue: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
- }
-
- *queue_out = new DvrReadBufferQueue(status.take());
- return 0;
-}
-
-int dvrSurfaceStateCreate(DvrSurfaceState** surface_state_out) {
- if (!surface_state_out)
- return -EINVAL;
-
- *surface_state_out = new DvrSurfaceState{};
- return 0;
-}
-
-void dvrSurfaceStateDestroy(DvrSurfaceState* surface_state) {
- delete surface_state;
-}
-
-int dvrSurfaceStateGetSurfaceCount(DvrSurfaceState* surface_state,
- size_t* count_out) {
- if (!surface_state)
- return -EINVAL;
-
- *count_out = surface_state->state.size();
- return 0;
-}
-
-int dvrSurfaceStateGetUpdateFlags(DvrSurfaceState* surface_state,
- size_t surface_index,
- DvrSurfaceUpdateFlags* flags_out) {
- if (!surface_state || surface_index >= surface_state->state.size())
- return -EINVAL;
-
- *flags_out = surface_state->state[surface_index].update_flags;
- return 0;
-}
-
-int dvrSurfaceStateGetSurfaceId(DvrSurfaceState* surface_state,
- size_t surface_index, int* surface_id_out) {
- if (!surface_state || surface_index >= surface_state->state.size())
- return -EINVAL;
-
- *surface_id_out = surface_state->state[surface_index].surface_id;
- return 0;
-}
-
-int dvrSurfaceStateGetProcessId(DvrSurfaceState* surface_state,
- size_t surface_index, int* process_id_out) {
- if (!surface_state || surface_index >= surface_state->state.size())
- return -EINVAL;
-
- *process_id_out = surface_state->state[surface_index].process_id;
- return 0;
-}
-
-int dvrSurfaceStateGetQueueCount(DvrSurfaceState* surface_state,
- size_t surface_index, size_t* count_out) {
- if (!surface_state || surface_index >= surface_state->state.size())
- return -EINVAL;
-
- *count_out = surface_state->state[surface_index].queue_ids.size();
- return 0;
-}
-
-ssize_t dvrSurfaceStateGetQueueIds(DvrSurfaceState* surface_state,
- size_t surface_index, int* queue_ids,
- size_t max_count) {
- if (!surface_state || surface_index >= surface_state->state.size())
- return -EINVAL;
-
- size_t i;
- const auto& state = surface_state->state[surface_index];
- for (i = 0; i < std::min(max_count, state.queue_ids.size()); i++) {
- queue_ids[i] = state.queue_ids[i];
- }
-
- return i;
-}
-
-int dvrSurfaceStateGetZOrder(DvrSurfaceState* surface_state,
- size_t surface_index, int* z_order_out) {
- if (!surface_state || surface_index >= surface_state->state.size() ||
- !z_order_out) {
- return -EINVAL;
- }
-
- *z_order_out = surface_state->state[surface_index].GetZOrder();
- return 0;
-}
-
-int dvrSurfaceStateGetVisible(DvrSurfaceState* surface_state,
- size_t surface_index, bool* visible_out) {
- if (!surface_state || surface_index >= surface_state->state.size() ||
- !visible_out) {
- return -EINVAL;
- }
-
- *visible_out = surface_state->state[surface_index].GetVisible();
- return 0;
-}
-
-int dvrSurfaceStateGetAttributeCount(DvrSurfaceState* surface_state,
- size_t surface_index, size_t* count_out) {
- if (!surface_state || surface_index >= surface_state->state.size() ||
- !count_out) {
- return -EINVAL;
- }
-
- *count_out = surface_state->state[surface_index].surface_attributes.size();
- return 0;
-}
-
-ssize_t dvrSurfaceStateGetAttributes(DvrSurfaceState* surface_state,
- size_t surface_index,
- DvrSurfaceAttribute* attributes,
- size_t max_count) {
- if (!surface_state || surface_index >= surface_state->state.size() ||
- !attributes) {
- return -EINVAL;
- }
-
- return ConvertSurfaceAttributes(
- surface_state->state[surface_index].surface_attributes, attributes,
- max_count);
-}
-
-} // extern "C"
diff --git a/libs/vr/libdvr/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
deleted file mode 100644
index 4e87cf6..0000000
--- a/libs/vr/libdvr/dvr_hardware_composer_client.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-#include "include/dvr/dvr_hardware_composer_client.h"
-
-#include <android/dvr/IVrComposer.h>
-#include <android/dvr/BnVrComposerCallback.h>
-#include <android/hardware_buffer.h>
-#include <binder/IServiceManager.h>
-#include <private/android/AHardwareBufferHelpers.h>
-
-#include <functional>
-#include <memory>
-#include <mutex>
-
-struct DvrHwcFrame {
- android::dvr::ComposerView::Frame frame;
-};
-
-namespace {
-
-class HwcCallback : public android::dvr::BnVrComposerCallback {
- public:
- 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:
- // android::dvr::BnVrComposerCallback:
- android::binder::Status onNewFrame(
- const android::dvr::ParcelableComposerFrame& frame,
- android::dvr::ParcelableUniqueFd* fence) override;
-
- // 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(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_(dvr_frame.release())));
- return android::binder::Status::ok();
-}
-
-} // namespace
-
-struct DvrHwcClient {
- android::sp<android::dvr::IVrComposer> composer;
- android::sp<HwcCallback> callback;
-};
-
-DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, void* data) {
- std::unique_ptr<DvrHwcClient> client(new DvrHwcClient());
-
- android::sp<android::IServiceManager> sm(android::defaultServiceManager());
- client->composer = android::interface_cast<android::dvr::IVrComposer>(
- sm->getService(android::dvr::IVrComposer::SERVICE_NAME()));
- if (!client->composer.get())
- return nullptr;
-
- client->callback = new HwcCallback(std::bind(callback, data,
- std::placeholders::_1));
- android::binder::Status status = client->composer->registerObserver(
- client->callback);
- if (!status.isOk())
- return nullptr;
-
- return client.release();
-}
-
-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;
-}
-
-void dvrHwcFrameDestroy(DvrHwcFrame* frame) {
- delete frame;
-}
-
-DvrHwcDisplay dvrHwcFrameGetDisplayId(DvrHwcFrame* frame) {
- return frame->frame.display_id;
-}
-
-int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame) {
- return frame->frame.display_width;
-}
-
-int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame) {
- return frame->frame.display_height;
-}
-
-bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame) {
- return frame->frame.removed;
-}
-
-size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame) {
- return frame->frame.layers.size();
-}
-
-uint32_t dvrHwcFrameGetActiveConfig(DvrHwcFrame* frame) {
- return static_cast<uint32_t>(frame->frame.active_config);
-}
-
-uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame) {
- return static_cast<uint32_t>(frame->frame.color_mode);
-}
-
-void dvrHwcFrameGetColorTransform(DvrHwcFrame* frame, float* out_matrix,
- int32_t* out_hint) {
- *out_hint = frame->frame.color_transform_hint;
- memcpy(out_matrix, frame->frame.color_transform,
- sizeof(frame->frame.color_transform));
-}
-
-uint32_t dvrHwcFrameGetPowerMode(DvrHwcFrame* frame) {
- return static_cast<uint32_t>(frame->frame.power_mode);
-}
-
-uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame) {
- return static_cast<uint32_t>(frame->frame.vsync_enabled);
-}
-
-DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index) {
- return frame->frame.layers[layer_index].id;
-}
-
-AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
- size_t layer_index) {
- AHardwareBuffer* buffer = android::AHardwareBuffer_from_GraphicBuffer(
- frame->frame.layers[layer_index].buffer.get());
- AHardwareBuffer_acquire(buffer);
- return buffer;
-}
-
-int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index) {
- return frame->frame.layers[layer_index].fence->dup();
-}
-
-DvrHwcRecti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame,
- size_t layer_index) {
- return DvrHwcRecti{
- frame->frame.layers[layer_index].display_frame.left,
- frame->frame.layers[layer_index].display_frame.top,
- frame->frame.layers[layer_index].display_frame.right,
- frame->frame.layers[layer_index].display_frame.bottom,
- };
-}
-
-DvrHwcRectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index) {
- return DvrHwcRectf{
- frame->frame.layers[layer_index].crop.left,
- frame->frame.layers[layer_index].crop.top,
- frame->frame.layers[layer_index].crop.right,
- frame->frame.layers[layer_index].crop.bottom,
- };
-}
-
-DvrHwcBlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame,
- size_t layer_index) {
- return static_cast<DvrHwcBlendMode>(
- frame->frame.layers[layer_index].blend_mode);
-}
-
-float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index) {
- return frame->frame.layers[layer_index].alpha;
-}
-
-uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index) {
- return frame->frame.layers[layer_index].type;
-}
-
-uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
- size_t layer_index) {
- return frame->frame.layers[layer_index].app_id;
-}
-
-uint32_t dvrHwcFrameGetLayerZOrder(DvrHwcFrame* frame, size_t layer_index) {
- return frame->frame.layers[layer_index].z_order;
-}
-
-void dvrHwcFrameGetLayerCursor(DvrHwcFrame* frame, size_t layer_index,
- int32_t* out_x, int32_t* out_y) {
- *out_x = frame->frame.layers[layer_index].cursor_x;
- *out_y = frame->frame.layers[layer_index].cursor_y;
-}
-
-uint32_t dvrHwcFrameGetLayerTransform(DvrHwcFrame* frame, size_t layer_index) {
- return frame->frame.layers[layer_index].transform;
-}
-
-uint32_t dvrHwcFrameGetLayerDataspace(DvrHwcFrame* frame, size_t layer_index) {
- return frame->frame.layers[layer_index].dataspace;
-}
-
-uint32_t dvrHwcFrameGetLayerColor(DvrHwcFrame* frame, size_t layer_index) {
- const auto& color = frame->frame.layers[layer_index].color;
- return color.r | (static_cast<uint32_t>(color.g) << 8) |
- (static_cast<uint32_t>(color.b) << 16) |
- (static_cast<uint32_t>(color.a) << 24);
-}
-
-uint32_t dvrHwcFrameGetLayerNumVisibleRegions(DvrHwcFrame* frame,
- size_t layer_index) {
- return frame->frame.layers[layer_index].visible_regions.size();
-}
-
-DvrHwcRecti dvrHwcFrameGetLayerVisibleRegion(DvrHwcFrame* frame,
- size_t layer_index, size_t index) {
- return DvrHwcRecti{
- frame->frame.layers[layer_index].visible_regions[index].left,
- frame->frame.layers[layer_index].visible_regions[index].top,
- frame->frame.layers[layer_index].visible_regions[index].right,
- frame->frame.layers[layer_index].visible_regions[index].bottom,
- };
-}
-
-uint32_t dvrHwcFrameGetLayerNumDamagedRegions(DvrHwcFrame* frame,
- size_t layer_index) {
- return frame->frame.layers[layer_index].damaged_regions.size();
-}
-
-DvrHwcRecti dvrHwcFrameGetLayerDamagedRegion(DvrHwcFrame* frame,
- size_t layer_index, size_t index) {
- return DvrHwcRecti{
- frame->frame.layers[layer_index].damaged_regions[index].left,
- frame->frame.layers[layer_index].damaged_regions[index].top,
- frame->frame.layers[layer_index].damaged_regions[index].right,
- frame->frame.layers[layer_index].damaged_regions[index].bottom,
- };
-}
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
deleted file mode 100644
index f845cd8..0000000
--- a/libs/vr/libdvr/dvr_internal.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef ANDROID_DVR_INTERNAL_H_
-#define ANDROID_DVR_INTERNAL_H_
-
-#include <sys/cdefs.h>
-
-#include <memory>
-
-extern "C" {
-
-typedef struct DvrBuffer DvrBuffer;
-typedef struct DvrReadBuffer DvrReadBuffer;
-typedef struct DvrWriteBuffer DvrWriteBuffer;
-
-} // extern "C"
-
-namespace android {
-namespace dvr {
-
-class IonBuffer;
-
-DvrBuffer* CreateDvrBufferFromIonBuffer(
- const std::shared_ptr<IonBuffer>& ion_buffer);
-
-} // namespace dvr
-} // namespace android
-
-extern "C" {
-
-struct DvrWriteBuffer {
- // The slot nubmer of the buffer, a valid slot number must be in the range of
- // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
- // DvrWriteBuffer acquired from a DvrWriteBufferQueue.
- int32_t slot = -1;
-
- std::shared_ptr<android::dvr::ProducerBuffer> write_buffer;
-};
-
-struct DvrReadBuffer {
- // The slot nubmer of the buffer, a valid slot number must be in the range of
- // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
- // DvrReadBuffer acquired from a DvrReadBufferQueue.
- int32_t slot = -1;
-
- std::shared_ptr<android::dvr::ConsumerBuffer> read_buffer;
-};
-
-struct DvrBuffer {
- std::shared_ptr<android::dvr::IonBuffer> buffer;
-};
-
-} // extern "C"
-
-#endif // ANDROID_DVR_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_performance.cpp b/libs/vr/libdvr/dvr_performance.cpp
deleted file mode 100644
index 599101f..0000000
--- a/libs/vr/libdvr/dvr_performance.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#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_pose.cpp b/libs/vr/libdvr/dvr_pose.cpp
deleted file mode 100644
index c379ef5..0000000
--- a/libs/vr/libdvr/dvr_pose.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "include/dvr/dvr_pose.h"
-
-#include <memory>
-
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/pose_client_internal.h>
-
-#include "dvr_buffer_queue_internal.h"
-
-using android::dvr::ConsumerQueue;
-
-int dvrPoseClientGetDataReader(DvrPoseClient* client, uint64_t data_type,
- DvrReadBufferQueue** queue_out) {
- if (!client || !queue_out)
- return -EINVAL;
-
- ConsumerQueue* consumer_queue;
- int status = android::dvr::dvrPoseClientGetDataReaderHandle(client,
- data_type,
- &consumer_queue);
- if (status != 0) {
- ALOGE("dvrPoseClientGetDataReader: Failed to get queue: %d", status);
- return status;
- }
-
- std::shared_ptr<ConsumerQueue> consumer_queue_ptr{consumer_queue};
- *queue_out = new DvrReadBufferQueue(consumer_queue_ptr);
- return 0;
-}
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
deleted file mode 100644
index 0c7ec01..0000000
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-#include "include/dvr/dvr_surface.h"
-
-#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::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,
- size_t* error_index) {
- for (size_t i = 0; i < attribute_count; i++) {
- SurfaceAttributeValue value;
- switch (attributes[i].value.type) {
- case DVR_SURFACE_ATTRIBUTE_TYPE_INT32:
- value = attributes[i].value.int32_value;
- break;
- case DVR_SURFACE_ATTRIBUTE_TYPE_INT64:
- value = attributes[i].value.int64_value;
- break;
- case DVR_SURFACE_ATTRIBUTE_TYPE_BOOL:
- // 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:
- ArrayCopy(&value, attributes[i].value.float2_value);
- break;
- case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3:
- ArrayCopy(&value, attributes[i].value.float3_value);
- break;
- case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4:
- ArrayCopy(&value, attributes[i].value.float4_value);
- break;
- case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8:
- ArrayCopy(&value, attributes[i].value.float8_value);
- break;
- case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16:
- ArrayCopy(&value, attributes[i].value.float16_value);
- break;
- case DVR_SURFACE_ATTRIBUTE_TYPE_NONE:
- value = EmptyVariant{};
- break;
- default:
- *error_index = i;
- return false;
- }
-
- surface_attributes->emplace(attributes[i].key, value);
- }
-
- return true;
-}
-
-} // anonymous namespace
-
-extern "C" {
-
-struct DvrSurface {
- std::unique_ptr<Surface> surface;
-};
-
-int dvrSurfaceCreate(const DvrSurfaceAttribute* attributes,
- size_t attribute_count, DvrSurface** out_surface) {
- if (out_surface == nullptr) {
- ALOGE("dvrSurfaceCreate: Invalid inputs: out_surface=%p.", out_surface);
- return -EINVAL;
- }
-
- size_t error_index;
- SurfaceAttributes surface_attributes;
- if (!ConvertSurfaceAttributes(attributes, attribute_count,
- &surface_attributes, &error_index)) {
- ALOGE("dvrSurfaceCreate: Invalid surface attribute type: %" PRIu64,
- attributes[error_index].value.type);
- return -EINVAL;
- }
-
- auto status = Surface::CreateSurface(surface_attributes);
- if (!status) {
- ALOGE("dvrSurfaceCreate:: Failed to create display surface: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
- }
-
- *out_surface = new DvrSurface{status.take()};
- return 0;
-}
-
-void dvrSurfaceDestroy(DvrSurface* surface) { delete surface; }
-
-int dvrSurfaceGetId(DvrSurface* surface) {
- return surface->surface->surface_id();
-}
-
-int dvrSurfaceSetAttributes(DvrSurface* surface,
- const DvrSurfaceAttribute* attributes,
- size_t attribute_count) {
- if (surface == nullptr || attributes == nullptr) {
- ALOGE(
- "dvrSurfaceSetAttributes: Invalid inputs: surface=%p attributes=%p "
- "attribute_count=%zu",
- surface, attributes, attribute_count);
- return -EINVAL;
- }
-
- size_t error_index;
- SurfaceAttributes surface_attributes;
- if (!ConvertSurfaceAttributes(attributes, attribute_count,
- &surface_attributes, &error_index)) {
- ALOGE("dvrSurfaceSetAttributes: Invalid surface attribute type: %" PRIu64,
- attributes[error_index].value.type);
- return -EINVAL;
- }
-
- auto status = surface->surface->SetAttributes(surface_attributes);
- if (!status) {
- ALOGE("dvrSurfaceSetAttributes: Failed to set attributes: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
- }
-
- return 0;
-}
-
-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 metadata_size,
- DvrWriteBufferQueue** out_writer) {
- if (surface == nullptr || out_writer == nullptr) {
- ALOGE(
- "dvrSurfaceCreateWriteBufferQueue: Invalid inputs: surface=%p, "
- "out_writer=%p.",
- surface, out_writer);
- return -EINVAL;
- }
-
- 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 = new DvrWriteBufferQueue(status.take());
- return 0;
-}
-
-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("dvrGetNativeDisplayMetrics: Failed to create display client!");
- return -ECOMM;
- }
-
- if (metrics == nullptr) {
- ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null");
- return -EINVAL;
- }
-
- auto status = client->GetDisplayMetrics();
-
- if (!status) {
- return -status.error();
- }
-
- if (sizeof_metrics >= 20) {
- metrics->display_width = status.get().display_width;
- metrics->display_height = status.get().display_height;
- metrics->display_x_dpi = status.get().display_x_dpi;
- metrics->display_y_dpi = status.get().display_y_dpi;
- metrics->vsync_period_ns = status.get().vsync_period_ns;
- }
-
- return 0;
-}
-
-} // extern "C"
diff --git a/libs/vr/libdvr/dvr_tracking.cpp b/libs/vr/libdvr/dvr_tracking.cpp
deleted file mode 100644
index 73addc9..0000000
--- a/libs/vr/libdvr/dvr_tracking.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#include "include/dvr/dvr_tracking.h"
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#if !DVR_TRACKING_IMPLEMENTED
-
-extern "C" {
-
-// This file provides the stub implementation of dvrTrackingXXX APIs. On
-// platforms that implement these APIs, set -DDVR_TRACKING_IMPLEMENTED=1 in the
-// build file.
-int dvrTrackingCameraCreate(DvrTrackingCamera**) {
- ALOGE("dvrTrackingCameraCreate is not implemented.");
- return -ENOSYS;
-}
-
-void dvrTrackingCameraDestroy(DvrTrackingCamera*) {
- ALOGE("dvrTrackingCameraDestroy is not implemented.");
-}
-
-int dvrTrackingCameraStart(DvrTrackingCamera*, DvrWriteBufferQueue*) {
- ALOGE("dvrTrackingCameraCreate is not implemented.");
- return -ENOSYS;
-}
-
-int dvrTrackingCameraStop(DvrTrackingCamera*) {
- ALOGE("dvrTrackingCameraCreate is not implemented.");
- return -ENOSYS;
-}
-
-int dvrTrackingFeatureExtractorCreate(DvrTrackingFeatureExtractor**) {
- ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
- return -ENOSYS;
-}
-
-void dvrTrackingFeatureExtractorDestroy(DvrTrackingFeatureExtractor*) {
- ALOGE("dvrTrackingFeatureExtractorDestroy is not implemented.");
-}
-
-int dvrTrackingFeatureExtractorStart(DvrTrackingFeatureExtractor*,
- DvrTrackingFeatureCallback, void*) {
- ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
- return -ENOSYS;
-}
-
-int dvrTrackingFeatureExtractorStop(DvrTrackingFeatureExtractor*) {
- ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
- return -ENOSYS;
-}
-
-int dvrTrackingFeatureExtractorProcessBuffer(DvrTrackingFeatureExtractor*,
- DvrReadBuffer*,
- const DvrTrackingBufferMetadata*,
- bool*) {
- ALOGE("dvrTrackingFeatureExtractorProcessBuffer is not implemented.");
- return -ENOSYS;
-}
-
-int dvrTrackingSensorsCreate(DvrTrackingSensors**, const char*) {
- ALOGE("dvrTrackingSensorsCreate is not implemented.");
- return -ENOSYS;
-}
-
-void dvrTrackingSensorsDestroy(DvrTrackingSensors*) {
- ALOGE("dvrTrackingSensorsDestroy is not implemented.");
-}
-
-int dvrTrackingSensorsStart(DvrTrackingSensors*, DvrTrackingSensorEventCallback,
- void*) {
- ALOGE("dvrTrackingStart is not implemented.");
- return -ENOSYS;
-}
-
-int dvrTrackingSensorsStop(DvrTrackingSensors*) {
- ALOGE("dvrTrackingStop is not implemented.");
- return -ENOSYS;
-}
-
-} // extern "C"
-
-#endif // DVR_TRACKING_IMPLEMENTED
diff --git a/libs/vr/libdvr/exported_apis.lds b/libs/vr/libdvr/exported_apis.lds
deleted file mode 100644
index 5ecb498..0000000
--- a/libs/vr/libdvr/exported_apis.lds
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- global:
- # Whitelist the function to load the dvr api.
- dvrGetApi;
-
- local:
- # Hide everything else.
- *;
-};
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
deleted file mode 100644
index fe7feb8..0000000
--- a/libs/vr/libdvr/tests/Android.bp
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_test {
- srcs: [
- "dvr_display_manager-test.cpp",
- "dvr_named_buffer-test.cpp",
- "dvr_tracking-test.cpp",
- ],
-
- header_libs: ["libdvr_headers"],
- static_libs: [
- "libdvr_static.google",
- "libchrome",
- "libdvrcommon",
- "libdisplay",
- "libbroadcastring",
- ],
- shared_libs: [
- "libbase",
- "libbinder",
- "libbufferhubqueue",
- "libcutils",
- "libgui",
- "liblog",
- "libhardware",
- "libui",
- "libutils",
- "libnativewindow",
- "libpdx_default_transport",
- ],
- cflags: [
- "-DDVR_TRACKING_IMPLEMENTED=0",
- "-DLOG_TAG=\"dvr_api-test\"",
- "-DTRACE=0",
- "-Wno-missing-field-initializers",
- "-O0",
- "-g",
- ],
- name: "dvr_api-test",
-}
-
-cc_test {
- name: "dvr_buffer_queue-test",
-
- // Includes the dvr_api.h header. Tests should only include "dvr_api.h",
- // and shall only get access to |dvrGetApi|, as other symbols are hidden
- // from the library.
- include_dirs: ["frameworks/native/libs/vr/libdvr/include"],
-
- srcs: ["dvr_buffer_queue-test.cpp"],
-
- shared_libs: [
- "libandroid",
- "liblog",
- ],
-
- cflags: [
- "-DTRACE=0",
- "-O2",
- "-g",
- ],
-
- // DTS Should only link to NDK libraries.
- sdk_version: "26",
- stl: "c++_static",
-}
-
-cc_test {
- name: "dvr_display-test",
-
- include_dirs: [
- "frameworks/native/libs/vr/libdvr/include",
- "frameworks/native/libs/nativewindow/include",
- ],
-
- srcs: ["dvr_display-test.cpp"],
-
- shared_libs: [
- "libandroid",
- "liblog",
- ],
-
- cflags: [
- "-DTRACE=0",
- "-O2",
- "-g",
- ],
-
- // DTS Should only link to NDK libraries.
- sdk_version: "26",
- stl: "c++_static",
-}
diff --git a/libs/vr/libdvr/tests/dvr_api_test.h b/libs/vr/libdvr/tests/dvr_api_test.h
deleted file mode 100644
index 5d2ec28..0000000
--- a/libs/vr/libdvr/tests/dvr_api_test.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <dlfcn.h>
-#include <dvr/dvr_api.h>
-
-#include <gtest/gtest.h>
-
-/** DvrTestBase loads the libdvr.so at runtime and get the Dvr API version 1. */
-class DvrApiTest : public ::testing::Test {
- protected:
- void SetUp() override {
- int flags = RTLD_NOW | RTLD_LOCAL;
-
- // Here we need to ensure that libdvr is loaded with RTLD_NODELETE flag set
- // (so that calls to `dlclose` don't actually unload the library). This is a
- // workaround for an Android NDK bug. See more detail:
- // https://github.com/android-ndk/ndk/issues/360
- flags |= RTLD_NODELETE;
- platform_handle_ = dlopen("libdvr.google.so", flags);
- ASSERT_NE(nullptr, platform_handle_) << "Dvr shared library missing.";
-
- auto dvr_get_api = reinterpret_cast<decltype(&dvrGetApi)>(
- dlsym(platform_handle_, "dvrGetApi"));
- ASSERT_NE(nullptr, dvr_get_api) << "Platform library missing dvrGetApi.";
-
- ASSERT_EQ(dvr_get_api(&api_, sizeof(api_), /*version=*/1), 0)
- << "Unable to find compatible Dvr API.";
- }
-
- void TearDown() override {
- if (platform_handle_ != nullptr) {
- dlclose(platform_handle_);
- }
- }
-
- void* platform_handle_ = nullptr;
- DvrApi_v1 api_;
-};
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
deleted file mode 100644
index df06097..0000000
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ /dev/null
@@ -1,579 +0,0 @@
-#include <android/log.h>
-#include <android/native_window.h>
-#include <dvr/dvr_api.h>
-#include <dvr/dvr_buffer_queue.h>
-
-#include <gtest/gtest.h>
-
-#include <array>
-#include <unordered_map>
-
-#include "dvr_api_test.h"
-
-#define LOG_TAG "dvr_buffer_queue-test"
-
-#ifndef ALOGD
-#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
-#endif
-
-#ifndef ALOGD_IF
-#define ALOGD_IF(cond, ...) \
- ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0)
-#endif
-
-namespace {
-
-static constexpr uint32_t kBufferWidth = 100;
-static constexpr uint32_t kBufferHeight = 1;
-static constexpr uint32_t kLayerCount = 1;
-static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB;
-static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
-static constexpr size_t kQueueCapacity = 3;
-
-class DvrBufferQueueTest : public DvrApiTest {
- 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 TearDown() override {
- if (write_queue_ != nullptr) {
- api_.WriteBufferQueueDestroy(write_queue_);
- write_queue_ = nullptr;
- }
- DvrApiTest::TearDown();
- }
-
- 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_);
- }
-
- DvrWriteBufferQueue* write_queue_ = nullptr;
- int buffer_available_count_{0};
- int buffer_removed_count_{0};
-};
-
-TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(0, ret);
-
- api_.WriteBufferQueueDestroy(write_queue_);
- write_queue_ = nullptr;
-}
-
-TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(0, ret);
-
- size_t capacity = api_.WriteBufferQueueGetCapacity(write_queue_);
-
- ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
- ASSERT_EQ(kQueueCapacity, capacity);
-}
-
-TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(0, ret);
-
- DvrReadBufferQueue* read_queue = nullptr;
- ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
-
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, read_queue);
-
- api_.ReadBufferQueueDestroy(read_queue);
-}
-
-TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(0, ret);
-
- DvrReadBufferQueue* read_queue1 = nullptr;
- DvrReadBufferQueue* read_queue2 = nullptr;
- ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
-
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, read_queue1);
-
- ret = api_.ReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, read_queue2);
- ASSERT_NE(read_queue1, read_queue2);
-
- api_.ReadBufferQueueDestroy(read_queue1);
- api_.ReadBufferQueueDestroy(read_queue2);
-}
-
-TEST_F(DvrBufferQueueTest, GainBuffer) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(ret, 0);
-
- DvrWriteBuffer* wb = nullptr;
- EXPECT_FALSE(api_.WriteBufferIsValid(wb));
-
- DvrNativeBufferMetadata meta;
- int fence_fd = -1;
- ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
- &fence_fd);
- ASSERT_EQ(ret, 0);
- EXPECT_EQ(fence_fd, -1);
- EXPECT_NE(wb, nullptr);
- EXPECT_TRUE(api_.WriteBufferIsValid(wb));
-}
-
-TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(ret, 0);
-
- DvrReadBufferQueue* read_queue = nullptr;
- DvrReadBuffer* rb = nullptr;
- DvrWriteBuffer* wb = nullptr;
- DvrNativeBufferMetadata meta1;
- DvrNativeBufferMetadata meta2;
- int fence_fd = -1;
-
- ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
-
- ASSERT_EQ(ret, 0);
- ASSERT_NE(read_queue, nullptr);
-
- api_.ReadBufferQueueSetBufferAvailableCallback(
- read_queue, &BufferAvailableCallback, this);
-
- // Gain buffer for writing.
- ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
- &meta1, &fence_fd);
- ASSERT_EQ(ret, 0);
- ASSERT_NE(wb, nullptr);
- ASSERT_TRUE(api_.WriteBufferIsValid(wb));
- ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
- wb, fence_fd);
- close(fence_fd);
-
- // Post buffer to the read_queue.
- meta1.timestamp = 42;
- ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
- ASSERT_EQ(ret, 0);
- ASSERT_FALSE(api_.WriteBufferIsValid(wb));
- wb = nullptr;
-
- // Acquire buffer for reading.
- ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
- &meta2, &fence_fd);
- ASSERT_EQ(ret, 0);
- ASSERT_NE(rb, nullptr);
-
- // Dequeue is successfully, BufferAvailableCallback should be fired once.
- ASSERT_EQ(buffer_available_count_, 1);
- ASSERT_TRUE(api_.ReadBufferIsValid(rb));
-
- // Metadata should be passed along from producer to consumer properly.
- ASSERT_EQ(meta1.timestamp, meta2.timestamp);
-
- ALOGD_IF(TRACE,
- "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
- fence_fd);
- close(fence_fd);
-
- // Release buffer to the write_queue.
- ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
- /*release_fence_fd=*/-1);
- ASSERT_EQ(ret, 0);
- ASSERT_FALSE(api_.ReadBufferIsValid(rb));
- rb = nullptr;
-
- // TODO(b/34387835) Currently buffer allocation has to happen after all queues
- // are initialized.
- size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
-
- ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity);
- ASSERT_EQ(kQueueCapacity, capacity);
-
- api_.ReadBufferQueueDestroy(read_queue);
-}
-
-TEST_F(DvrBufferQueueTest, GetANativeWindow) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/0, /*user_metadata_size=*/0, &write_queue_);
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, write_queue_);
-
- ANativeWindow* window = nullptr;
- ret = api_.WriteBufferQueueGetANativeWindow(write_queue_, &window);
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, window);
-
- uint32_t width = ANativeWindow_getWidth(window);
- uint32_t height = ANativeWindow_getHeight(window);
- uint32_t format = ANativeWindow_getFormat(window);
- ASSERT_EQ(kBufferWidth, width);
- ASSERT_EQ(kBufferHeight, height);
- ASSERT_EQ(kBufferFormat, format);
-}
-
-// 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, ResizeBuffer) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(0, ret);
-
- int fence_fd = -1;
-
- DvrNativeBufferMetadata meta;
- 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;
-
- ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
-
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, read_queue);
-
- api_.ReadBufferQueueSetBufferRemovedCallback(read_queue,
- &BufferRemovedCallback, this);
-
- // Handle all pending events on the read queue.
- ret = api_.ReadBufferQueueHandleEvents(read_queue);
- ASSERT_EQ(0, ret);
-
- size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
- ALOGD_IF(TRACE, "TestResizeBuffer, capacity=%zu", capacity);
- ASSERT_EQ(kQueueCapacity, capacity);
-
- // Resize before dequeuing.
- constexpr uint32_t w1 = 10;
- ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
- ASSERT_EQ(0, ret);
-
- // Gain first buffer for writing. All buffers will be resized.
- ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1,
- &meta, &fence_fd);
- ASSERT_EQ(0, ret);
- ASSERT_TRUE(api_.WriteBufferIsValid(wb1));
- ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
- close(fence_fd);
-
- // Check the buffer dimension.
- ret = api_.WriteBufferGetAHardwareBuffer(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 = api_.ReadBufferQueueHandleEvents(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 = api_.WriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
- ASSERT_EQ(0, ret);
-
- // The next buffer we dequeued should have new width.
- ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2,
- &meta, &fence_fd);
- ASSERT_EQ(0, ret);
- ASSERT_TRUE(api_.WriteBufferIsValid(wb2));
- ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
- fence_fd);
- close(fence_fd);
-
- // Check the buffer dimension, should be new width
- ret = api_.WriteBufferGetAHardwareBuffer(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 = api_.ReadBufferQueueHandleEvents(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 = api_.WriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
- ASSERT_EQ(0, ret);
-
- // The next buffer we dequeued should have new width.
- ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3,
- &meta, &fence_fd);
- ASSERT_EQ(0, ret);
- ASSERT_TRUE(api_.WriteBufferIsValid(wb3));
- ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
- fence_fd);
- close(fence_fd);
-
- // Check the buffer dimension, should be new width
- ret = api_.WriteBufferGetAHardwareBuffer(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 = api_.ReadBufferQueueHandleEvents(read_queue);
- ASSERT_EQ(0, ret);
- ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
-
- api_.ReadBufferQueueDestroy(read_queue);
-}
-
-TEST_F(DvrBufferQueueTest, ReadQueueEventFd) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(0, ret);
-
- DvrReadBufferQueue* read_queue = nullptr;
- ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
-
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, read_queue);
-
- int event_fd = api_.ReadBufferQueueGetEventFd(read_queue);
- ASSERT_GT(event_fd, 0);
-}
-
-// Verifies a Dvr{Read,Write}BufferQueue contains the same set of
-// Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
-// the corresponding AHardwareBuffer handle stays the same.
-TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(0, ret);
-
- int fence_fd = -1;
- DvrReadBufferQueue* read_queue = nullptr;
- EXPECT_EQ(0, api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
-
- // Read buffers.
- std::array<DvrReadBuffer*, kQueueCapacity> rbs;
- // Write buffers.
- std::array<DvrWriteBuffer*, kQueueCapacity> wbs;
- // Buffer metadata.
- std::array<DvrNativeBufferMetadata, kQueueCapacity> metas;
- // Hardware buffers for Read buffers.
- std::unordered_map<int, AHardwareBuffer*> rhbs;
- // Hardware buffers for Write buffers.
- std::unordered_map<int, AHardwareBuffer*> whbs;
-
- constexpr int kNumTests = 100;
-
- // This test runs the following operations many many times. Thus we prefer to
- // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output.
- std::function<void(size_t i)> Gain = [&](size_t i) {
- int ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
- &wbs[i], &metas[i], &fence_fd);
- ASSERT_EQ(ret, 0);
- ASSERT_LT(fence_fd, 0); // expect invalid fence.
- ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
- int buffer_id = api_.WriteBufferGetId(wbs[i]);
- ASSERT_GT(buffer_id, 0);
-
- AHardwareBuffer* hb = nullptr;
- ASSERT_EQ(0, api_.WriteBufferGetAHardwareBuffer(wbs[i], &hb));
-
- auto whb_it = whbs.find(buffer_id);
- if (whb_it == whbs.end()) {
- // If this is a new buffer id, check that total number of unique
- // hardware buffers won't exceed queue capacity.
- ASSERT_LT(whbs.size(), kQueueCapacity);
- whbs.emplace(buffer_id, hb);
- } else {
- // If this is a buffer id we have seen before, check that the
- // buffer_id maps to the same AHardwareBuffer handle.
- ASSERT_EQ(hb, whb_it->second);
- }
- };
-
- std::function<void(size_t i)> Post = [&](size_t i) {
- ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
-
- metas[i].timestamp++;
- int ret = api_.WriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
- /*fence=*/-1);
- ASSERT_EQ(ret, 0);
- };
-
- std::function<void(size_t i)> Acquire = [&](size_t i) {
- int ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
- &rbs[i], &metas[i], &fence_fd);
- ASSERT_EQ(ret, 0);
- ASSERT_LT(fence_fd, 0); // expect invalid fence.
- ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
-
- int buffer_id = api_.ReadBufferGetId(rbs[i]);
- ASSERT_GT(buffer_id, 0);
-
- AHardwareBuffer* hb = nullptr;
- ASSERT_EQ(0, api_.ReadBufferGetAHardwareBuffer(rbs[i], &hb));
-
- auto rhb_it = rhbs.find(buffer_id);
- if (rhb_it == rhbs.end()) {
- // If this is a new buffer id, check that total number of unique hardware
- // buffers won't exceed queue capacity.
- ASSERT_LT(rhbs.size(), kQueueCapacity);
- rhbs.emplace(buffer_id, hb);
- } else {
- // If this is a buffer id we have seen before, check that the buffer_id
- // maps to the same AHardwareBuffer handle.
- ASSERT_EQ(hb, rhb_it->second);
- }
- };
-
- std::function<void(size_t i)> Release = [&](size_t i) {
- ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
-
- int ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
- /*release_fence_fd=*/-1);
- ASSERT_EQ(ret, 0);
- };
-
- // Scenario one:
- for (int i = 0; i < kNumTests; i++) {
- // Gain all write buffers.
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Gain(i));
- }
- // Post all write buffers.
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Post(i));
- }
- // Acquire all read buffers.
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Acquire(i));
- }
- // Release all read buffers.
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Release(i));
- }
- }
-
- // Scenario two:
- for (int i = 0; i < kNumTests; i++) {
- // Gain and post all write buffers.
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Gain(i));
- ASSERT_NO_FATAL_FAILURE(Post(i));
- }
- // Acquire and release all read buffers.
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Acquire(i));
- ASSERT_NO_FATAL_FAILURE(Release(i));
- }
- }
-
- // Scenario three:
- for (int i = 0; i < kNumTests; i++) {
- // Gain all write buffers then post them in reversed order.
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Gain(i));
- }
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Post(kQueueCapacity - 1 - i));
- }
-
- // Acquire all write buffers then release them in reversed order.
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Acquire(i));
- }
- for (size_t i = 0; i < kQueueCapacity; i++) {
- ASSERT_NO_FATAL_FAILURE(Release(kQueueCapacity - 1 - i));
- }
- }
-}
-
-TEST_F(DvrBufferQueueTest, ConsumerReleaseAfterProducerDestroy) {
- int ret = api_.WriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
- ASSERT_EQ(ret, 0);
-
- DvrReadBufferQueue* read_queue = nullptr;
- DvrReadBuffer* rb = nullptr;
- DvrWriteBuffer* wb = nullptr;
- DvrNativeBufferMetadata meta1;
- DvrNativeBufferMetadata meta2;
- int fence_fd = -1;
-
- ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
- ASSERT_EQ(ret, 0);
-
- api_.ReadBufferQueueSetBufferAvailableCallback(
- read_queue, &BufferAvailableCallback, this);
-
- // Gain buffer for writing.
- ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
- &meta1, &fence_fd);
- ASSERT_EQ(ret, 0);
- close(fence_fd);
-
- // Post buffer to the read_queue.
- ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
- ASSERT_EQ(ret, 0);
- wb = nullptr;
-
- // Acquire buffer for reading.
- ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
- &meta2, &fence_fd);
- ASSERT_EQ(ret, 0);
- close(fence_fd);
-
- // Destroy the write buffer queue and make sure the reader queue is picking
- // these events up.
- api_.WriteBufferQueueDestroy(write_queue_);
- ret = api_.ReadBufferQueueHandleEvents(read_queue);
- ASSERT_EQ(0, ret);
-
- // Release buffer to the write_queue.
- ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
- /*release_fence_fd=*/-1);
- ASSERT_EQ(ret, 0);
- rb = nullptr;
-
- api_.ReadBufferQueueDestroy(read_queue);
-}
-
-} // namespace
diff --git a/libs/vr/libdvr/tests/dvr_display-test.cpp b/libs/vr/libdvr/tests/dvr_display-test.cpp
deleted file mode 100644
index c72f940..0000000
--- a/libs/vr/libdvr/tests/dvr_display-test.cpp
+++ /dev/null
@@ -1,351 +0,0 @@
-#include <android/hardware_buffer.h>
-#include <android/log.h>
-#include <dvr/dvr_api.h>
-#include <dvr/dvr_display_types.h>
-#include <dvr/dvr_surface.h>
-
-#include <gtest/gtest.h>
-
-#include "dvr_api_test.h"
-
-#define LOG_TAG "dvr_display-test"
-
-#ifndef ALOGD
-#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
-#endif
-
-class DvrDisplayTest : public DvrApiTest {
- protected:
- void SetUp() override {
- DvrApiTest::SetUp();
- int ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics_),
- &display_metrics_);
- ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
- ALOGD(
- "display_width: %d, display_height: %d, display_x_dpi: %d, "
- "display_y_dpi: %d, vsync_period_ns: %d.",
- display_metrics_.display_width, display_metrics_.display_height,
- display_metrics_.display_x_dpi, display_metrics_.display_y_dpi,
- display_metrics_.vsync_period_ns);
- }
-
- void TearDown() override {
- if (write_queue_ != nullptr) {
- api_.WriteBufferQueueDestroy(write_queue_);
- write_queue_ = nullptr;
- }
- if (direct_surface_ != nullptr) {
- api_.SurfaceDestroy(direct_surface_);
- direct_surface_ = nullptr;
- }
- DvrApiTest::TearDown();
- }
-
- /* Convert a write buffer to an android hardware buffer and fill in
- * color_textures evenly to the buffer.
- * AssertionError if the width of the buffer is not equal to the input width,
- * AssertionError if the height of the buffer is not equal to the input
- * height.
- */
- void FillWriteBuffer(DvrWriteBuffer* write_buffer,
- const std::vector<uint32_t>& color_textures,
- uint32_t width, uint32_t height);
-
- // Write buffer queue properties.
- static constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
- AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
- AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
- uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
- static constexpr size_t kMetadataSize = 0;
- static constexpr int kTimeoutMs = 1000; // Time for getting buffer.
- uint32_t kLayerCount = 1;
- DvrWriteBufferQueue* write_queue_ = nullptr;
- DvrSurface* direct_surface_ = nullptr;
-
- // Device display properties.
- DvrNativeDisplayMetrics display_metrics_;
-};
-
-TEST_F(DvrDisplayTest, DisplayWithOneBuffer) {
- // Create a direct surface.
- std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
- {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
- .value.bool_value = true},
- {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
- .value.int32_value = 10},
- {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
- .value.bool_value = true},
- };
- int ret =
- api_.SurfaceCreate(direct_surface_attributes.data(),
- direct_surface_attributes.size(), &direct_surface_);
- ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
-
- // Create a buffer queue with the direct surface.
- constexpr size_t kCapacity = 1;
- uint32_t width = display_metrics_.display_width;
- uint32_t height = display_metrics_.display_height;
- ret = api_.SurfaceCreateWriteBufferQueue(
- direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
- kMetadataSize, &write_queue_);
- EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
- ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
-
- // Get buffer from WriteBufferQueue.
- DvrWriteBuffer* write_buffer = nullptr;
- DvrNativeBufferMetadata out_meta;
- int out_fence_fd = -1;
- ret = api_.WriteBufferQueueGainBuffer(write_queue_, kTimeoutMs, &write_buffer,
- &out_meta, &out_fence_fd);
- EXPECT_EQ(0, ret) << "Failed to get the buffer.";
- ASSERT_NE(nullptr, write_buffer) << "Gained buffer should not be null.";
-
- // Color the write buffer.
- FillWriteBuffer(write_buffer,
- {0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
- width, height);
-
- // Post buffer.
- int ready_fence_fd = -1;
- ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
- ready_fence_fd);
- EXPECT_EQ(0, ret) << "Failed to post the buffer.";
-
- sleep(5); // For visual check on the device under test.
- // Should observe three primary colors on the screen center.
-}
-
-TEST_F(DvrDisplayTest, DisplayWithDoubleBuffering) {
- // Create a direct surface.
- std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
- {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
- .value.bool_value = true},
- {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
- .value.int32_value = 10},
- {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
- .value.bool_value = true},
- };
- int ret =
- api_.SurfaceCreate(direct_surface_attributes.data(),
- direct_surface_attributes.size(), &direct_surface_);
- ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
-
- // Create a buffer queue with the direct surface.
- constexpr size_t kCapacity = 2;
- uint32_t width = display_metrics_.display_width;
- uint32_t height = display_metrics_.display_height;
- ret = api_.SurfaceCreateWriteBufferQueue(
- direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
- kMetadataSize, &write_queue_);
- EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
- ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
-
- int num_display_cycles_in_5s = 5 / (display_metrics_.vsync_period_ns / 1e9);
- ALOGD("The number of display cycles: %d", num_display_cycles_in_5s);
- int bufferhub_id_prev_write_buffer = -1;
- for (int i = 0; i < num_display_cycles_in_5s; ++i) {
- // Get a buffer from the WriteBufferQueue.
- DvrWriteBuffer* write_buffer = nullptr;
- DvrNativeBufferMetadata out_meta;
- int out_fence_fd = -1;
- ret = api_.WriteBufferQueueGainBuffer(
- write_queue_, kTimeoutMs, &write_buffer, &out_meta, &out_fence_fd);
- EXPECT_EQ(0, ret) << "Failed to get the a write buffer.";
- ASSERT_NE(nullptr, write_buffer) << "The gained buffer should not be null.";
-
- int bufferhub_id = api_.WriteBufferGetId(write_buffer);
- ALOGD("Display cycle: %d, bufferhub id of the write buffer: %d", i,
- bufferhub_id);
- EXPECT_NE(bufferhub_id_prev_write_buffer, bufferhub_id)
- << "Double buffering should be using the two buffers in turns, not "
- "reusing the same write buffer.";
- bufferhub_id_prev_write_buffer = bufferhub_id;
-
- // Color the write buffer.
- if (i % 2) {
- FillWriteBuffer(write_buffer, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
- height);
- } else {
- FillWriteBuffer(write_buffer, {0xff00ff00, 0xff0000ff, 0xffff0000}, width,
- height);
- }
-
- // Post the write buffer.
- int ready_fence_fd = -1;
- ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
- ready_fence_fd);
- EXPECT_EQ(0, ret) << "Failed to post the buffer.";
- }
- // Should observe blinking screen in secondary colors
- // although it is actually displaying primary colors.
-}
-
-TEST_F(DvrDisplayTest, DisplayWithTwoHardwareLayers) {
- // Create the direct_surface_0 of z order 10 and direct_surface_1 of z
- // order 11.
- DvrSurface* direct_surface_0 = nullptr;
- std::vector<DvrSurfaceAttribute> direct_surface_0_attributes = {
- {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
- .value.bool_value = true},
- {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
- .value.int32_value = 10},
- {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
- .value.bool_value = true},
- };
- int ret =
- api_.SurfaceCreate(direct_surface_0_attributes.data(),
- direct_surface_0_attributes.size(), &direct_surface_0);
- EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
-
- DvrSurface* direct_surface_1 = nullptr;
- std::vector<DvrSurfaceAttribute> direct_surface_1_attributes = {
- {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
- .value.bool_value = true},
- {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
- .value.int32_value = 11},
- {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
- .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
- .value.bool_value = true},
- };
- ret =
- api_.SurfaceCreate(direct_surface_1_attributes.data(),
- direct_surface_1_attributes.size(), &direct_surface_1);
- EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
-
- // Create a buffer queue for each of the direct surfaces.
- constexpr size_t kCapacity = 1;
- uint32_t width = display_metrics_.display_width;
- uint32_t height = display_metrics_.display_height;
-
- DvrWriteBufferQueue* write_queue_0 = nullptr;
- ret = api_.SurfaceCreateWriteBufferQueue(
- direct_surface_0, width, height, kFormat, kLayerCount, kUsage, kCapacity,
- kMetadataSize, &write_queue_0);
- EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
- EXPECT_NE(nullptr, write_queue_0) << "Write buffer queue should not be null.";
-
- DvrWriteBufferQueue* write_queue_1 = nullptr;
- ret = api_.SurfaceCreateWriteBufferQueue(
- direct_surface_1, width, height, kFormat, kLayerCount, kUsage, kCapacity,
- kMetadataSize, &write_queue_1);
- EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
- EXPECT_NE(nullptr, write_queue_1) << "Write buffer queue should not be null.";
-
- // Get a buffer from each of the write buffer queues.
- DvrWriteBuffer* write_buffer_0 = nullptr;
- DvrNativeBufferMetadata out_meta_0;
- int out_fence_fd = -1;
- ret = api_.WriteBufferQueueGainBuffer(
- write_queue_0, kTimeoutMs, &write_buffer_0, &out_meta_0, &out_fence_fd);
- EXPECT_EQ(0, ret) << "Failed to get the buffer.";
- EXPECT_NE(nullptr, write_buffer_0) << "Gained buffer should not be null.";
-
- DvrWriteBuffer* write_buffer_1 = nullptr;
- DvrNativeBufferMetadata out_meta_1;
- out_fence_fd = -1;
- ret = api_.WriteBufferQueueGainBuffer(
- write_queue_1, kTimeoutMs, &write_buffer_1, &out_meta_1, &out_fence_fd);
- EXPECT_EQ(0, ret) << "Failed to get the buffer.";
- EXPECT_NE(nullptr, write_buffer_1) << "Gained buffer should not be null.";
-
- // Color the write buffers.
- FillWriteBuffer(write_buffer_0, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
- height);
- FillWriteBuffer(write_buffer_1, {0x7f00ff00, 0x7f0000ff, 0x7fff0000}, width,
- height);
-
- // Post buffers.
- int ready_fence_fd = -1;
- ret = api_.WriteBufferQueuePostBuffer(write_queue_0, write_buffer_0,
- &out_meta_0, ready_fence_fd);
- EXPECT_EQ(0, ret) << "Failed to post the buffer.";
-
- ready_fence_fd = -1;
- ret = api_.WriteBufferQueuePostBuffer(write_queue_1, write_buffer_1,
- &out_meta_1, ready_fence_fd);
- EXPECT_EQ(0, ret) << "Failed to post the buffer.";
-
- sleep(5); // For visual check on the device under test.
- // Should observe three secondary colors.
-
- // Test finished. Clean up buffers and surfaces.
- if (write_queue_0 != nullptr) {
- api_.WriteBufferQueueDestroy(write_queue_0);
- write_queue_0 = nullptr;
- }
- if (write_queue_1 != nullptr) {
- api_.WriteBufferQueueDestroy(write_queue_1);
- write_queue_1 = nullptr;
- }
- if (direct_surface_0 != nullptr) {
- api_.SurfaceDestroy(direct_surface_0);
- }
- if (direct_surface_1 != nullptr) {
- api_.SurfaceDestroy(direct_surface_1);
- }
-}
-
-void DvrDisplayTest::FillWriteBuffer(
- DvrWriteBuffer* write_buffer, const std::vector<uint32_t>& color_textures,
- uint32_t width, uint32_t height) {
- uint32_t num_colors = color_textures.size();
- // Convert the first write buffer to an android hardware buffer.
- AHardwareBuffer* ah_buffer = nullptr;
- int ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
- ASSERT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
- ASSERT_NE(nullptr, ah_buffer) << "AHardware buffer should not be null.";
- AHardwareBuffer_Desc ah_buffer_describe;
- AHardwareBuffer_describe(ah_buffer, &ah_buffer_describe);
- ASSERT_EQ(ah_buffer_describe.format, kFormat)
- << "The format of the android hardware buffer is wrong.";
- ASSERT_EQ(ah_buffer_describe.layers, kLayerCount)
- << "The obtained android hardware buffer should have 2 layers.";
- ASSERT_EQ(ah_buffer_describe.width, width)
- << "The obtained android hardware buffer width is wrong.";
- ASSERT_EQ(ah_buffer_describe.height, height)
- << "The obtained android hardware buffer height is wrong.";
- // Change the content of the android hardware buffer.
- void* buffer_data = nullptr;
- int32_t fence = -1;
- ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
- fence, nullptr, &buffer_data);
- ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer.";
- ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null.";
-
- uint32_t num_pixels = width * height / num_colors;
- for (uint32_t color_index = 0; color_index < num_colors - 1; ++color_index) {
- uint32_t color_texture = color_textures[color_index];
- for (uint32_t i = 0; i < num_pixels; ++i) {
- memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
- (i + num_pixels * color_index) *
- sizeof(color_texture)),
- &color_texture, sizeof(color_texture));
- }
- }
- uint32_t color_texture = color_textures[num_colors - 1];
- uint32_t num_colored_pixels = num_pixels * (num_colors - 1);
- num_pixels = width * height - num_colored_pixels;
- for (uint32_t i = 0; i < num_pixels; ++i) {
- memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
- (i + num_colored_pixels) *
- sizeof(color_texture)),
- &color_texture, sizeof(color_texture));
- }
- fence = -1;
- ret = AHardwareBuffer_unlock(ah_buffer, &fence);
- EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";
-
- // Release the android hardware buffer.
- AHardwareBuffer_release(ah_buffer);
-}
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
deleted file mode 100644
index 07e2121..0000000
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ /dev/null
@@ -1,891 +0,0 @@
-#include <android-base/properties.h>
-#include <base/logging.h>
-#include <cutils/properties.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>
-
-#include <pdx/status.h>
-
-using android::pdx::ErrorStatus;
-using android::pdx::Status;
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-using ::testing::Test;
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, nullptr_t) {
- DvrSurfaceAttribute attribute;
- attribute.key = key;
- attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
- return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int32_t value) {
- DvrSurfaceAttribute attribute;
- attribute.key = key;
- attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
- attribute.value.int32_value = value;
- return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int64_t value) {
- DvrSurfaceAttribute attribute;
- attribute.key = key;
- attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64;
- attribute.value.int64_value = value;
- return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, bool value) {
- DvrSurfaceAttribute attribute;
- attribute.key = key;
- attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
- 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[] = {
- 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);
- if (ret < 0)
- return ErrorStatus(-ret);
- else
- return {UniqueDvrSurface(surface)};
-}
-
-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,
- size_t metadata_size) {
- DvrWriteBufferQueue* queue;
- const int ret = dvrSurfaceCreateWriteBufferQueue(
- surface.get(), width, height, format, layer_count, usage, capacity,
- metadata_size, &queue);
- if (ret < 0)
- return ErrorStatus(-ret);
- else
- return {UniqueDvrWriteBufferQueue(queue)};
-}
-
-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)};
-}
-
-class TestDisplayManager {
- public:
- TestDisplayManager(UniqueDvrDisplayManager display_manager,
- UniqueDvrSurfaceState surface_state)
- : display_manager_(std::move(display_manager)),
- surface_state_(std::move(surface_state)) {
- const int fd = dvrDisplayManagerGetEventFd(display_manager_.get());
- LOG_IF(INFO, fd < 0) << "Failed to get event fd: " << strerror(-fd);
- display_manager_event_fd_ = fd;
- }
-
- Status<UniqueDvrReadBufferQueue> GetReadBufferQueue(int surface_id,
- int queue_id) {
- DvrReadBufferQueue* queue;
- const int ret = dvrDisplayManagerGetReadBufferQueue(
- display_manager_.get(), surface_id, queue_id, &queue);
- if (ret < 0)
- return ErrorStatus(-ret);
- else
- return {UniqueDvrReadBufferQueue(queue)};
- }
-
- Status<void> UpdateSurfaceState() {
- const int ret = dvrDisplayManagerGetSurfaceState(display_manager_.get(),
- surface_state_.get());
- if (ret < 0)
- return ErrorStatus(-ret);
- else
- return {};
- }
-
- enum : int { kTimeoutMs = 10000 }; // 10s
-
- Status<void> WaitForUpdate(int timeout_ms = kTimeoutMs) {
- if (display_manager_event_fd_ < 0)
- return ErrorStatus(-display_manager_event_fd_);
-
- pollfd pfd = {display_manager_event_fd_, POLLIN, 0};
- const int count = poll(&pfd, 1, timeout_ms);
- if (count < 0)
- return ErrorStatus(errno);
- else if (count == 0)
- return ErrorStatus(ETIMEDOUT);
-
- int events;
- const int ret = dvrDisplayManagerTranslateEpollEventMask(
- display_manager_.get(), pfd.revents, &events);
- if (ret < 0)
- return ErrorStatus(-ret);
- else if (events & POLLIN)
- return UpdateSurfaceState();
- else
- return ErrorStatus(EPROTO);
- }
-
- Status<size_t> GetSurfaceCount() {
- size_t count = 0;
- const int ret =
- dvrSurfaceStateGetSurfaceCount(surface_state_.get(), &count);
- if (ret < 0)
- return ErrorStatus(-ret);
- else
- return {count};
- }
-
- Status<DvrSurfaceUpdateFlags> GetUpdateFlags(size_t surface_index) {
- DvrSurfaceUpdateFlags update_flags;
- const int ret = dvrSurfaceStateGetUpdateFlags(surface_state_.get(),
- surface_index, &update_flags);
- if (ret < 0)
- return ErrorStatus(-ret);
- else
- return {update_flags};
- }
-
- Status<int> GetSurfaceId(size_t surface_index) {
- int surface_id;
- const int ret = dvrSurfaceStateGetSurfaceId(surface_state_.get(),
- surface_index, &surface_id);
- if (ret < 0)
- return ErrorStatus(-ret);
- else
- return {surface_id};
- }
-
- Status<int> GetProcessId(size_t surface_index) {
- int process_id;
- const int ret = dvrSurfaceStateGetProcessId(surface_state_.get(),
- surface_index, &process_id);
- if (ret < 0)
- return ErrorStatus(-ret);
- else
- return {process_id};
- }
-
- Status<std::vector<DvrSurfaceAttribute>> GetAttributes(size_t surface_index) {
- std::vector<DvrSurfaceAttribute> attributes;
- size_t count = 0;
- const int ret = dvrSurfaceStateGetAttributeCount(surface_state_.get(),
- surface_index, &count);
- if (ret < 0)
- return ErrorStatus(-ret);
-
- attributes.resize(count);
- const ssize_t return_count = dvrSurfaceStateGetAttributes(
- surface_state_.get(), surface_index, attributes.data(), count);
- if (return_count < 0)
- return ErrorStatus(-return_count);
-
- attributes.resize(return_count);
- return {std::move(attributes)};
- }
-
- Status<std::vector<int>> GetQueueIds(size_t surface_index) {
- std::vector<int> queue_ids;
- size_t count = 0;
- const int ret = dvrSurfaceStateGetQueueCount(surface_state_.get(),
- surface_index, &count);
- if (ret < 0)
- return ErrorStatus(-ret);
-
- if (count > 0) {
- queue_ids.resize(count);
- const ssize_t return_count = dvrSurfaceStateGetQueueIds(
- surface_state_.get(), surface_index, queue_ids.data(), count);
- if (return_count < 0)
- return ErrorStatus(-return_count);
-
- queue_ids.resize(return_count);
- }
-
- return {std::move(queue_ids)};
- }
-
- private:
- UniqueDvrDisplayManager display_manager_;
- UniqueDvrSurfaceState surface_state_;
-
- // Owned by object in display_manager_, do not explicitly close.
- int display_manager_event_fd_;
-
- TestDisplayManager(const TestDisplayManager&) = delete;
- void operator=(const TestDisplayManager&) = delete;
-};
-
-class DvrDisplayManagerTest : public Test {
- protected:
- void SetUp() override {
- int ret;
- DvrDisplayManager* display_manager;
- DvrSurfaceState* surface_state;
-
- ret = dvrDisplayManagerCreate(&display_manager);
- ASSERT_EQ(0, ret) << "Failed to create display manager client";
- ASSERT_NE(nullptr, display_manager);
-
- ret = dvrSurfaceStateCreate(&surface_state);
- ASSERT_EQ(0, ret) << "Failed to create surface state object";
- ASSERT_NE(nullptr, surface_state);
-
- manager_.reset(
- new TestDisplayManager(UniqueDvrDisplayManager(display_manager),
- UniqueDvrSurfaceState(surface_state)));
- }
- void TearDown() override {}
-
- std::unique_ptr<TestDisplayManager> manager_;
-};
-
-// TODO(eieio): Consider moving these somewhere more central because they are
-// broadly useful.
-
-template <typename T>
-testing::AssertionResult StatusOk(const char* status_expression,
- const Status<T>& status) {
- if (!status.ok()) {
- return testing::AssertionFailure()
- << "(" << status_expression
- << ") expected to indicate success but actually contains error ("
- << status.error() << ")";
- } else {
- return testing::AssertionSuccess();
- }
-}
-
-template <typename T>
-testing::AssertionResult StatusError(const char* status_expression,
- const Status<T>& status) {
- if (status.ok()) {
- return testing::AssertionFailure()
- << "(" << status_expression
- << ") expected to indicate error but instead indicates success.";
- } else {
- return testing::AssertionSuccess();
- }
-}
-
-template <typename T>
-testing::AssertionResult StatusHasError(const char* status_expression,
- const char* /*error_code_expression*/,
- const Status<T>& status,
- int error_code) {
- if (status.ok()) {
- return StatusError(status_expression, status);
- } else if (status.error() != error_code) {
- return testing::AssertionFailure()
- << "(" << status_expression << ") expected to indicate error ("
- << error_code << ") but actually indicates error (" << status.error()
- << ")";
- } else {
- return testing::AssertionSuccess();
- }
-}
-
-template <typename T, typename U>
-testing::AssertionResult StatusHasValue(const char* status_expression,
- const char* /*value_expression*/,
- const Status<T>& status,
- const U& value) {
- if (!status.ok()) {
- return StatusOk(status_expression, status);
- } else if (status.get() != value) {
- return testing::AssertionFailure()
- << "(" << status_expression << ") expected to contain value ("
- << testing::PrintToString(value) << ") but actually contains value ("
- << testing::PrintToString(status.get()) << ")";
- } else {
- return testing::AssertionSuccess();
- }
-}
-
-template <typename T, typename Op>
-testing::AssertionResult StatusPred(const char* status_expression,
- const char* pred_expression,
- const Status<T>& status, Op pred) {
- if (!status.ok()) {
- return StatusOk(status_expression, status);
- } else if (!pred(status.get())) {
- return testing::AssertionFailure()
- << status_expression << " value ("
- << testing::PrintToString(status.get())
- << ") failed to pass predicate " << pred_expression;
- } else {
- return testing::AssertionSuccess();
- }
-}
-
-#define ASSERT_STATUS_OK(status) ASSERT_PRED_FORMAT1(StatusOk, status)
-#define ASSERT_STATUS_ERROR(status) ASSERT_PRED_FORMAT1(StatusError, status)
-
-#define ASSERT_STATUS_ERROR_VALUE(value, status) \
- ASSERT_PRED_FORMAT2(StatusHasError, status, value)
-
-#define ASSERT_STATUS_EQ(value, status) \
- ASSERT_PRED_FORMAT2(StatusHasValue, status, value)
-
-#define EXPECT_STATUS_OK(status) EXPECT_PRED_FORMAT1(StatusOk, status)
-#define EXPECT_STATUS_ERROR(status) EXPECT_PRED_FORMAT1(StatusError, status)
-
-#define EXPECT_STATUS_ERROR_VALUE(value, status) \
- EXPECT_PRED_FORMAT2(StatusHasError, status, value)
-
-#define EXPECT_STATUS_EQ(value, status) \
- EXPECT_PRED_FORMAT2(StatusHasValue, status, value)
-
-#define EXPECT_STATUS_PRED(pred, status) \
- EXPECT_PRED_FORMAT2(StatusPred, status, pred)
-
-#if 0
-// Verify utility predicate/macro functionality. This section is commented out
-// because it is designed to fail in some cases to validate the helpers.
-TEST_F(Test, ExpectVoid) {
- Status<void> status_error{ErrorStatus{EINVAL}};
- Status<void> status_ok{};
-
- EXPECT_STATUS_ERROR(status_error);
- EXPECT_STATUS_ERROR(status_ok);
- EXPECT_STATUS_OK(status_error);
- EXPECT_STATUS_OK(status_ok);
-
- EXPECT_STATUS_ERROR_VALUE(EINVAL, status_error);
- EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_error);
- EXPECT_STATUS_ERROR_VALUE(EINVAL, status_ok);
- EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_ok);
-}
-
-TEST_F(Test, ExpectInt) {
- Status<int> status_error{ErrorStatus{EINVAL}};
- Status<int> status_ok{10};
-
- EXPECT_STATUS_ERROR(status_error);
- EXPECT_STATUS_ERROR(status_ok);
- EXPECT_STATUS_OK(status_error);
- EXPECT_STATUS_OK(status_ok);
-
- EXPECT_STATUS_ERROR_VALUE(EINVAL, status_error);
- EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_error);
- EXPECT_STATUS_ERROR_VALUE(EINVAL, status_ok);
- EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_ok);
-
- EXPECT_STATUS_EQ(10, status_error);
- EXPECT_STATUS_EQ(20, status_error);
- EXPECT_STATUS_EQ(10, status_ok);
- EXPECT_STATUS_EQ(20, status_ok);
-
- auto pred1 = [](const auto& value) { return value < 15; };
- auto pred2 = [](const auto& value) { return value > 5; };
- auto pred3 = [](const auto& value) { return value > 15; };
- auto pred4 = [](const auto& value) { return value < 5; };
-
- EXPECT_STATUS_PRED(pred1, status_error);
- EXPECT_STATUS_PRED(pred2, status_error);
- EXPECT_STATUS_PRED(pred3, status_error);
- EXPECT_STATUS_PRED(pred4, status_error);
- EXPECT_STATUS_PRED(pred1, status_ok);
- EXPECT_STATUS_PRED(pred2, status_ok);
- EXPECT_STATUS_PRED(pred3, status_ok);
- EXPECT_STATUS_PRED(pred4, status_ok);
-}
-#endif
-
-TEST_F(DvrDisplayManagerTest, SurfaceCreateEvent) {
- // Get surface state and verify there are no surfaces.
- ASSERT_STATUS_OK(manager_->UpdateSurfaceState());
- ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount());
-
- // Get flags for invalid surface index.
- EXPECT_STATUS_ERROR_VALUE(EINVAL, manager_->GetUpdateFlags(0));
-
- // Create an application surface.
- auto surface_status = CreateApplicationSurface();
- ASSERT_STATUS_OK(surface_status);
- UniqueDvrSurface surface = surface_status.take();
- ASSERT_NE(nullptr, surface.get());
-
- const int surface_id = dvrSurfaceGetId(surface.get());
- ASSERT_GE(surface_id, 0);
-
- // Now there should be one new surface.
- ASSERT_STATUS_OK(manager_->WaitForUpdate());
- EXPECT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
- // Verify the new surface flag is set.
- auto check_flags = [](const auto& value) {
- return value & DVR_SURFACE_UPDATE_FLAGS_NEW_SURFACE;
- };
- EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
-
- // Verify the surface id matches.
- EXPECT_STATUS_EQ(surface_id, manager_->GetSurfaceId(0));
-
- // Verify the owning process of the surface.
- EXPECT_STATUS_EQ(getpid(), manager_->GetProcessId(0));
-
- surface.reset();
-
- ASSERT_STATUS_OK(manager_->WaitForUpdate());
- EXPECT_STATUS_EQ(0u, manager_->GetSurfaceCount());
-}
-
-TEST_F(DvrDisplayManagerTest, SurfaceAttributeEvent) {
- // Get surface state and verify there are no surfaces.
- ASSERT_STATUS_OK(manager_->UpdateSurfaceState());
- ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount());
-
- // Get attributes for an invalid surface index.
- EXPECT_STATUS_ERROR_VALUE(EINVAL, manager_->GetAttributes(0));
-
- const bool kInitialVisibility = true;
- const int32_t kInitialZOrder = 10;
- auto surface_status =
- CreateApplicationSurface(kInitialVisibility, kInitialZOrder);
- ASSERT_STATUS_OK(surface_status);
- auto surface = surface_status.take();
- ASSERT_NE(nullptr, surface.get());
-
- ASSERT_STATUS_OK(manager_->WaitForUpdate());
- ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
- // Check the initial attribute values.
- auto attribute_status = manager_->GetAttributes(0);
- ASSERT_STATUS_OK(attribute_status);
- auto attributes = attribute_status.take();
- EXPECT_GE(attributes.size(), 2u);
-
- 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.
- 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();
- ASSERT_STATUS_OK(surface_status);
- UniqueDvrSurface surface = surface_status.take();
- ASSERT_NE(nullptr, surface.get());
-
- const int surface_id = dvrSurfaceGetId(surface.get());
- ASSERT_GE(surface_id, 0);
- // Get surface state and verify there is one surface.
- ASSERT_STATUS_OK(manager_->WaitForUpdate());
- ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
- // 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, 0);
- ASSERT_STATUS_OK(write_queue_status);
- UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
- ASSERT_NE(nullptr, write_queue.get());
-
- const int queue_id = dvrWriteBufferQueueGetId(write_queue.get());
- ASSERT_GE(queue_id, 0);
-
- // Update surface state.
- ASSERT_STATUS_OK(manager_->WaitForUpdate());
- ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
- // Verify the buffers changed flag is set.
- auto check_flags = [](const auto& value) {
- return value & DVR_SURFACE_UPDATE_FLAGS_BUFFERS_CHANGED;
- };
- EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
-
- auto queue_ids_status = manager_->GetQueueIds(0);
- ASSERT_STATUS_OK(queue_ids_status);
-
- auto queue_ids = queue_ids_status.take();
- ASSERT_EQ(1u, queue_ids.size());
- EXPECT_EQ(queue_id, queue_ids[0]);
-
- auto read_queue_status = manager_->GetReadBufferQueue(surface_id, queue_id);
- ASSERT_STATUS_OK(read_queue_status);
- UniqueDvrReadBufferQueue read_queue = read_queue_status.take();
- ASSERT_NE(nullptr, read_queue.get());
- EXPECT_EQ(queue_id, dvrReadBufferQueueGetId(read_queue.get()));
-
- write_queue.reset();
-
- // Verify that destroying the queue generates a surface update event.
- ASSERT_STATUS_OK(manager_->WaitForUpdate());
- ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
- // Verify that the buffers changed flag is set.
- EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
-
- // Verify that the queue ids reflect the change.
- queue_ids_status = manager_->GetQueueIds(0);
- ASSERT_STATUS_OK(queue_ids_status);
-
- queue_ids = queue_ids_status.take();
- ASSERT_EQ(0u, queue_ids.size());
-}
-
-TEST_F(DvrDisplayManagerTest, MultiLayerBufferQueue) {
- // Create an application surface.
- auto surface_status = CreateApplicationSurface();
- ASSERT_STATUS_OK(surface_status);
- UniqueDvrSurface surface = surface_status.take();
- ASSERT_NE(nullptr, surface.get());
-
- // Get surface state and verify there is one surface.
- ASSERT_STATUS_OK(manager_->WaitForUpdate());
- ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
- // Create a new queue in the surface.
- const uint32_t kLayerCount = 3;
- auto write_queue_status = CreateSurfaceQueue(
- surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, kLayerCount,
- 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());
-
- DvrWriteBuffer* buffer = nullptr;
- DvrNativeBufferMetadata metadata;
- int fence_fd = -1;
- int error = dvrWriteBufferQueueGainBuffer(write_queue.get(), /*timeout=*/1000,
- &buffer, &metadata, &fence_fd);
- ASSERT_EQ(0, error);
-
- AHardwareBuffer* hardware_buffer = nullptr;
- error = dvrWriteBufferGetAHardwareBuffer(buffer, &hardware_buffer);
- ASSERT_EQ(0, error);
-
- AHardwareBuffer_Desc desc = {};
- AHardwareBuffer_describe(hardware_buffer, &desc);
- ASSERT_EQ(kLayerCount, desc.layers);
-
- AHardwareBuffer_release(hardware_buffer);
- dvrWriteBufferDestroy(buffer);
-}
-
-TEST_F(Test, ConfigurationData) {
- // TODO(hendrikw): Move this test and GetConfigData helper function out of the
- // display manager tests.
- auto data1 = 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 = 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
-} // namespace android
diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
deleted file mode 100644
index 5c837e7..0000000
--- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
+++ /dev/null
@@ -1,284 +0,0 @@
-#include <android/hardware_buffer.h>
-#include <dvr/dvr_buffer.h>
-#include <dvr/dvr_config.h>
-#include <dvr/dvr_shared_buffers.h>
-#include <dvr/dvr_surface.h>
-#include <system/graphics.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-TEST(DvrGlobalBufferTest, TestGlobalBuffersSameName) {
- const DvrGlobalBufferKey buffer_key = 101;
- DvrBuffer* buffer1 = nullptr;
- int ret1 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer1);
- ASSERT_EQ(0, ret1);
- ASSERT_NE(nullptr, buffer1);
-
- DvrBuffer* buffer2 = nullptr;
- int ret2 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer2);
- ASSERT_EQ(0, ret2);
- ASSERT_NE(nullptr, buffer2);
-
- AHardwareBuffer* hardware_buffer1 = nullptr;
- int e1 = dvrBufferGetAHardwareBuffer(buffer1, &hardware_buffer1);
- ASSERT_EQ(0, e1);
- ASSERT_NE(nullptr, hardware_buffer1);
-
- AHardwareBuffer* hardware_buffer2 = nullptr;
- int e2 = dvrBufferGetAHardwareBuffer(buffer2, &hardware_buffer2);
- ASSERT_EQ(0, e2);
- ASSERT_NE(nullptr, hardware_buffer2);
-
- AHardwareBuffer_Desc desc1 = {};
- AHardwareBuffer_describe(hardware_buffer1, &desc1);
- AHardwareBuffer_Desc desc2 = {};
- AHardwareBuffer_describe(hardware_buffer2, &desc2);
- ASSERT_EQ(desc1.width, 10u);
- ASSERT_EQ(desc1.height, 1u);
- ASSERT_EQ(desc1.layers, 1u);
- ASSERT_EQ(desc1.format, HAL_PIXEL_FORMAT_BLOB);
- ASSERT_EQ(desc1.usage, 0u);
- ASSERT_EQ(desc2.width, 10u);
- ASSERT_EQ(desc2.height, 1u);
- ASSERT_EQ(desc2.layers, 1u);
- ASSERT_EQ(desc2.format, HAL_PIXEL_FORMAT_BLOB);
- ASSERT_EQ(desc2.usage, 0u);
-
- dvrBufferDestroy(buffer1);
- dvrBufferDestroy(buffer2);
-
- DvrBuffer* buffer3 = nullptr;
- int e3 = dvrGetGlobalBuffer(buffer_key, &buffer3);
- ASSERT_NE(nullptr, buffer3);
- ASSERT_EQ(0, e3);
-
- AHardwareBuffer* hardware_buffer3 = nullptr;
- int e4 = dvrBufferGetAHardwareBuffer(buffer3, &hardware_buffer3);
- ASSERT_EQ(0, e4);
- ASSERT_NE(nullptr, hardware_buffer3);
-
- AHardwareBuffer_Desc desc3 = {};
- AHardwareBuffer_describe(hardware_buffer3, &desc3);
- ASSERT_EQ(desc3.width, 10u);
- ASSERT_EQ(desc3.height, 1u);
- ASSERT_EQ(desc3.layers, 1u);
- ASSERT_EQ(desc3.format, HAL_PIXEL_FORMAT_BLOB);
- ASSERT_EQ(desc3.usage, 0u);
-
- dvrBufferDestroy(buffer3);
-
- AHardwareBuffer_release(hardware_buffer1);
- AHardwareBuffer_release(hardware_buffer2);
- AHardwareBuffer_release(hardware_buffer3);
-}
-
-TEST(DvrGlobalBufferTest, TestMultipleGlobalBuffers) {
- const DvrGlobalBufferKey buffer_key1 = 102;
- const DvrGlobalBufferKey buffer_key2 = 103;
- DvrBuffer* setup_buffer1 = nullptr;
- 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 = dvrSetupGlobalBuffer(buffer_key2, 10, 0, &setup_buffer2);
- ASSERT_EQ(0, ret2);
- ASSERT_NE(nullptr, setup_buffer2);
- dvrBufferDestroy(setup_buffer2);
-
- DvrBuffer* buffer1 = nullptr;
- int e1 = dvrGetGlobalBuffer(buffer_key1, &buffer1);
- ASSERT_NE(nullptr, buffer1);
- ASSERT_EQ(0, e1);
- dvrBufferDestroy(buffer1);
-
- DvrBuffer* buffer2 = nullptr;
- int e2 = dvrGetGlobalBuffer(buffer_key2, &buffer2);
- ASSERT_NE(nullptr, buffer2);
- ASSERT_EQ(0, e2);
- dvrBufferDestroy(buffer2);
-}
-
-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
- // GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, and these two values are different.
- // If all is good, when we get the AHardwareBuffer, it should be converted
- // back to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE.
- const uint64_t usage = AHARDWAREBUFFER_USAGE_VIDEO_ENCODE;
-
- DvrBuffer* setup_buffer = nullptr;
- int e1 = dvrSetupGlobalBuffer(buffer_key, 10, 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);
-
- AHardwareBuffer_Desc desc = {};
- AHardwareBuffer_describe(hardware_buffer, &desc);
- ASSERT_EQ(usage, desc.usage);
-
- dvrBufferDestroy(setup_buffer);
- 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(0U, 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(0U, 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(0U, 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(0U, 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
-} // namespace android
diff --git a/libs/vr/libdvr/tests/dvr_tracking-test.cpp b/libs/vr/libdvr/tests/dvr_tracking-test.cpp
deleted file mode 100644
index 3b6d6e1..0000000
--- a/libs/vr/libdvr/tests/dvr_tracking-test.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#include <android/log.h>
-#include <gtest/gtest.h>
-
-#include "dvr_api_test.h"
-
-namespace {
-
-class DvrTrackingTest : public DvrApiTest {};
-
-#if DVR_TRACKING_IMPLEMENTED
-
-TEST_F(DvrTrackingTest, Implemented) {
- ASSERT_TRUE(api_.TrackingCameraCreate != nullptr);
- ASSERT_TRUE(api_.TrackingCameraStart != nullptr);
- ASSERT_TRUE(api_.TrackingCameraStop != nullptr);
-
- ASSERT_TRUE(api_.TrackingFeatureExtractorCreate != nullptr);
- ASSERT_TRUE(api_.TrackingFeatureExtractorDestroy != nullptr);
- ASSERT_TRUE(api_.TrackingFeatureExtractorStart != nullptr);
- ASSERT_TRUE(api_.TrackingFeatureExtractorStop != nullptr);
- ASSERT_TRUE(api_.TrackingFeatureExtractorProcessBuffer != nullptr);
-}
-
-TEST_F(DvrTrackingTest, CameraCreateFailsForInvalidInput) {
- int ret;
- ret = api_.TrackingCameraCreate(nullptr);
- EXPECT_EQ(ret, -EINVAL);
-
- DvrTrackingCamera* camera = reinterpret_cast<DvrTrackingCamera*>(42);
- ret = api_.TrackingCameraCreate(&camera);
- EXPECT_EQ(ret, -EINVAL);
-}
-
-TEST_F(DvrTrackingTest, CameraCreateDestroy) {
- DvrTrackingCamera* camera = nullptr;
- int ret = api_.TrackingCameraCreate(&camera);
-
- EXPECT_EQ(ret, 0);
- ASSERT_TRUE(camera != nullptr);
-
- api_.TrackingCameraDestroy(camera);
-}
-
-TEST_F(DvrTrackingTest, FeatureExtractorCreateFailsForInvalidInput) {
- int ret;
- ret = api_.TrackingFeatureExtractorCreate(nullptr);
- EXPECT_EQ(ret, -EINVAL);
-
- DvrTrackingFeatureExtractor* camera =
- reinterpret_cast<DvrTrackingFeatureExtractor*>(42);
- ret = api_.TrackingFeatureExtractorCreate(&camera);
- EXPECT_EQ(ret, -EINVAL);
-}
-
-TEST_F(DvrTrackingTest, FeatureExtractorCreateDestroy) {
- DvrTrackingFeatureExtractor* camera = nullptr;
- int ret = api_.TrackingFeatureExtractorCreate(&camera);
-
- EXPECT_EQ(ret, 0);
- ASSERT_TRUE(camera != nullptr);
-
- api_.TrackingFeatureExtractorDestroy(camera);
-}
-
-#else // !DVR_TRACKING_IMPLEMENTED
-
-TEST_F(DvrTrackingTest, NotImplemented) {
- ASSERT_TRUE(api_.TrackingCameraCreate != nullptr);
- ASSERT_TRUE(api_.TrackingCameraDestroy != nullptr);
- ASSERT_TRUE(api_.TrackingCameraStart != nullptr);
- ASSERT_TRUE(api_.TrackingCameraStop != nullptr);
-
- EXPECT_EQ(api_.TrackingCameraCreate(nullptr), -ENOSYS);
- EXPECT_EQ(api_.TrackingCameraStart(nullptr, nullptr), -ENOSYS);
- EXPECT_EQ(api_.TrackingCameraStop(nullptr), -ENOSYS);
-
- ASSERT_TRUE(api_.TrackingFeatureExtractorCreate != nullptr);
- ASSERT_TRUE(api_.TrackingFeatureExtractorDestroy != nullptr);
- ASSERT_TRUE(api_.TrackingFeatureExtractorStart != nullptr);
- ASSERT_TRUE(api_.TrackingFeatureExtractorStop != nullptr);
- ASSERT_TRUE(api_.TrackingFeatureExtractorProcessBuffer != nullptr);
-
- EXPECT_EQ(api_.TrackingFeatureExtractorCreate(nullptr), -ENOSYS);
- EXPECT_EQ(api_.TrackingFeatureExtractorStart(nullptr, nullptr, nullptr),
- -ENOSYS);
- EXPECT_EQ(api_.TrackingFeatureExtractorStop(nullptr), -ENOSYS);
- EXPECT_EQ(api_.TrackingFeatureExtractorProcessBuffer(nullptr, nullptr,
- nullptr, nullptr),
- -ENOSYS);
-
- ASSERT_TRUE(api_.TrackingSensorsCreate != nullptr);
- ASSERT_TRUE(api_.TrackingSensorsDestroy != nullptr);
- ASSERT_TRUE(api_.TrackingSensorsStart != nullptr);
- ASSERT_TRUE(api_.TrackingSensorsStop != nullptr);
-
- EXPECT_EQ(api_.TrackingSensorsCreate(nullptr, nullptr), -ENOSYS);
- EXPECT_EQ(api_.TrackingSensorsStart(nullptr, nullptr, nullptr), -ENOSYS);
- EXPECT_EQ(api_.TrackingSensorsStop(nullptr), -ENOSYS);
-}
-
-#endif // DVR_TRACKING_IMPLEMENTED
-
-} // namespace
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
deleted file mode 100644
index 40a5099..0000000
--- a/libs/vr/libvrsensor/Android.bp
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-sourceFiles = [
- "pose_client.cpp",
- "latency_model.cpp",
-]
-
-includeFiles = [
- "include",
-]
-
-staticLibraries = [
- "libdisplay",
- "libdvrcommon",
- "libbroadcastring",
-]
-
-sharedLibraries = [
- "libbase",
- "libbinder",
- "libbufferhubqueue",
- "libcutils",
- "libhardware",
- "liblog",
- "libutils",
- "libui",
- "libpdx_default_transport",
-]
-
-cc_library {
- srcs: sourceFiles,
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-macro-redefined",
- ],
- export_include_dirs: includeFiles,
- static_libs: staticLibraries,
- shared_libs: sharedLibraries,
- header_libs: ["libdvr_headers"],
- name: "libvrsensor",
-}
diff --git a/libs/vr/libvrsensor/include/CPPLINT.cfg b/libs/vr/libvrsensor/include/CPPLINT.cfg
deleted file mode 100644
index 2f8a3c0..0000000
--- a/libs/vr/libvrsensor/include/CPPLINT.cfg
+++ /dev/null
@@ -1 +0,0 @@
-filter=-build/header_guard
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
deleted file mode 100644
index b663a67..0000000
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ /dev/null
@@ -1,176 +0,0 @@
-#ifndef ANDROID_DVR_POSE_CLIENT_H_
-#define ANDROID_DVR_POSE_CLIENT_H_
-
-#ifdef __ARM_NEON
-#include <arm_neon.h>
-#else
-#ifndef __FLOAT32X4T_86
-#define __FLOAT32X4T_86
-typedef float float32x4_t __attribute__ ((__vector_size__ (16)));
-typedef struct float32x4x4_t { float32x4_t val[4]; } float32x4x4_t;
-#endif
-#endif
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <dvr/dvr_pose.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct DvrPoseClient DvrPoseClient;
-
-// Returned by the async pose ring buffer access API.
-typedef struct DvrPoseRingBufferInfo {
- // Read-only pointer to the pose ring buffer. The current pose is in this
- // buffer at element buffer[current_frame & (buffer_size - 1)]. The next
- // frame's forecasted pose is at element
- // ((current_frame + 1) & (buffer_size - 1)). And so on. The poses are
- // predicted for when 50% of the corresponding frame's pixel data is visible
- // to the user.
- // The last value returned by dvrPresent is the count for the next frame,
- // which is the earliest that the application could display something if they
- // were to render promptly. (TODO(jbates) move this comment to dvrPresent).
- volatile const DvrPoseAsync* buffer;
- // Minimum number of accurate forecasted poses including the current frame's
- // pose. This is the number of poses that are udpated by the pose service.
- // If the application reads past this count, they will get a stale prediction
- // from a previous frame. Guaranteed to be at least 2.
- uint32_t min_future_count;
- // Number of elements in buffer. At least 8 and greater than min_future_count.
- // Guaranteed to be a power of two. The total size of the buffer in bytes is:
- // total_count * sizeof(DvrPoseAsync)
- uint32_t total_count;
-} DvrPoseRingBufferInfo;
-
-typedef enum DvrPoseMode {
- DVR_POSE_MODE_6DOF = 0,
- DVR_POSE_MODE_3DOF,
- DVR_POSE_MODE_MOCK_FROZEN,
- DVR_POSE_MODE_MOCK_HEAD_TURN_SLOW,
- DVR_POSE_MODE_MOCK_HEAD_TURN_FAST,
- DVR_POSE_MODE_MOCK_ROTATE_SLOW,
- 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,
-} DvrPoseMode;
-
-typedef enum DvrControllerId {
- DVR_CONTROLLER_0 = 0,
- DVR_CONTROLLER_1 = 1,
-} DvrControllerId;
-
-// Creates a new pose client.
-//
-// @return Pointer to the created pose client, nullptr on failure.
-DvrPoseClient* dvrPoseClientCreate();
-
-// Destroys a pose client.
-//
-// @param client Pointer to the pose client to be destroyed.
-void dvrPoseClientDestroy(DvrPoseClient* client);
-
-// Gets the pose for the given vsync count.
-//
-// @param client Pointer to the pose client.
-// @param vsync_count Vsync that this pose should be forward-predicted to.
-// 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 dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count,
- DvrPoseAsync* out_pose);
-
-// Gets the current vsync count.
-uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client);
-
-// Gets the pose for the given controller at the given vsync count.
-//
-// @param client Pointer to the pose client.
-// @param controller_id The controller id.
-// @param vsync_count Vsync that this pose should be forward-predicted to.
-// 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 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 dvrPoseClientLogController(DvrPoseClient* client, bool enable);
-
-// DEPRECATED
-// Polls current pose state.
-//
-// @param client Pointer to the pose client.
-// @param state Struct to store polled state.
-// @return Zero on success, negative error code on failure.
-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 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 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 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 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:
-// index = (<current> + <offset>) % out_buffer_size
-// Where <current> was the last value returned by dvrPresent and
-// <offset> is less than or equal to |out_min_future_count|.
-// |out_buffer| will be set to a pointer to the buffer.
-// |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 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);
-
-// Requests a burst of data samples from pose service. The data samples are
-// passed through a shared memory buffer obtained by calling
-// dvrPoseClientGetDataReader().
-//
-// @param DvrPoseDataCaptureRequest Parameters on how to capture data.
-// @return Zero on success.
-int dvrPoseClientDataCapture(DvrPoseClient* client,
- const DvrPoseDataCaptureRequest* request);
-
-// Destroys the write buffer queue for the given |data_type|.
-int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // ANDROID_DVR_POSE_CLIENT_H_
diff --git a/libs/vr/libvrsensor/include/private/dvr/latency_model.h b/libs/vr/libvrsensor/include/private/dvr/latency_model.h
deleted file mode 100644
index bf0e687..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/latency_model.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef ANDROID_DVR_LATENCY_MODEL_H_
-#define ANDROID_DVR_LATENCY_MODEL_H_
-
-#include <vector>
-
-namespace android {
-namespace dvr {
-
-// This class models the latency from sensors. It will look at the first
-// window_size measurements and return their average after that.
-class LatencyModel {
- public:
- explicit LatencyModel(size_t window_size);
- ~LatencyModel() = default;
-
- void AddLatency(int64_t latency_ns);
- int64_t CurrentLatencyEstimate() const { return latency_; }
-
- private:
- size_t window_size_;
- int64_t latency_sum_ = 0;
- size_t num_summed_ = 0;
- int64_t latency_ = 0;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_LATENCY_MODEL_H_
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
deleted file mode 100644
index 7bf1cd4..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef ANDROID_DVR_POSE_IPC_H_
-#define ANDROID_DVR_POSE_IPC_H_
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DVR_POSE_SERVICE_BASE "system/vr/pose"
-#define DVR_POSE_SERVICE_CLIENT (DVR_POSE_SERVICE_BASE "/client")
-
-enum {
- DVR_POSE_FREEZE = 0,
- DVR_POSE_SET_MODE,
- DVR_POSE_GET_MODE,
- DVR_POSE_GET_CONTROLLER_RING_BUFFER,
- DVR_POSE_LOG_CONTROLLER,
- DVR_POSE_SENSORS_ENABLE,
- DVR_POSE_GET_TANGO_READER,
- DVR_POSE_DATA_CAPTURE,
- DVR_POSE_TANGO_READER_DESTROY,
-};
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // ANDROID_DVR_POSE_IPC_H_
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 39592bb..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
-#define ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
-
-#include <private/dvr/buffer_hub_queue_client.h>
-
-using android::dvr::ConsumerQueue;
-
-typedef struct DvrPoseClient DvrPoseClient;
-
-namespace android {
-namespace dvr {
-
-int dvrPoseClientGetDataReaderHandle(DvrPoseClient *client, uint64_t data_type,
- ConsumerQueue **queue_out);
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
diff --git a/libs/vr/libvrsensor/latency_model.cpp b/libs/vr/libvrsensor/latency_model.cpp
deleted file mode 100644
index d3a4521..0000000
--- a/libs/vr/libvrsensor/latency_model.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <private/dvr/latency_model.h>
-
-#include <cmath>
-
-namespace android {
-namespace dvr {
-
-LatencyModel::LatencyModel(size_t window_size) : window_size_(window_size) {}
-
-void LatencyModel::AddLatency(int64_t latency_ns) {
- // Not enough samples yet?
- if (num_summed_ < window_size_) {
- // Accumulate.
- latency_sum_ += latency_ns;
-
- // Have enough samples for latency estimate?
- if (++num_summed_ == window_size_) {
- latency_ = latency_sum_ / window_size_;
- }
- }
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
deleted file mode 100644
index 4ff6a09..0000000
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ /dev/null
@@ -1,368 +0,0 @@
-#define LOG_TAG "PoseClient"
-#include <dvr/dvr_shared_buffers.h>
-#include <dvr/pose_client.h>
-
-#include <stdint.h>
-
-#include <log/log.h>
-#include <pdx/client.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/display_client.h>
-#include <private/dvr/pose-ipc.h>
-#include <private/dvr/shared_buffer_helpers.h>
-
-using android::dvr::ConsumerQueue;
-using android::pdx::LocalHandle;
-using android::pdx::LocalChannelHandle;
-using android::pdx::Status;
-using android::pdx::Transaction;
-
-namespace android {
-namespace dvr {
-namespace {
-
-typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing;
-
-constexpr static int32_t MAX_CONTROLLERS = 2;
-} // namespace
-
-// PoseClient is a remote interface to the pose service in sensord.
-class PoseClient : public pdx::ClientBase<PoseClient> {
- public:
- ~PoseClient() override {}
-
- // Casts C handle into an instance of this class.
- 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(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) {
- const auto vsync_buffer = GetVsyncBuffer();
- if (vsync_buffer) {
- *out_pose =
- vsync_buffer
- ->vsync_poses[vsync_count & DvrVsyncPoseBuffer::kIndexMask];
- return 0;
- } else {
- return -EAGAIN;
- }
- }
-
- uint32_t GetVsyncCount() {
- const auto vsync_buffer = GetVsyncBuffer();
- if (vsync_buffer) {
- return vsync_buffer->vsync_count;
- }
-
- return 0;
- }
-
- int GetControllerPose(int32_t controller_id, uint32_t vsync_count,
- DvrPoseAsync* out_pose) {
- if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) {
- return -EINVAL;
- }
- if (!controllers_[controller_id].mapped_pose_buffer) {
- int ret = GetControllerRingBuffer(controller_id);
- if (ret < 0)
- return ret;
- }
- *out_pose =
- controllers_[controller_id]
- .mapped_pose_buffer[vsync_count & DvrVsyncPoseBuffer::kIndexMask];
- return 0;
- }
-
- int LogController(bool enable) {
- Transaction trans{*this};
- Status<int> status = trans.Send<int>(DVR_POSE_LOG_CONTROLLER, &enable,
- sizeof(enable), nullptr, 0);
- ALOGE_IF(!status, "Pose LogController() failed because: %s",
- status.GetErrorMessage().c_str());
- return ReturnStatusOrError(status);
- }
-
- // Freezes the pose to the provided state. Future poll operations will return
- // 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 DvrPose& frozen_state) {
- Transaction trans{*this};
- Status<int> status = trans.Send<int>(DVR_POSE_FREEZE, &frozen_state,
- sizeof(frozen_state), nullptr, 0);
- ALOGE_IF(!status, "Pose Freeze() failed because: %s\n",
- status.GetErrorMessage().c_str());
- return ReturnStatusOrError(status);
- }
-
- // Sets the data mode for the pose service.
- int SetMode(DvrPoseMode mode) {
- Transaction trans{*this};
- Status<int> status =
- trans.Send<int>(DVR_POSE_SET_MODE, &mode, sizeof(mode), nullptr, 0);
- ALOGE_IF(!status, "Pose SetPoseMode() failed because: %s",
- status.GetErrorMessage().c_str());
- return ReturnStatusOrError(status);
- }
-
- // Gets the data mode for the pose service.
- int GetMode(DvrPoseMode* out_mode) {
- int mode;
- Transaction trans{*this};
- Status<int> status =
- trans.Send<int>(DVR_POSE_GET_MODE, nullptr, 0, &mode, sizeof(mode));
- ALOGE_IF(!status, "Pose GetPoseMode() failed because: %s",
- status.GetErrorMessage().c_str());
- if (status)
- *out_mode = DvrPoseMode(mode);
- return ReturnStatusOrError(status);
- }
-
- int GetTangoReaderHandle(uint64_t data_type, ConsumerQueue** queue_out) {
- // Get buffer.
- Transaction trans{*this};
- Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>(
- DVR_POSE_GET_TANGO_READER, &data_type, sizeof(data_type), nullptr, 0);
-
- if (!status) {
- ALOGE("PoseClient GetTangoReaderHandle() failed because: %s",
- status.GetErrorMessage().c_str());
- *queue_out = nullptr;
- return -status.error();
- }
-
- std::unique_ptr<ConsumerQueue> consumer_queue =
- ConsumerQueue::Import(status.take());
- *queue_out = consumer_queue.release();
- return 0;
- }
-
- int DataCapture(const DvrPoseDataCaptureRequest* request) {
- Transaction trans{*this};
- Status<int> status = trans.Send<int>(DVR_POSE_DATA_CAPTURE, request,
- sizeof(*request), nullptr, 0);
- ALOGE_IF(!status, "PoseClient DataCapture() failed because: %s\n",
- status.GetErrorMessage().c_str());
- return ReturnStatusOrError(status);
- }
-
- int DataReaderDestroy(uint64_t data_type) {
- Transaction trans{*this};
- Status<int> status = trans.Send<int>(DVR_POSE_TANGO_READER_DESTROY,
- &data_type, sizeof(data_type), nullptr,
- 0);
- ALOGE_IF(!status, "PoseClient DataReaderDestroy() failed because: %s\n",
- status.GetErrorMessage().c_str());
- 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) {
- // First time mapping the buffer?
- const auto vsync_buffer = GetVsyncBuffer();
- if (vsync_buffer) {
- if (out_info) {
- out_info->min_future_count = DvrVsyncPoseBuffer::kMinFutureCount;
- out_info->total_count = DvrVsyncPoseBuffer::kSize;
- out_info->buffer = vsync_buffer->vsync_poses;
- }
- return -EINVAL;
- }
-
- return -EAGAIN;
- }
-
- int GetControllerRingBuffer(int32_t controller_id) {
- if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) {
- return -EINVAL;
- }
- ControllerClientState& client_state = controllers_[controller_id];
- if (client_state.pose_buffer.get()) {
- return 0;
- }
-
- Transaction trans{*this};
- Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>(
- DVR_POSE_GET_CONTROLLER_RING_BUFFER, &controller_id,
- sizeof(controller_id), nullptr, 0);
- if (!status) {
- return -status.error();
- }
-
- auto buffer = ConsumerBuffer::Import(status.take());
- if (!buffer) {
- ALOGE("Pose failed to import ring buffer");
- return -EIO;
- }
- constexpr size_t size = DvrVsyncPoseBuffer::kSize * sizeof(DvrPoseAsync);
- void* addr = nullptr;
- int ret = buffer->GetBlobReadWritePointer(size, &addr);
- if (ret < 0 || !addr) {
- ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr);
- return -EIO;
- }
- client_state.pose_buffer.swap(buffer);
- 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].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],
- client_state.mapped_pose_buffer[0].orientation[3]);
- return 0;
- }
-
- private:
- friend BASE;
-
- // Set up a channel to the pose service.
- PoseClient()
- : BASE(pdx::default_transport::ClientChannelFactory::Create(
- DVR_POSE_SERVICE_CLIENT)) {
- // TODO(eieio): Cache the pose and make timeout 0 so that the API doesn't
- // block while waiting for the pose service to come back up.
- EnableAutoReconnect(kInfiniteTimeout);
- }
-
- PoseClient(const PoseClient&) = delete;
- PoseClient& operator=(const PoseClient&) = delete;
-
- 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_;
- }
-
- // 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<ConsumerBuffer> pose_buffer;
- const DvrPoseAsync* mapped_pose_buffer = nullptr;
- };
- ControllerClientState controllers_[MAX_CONTROLLERS];
-};
-
-int dvrPoseClientGetDataReaderHandle(DvrPoseClient* client, uint64_t type,
- ConsumerQueue** queue_out) {
- return PoseClient::FromC(client)->GetTangoReaderHandle(type, queue_out);
-}
-
-} // namespace dvr
-} // namespace android
-
-using android::dvr::PoseClient;
-
-extern "C" {
-
-DvrPoseClient* dvrPoseClientCreate() {
- auto* client = PoseClient::Create().release();
- return reinterpret_cast<DvrPoseClient*>(client);
-}
-
-void dvrPoseClientDestroy(DvrPoseClient* client) {
- delete PoseClient::FromC(client);
-}
-
-int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count,
- DvrPoseAsync* out_pose) {
- return PoseClient::FromC(client)->GetPose(vsync_count, out_pose);
-}
-
-uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client) {
- return PoseClient::FromC(client)->GetVsyncCount();
-}
-
-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 dvrPoseClientLogController(DvrPoseClient* client, bool enable) {
- return PoseClient::FromC(client)->LogController(enable);
-}
-
-int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state) {
- return PoseClient::FromC(client)->Poll(state);
-}
-
-int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state) {
- return PoseClient::FromC(client)->Freeze(*frozen_state);
-}
-
-int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode) {
- return PoseClient::FromC(client)->SetMode(mode);
-}
-
-int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode) {
- return PoseClient::FromC(client)->GetMode(mode);
-}
-
-int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled) {
- return PoseClient::FromC(client)->EnableSensors(enabled);
-}
-
-int dvrPoseClientDataCapture(DvrPoseClient* client,
- const DvrPoseDataCaptureRequest* request) {
- return PoseClient::FromC(client)->DataCapture(request);
-}
-
-int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type) {
- return PoseClient::FromC(client)->DataReaderDestroy(data_type);
-}
-
-} // extern "C"
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 76fd7f0..dd14bcf 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -207,7 +207,8 @@
ATRACE_CALL();
const nsecs_t openTime = systemTime();
- if (should_unload_system_driver(cnx)) {
+ if (!android::GraphicsEnv::getInstance().angleIsSystemDriver() &&
+ should_unload_system_driver(cnx)) {
unload_system_driver(cnx);
}
@@ -216,8 +217,13 @@
return cnx->dso;
}
- // Firstly, try to load ANGLE driver.
- driver_t* hnd = attempt_to_load_angle(cnx);
+ // Firstly, try to load ANGLE driver, unless we know that we shouldn't.
+ bool shouldForceLegacyDriver = android::GraphicsEnv::getInstance().shouldForceLegacyDriver();
+ driver_t* hnd = nullptr;
+ if (!shouldForceLegacyDriver) {
+ hnd = attempt_to_load_angle(cnx);
+ }
+
if (!hnd) {
// Secondly, try to load from driver apk.
hnd = attempt_to_load_updated_driver(cnx);
@@ -230,21 +236,29 @@
LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s",
android::GraphicsEnv::getInstance().getDriverPath().c_str());
}
- // Finally, try to load system driver, start by searching for the library name appended by
- // the system properties of the GLES userspace driver in both locations.
- // i.e.:
- // libGLES_${prop}.so, or:
- // libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
- for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
- auto prop = base::GetProperty(key, "");
- if (prop.empty()) {
- continue;
- }
- hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true);
- if (hnd) {
- break;
- } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
- failToLoadFromDriverSuffixProperty = true;
+ // Finally, try to load system driver. If ANGLE is the system driver
+ // (i.e. we are forcing the legacy system driver instead of ANGLE), use
+ // the driver suffix that was passed down from above.
+ if (shouldForceLegacyDriver) {
+ std::string suffix = android::GraphicsEnv::getInstance().getLegacySuffix();
+ hnd = attempt_to_load_system_driver(cnx, suffix.c_str(), true);
+ } else {
+ // Start by searching for the library name appended by the system
+ // properties of the GLES userspace driver in both locations.
+ // i.e.:
+ // libGLES_${prop}.so, or:
+ // libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
+ for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
+ auto prop = base::GetProperty(key, "");
+ if (prop.empty()) {
+ continue;
+ }
+ hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true);
+ if (hnd) {
+ break;
+ } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
+ failToLoadFromDriverSuffixProperty = true;
+ }
}
}
}
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index b3d6f74..e0ba946 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -118,70 +118,27 @@
: "rax", "cc" \
);
-#elif defined(__mips64)
+#elif defined(__riscv)
+ #define API_ENTRY(_api) __attribute__((noinline)) _api
- #define API_ENTRY(_api) __attribute__((noinline)) _api
-
- #define CALL_GL_EXTENSION_API(_api, ...) \
- register unsigned int _t0 asm("$12"); \
- register unsigned int _fn asm("$25"); \
- register unsigned int _tls asm("$3"); \
- asm volatile( \
- ".set push\n\t" \
- ".set noreorder\n\t" \
- "rdhwr %[tls], $29\n\t" \
- "ld %[t0], %[OPENGL_API](%[tls])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " move %[fn], $ra\n\t" \
- "ld %[t0], %[API](%[t0])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " nop\n\t" \
- "move %[fn], %[t0]\n\t" \
- "1:\n\t" \
- "jalr $0, %[fn]\n\t" \
- " nop\n\t" \
- ".set pop\n\t" \
- : [fn] "=c"(_fn), \
- [tls] "=&r"(_tls), \
- [t0] "=&r"(_t0) \
- : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \
- [API] "I"(__builtin_offsetof(gl_hooks_t, \
- ext.extensions[_api])) \
- : \
- );
-
-#elif defined(__mips__)
-
- #define API_ENTRY(_api) __attribute__((noinline)) _api
-
- #define CALL_GL_EXTENSION_API(_api, ...) \
- register unsigned int _t0 asm("$8"); \
- register unsigned int _fn asm("$25"); \
- register unsigned int _tls asm("$3"); \
- asm volatile( \
- ".set push\n\t" \
- ".set noreorder\n\t" \
- ".set mips32r2\n\t" \
- "rdhwr %[tls], $29\n\t" \
- "lw %[t0], %[OPENGL_API](%[tls])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " move %[fn], $ra\n\t" \
- "lw %[t0], %[API](%[t0])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " nop\n\t" \
- "move %[fn], %[t0]\n\t" \
- "1:\n\t" \
- "jalr $0, %[fn]\n\t" \
- " nop\n\t" \
- ".set pop\n\t" \
- : [fn] "=c"(_fn), \
- [tls] "=&r"(_tls), \
- [t0] "=&r"(_t0) \
- : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \
- [API] "I"(__builtin_offsetof(gl_hooks_t, \
- ext.extensions[_api])) \
- : \
- );
+ #define CALL_GL_EXTENSION_API(_api) \
+ asm volatile( \
+ "mv t0, tp\n" \
+ "li t1, %[tls]\n" \
+ "add t0, t0, t1\n" \
+ "ld t0, 0(t0)\n" \
+ "beqz t0, 1f\n" \
+ "li t1, %[api]\n" \
+ "add t0, t0, t1\n" \
+ "ld t0, 0(t0)\n" \
+ "jalr x0, t0\n" \
+ "1: ret\n" \
+ : \
+ : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \
+ [api] "i" (__builtin_offsetof(gl_hooks_t, \
+ ext.extensions[_api])) \
+ : "t0", "t1" \
+ );
#endif
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index 65f50f5..5bd5c14 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -191,73 +191,44 @@
: \
);
-#elif defined(__mips64)
+#elif defined(__riscv)
#define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- // t0: $12
- // fn: $25
- // tls: $3
- // v0: $2
- #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
- asm volatile( \
- ".set push\n\t" \
- ".set noreorder\n\t" \
- "rdhwr $3, $29\n\t" \
- "ld $12, %[OPENGL_API]($3)\n\t" \
- "beqz $12, 1f\n\t" \
- " move $25, $ra\n\t" \
- "ld $12, %[API]($12)\n\t" \
- "beqz $12, 1f\n\t" \
- " nop\n\t" \
- "move $25, $12\n\t" \
- "1:\n\t" \
- "jalr $0, $25\n\t" \
- " move $2, $0\n\t" \
- ".set pop\n\t" \
- : \
- : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
- [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", \
- "$10", "$11", "$12", "$25" \
- );
-
- #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
- #define CALL_GL_API_INTERNAL_DO_RETURN
-
-#elif defined(__mips__)
-
- #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
-
- // t0: $8
- // fn: $25
- // tls: $3
- // v0: $2
#define CALL_GL_API_INTERNAL_CALL(_api, ...) \
asm volatile( \
- ".set push\n\t" \
- ".set noreorder\n\t" \
- ".set mips32r2\n\t" \
- "rdhwr $3, $29\n\t" \
- "lw $3, %[OPENGL_API]($3)\n\t" \
- "beqz $3, 1f\n\t" \
- " move $25,$ra\n\t" \
- "lw $3, %[API]($3)\n\t" \
- "beqz $3, 1f\n\t" \
- " nop\n\t" \
- "move $25, $3\n\t" \
- "1:\n\t" \
- "jalr $0, $25\n\t" \
- " move $2, $0\n\t" \
- ".set pop\n\t" \
+ "mv t0, tp\n" \
+ "li t1, %[tls]\n" \
+ "add t0, t0, t1\n" \
+ "ld t0, 0(t0)\n" \
+ "beqz t0, 1f\n" \
+ "li t1, %[api]\n" \
+ "add t0, t0, t1\n" \
+ "ld t0, 0(t0)\n" \
+ "jalr x0, t0\n" \
+ "1:\n" \
: \
- : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \
- [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25" \
+ : [tls] "i"(TLS_SLOT_OPENGL_API*sizeof(void *)), \
+ [api] "i"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+ : "t0", "t1", "t2", "a0", "a1", "a2", "a3", "a4", \
+ "a5", "t6", "t3", "t4", "t5", "t6" \
);
- #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
- #define CALL_GL_API_INTERNAL_DO_RETURN
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ asm volatile( \
+ "li a0, 0\n" \
+ : \
+ : \
+ : "a0" \
+ );
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ asm volatile( \
+ "ret\n" \
+ : \
+ : \
+ : \
+ );
#endif
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index bacd4b4..64c0f97 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -247,73 +247,44 @@
: \
);
-#elif defined(__mips64)
+#elif defined(__riscv)
#define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- // t0: $12
- // fn: $25
- // tls: $3
- // v0: $2
- #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
- asm volatile( \
- ".set push\n\t" \
- ".set noreorder\n\t" \
- "rdhwr $3, $29\n\t" \
- "ld $12, %[OPENGL_API]($3)\n\t" \
- "beqz $12, 1f\n\t" \
- " move $25, $ra\n\t" \
- "ld $12, %[API]($12)\n\t" \
- "beqz $12, 1f\n\t" \
- " nop\n\t" \
- "move $25, $12\n\t" \
- "1:\n\t" \
- "jalr $0, $25\n\t" \
- " move $2, $0\n\t" \
- ".set pop\n\t" \
- : \
- : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
- [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", \
- "$10", "$11", "$12", "$25" \
- );
-
- #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
- #define CALL_GL_API_INTERNAL_DO_RETURN
-
-#elif defined(__mips__)
-
- #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
-
- // t0: $8
- // fn: $25
- // tls: $3
- // v0: $2
#define CALL_GL_API_INTERNAL_CALL(_api, ...) \
asm volatile( \
- ".set push\n\t" \
- ".set noreorder\n\t" \
- ".set mips32r2\n\t" \
- "rdhwr $3, $29\n\t" \
- "lw $3, %[OPENGL_API]($3)\n\t" \
- "beqz $3, 1f\n\t" \
- " move $25,$ra\n\t" \
- "lw $3, %[API]($3)\n\t" \
- "beqz $3, 1f\n\t" \
- " nop\n\t" \
- "move $25, $3\n\t" \
- "1:\n\t" \
- "jalr $0, $25\n\t" \
- " move $2, $0\n\t" \
- ".set pop\n\t" \
+ "mv t0, tp\n" \
+ "li t1, %[tls]\n" \
+ "add t0, t0, t1\n" \
+ "ld t0, 0(t0)\n" \
+ "beqz t0, 1f\n" \
+ "li t1, %[api]\n" \
+ "add t0, t0, t1\n" \
+ "ld t0, 0(t0)\n" \
+ "jalr x0, t0\n" \
+ "1:\n" \
: \
- : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \
- [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25" \
+ : [tls] "i"(TLS_SLOT_OPENGL_API*sizeof(void *)), \
+ [api] "i"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+ : "t0", "t1", "t2", "a0", "a1", "a2", "a3", "a4", \
+ "a5", "t6", "t3", "t4", "t5", "t6" \
);
- #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
- #define CALL_GL_API_INTERNAL_DO_RETURN
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ asm volatile( \
+ "li a0, 0\n" \
+ : \
+ : \
+ : "a0" \
+ );
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ asm volatile( \
+ "ret\n" \
+ : \
+ : \
+ : \
+ );
#endif
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 2a3924b..dce327e 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -196,9 +196,20 @@
}
coords += StringPrintf("{%" PRIu32 ": ", i);
coords +=
- StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f, pressure=%.1f", pointerProperties[i].id,
+ StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f pressure=%.1f", pointerProperties[i].id,
pointerCoords[i].getX(), pointerCoords[i].getY(),
pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+ const int32_t toolType = pointerProperties[i].toolType;
+ if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) {
+ coords += StringPrintf(" toolType=%s", motionToolTypeToString(toolType));
+ }
+ const float major = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
+ const float minor = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR);
+ const float orientation = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+ if (major != 0 || minor != 0) {
+ coords += StringPrintf(" major=%.1f minor=%.1f orientation=%.1f", major, minor,
+ orientation);
+ }
coords += "}";
}
return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index b4b617e..8d5d883 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -15,6 +15,9 @@
"name": "inputflinger_tests"
},
{
+ "name": "libchrome-gestures_test"
+ },
+ {
"name": "libpalmrejection_test"
},
{
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
index f57ff33..ec41025 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.cpp
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -29,8 +29,40 @@
using android::base::StringPrintf;
+/**
+ * This type is declared here to ensure consistency between the instantiated type (used in the
+ * constructor via std::make_unique) and the cast-to type (used in PalmRejector::dump() with
+ * static_cast). Due to the lack of rtti support, dynamic_cast is not available, so this can't be
+ * checked at runtime to avoid undefined behaviour.
+ */
+using PalmFilterImplementation = ::ui::NeuralStylusPalmDetectionFilter;
+
namespace android {
+/**
+ * Log detailed debug messages about each inbound motion event notification to the blocker.
+ * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerInboundMotion DEBUG"
+ * (requires restart)
+ */
+const bool DEBUG_INBOUND_MOTION =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "InboundMotion", ANDROID_LOG_INFO);
+
+/**
+ * Log detailed debug messages about each outbound motion event processed by the blocker.
+ * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerOutboundMotion DEBUG"
+ * (requires restart)
+ */
+const bool DEBUG_OUTBOUND_MOTION =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "OutboundMotion", ANDROID_LOG_INFO);
+
+/**
+ * Log the data sent to the model and received back from the model.
+ * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerModel DEBUG"
+ * (requires restart)
+ */
+const bool DEBUG_MODEL =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Model", ANDROID_LOG_INFO);
+
// Category (=namespace) name for the input settings that are applied at boot time
static const char* INPUT_NATIVE_BOOT = "input_native_boot";
/**
@@ -45,13 +77,11 @@
}
static bool isFromTouchscreen(int32_t source) {
- return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN) &&
- !isFromSource(source, AINPUT_SOURCE_STYLUS);
+ return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN);
}
static ::base::TimeTicks toChromeTimestamp(nsecs_t eventTime) {
- return ::base::TimeTicks::UnixEpoch() +
- ::base::Milliseconds(static_cast<float>(ns2ms(eventTime)));
+ return ::base::TimeTicks::UnixEpoch() + ::base::TimeDelta::FromNanosecondsD(eventTime);
}
/**
@@ -61,39 +91,22 @@
static bool isPalmRejectionEnabled() {
std::string value = toLower(
server_configurable_flags::GetServerConfigurableFlag(INPUT_NATIVE_BOOT,
- PALM_REJECTION_ENABLED, "false"));
- if (value == "true" || value == "1") {
+ PALM_REJECTION_ENABLED, "0"));
+ if (value == "1") {
return true;
}
return false;
}
-static int getLinuxToolType(int32_t toolType) {
- switch (toolType) {
- case AMOTION_EVENT_TOOL_TYPE_FINGER:
- return MT_TOOL_FINGER;
- case AMOTION_EVENT_TOOL_TYPE_STYLUS:
- return MT_TOOL_PEN;
- case AMOTION_EVENT_TOOL_TYPE_PALM:
- return MT_TOOL_PALM;
+static int getLinuxToolCode(int toolType) {
+ if (toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS) {
+ return BTN_TOOL_PEN;
}
- ALOGW("Got tool type %" PRId32 ", converting to MT_TOOL_FINGER", toolType);
- return MT_TOOL_FINGER;
-}
-
-static std::string dumpDeviceInfo(const AndroidPalmFilterDeviceInfo& info) {
- std::string out;
- out += StringPrintf("max_x = %.2f\n", info.max_x);
- out += StringPrintf("max_y = %.2f\n", info.max_y);
- out += StringPrintf("x_res = %.2f\n", info.x_res);
- out += StringPrintf("y_res = %.2f\n", info.y_res);
- out += StringPrintf("major_radius_res = %.2f\n", info.major_radius_res);
- out += StringPrintf("minor_radius_res = %.2f\n", info.minor_radius_res);
- out += StringPrintf("minor_radius_supported = %s\n",
- info.minor_radius_supported ? "true" : "false");
- out += StringPrintf("touch_major_res = %" PRId32 "\n", info.touch_major_res);
- out += StringPrintf("touch_minor_res = %" PRId32 "\n", info.touch_minor_res);
- return out;
+ if (toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) {
+ return BTN_TOOL_FINGER;
+ }
+ ALOGW("Got tool type %" PRId32 ", converting to BTN_TOOL_FINGER", toolType);
+ return BTN_TOOL_FINGER;
}
static int32_t getActionUpForPointerId(const NotifyMotionArgs& args, int32_t pointerId) {
@@ -128,32 +141,6 @@
return AMOTION_EVENT_ACTION_MOVE;
}
-std::string toString(const ::ui::InProgressTouchEvdev& touch) {
- return StringPrintf("x=%.1f, y=%.1f, tracking_id=%i, slot=%zu,"
- " pressure=%.1f, major=%i, minor=%i, "
- "tool_type=%i, altered=%s, was_touching=%s, touching=%s",
- touch.x, touch.y, touch.tracking_id, touch.slot, touch.pressure,
- touch.major, touch.minor, touch.tool_type, toString(touch.altered),
- toString(touch.was_touching), toString(touch.touching));
-}
-
-/**
- * Remove the data for the provided pointers from the args. The pointers are identified by their
- * pointerId, not by the index inside the array.
- * Return the new NotifyMotionArgs struct that has the remaining pointers.
- * The only fields that may be different in the returned args from the provided args are:
- * - action
- * - pointerCount
- * - pointerProperties
- * - pointerCoords
- * Action might change because it contains a pointer index. If another pointer is removed, the
- * active pointer index would be shifted.
- * Do not call this function for events with POINTER_UP or POINTER_DOWN events when removed pointer
- * id is the acting pointer id.
- *
- * @param args the args from which the pointers should be removed
- * @param pointerIds the pointer ids of the pointers that should be removed
- */
NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
const std::set<int32_t>& pointerIds) {
const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
@@ -199,6 +186,26 @@
return newArgs;
}
+/**
+ * Remove stylus pointers from the provided NotifyMotionArgs.
+ *
+ * Return NotifyMotionArgs where the stylus pointers have been removed.
+ * If this results in removal of the active pointer, then return nullopt.
+ */
+static std::optional<NotifyMotionArgs> removeStylusPointerIds(const NotifyMotionArgs& args) {
+ std::set<int32_t> stylusPointerIds;
+ for (uint32_t i = 0; i < args.pointerCount; i++) {
+ if (args.pointerProperties[i].toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS) {
+ stylusPointerIds.insert(args.pointerProperties[i].id);
+ }
+ }
+ NotifyMotionArgs withoutStylusPointers = removePointerIds(args, stylusPointerIds);
+ if (withoutStylusPointers.pointerCount == 0 || withoutStylusPointers.action == ACTION_UNKNOWN) {
+ return std::nullopt;
+ }
+ return withoutStylusPointers;
+}
+
std::optional<AndroidPalmFilterDeviceInfo> createPalmFilterDeviceInfo(
const InputDeviceInfo& deviceInfo) {
if (!isFromTouchscreen(deviceInfo.getSources())) {
@@ -326,6 +333,7 @@
}
void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) {
+ ALOGD_IF(DEBUG_INBOUND_MOTION, "%s: %s", __func__, args->dump().c_str());
{ // acquire lock
std::scoped_lock lock(mLock);
const std::vector<NotifyMotionArgs> processedArgs =
@@ -339,17 +347,22 @@
mQueuedListener.flush();
}
+void UnwantedInteractionBlocker::enqueueOutboundMotionLocked(const NotifyMotionArgs& args) {
+ ALOGD_IF(DEBUG_OUTBOUND_MOTION, "%s: %s", __func__, args.dump().c_str());
+ mQueuedListener.notifyMotion(&args);
+}
+
void UnwantedInteractionBlocker::notifyMotionLocked(const NotifyMotionArgs* args) {
auto it = mPalmRejectors.find(args->deviceId);
const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source);
if (!sendToPalmRejector) {
- mQueuedListener.notifyMotion(args);
+ enqueueOutboundMotionLocked(*args);
return;
}
std::vector<NotifyMotionArgs> processedArgs = it->second.processMotion(*args);
for (const NotifyMotionArgs& loopArgs : processedArgs) {
- mQueuedListener.notifyMotion(&loopArgs);
+ enqueueOutboundMotionLocked(loopArgs);
}
}
@@ -428,9 +441,10 @@
dump += "UnwantedInteractionBlocker:\n";
dump += " mPreferStylusOverTouchBlocker:\n";
dump += addLinePrefix(mPreferStylusOverTouchBlocker.dump(), " ");
- dump += StringPrintf(" mEnablePalmRejection: %s\n", toString(mEnablePalmRejection));
+ dump += StringPrintf(" mEnablePalmRejection: %s\n",
+ std::to_string(mEnablePalmRejection).c_str());
dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n",
- toString(isPalmRejectionEnabled()));
+ std::to_string(isPalmRejectionEnabled()).c_str());
dump += mPalmRejectors.empty() ? " mPalmRejectors: None\n" : " mPalmRejectors:\n";
for (const auto& [deviceId, palmRejector] : mPalmRejectors) {
dump += StringPrintf(" deviceId = %" PRId32 ":\n", deviceId);
@@ -512,6 +526,15 @@
return out;
}
+class AndroidPalmRejectionModel : public ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel {
+public:
+ AndroidPalmRejectionModel()
+ : ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel(/*default version*/ "",
+ std::vector<float>()) {
+ config_.resample_period = ::ui::kResamplePeriod;
+ }
+};
+
PalmRejector::PalmRejector(const AndroidPalmFilterDeviceInfo& info,
std::unique_ptr<::ui::PalmDetectionFilter> filter)
: mSharedPalmState(std::make_unique<::ui::SharedPalmDetectionFilterState>()),
@@ -523,11 +546,9 @@
return;
}
std::unique_ptr<::ui::NeuralStylusPalmDetectionFilterModel> model =
- std::make_unique<::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel>(
- std::vector<float>());
- mPalmDetectionFilter =
- std::make_unique<::ui::NeuralStylusPalmDetectionFilter>(mDeviceInfo, std::move(model),
- mSharedPalmState.get());
+ std::make_unique<AndroidPalmRejectionModel>();
+ mPalmDetectionFilter = std::make_unique<PalmFilterImplementation>(mDeviceInfo, std::move(model),
+ mSharedPalmState.get());
}
std::vector<::ui::InProgressTouchEvdev> getTouches(const NotifyMotionArgs& args,
@@ -541,7 +562,7 @@
touches.emplace_back(::ui::InProgressTouchEvdev());
touches.back().major = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
touches.back().minor = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR);
- touches.back().tool_type = getLinuxToolType(args.pointerProperties[i].toolType);
+ // The field 'tool_type' is not used for palm rejection
// Whether there is new information for the touch.
touches.back().altered = true;
@@ -588,15 +609,57 @@
// The fields 'radius_x' and 'radius_x' are not used for palm rejection
touches.back().pressure = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
- touches.back().tool_code = BTN_TOOL_FINGER;
+ touches.back().tool_code = getLinuxToolCode(args.pointerProperties[i].toolType);
// The field 'orientation' is not used for palm rejection
// The fields 'tilt_x' and 'tilt_y' are not used for palm rejection
- touches.back().reported_tool_type = ::ui::EventPointerType::kTouch;
+ // The field 'reported_tool_type' is not used for palm rejection
touches.back().stylus_button = false;
}
return touches;
}
+std::set<int32_t> PalmRejector::detectPalmPointers(const NotifyMotionArgs& args) {
+ std::bitset<::ui::kNumTouchEvdevSlots> slotsToHold;
+ std::bitset<::ui::kNumTouchEvdevSlots> slotsToSuppress;
+
+ // Store the slot state before we call getTouches and update it. This way, we can find
+ // the slots that have been removed due to the incoming event.
+ SlotState oldSlotState = mSlotState;
+ mSlotState.update(args);
+
+ std::vector<::ui::InProgressTouchEvdev> touches =
+ getTouches(args, mDeviceInfo, oldSlotState, mSlotState);
+ ::base::TimeTicks chromeTimestamp = toChromeTimestamp(args.eventTime);
+
+ if (DEBUG_MODEL) {
+ std::stringstream touchesStream;
+ for (const ::ui::InProgressTouchEvdev& touch : touches) {
+ touchesStream << touch.tracking_id << " : " << touch << "\n";
+ }
+ ALOGD("Filter: touches = %s", touchesStream.str().c_str());
+ }
+
+ mPalmDetectionFilter->Filter(touches, chromeTimestamp, &slotsToHold, &slotsToSuppress);
+
+ ALOGD_IF(DEBUG_MODEL, "Response: slotsToHold = %s, slotsToSuppress = %s",
+ slotsToHold.to_string().c_str(), slotsToSuppress.to_string().c_str());
+
+ // Now that we know which slots should be suppressed, let's convert those to pointer id's.
+ std::set<int32_t> newSuppressedIds;
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ const int32_t pointerId = args.pointerProperties[i].id;
+ std::optional<size_t> slot = oldSlotState.getSlotForPointerId(pointerId);
+ if (!slot) {
+ slot = mSlotState.getSlotForPointerId(pointerId);
+ LOG_ALWAYS_FATAL_IF(!slot, "Could not find slot for pointer id %" PRId32, pointerId);
+ }
+ if (slotsToSuppress.test(*slot)) {
+ newSuppressedIds.insert(pointerId);
+ }
+ }
+ return newSuppressedIds;
+}
+
std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs& args) {
if (mPalmDetectionFilter == nullptr) {
return {args};
@@ -614,32 +677,17 @@
if (args.action == AMOTION_EVENT_ACTION_DOWN) {
mSuppressedPointerIds.clear();
}
- std::bitset<::ui::kNumTouchEvdevSlots> slotsToHold;
- std::bitset<::ui::kNumTouchEvdevSlots> slotsToSuppress;
- // Store the slot state before we call getTouches and update it. This way, we can find
- // the slots that have been removed due to the incoming event.
- SlotState oldSlotState = mSlotState;
- mSlotState.update(args);
- std::vector<::ui::InProgressTouchEvdev> touches =
- getTouches(args, mDeviceInfo, oldSlotState, mSlotState);
- ::base::TimeTicks chromeTimestamp = toChromeTimestamp(args.eventTime);
-
- mPalmDetectionFilter->Filter(touches, chromeTimestamp, &slotsToHold, &slotsToSuppress);
-
- // Now that we know which slots should be suppressed, let's convert those to pointer id's.
std::set<int32_t> oldSuppressedIds;
std::swap(oldSuppressedIds, mSuppressedPointerIds);
- for (size_t i = 0; i < args.pointerCount; i++) {
- const int32_t pointerId = args.pointerProperties[i].id;
- std::optional<size_t> slot = oldSlotState.getSlotForPointerId(pointerId);
- if (!slot) {
- slot = mSlotState.getSlotForPointerId(pointerId);
- LOG_ALWAYS_FATAL_IF(!slot, "Could not find slot for pointer id %" PRId32, pointerId);
- }
- if (slotsToSuppress.test(*slot)) {
- mSuppressedPointerIds.insert(pointerId);
- }
+
+ std::optional<NotifyMotionArgs> touchOnlyArgs = removeStylusPointerIds(args);
+ if (touchOnlyArgs) {
+ mSuppressedPointerIds = detectPalmPointers(*touchOnlyArgs);
+ } else {
+ // This is a stylus-only event.
+ // We can skip this event and just keep the suppressed pointer ids the same as before.
+ mSuppressedPointerIds = oldSuppressedIds;
}
std::vector<NotifyMotionArgs> argsWithoutUnwantedPointers =
@@ -648,29 +696,40 @@
LOG_ALWAYS_FATAL_IF(checkArgs.action == ACTION_UNKNOWN, "%s", checkArgs.dump().c_str());
}
- if (mSuppressedPointerIds != oldSuppressedIds) {
- if (argsWithoutUnwantedPointers.size() != 1 ||
- argsWithoutUnwantedPointers[0].pointerCount != args.pointerCount) {
- ALOGI("Palm detected, removing pointer ids %s from %s",
- dumpSet(mSuppressedPointerIds).c_str(), args.dump().c_str());
- }
+ // Only log if new pointers are getting rejected. That means mSuppressedPointerIds is not a
+ // subset of oldSuppressedIds.
+ if (!std::includes(oldSuppressedIds.begin(), oldSuppressedIds.end(),
+ mSuppressedPointerIds.begin(), mSuppressedPointerIds.end())) {
+ ALOGI("Palm detected, removing pointer ids %s after %" PRId64 "ms from %s",
+ dumpSet(mSuppressedPointerIds).c_str(), ns2ms(args.eventTime - args.downTime),
+ args.dump().c_str());
}
return argsWithoutUnwantedPointers;
}
-const AndroidPalmFilterDeviceInfo& PalmRejector::getPalmFilterDeviceInfo() {
+const AndroidPalmFilterDeviceInfo& PalmRejector::getPalmFilterDeviceInfo() const {
return mDeviceInfo;
}
std::string PalmRejector::dump() const {
std::string out;
out += "mDeviceInfo:\n";
- out += addLinePrefix(dumpDeviceInfo(mDeviceInfo), " ");
+ std::stringstream deviceInfo;
+ deviceInfo << mDeviceInfo << ", touch_major_res=" << mDeviceInfo.touch_major_res
+ << ", touch_minor_res=" << mDeviceInfo.touch_minor_res << "\n";
+ out += addLinePrefix(deviceInfo.str(), " ");
out += "mSlotState:\n";
out += addLinePrefix(mSlotState.dump(), " ");
out += "mSuppressedPointerIds: ";
out += dumpSet(mSuppressedPointerIds) + "\n";
+ std::stringstream state;
+ state << *mSharedPalmState;
+ out += "mSharedPalmState: " + state.str() + "\n";
+ std::stringstream filter;
+ filter << static_cast<const PalmFilterImplementation&>(*mPalmDetectionFilter);
+ out += "mPalmDetectionFilter:\n";
+ out += addLinePrefix(filter.str(), " ") + "\n";
return out;
}
diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h
index a433764..5d0dde8 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.h
+++ b/services/inputflinger/UnwantedInteractionBlocker.h
@@ -43,6 +43,25 @@
static constexpr int32_t ACTION_UNKNOWN = -1;
+/**
+ * Remove the data for the provided pointers from the args. The pointers are identified by their
+ * pointerId, not by the index inside the array.
+ * Return the new NotifyMotionArgs struct that has the remaining pointers.
+ * The only fields that may be different in the returned args from the provided args are:
+ * - action
+ * - pointerCount
+ * - pointerProperties
+ * - pointerCoords
+ * Action might change because it contains a pointer index. If another pointer is removed, the
+ * active pointer index would be shifted.
+ *
+ * If the active pointer id is removed (for example, for events like
+ * POINTER_UP or POINTER_DOWN), then the action is set to ACTION_UNKNOWN. It is up to the caller
+ * to set the action appropriately after the call.
+ *
+ * @param args the args from which the pointers should be removed
+ * @param pointerIds the pointer ids of the pointers that should be removed
+ */
NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
const std::set<int32_t>& pointerIds);
@@ -101,6 +120,9 @@
std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors GUARDED_BY(mLock);
// TODO(b/210159205): delete this when simultaneous stylus and touch is supported
void notifyMotionLocked(const NotifyMotionArgs* args) REQUIRES(mLock);
+
+ // Call this function for outbound events so that they can be logged when logging is enabled.
+ void enqueueOutboundMotionLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
};
class SlotState {
@@ -144,13 +166,21 @@
std::vector<NotifyMotionArgs> processMotion(const NotifyMotionArgs& args);
// Get the device info of this device, for comparison purposes
- const AndroidPalmFilterDeviceInfo& getPalmFilterDeviceInfo();
+ const AndroidPalmFilterDeviceInfo& getPalmFilterDeviceInfo() const;
std::string dump() const;
private:
PalmRejector(const PalmRejector&) = delete;
PalmRejector& operator=(const PalmRejector&) = delete;
+ /**
+ * Update the slot state and send this event to the palm rejection model for palm detection.
+ * Return the pointer ids that should be suppressed.
+ *
+ * This function is not const because it has side-effects. It will update the slot state using
+ * the incoming args! Also, it will call Filter(..), which has side-effects.
+ */
+ std::set<int32_t> detectPalmPointers(const NotifyMotionArgs& args);
std::unique_ptr<::ui::SharedPalmDetectionFilterState> mSharedPalmState;
AndroidPalmFilterDeviceInfo mDeviceInfo;
std::unique_ptr<::ui::PalmDetectionFilter> mPalmDetectionFilter;
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
index 4f8995f..9a2aea6 100644
--- a/services/inputflinger/dispatcher/DebugConfig.h
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -75,11 +75,8 @@
/**
* Log debug messages about touch occlusion
- * Enable this via "adb shell setprop log.tag.InputDispatcherTouchOcclusion DEBUG" (requires
- * restart)
*/
-const bool DEBUG_TOUCH_OCCLUSION =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchOcclusion", ANDROID_LOG_INFO);
+constexpr bool DEBUG_TOUCH_OCCLUSION = true;
/**
* Log debug messages about the app switch latency optimization.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 564acc0..b0f5932 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2195,10 +2195,7 @@
// Update the temporary touch state.
BitSet32 pointerIds;
- if (isSplit) {
- uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
- pointerIds.markBit(pointerId);
- }
+ pointerIds.markBit(entry.pointerProperties[pointerIndex].id);
tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds);
}
@@ -2275,9 +2272,7 @@
}
BitSet32 pointerIds;
- if (isSplit) {
- pointerIds.markBit(entry.pointerProperties[0].id);
- }
+ pointerIds.markBit(entry.pointerProperties[0].id);
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
}
}
@@ -2453,21 +2448,28 @@
}
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
// One pointer went up.
- if (isSplit) {
- int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
+ int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+ uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
- for (size_t i = 0; i < tempTouchState.windows.size();) {
- TouchedWindow& touchedWindow = tempTouchState.windows[i];
- if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
- touchedWindow.pointerIds.clearBit(pointerId);
- if (touchedWindow.pointerIds.isEmpty()) {
- tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
- continue;
- }
- }
- i += 1;
+ for (size_t i = 0; i < tempTouchState.windows.size();) {
+ TouchedWindow& touchedWindow = tempTouchState.windows[i];
+ touchedWindow.pointerIds.clearBit(pointerId);
+ if (touchedWindow.pointerIds.isEmpty()) {
+ tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
+ continue;
}
+ i += 1;
+ }
+ } else if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+ // If no split, we suppose all touched windows should receive pointer down.
+ const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+ for (size_t i = 0; i < tempTouchState.windows.size(); i++) {
+ TouchedWindow& touchedWindow = tempTouchState.windows[i];
+ // Ignore drag window for it should just track one pointer.
+ if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
+ continue;
+ }
+ touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id);
}
}
@@ -4479,6 +4481,14 @@
if (it == mDisplayInfos.end()) return;
const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform;
+ if (entry.xCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION &&
+ entry.yCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION) {
+ const vec2 cursor =
+ MotionEvent::calculateTransformedXY(entry.source, transformToDisplay,
+ {entry.xCursorPosition, entry.yCursorPosition});
+ entry.xCursorPosition = cursor.x;
+ entry.yCursorPosition = cursor.y;
+ }
for (uint32_t i = 0; i < entry.pointerCount; i++) {
entry.pointerCoords[i] =
MotionEvent::calculateTransformedCoords(entry.source, transformToDisplay,
@@ -4721,10 +4731,13 @@
updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);
const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
- if (mLastHoverWindowHandle &&
- std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) ==
- windowHandles.end()) {
- mLastHoverWindowHandle = nullptr;
+ if (mLastHoverWindowHandle) {
+ const WindowInfo* lastHoverWindowInfo = mLastHoverWindowHandle->getInfo();
+ if (lastHoverWindowInfo->displayId == displayId &&
+ std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) ==
+ windowHandles.end()) {
+ mLastHoverWindowHandle = nullptr;
+ }
}
std::optional<FocusResolver::FocusChanges> changes =
@@ -5088,14 +5101,13 @@
// Store the dragging window.
if (isDragDrop) {
- if (pointerIds.count() > 1) {
- ALOGW("The drag and drop cannot be started when there is more than 1 pointer on the"
- " window.");
+ if (pointerIds.count() != 1) {
+ ALOGW("The drag and drop cannot be started when there is no pointer or more than 1"
+ " pointer on the window.");
return false;
}
- // If the window didn't not support split or the source is mouse, the pointerIds count
- // would be 0, so we have to track the pointer 0.
- const int32_t id = pointerIds.count() == 0 ? 0 : pointerIds.firstMarkedBit();
+ // Track the pointer id for drag window and generate the drag state.
+ const int32_t id = pointerIds.firstMarkedBit();
mDragState = std::make_unique<DragState>(toWindowHandle, id);
}
@@ -6331,6 +6343,13 @@
{ // acquire lock
std::scoped_lock _l(mLock);
+
+ // Ensure that we have an entry created for all existing displays so that if a displayId has
+ // no windows, we can tell that the windows were removed from the display.
+ for (const auto& [displayId, _] : mWindowHandlesByDisplay) {
+ handlesPerDisplay[displayId];
+ }
+
mDisplayInfos.clear();
for (const auto& displayInfo : displayInfos) {
mDisplayInfos.emplace(displayInfo.displayId, displayInfo);
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index d39113b..2df97d9 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -43,8 +43,8 @@
}
void InputTarget::addPointers(BitSet32 newPointerIds, const ui::Transform& transform) {
- // The pointerIds can be empty, but still a valid InputTarget. This can happen for Monitors
- // and non splittable windows since we will just use all the pointers from the input event.
+ // The pointerIds can be empty, but still a valid InputTarget. This can happen when there is no
+ // valid pointer property from the input event.
if (newPointerIds.isEmpty()) {
setDefaultPointerTransform(transform);
return;
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 4c31ec3..6783022 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -29,7 +29,7 @@
struct TouchedWindow {
sp<gui::WindowInfoHandle> windowHandle;
int32_t targetFlags;
- BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
+ BitSet32 pointerIds;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 0d73e07..3f26aaa 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -110,7 +110,8 @@
dump += "<none>\n";
}
dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic));
- dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
+ dump += StringPrintf(INDENT2 "Sources: %s\n",
+ inputEventSourceToString(deviceInfo.getSources()).c_str());
dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
dump += StringPrintf(INDENT2 "ControllerNum: %d\n", deviceInfo.getControllerNumber());
@@ -128,10 +129,10 @@
snprintf(name, sizeof(name), "%d", range.axis);
}
dump += StringPrintf(INDENT3
- "%s: source=0x%08x, "
+ "%s: source=%s, "
"min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
- name, range.source, range.min, range.max, range.flat, range.fuzz,
- range.resolution);
+ name, inputEventSourceToString(range.source).c_str(), range.min,
+ range.max, range.flat, range.fuzz, range.resolution);
}
}
@@ -231,6 +232,10 @@
}
void InputDevice::removeEventHubDevice(int32_t eventHubId) {
+ if (mController != nullptr && mController->getEventHubId() == eventHubId) {
+ // Delete mController, since the corresponding eventhub device is going away
+ mController = nullptr;
+ }
mDevices.erase(eventHubId);
}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index e9a82b4..905b348 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -216,9 +216,9 @@
"(ignored non-input device)",
device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str());
} else {
- ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=0x%08x",
+ ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=%s",
device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str(),
- device->getSources());
+ inputEventSourceToString(device->getSources()).c_str());
}
mDevices.emplace(eventHubId, device);
@@ -270,9 +270,10 @@
device->getId(), eventHubId, device->getName().c_str(),
device->getDescriptor().c_str());
} else {
- ALOGI("Device removed: id=%d, eventHubId=%d, name='%s', descriptor='%s', sources=0x%08x",
+ ALOGI("Device removed: id=%d, eventHubId=%d, name='%s', descriptor='%s', sources=%s",
device->getId(), eventHubId, device->getName().c_str(),
- device->getDescriptor().c_str(), device->getSources());
+ device->getDescriptor().c_str(),
+ inputEventSourceToString(device->getSources()).c_str());
}
device->removeEventHubDevice(eventHubId);
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 76a87bb..f4f3ae9 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -25,6 +25,8 @@
#include "PointerControllerInterface.h"
#include "TouchCursorInputMapperCommon.h"
+#include "input/PrintTools.h"
+
namespace android {
// The default velocity control parameters that has no effect.
@@ -80,7 +82,7 @@
void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
InputMapper::populateDeviceInfo(info);
- if (mParameters.mode == Parameters::MODE_POINTER) {
+ if (mParameters.mode == Parameters::Mode::POINTER) {
float minX, minY, maxX, maxY;
if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
@@ -117,6 +119,7 @@
toString(mCursorScrollAccumulator.haveRelativeHWheel()));
dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
+ dump += StringPrintf(INDENT3 "DisplayId: %s\n", toString(mDisplayId).c_str());
dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
@@ -135,12 +138,12 @@
// Configure device mode.
switch (mParameters.mode) {
- case Parameters::MODE_POINTER_RELATIVE:
+ case Parameters::Mode::POINTER_RELATIVE:
// Should not happen during first time configuration.
ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER");
- mParameters.mode = Parameters::MODE_POINTER;
+ mParameters.mode = Parameters::Mode::POINTER;
[[fallthrough]];
- case Parameters::MODE_POINTER:
+ case Parameters::Mode::POINTER:
mSource = AINPUT_SOURCE_MOUSE;
mXPrecision = 1.0f;
mYPrecision = 1.0f;
@@ -148,7 +151,7 @@
mYScale = 1.0f;
mPointerController = getContext()->getPointerController(getDeviceId());
break;
- case Parameters::MODE_NAVIGATION:
+ case Parameters::Mode::NAVIGATION:
mSource = AINPUT_SOURCE_TRACKBALL;
mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
@@ -161,12 +164,13 @@
mHWheelScale = 1.0f;
}
- const bool configurePointerCapture = (!changes && config->pointerCaptureRequest.enable) ||
- (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ const bool configurePointerCapture = mParameters.mode != Parameters::Mode::NAVIGATION &&
+ ((!changes && config->pointerCaptureRequest.enable) ||
+ (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE));
if (configurePointerCapture) {
if (config->pointerCaptureRequest.enable) {
- if (mParameters.mode == Parameters::MODE_POINTER) {
- mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
+ if (mParameters.mode == Parameters::Mode::POINTER) {
+ mParameters.mode = Parameters::Mode::POINTER_RELATIVE;
mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
// Keep PointerController around in order to preserve the pointer position.
mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
@@ -174,8 +178,8 @@
ALOGE("Cannot request pointer capture, device is not in MODE_POINTER");
}
} else {
- if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) {
- mParameters.mode = Parameters::MODE_POINTER;
+ if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) {
+ mParameters.mode = Parameters::Mode::POINTER;
mSource = AINPUT_SOURCE_MOUSE;
} else {
ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE");
@@ -190,8 +194,8 @@
if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED) ||
configurePointerCapture) {
- if (config->pointerCaptureRequest.enable) {
- // Disable any acceleration or scaling when Pointer Capture is enabled.
+ if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) {
+ // Disable any acceleration or scaling for the pointer when Pointer Capture is enabled.
mPointerVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
@@ -202,21 +206,36 @@
}
}
- if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+ if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) ||
+ configurePointerCapture) {
+ const bool isPointer = mParameters.mode == Parameters::Mode::POINTER;
+
+ mDisplayId = ADISPLAY_ID_NONE;
+ if (auto viewport = mDeviceContext.getAssociatedViewport(); viewport) {
+ // This InputDevice is associated with a viewport.
+ // Only generate events for the associated display.
+ const bool mismatchedPointerDisplay =
+ isPointer && (viewport->displayId != mPointerController->getDisplayId());
+ mDisplayId = mismatchedPointerDisplay ? std::nullopt
+ : std::make_optional(viewport->displayId);
+ } else if (isPointer) {
+ // The InputDevice is not associated with a viewport, but it controls the mouse pointer.
+ mDisplayId = mPointerController->getDisplayId();
+ }
+
mOrientation = DISPLAY_ORIENTATION_0;
const bool isOrientedDevice =
(mParameters.orientationAware && mParameters.hasAssociatedDisplay);
-
// InputReader works in the un-rotated display coordinate space, so we don't need to do
// anything if the device is already orientation-aware. If the device is not
// orientation-aware, then we need to apply the inverse rotation of the display so that
// when the display rotation is applied later as a part of the per-window transform, we
- // get the expected screen coordinates.
- if (!isOrientedDevice) {
- std::optional<DisplayViewport> internalViewport =
- config->getDisplayViewportByType(ViewportType::INTERNAL);
- if (internalViewport) {
- mOrientation = getInverseRotation(internalViewport->orientation);
+ // get the expected screen coordinates. When pointer capture is enabled, we do not apply any
+ // rotations and report values directly from the input device.
+ if (!isOrientedDevice && mDisplayId &&
+ mParameters.mode != Parameters::Mode::POINTER_RELATIVE) {
+ if (auto viewport = config->getDisplayViewportById(*mDisplayId); viewport) {
+ mOrientation = getInverseRotation(viewport->orientation);
}
}
@@ -225,12 +244,12 @@
}
void CursorInputMapper::configureParameters() {
- mParameters.mode = Parameters::MODE_POINTER;
+ mParameters.mode = Parameters::Mode::POINTER;
String8 cursorModeString;
if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"),
cursorModeString)) {
if (cursorModeString == "navigation") {
- mParameters.mode = Parameters::MODE_NAVIGATION;
+ mParameters.mode = Parameters::Mode::NAVIGATION;
} else if (cursorModeString != "pointer" && cursorModeString != "default") {
ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
}
@@ -241,7 +260,7 @@
mParameters.orientationAware);
mParameters.hasAssociatedDisplay = false;
- if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
+ if (mParameters.mode == Parameters::Mode::POINTER || mParameters.orientationAware) {
mParameters.hasAssociatedDisplay = true;
}
}
@@ -250,21 +269,7 @@
dump += INDENT3 "Parameters:\n";
dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
toString(mParameters.hasAssociatedDisplay));
-
- switch (mParameters.mode) {
- case Parameters::MODE_POINTER:
- dump += INDENT4 "Mode: pointer\n";
- break;
- case Parameters::MODE_POINTER_RELATIVE:
- dump += INDENT4 "Mode: relative pointer\n";
- break;
- case Parameters::MODE_NAVIGATION:
- dump += INDENT4 "Mode: navigation\n";
- break;
- default:
- ALOG_ASSERT(false);
- }
-
+ dump += StringPrintf(INDENT4 "Mode: %s\n", ftl::enum_string(mParameters.mode).c_str());
dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
}
@@ -294,6 +299,11 @@
}
void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+ if (!mDisplayId) {
+ // Ignore events when there is no target display configured.
+ return;
+ }
+
int32_t lastButtonState = mButtonState;
int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
mButtonState = currentButtonState;
@@ -339,7 +349,6 @@
mPointerVelocityControl.move(when, &deltaX, &deltaY);
- int32_t displayId = ADISPLAY_ID_NONE;
float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
if (mSource == AINPUT_SOURCE_MOUSE) {
@@ -363,7 +372,6 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
- displayId = mPointerController->getDisplayId();
} else {
// Pointer capture and navigation modes
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
@@ -385,7 +393,7 @@
// Synthesize key down from buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
- mSource, displayId, policyFlags, lastButtonState, currentButtonState);
+ mSource, *mDisplayId, policyFlags, lastButtonState, currentButtonState);
// Send motion event.
if (downChanged || moved || scrolled || buttonsChanged) {
@@ -406,7 +414,7 @@
int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
buttonState &= ~actionButton;
NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, readTime,
- getDeviceId(), mSource, displayId, policyFlags,
+ getDeviceId(), mSource, *mDisplayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
metaState, buttonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -418,7 +426,7 @@
}
NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, motionEventAction, 0, 0, metaState,
+ *mDisplayId, policyFlags, motionEventAction, 0, 0, metaState,
currentButtonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
@@ -431,7 +439,7 @@
int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
buttonState |= actionButton;
NotifyMotionArgs pressArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, displayId, policyFlags,
+ mSource, *mDisplayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
metaState, buttonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -447,7 +455,7 @@
// Send hover move after UP to tell the application that the mouse is hovering now.
if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, displayId, policyFlags,
+ mSource, *mDisplayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
currentButtonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -462,7 +470,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, displayId, policyFlags,
+ mSource, *mDisplayId, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
currentButtonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -474,7 +482,7 @@
// Synthesize key up from buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, lastButtonState, currentButtonState);
+ *mDisplayId, policyFlags, lastButtonState, currentButtonState);
mCursorMotionAccumulator.finishSync();
mCursorScrollAccumulator.finishSync();
@@ -489,16 +497,7 @@
}
std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
- if (mParameters.hasAssociatedDisplay) {
- if (mParameters.mode == Parameters::MODE_POINTER) {
- return std::make_optional(mPointerController->getDisplayId());
- } else {
- // If the device is orientationAware and not a mouse,
- // it expects to dispatch events to any display
- return std::make_optional(ADISPLAY_ID_NONE);
- }
- }
- return std::nullopt;
+ return mDisplayId;
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index c84c6c4..60b3dd9 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -74,10 +74,17 @@
// Immutable configuration parameters.
struct Parameters {
- enum Mode {
- MODE_POINTER,
- MODE_POINTER_RELATIVE,
- MODE_NAVIGATION,
+ enum class Mode {
+ // In POINTER mode, the device is a mouse that controls the mouse cursor on the screen,
+ // reporting absolute screen locations using SOURCE_MOUSE.
+ POINTER,
+ // A mouse device in POINTER mode switches to the POINTER_RELATIVE mode when Pointer
+ // Capture is enabled, and reports relative values only using SOURCE_MOUSE_RELATIVE.
+ POINTER_RELATIVE,
+ // A device in NAVIGATION mode emits relative values using SOURCE_TRACKBALL.
+ NAVIGATION,
+
+ ftl_last = NAVIGATION,
};
Mode mode;
@@ -104,6 +111,10 @@
VelocityControl mWheelXVelocityControl;
VelocityControl mWheelYVelocityControl;
+ // The display that events generated by this mapper should target. This can be set to
+ // ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e.
+ // std::nullopt), all events will be ignored.
+ std::optional<int32_t> mDisplayId;
int32_t mOrientation;
std::shared_ptr<PointerControllerInterface> mPointerController;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 00fc288..2ddacef 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -44,6 +44,8 @@
// --- Static Definitions ---
+static const DisplayViewport kUninitializedViewport;
+
template <typename T>
inline static void swap(T& a, T& b) {
T temp = a;
@@ -390,10 +392,10 @@
}
if (changes && resetNeeded) {
- // If device was reset, cancel touch event and update touch spot state.
- cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime);
- mCurrentCookedState.clear();
- updateTouchSpots();
+ // If the device needs to be reset, cancel any ongoing gestures and reset the state.
+ cancelTouch(when, when);
+ reset(when);
+
// Send reset, unless this is the first time the device has been configured,
// in which case the reader will call reset itself after all mappers are ready.
NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
@@ -881,7 +883,7 @@
}
void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) {
- DeviceMode oldDeviceMode = mDeviceMode;
+ const DeviceMode oldDeviceMode = mDeviceMode;
resolveExternalStylusPresence();
@@ -910,43 +912,37 @@
mDeviceMode = DeviceMode::UNSCALED;
}
- // Ensure we have valid X and Y axes.
+ const std::optional<DisplayViewport> newViewportOpt = findViewport();
+
+ // Ensure the device is valid and can be used.
if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
ALOGW("Touch device '%s' did not report support for X or Y axis! "
"The device will be inoperable.",
getDeviceName().c_str());
mDeviceMode = DeviceMode::DISABLED;
- return;
- }
-
- // Get associated display dimensions.
- std::optional<DisplayViewport> newViewport = findViewport();
- if (!newViewport) {
+ } else if (!newViewportOpt) {
ALOGI("Touch device '%s' could not query the properties of its associated "
"display. The device will be inoperable until the display size "
"becomes available.",
getDeviceName().c_str());
mDeviceMode = DeviceMode::DISABLED;
- return;
- }
-
- if (!newViewport->isActive) {
+ } else if (!newViewportOpt->isActive) {
ALOGI("Disabling %s (device %i) because the associated viewport is not active",
getDeviceName().c_str(), getDeviceId());
mDeviceMode = DeviceMode::DISABLED;
- return;
}
// Raw width and height in the natural orientation.
const int32_t rawWidth = mRawPointerAxes.getRawWidth();
const int32_t rawHeight = mRawPointerAxes.getRawHeight();
- const bool viewportChanged = mViewport != *newViewport;
+ const DisplayViewport& newViewport = newViewportOpt.value_or(kUninitializedViewport);
+ const bool viewportChanged = mViewport != newViewport;
bool skipViewportUpdate = false;
if (viewportChanged) {
- const bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation;
- const bool viewportDisplayIdChanged = mViewport.displayId != newViewport->displayId;
- mViewport = *newViewport;
+ const bool viewportOrientationChanged = mViewport.orientation != newViewport.orientation;
+ const bool viewportDisplayIdChanged = mViewport.displayId != newViewport.displayId;
+ mViewport = newViewport;
if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
// Convert rotated viewport to the natural orientation.
@@ -1105,10 +1101,6 @@
// of the diagonal axis of the touch pad. Touches that are wider than this are
// translated into freeform gestures.
mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal;
-
- // Abort current pointer usages because the state has changed.
- const nsecs_t readTime = when; // synthetic event
- abortPointerUsage(when, readTime, 0 /*policyFlags*/);
}
// Inform the dispatcher about the changes.
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 76a7c19..75cd9da 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -60,6 +60,7 @@
},
static_libs: [
"libc++fs",
+ "libgmock",
],
require_root: true,
test_suites: ["device-tests"],
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index df43071..4977c39 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2131,6 +2131,59 @@
ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
}
+TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> windowDefaultDisplay =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
+ ADISPLAY_ID_DEFAULT);
+ windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
+ sp<FakeWindowHandle> windowSecondDisplay =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
+ SECOND_DISPLAY_ID);
+ windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDefaultDisplay}},
+ {SECOND_DISPLAY_ID, {windowSecondDisplay}}});
+
+ // Set cursor position in window in default display and check that hover enter and move
+ // events are generated.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
+ AINPUT_SOURCE_MOUSE)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(300)
+ .y(600))
+ .build()));
+ windowDefaultDisplay->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_HOVER_ENTER,
+ ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
+ windowDefaultDisplay->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_HOVER_MOVE,
+ ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
+
+ // Remove all windows in secondary display and check that no event happens on window in
+ // primary display.
+ mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {}}});
+ windowDefaultDisplay->assertNoEvents();
+
+ // Move cursor position in window in default display and check that only hover move
+ // event is generated and not hover enter event.
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDefaultDisplay}},
+ {SECOND_DISPLAY_ID, {windowSecondDisplay}}});
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
+ AINPUT_SOURCE_MOUSE)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(400)
+ .y(700))
+ .build()));
+ windowDefaultDisplay->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_HOVER_MOVE,
+ ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
+ windowDefaultDisplay->assertNoEvents();
+}
+
TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
@@ -2293,6 +2346,35 @@
thirdWindow->consumeMotionDown();
}
+TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFocusable(true);
+
+ mDispatcher->onWindowInfosChanged({*window->getInfo()}, {});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyDown);
+ mDispatcher->notifyKey(&keyUp);
+
+ window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+
+ // All windows are removed from the display. Ensure that we can no longer dispatch to it.
+ mDispatcher->onWindowInfosChanged({}, {});
+
+ window->consumeFocusEvent(false);
+
+ mDispatcher->notifyKey(&keyDown);
+ mDispatcher->notifyKey(&keyUp);
+ window->assertNoEvents();
+}
+
/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
@@ -6096,6 +6178,8 @@
sp<FakeWindowHandle> mWindow;
sp<FakeWindowHandle> mSecondWindow;
sp<FakeWindowHandle> mDragWindow;
+ // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
+ static constexpr int32_t MOUSE_POINTER_ID = 1;
void SetUp() override {
InputDispatcherTest::SetUp();
@@ -6110,11 +6194,41 @@
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
}
- void injectDown() {
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {50, 50}))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
+ switch (fromSource) {
+ case AINPUT_SOURCE_TOUCHSCREEN:
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ break;
+ case AINPUT_SOURCE_STYLUS:
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(
+ mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_STYLUS)
+ .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS)
+ .x(50)
+ .y(50))
+ .build()));
+ break;
+ case AINPUT_SOURCE_MOUSE:
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(
+ mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(50)
+ .y(50))
+ .build()));
+ break;
+ default:
+ FAIL() << "Source " << fromSource << " doesn't support drag and drop";
+ }
// Window should receive motion event.
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
@@ -6123,9 +6237,9 @@
// Start performing drag, we will create a drag window and transfer touch to it.
// @param sendDown : if true, send a motion down on first window before perform drag and drop.
// Returns true on success.
- bool performDrag(bool sendDown = true) {
+ bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
if (sendDown) {
- injectDown();
+ injectDown(fromSource);
}
// The drag window covers the entire display
@@ -6143,36 +6257,10 @@
}
return transferred;
}
-
- // Start performing drag, we will create a drag window and transfer touch to it.
- void performStylusDrag() {
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher,
- MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
- AINPUT_SOURCE_STYLUS)
- .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
- .pointer(PointerBuilder(0,
- AMOTION_EVENT_TOOL_TYPE_STYLUS)
- .x(50)
- .y(50))
- .build()));
- mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
-
- // The drag window covers the entire display
- mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
- mDispatcher->setInputWindows(
- {{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
-
- // Transfer touch focus to the drag window
- mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
- true /* isDragDrop */);
- mWindow->consumeMotionCancel();
- mDragWindow->consumeMotionDown();
- }
};
TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
- performDrag();
+ startDrag();
// Move on window.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6210,7 +6298,7 @@
}
TEST_F(InputDispatcherDragTests, DragAndDrop) {
- performDrag();
+ startDrag();
// Move on window.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6242,7 +6330,7 @@
}
TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
- performStylusDrag();
+ startDrag(true, AINPUT_SOURCE_STYLUS);
// Move on window and keep button pressed.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6289,7 +6377,7 @@
}
TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
- performDrag();
+ startDrag();
// Set second window invisible.
mSecondWindow->setVisible(false);
@@ -6325,6 +6413,9 @@
}
TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
+ // Ensure window could track pointerIds if it didn't support split touch.
+ mWindow->setPreventSplitting(true);
+
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
{50, 50}))
@@ -6345,7 +6436,7 @@
mWindow->consumeMotionPointerDown(1 /* pointerIndex */);
// Should not perform drag and drop when window has multi fingers.
- ASSERT_FALSE(performDrag(false));
+ ASSERT_FALSE(startDrag(false));
}
TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
@@ -6373,7 +6464,7 @@
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
// Perform drag and drop from first window.
- ASSERT_TRUE(performDrag(false));
+ ASSERT_TRUE(startDrag(false));
// Move on window.
const MotionEvent secondFingerMoveEvent =
@@ -6408,7 +6499,7 @@
}
TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
- performDrag();
+ startDrag();
// Update window of second display.
sp<FakeWindowHandle> windowInSecondary =
@@ -6459,6 +6550,55 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
+ startDrag(true, AINPUT_SOURCE_MOUSE);
+ // Move on window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(50)
+ .y(50))
+ .build()))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(false, 50, 50);
+ mSecondWindow->assertNoEvents();
+
+ // Move to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(150)
+ .y(50))
+ .build()))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(true, 150, 50);
+ mSecondWindow->consumeDragEvent(false, 50, 50);
+
+ // drop to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
+ .buttonState(0)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(150)
+ .y(50))
+ .build()))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ mFakePolicy->assertDropTargetEquals(mSecondWindow->getToken());
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+}
+
class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index db46699..3afa52c 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -56,7 +56,9 @@
// Arbitrary display properties.
static constexpr int32_t DISPLAY_ID = 0;
+static const std::string DISPLAY_UNIQUE_ID = "local:1";
static constexpr int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1;
+static const std::string SECONDARY_DISPLAY_UNIQUE_ID = "local:2";
static constexpr int32_t DISPLAY_WIDTH = 480;
static constexpr int32_t DISPLAY_HEIGHT = 800;
static constexpr int32_t VIRTUAL_DISPLAY_ID = 1;
@@ -91,6 +93,24 @@
// Error tolerance for floating point assertions.
static const float EPSILON = 0.001f;
+using ::testing::AllOf;
+
+MATCHER_P(WithAction, action, "InputEvent with specified action") {
+ return arg.action == action;
+}
+
+MATCHER_P(WithSource, source, "InputEvent with specified source") {
+ return arg.source == source;
+}
+
+MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") {
+ return arg.displayId == displayId;
+}
+
+MATCHER_P2(WithCoords, x, y, "MotionEvent with specified action") {
+ return arg.pointerCoords[0].getX() == x && arg.pointerCoords[0].getY();
+}
+
template<typename T>
static inline T min(T a, T b) {
return a < b ? a : b;
@@ -2877,7 +2897,6 @@
// Device should be disabled because it is associated with a specific display, but the
// corresponding display is not found.
- const std::string DISPLAY_UNIQUE_ID = "displayUniqueId";
mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
InputReaderConfiguration::CHANGE_DISPLAY_INFO);
@@ -2908,7 +2927,6 @@
mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
- const std::string DISPLAY_UNIQUE_ID = "displayUniqueId";
mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
@@ -2918,6 +2936,21 @@
ASSERT_EQ(DISPLAY_UNIQUE_ID, mDevice->getAssociatedDisplayUniqueId());
}
+/**
+ * This test reproduces a crash caused by a dangling reference that remains after device is added
+ * and removed. The reference is accessed in InputDevice::dump(..);
+ */
+TEST_F(InputDeviceTest, DumpDoesNotCrash) {
+ constexpr int32_t TEST_EVENTHUB_ID = 10;
+ mFakeEventHub->addDevice(TEST_EVENTHUB_ID, "Test EventHub device", InputDeviceClass::BATTERY);
+
+ InputDevice device(mReader->getContext(), 1 /*id*/, 2 /*generation*/, {} /*identifier*/);
+ device.addEventHubDevice(TEST_EVENTHUB_ID, true /*populateMappers*/);
+ device.removeEventHubDevice(TEST_EVENTHUB_ID);
+ std::string dumpStr, eventHubDevStr;
+ device.dump(dumpStr, eventHubDevStr);
+}
+
// --- InputMapperTest ---
class InputMapperTest : public testing::Test {
@@ -2943,6 +2976,8 @@
mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
*mFakeListener);
mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
+ // Consume the device reset notification generated when adding a new device.
+ mFakeListener->assertNotifyDeviceResetWasCalled();
}
void SetUp() override {
@@ -2967,6 +3002,8 @@
mReader->loopOnce();
}
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
+ // Loop the reader to flush the input listener queue.
+ mReader->loopOnce();
}
std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
@@ -2990,6 +3027,8 @@
configureDevice(0);
mDevice->reset(ARBITRARY_TIME);
mapper.reset(ARBITRARY_TIME);
+ // Loop the reader to flush the input listener queue.
+ mReader->loopOnce();
return mapper;
}
@@ -3015,6 +3054,7 @@
event.code = code;
event.value = value;
mapper.process(&event);
+ // Loop the reader to flush the input listener queue.
mReader->loopOnce();
}
@@ -4186,10 +4226,14 @@
int32_t rotatedX, int32_t rotatedY);
void prepareDisplay(int32_t orientation) {
- const std::string uniqueId = "local:0";
- const ViewportType viewportType = ViewportType::INTERNAL;
- setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- orientation, uniqueId, NO_PORT, viewportType);
+ setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation,
+ DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
+ }
+
+ void prepareSecondaryDisplay() {
+ setDisplayInfoAndReconfigure(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, SECONDARY_DISPLAY_UNIQUE_ID, NO_PORT,
+ ViewportType::EXTERNAL);
}
static void assertCursorPointerCoords(const PointerCoords& coords, float x, float y,
@@ -4466,6 +4510,7 @@
}
TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotions) {
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
addConfigurationProperty("cursor.mode", "navigation");
// InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
// need to be rotated.
@@ -4484,11 +4529,13 @@
}
TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotions) {
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
addConfigurationProperty("cursor.mode", "navigation");
// Since InputReader works in the un-rotated coordinate space, only devices that are not
// orientation-aware are affected by display rotation.
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_0);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1));
@@ -4499,6 +4546,7 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1));
@@ -4509,6 +4557,7 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1));
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_180);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1));
@@ -4519,6 +4568,7 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1));
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_270);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1));
@@ -4912,7 +4962,6 @@
ASSERT_TRUE(mReader->getContext()->getGeneration() != generation);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
- ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
@@ -4974,33 +5023,118 @@
ASSERT_EQ(20, args.pointerCoords[0].getY());
}
-TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
+TEST_F(CursorInputMapperTest, PointerCaptureDisablesOrientationChanges) {
+ addConfigurationProperty("cursor.mode", "pointer");
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
- // Setup for second display.
- constexpr int32_t SECOND_DISPLAY_ID = 1;
- const std::string SECOND_DISPLAY_UNIQUE_ID = "local:1";
- mFakePolicy->addDisplayViewport(SECOND_DISPLAY_ID, 800, 480, DISPLAY_ORIENTATION_0,
- true /*isActive*/, SECOND_DISPLAY_UNIQUE_ID, NO_PORT,
- ViewportType::EXTERNAL);
- mFakePolicy->setDefaultPointerDisplayId(SECOND_DISPLAY_ID);
- configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ NotifyDeviceResetArgs resetArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+ ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
- mFakePointerController->setPosition(100, 200);
- mFakePointerController->setButtonState(0);
+ // Ensure the display is rotated.
+ prepareDisplay(DISPLAY_ORIENTATION_90);
NotifyMotionArgs args;
+
+ // Verify that the coordinates are rotated.
process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
- ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
- 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_EQ(-20, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X));
+ ASSERT_EQ(10, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
+
+ // Enable Pointer Capture.
+ mFakePolicy->setPointerCapture(true);
+ configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ NotifyPointerCaptureChangedArgs captureArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyCaptureWasCalled(&captureArgs));
+ ASSERT_TRUE(captureArgs.request.enable);
+
+ // Move and verify rotation is not applied.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ ASSERT_EQ(10, args.pointerCoords[0].getX());
+ ASSERT_EQ(20, args.pointerCoords[0].getY());
+}
+
+TEST_F(CursorInputMapperTest, ConfigureDisplayId_NoAssociatedViewport) {
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ // Set up the default display.
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+
+ // Set up the secondary display as the display on which the pointer should be shown.
+ // The InputDevice is not associated with any display.
+ prepareSecondaryDisplay();
+ mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+ mFakePointerController->setPosition(100, 200);
+ mFakePointerController->setButtonState(0);
+
+ // Ensure input events are generated for the secondary display.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
+ WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f))));
ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
- ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
+}
+
+TEST_F(CursorInputMapperTest, ConfigureDisplayId_WithAssociatedViewport) {
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ // Set up the default display.
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+
+ // Set up the secondary display as the display on which the pointer should be shown,
+ // and associate the InputDevice with the secondary display.
+ prepareSecondaryDisplay();
+ mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+ mFakePointerController->setPosition(100, 200);
+ mFakePointerController->setButtonState(0);
+
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
+ WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f))));
+ ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
+}
+
+TEST_F(CursorInputMapperTest, ConfigureDisplayId_IgnoresEventsForMismatchedPointerDisplay) {
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ // Set up the default display as the display on which the pointer should be shown.
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+ mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID);
+
+ // Associate the InputDevice with the secondary display.
+ prepareSecondaryDisplay();
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ // The mapper should not generate any events because it is associated with a display that is
+ // different from the pointer display.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
}
// --- TouchInputMapperTest ---
@@ -6683,6 +6817,61 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
}
+TEST_F(SingleTouchInputMapperTest,
+ Process_WhenViewportActiveStatusChanged_TouchIsCanceledAndDeviceIsReset) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
+ prepareAxes(POSITION);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+ NotifyMotionArgs motionArgs;
+
+ // Start a new gesture.
+ processDown(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+ // Make the viewport inactive. This will put the device in disabled mode.
+ auto viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
+ viewport->isActive = false;
+ mFakePolicy->updateViewport(*viewport);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ // We should receive a cancel event for the ongoing gesture.
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+ // Then we should be notified that the device was reset.
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+
+ // No events are generated while the viewport is inactive.
+ processMove(mapper, 101, 201);
+ processSync(mapper);
+ processDown(mapper, 102, 202);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // Make the viewport active again. The device should resume processing events.
+ viewport->isActive = true;
+ mFakePolicy->updateViewport(*viewport);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ // The device is reset because it changes back to direct mode, without generating any events.
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // Start a new gesture.
+ processDown(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+ // No more events.
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasNotCalled());
+}
+
// --- TouchDisplayProjectionTest ---
class TouchDisplayProjectionTest : public SingleTouchInputMapperTest {
@@ -8540,27 +8729,27 @@
ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
- // Finger move
+ // The ongoing touch should be canceled immediately
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+
+ // Finger move is ignored
x += 10, y += 10;
processPosition(mapper, x, y);
processSync(mapper);
-
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
// Reactivate display viewport
displayViewport.isActive = true;
ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
- // Finger move again
+ // Finger move again starts new gesture
x += 10, y += 10;
processPosition(mapper, x, y);
processSync(mapper);
-
- // Gesture is aborted, so events after display is activated won't be dispatched until there is
- // no pointer on the touch device.
- mFakeListener->assertNotifyMotionWasNotCalled();
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
}
TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) {
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 6a26c63..57b382c 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -69,6 +69,13 @@
"Expected notifyMotion() to have been called."));
}
+void TestInputListener::assertNotifyMotionWasCalled(
+ const ::testing::Matcher<NotifyMotionArgs>& matcher) {
+ NotifyMotionArgs outEventArgs;
+ ASSERT_NO_FATAL_FAILURE(assertNotifyMotionWasCalled(&outEventArgs));
+ ASSERT_THAT(outEventArgs, matcher);
+}
+
void TestInputListener::assertNotifyMotionWasNotCalled() {
ASSERT_NO_FATAL_FAILURE(
assertNotCalled<NotifyMotionArgs>("notifyMotion() should not be called."));
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index 626cdfc..0bdfc6b 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -18,6 +18,7 @@
#define _UI_TEST_INPUT_LISTENER_H
#include <android-base/thread_annotations.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "InputListener.h"
@@ -48,6 +49,8 @@
void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = nullptr);
+ void assertNotifyMotionWasCalled(const ::testing::Matcher<NotifyMotionArgs>& matcher);
+
void assertNotifyMotionWasNotCalled();
void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr);
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index 0062f42..29fa001 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -16,13 +16,17 @@
#include "../UnwantedInteractionBlocker.h"
#include <android-base/silent_death_test.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <gui/constants.h>
#include <linux/input.h>
#include <thread>
+#include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter.h"
#include "TestInputListener.h"
+using ::testing::AllOf;
+
namespace android {
constexpr int32_t DEVICE_ID = 3;
@@ -30,6 +34,8 @@
constexpr int32_t Y_RESOLUTION = 11;
constexpr int32_t MAJOR_RESOLUTION = 1;
+const nsecs_t RESAMPLE_PERIOD = ::ui::kResamplePeriod.InNanoseconds();
+
constexpr int POINTER_0_DOWN =
AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
constexpr int POINTER_1_DOWN =
@@ -47,6 +53,27 @@
constexpr int UP = AMOTION_EVENT_ACTION_UP;
constexpr int CANCEL = AMOTION_EVENT_ACTION_CANCEL;
+constexpr int32_t FLAG_CANCELED = AMOTION_EVENT_FLAG_CANCELED;
+
+MATCHER_P(WithAction, action, "MotionEvent with specified action") {
+ bool result = true;
+ if (action == CANCEL) {
+ result &= (arg.flags & FLAG_CANCELED) != 0;
+ }
+ result &= arg.action == action;
+ *result_listener << "expected to receive " << MotionEvent::actionToString(action)
+ << " but received " << MotionEvent::actionToString(arg.action) << " instead.";
+ return result;
+}
+
+MATCHER_P(WithFlags, flags, "MotionEvent with specified flags") {
+ return arg.flags == flags;
+}
+
+static nsecs_t toNs(std::chrono::nanoseconds duration) {
+ return duration.count();
+}
+
struct PointerData {
float x;
float y;
@@ -252,7 +279,7 @@
/*newSuppressedPointerIds*/ {1});
ASSERT_EQ(2u, result.size());
assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}});
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, result[0].flags);
assertArgs(result[1], MOVE, {{0, {1, 2, 3}}, {2, {7, 8, 9}}});
}
@@ -267,7 +294,7 @@
/*newSuppressedPointerIds*/ {0});
ASSERT_EQ(1u, result.size());
assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}});
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, result[0].flags);
}
/**
@@ -282,7 +309,7 @@
/*newSuppressedPointerIds*/ {1});
ASSERT_EQ(1u, result.size());
assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}});
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, result[0].flags);
}
/**
@@ -297,7 +324,7 @@
/*newSuppressedPointerIds*/ {0});
ASSERT_EQ(1u, result.size());
assertArgs(result[0], POINTER_0_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}});
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, result[0].flags);
}
/**
@@ -312,7 +339,7 @@
/*newSuppressedPointerIds*/ {0, 1});
ASSERT_EQ(1u, result.size());
assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}, {1, {4, 5, 6}}});
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, result[0].flags);
}
/**
@@ -328,7 +355,7 @@
/*newSuppressedPointerIds*/ {0, 1});
ASSERT_EQ(1u, result.size());
assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}});
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, result[0].flags);
}
/**
@@ -384,7 +411,7 @@
expected.reported_tool_type = ::ui::EventPointerType::kTouch;
expected.stylus_button = false;
- ASSERT_EQ(expected, touches[0]) << toString(touches[0]);
+ ASSERT_EQ(expected, touches[0]) << touches[0];
}
// --- UnwantedInteractionBlockerTest ---
@@ -569,6 +596,114 @@
dumpThread.join();
}
+/**
+ * Heuristic filter that's present in the palm rejection model blocks touches early if the size
+ * of the touch is large. This is an integration test that checks that this filter kicks in.
+ */
+TEST_F(UnwantedInteractionBlockerTest, HeuristicFilterWorks) {
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+ // Small touch down
+ NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+ mBlocker->notifyMotion(&args1);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));
+
+ // Large touch oval on the next move
+ NotifyMotionArgs args2 =
+ generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}});
+ mBlocker->notifyMotion(&args2);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+
+ // Lift up the touch to force the model to decide on whether it's a palm
+ NotifyMotionArgs args3 =
+ generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
+ mBlocker->notifyMotion(&args3);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(CANCEL));
+}
+
+/**
+ * Send a stylus event that would have triggered the heuristic palm detector if it were a touch
+ * event. However, since it's a stylus event, it should propagate without being canceled through
+ * the blocker.
+ * This is similar to `HeuristicFilterWorks` test, but for stylus tool.
+ */
+TEST_F(UnwantedInteractionBlockerTest, StylusIsNotBlocked) {
+ InputDeviceInfo info = generateTestDeviceInfo();
+ info.addSource(AINPUT_SOURCE_STYLUS);
+ mBlocker->notifyInputDevicesChanged({info});
+ NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+ args1.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mBlocker->notifyMotion(&args1);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));
+
+ // Move the stylus, setting large TOUCH_MAJOR/TOUCH_MINOR dimensions
+ NotifyMotionArgs args2 =
+ generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}});
+ args2.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mBlocker->notifyMotion(&args2);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+
+ // Lift up the stylus. If it were a touch event, this would force the model to decide on whether
+ // it's a palm.
+ NotifyMotionArgs args3 =
+ generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
+ args3.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mBlocker->notifyMotion(&args3);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(UP));
+}
+
+/**
+ * Send a mixed touch and stylus event.
+ * The touch event goes first, and is a palm. The stylus event goes down after.
+ * Stylus event should continue to work even after touch is detected as a palm.
+ */
+TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) {
+ InputDeviceInfo info = generateTestDeviceInfo();
+ info.addSource(AINPUT_SOURCE_STYLUS);
+ mBlocker->notifyInputDevicesChanged({info});
+
+ // Touch down
+ NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+ mBlocker->notifyMotion(&args1);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));
+
+ // Stylus pointer down
+ NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, POINTER_1_DOWN,
+ {{1, 2, 3}, {10, 20, 30}});
+ args2.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mBlocker->notifyMotion(&args2);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(POINTER_1_DOWN));
+
+ // Large touch oval on the next finger move
+ NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, MOVE,
+ {{1, 2, 300}, {11, 21, 30}});
+ args3.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mBlocker->notifyMotion(&args3);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+
+ // Lift up the finger pointer. It should be canceled due to the heuristic filter.
+ NotifyMotionArgs args4 = generateMotionArgs(0 /*downTime*/, 3 * RESAMPLE_PERIOD, POINTER_0_UP,
+ {{1, 2, 300}, {11, 21, 30}});
+ args4.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mBlocker->notifyMotion(&args4);
+ mTestListener.assertNotifyMotionWasCalled(
+ AllOf(WithAction(POINTER_0_UP), WithFlags(FLAG_CANCELED)));
+
+ NotifyMotionArgs args5 =
+ generateMotionArgs(0 /*downTime*/, 4 * RESAMPLE_PERIOD, MOVE, {{12, 22, 30}});
+ args5.pointerProperties[0].id = args4.pointerProperties[1].id;
+ args5.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mBlocker->notifyMotion(&args5);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+
+ // Lift up the stylus pointer
+ NotifyMotionArgs args6 =
+ generateMotionArgs(0 /*downTime*/, 5 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
+ args6.pointerProperties[0].id = args4.pointerProperties[1].id;
+ args6.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mBlocker->notifyMotion(&args6);
+ mTestListener.assertNotifyMotionWasCalled(WithAction(UP));
+}
+
using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;
/**
@@ -630,138 +765,138 @@
*/
TEST_F(PalmRejectorTest, TwoPointersAreCanceled) {
std::vector<NotifyMotionArgs> argsList;
- constexpr nsecs_t downTime = 255955749837000;
+ const nsecs_t downTime = toNs(0ms);
mPalmRejector->processMotion(
generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955759313000, MOVE, {{1406.0, 650.0, 52.0}}));
+ generateMotionArgs(downTime, toNs(8ms), MOVE, {{1406.0, 650.0, 52.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955766361000, MOVE, {{1429.0, 672.0, 46.0}}));
+ generateMotionArgs(downTime, toNs(16ms), MOVE, {{1429.0, 672.0, 46.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955775989000, MOVE, {{1417.0, 685.0, 41.0}}));
+ generateMotionArgs(downTime, toNs(24ms), MOVE, {{1417.0, 685.0, 41.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955775989000, POINTER_1_DOWN,
+ generateMotionArgs(downTime, toNs(32ms), POINTER_1_DOWN,
{{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955783039000, MOVE,
+ generateMotionArgs(downTime, toNs(40ms), MOVE,
{{1414.0, 702.0, 41.0}, {1059.0, 731.0, 12.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955792536000, MOVE,
+ generateMotionArgs(downTime, toNs(48ms), MOVE,
{{1415.0, 719.0, 44.0}, {1060.0, 760.0, 11.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955799474000, MOVE,
+ generateMotionArgs(downTime, toNs(56ms), MOVE,
{{1421.0, 733.0, 42.0}, {1065.0, 769.0, 13.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955809177000, MOVE,
+ generateMotionArgs(downTime, toNs(64ms), MOVE,
{{1426.0, 742.0, 43.0}, {1068.0, 771.0, 13.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955816131000, MOVE,
+ generateMotionArgs(downTime, toNs(72ms), MOVE,
{{1430.0, 748.0, 45.0}, {1069.0, 772.0, 13.0}}));
argsList = mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955825907000, MOVE,
+ generateMotionArgs(downTime, toNs(80ms), MOVE,
{{1432.0, 750.0, 44.0}, {1069.0, 772.0, 13.0}}));
ASSERT_EQ(1u, argsList.size());
ASSERT_EQ(0 /* No FLAG_CANCELED */, argsList[0].flags);
argsList = mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955832736000, MOVE,
+ generateMotionArgs(downTime, toNs(88ms), MOVE,
{{1433.0, 751.0, 44.0}, {1070.0, 771.0, 13.0}}));
ASSERT_EQ(2u, argsList.size());
ASSERT_EQ(POINTER_0_UP, argsList[0].action);
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
ASSERT_EQ(MOVE, argsList[1].action);
ASSERT_EQ(1u, argsList[1].pointerCount);
ASSERT_EQ(0, argsList[1].flags);
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955842432000, MOVE,
+ generateMotionArgs(downTime, toNs(96ms), MOVE,
{{1433.0, 751.0, 42.0}, {1071.0, 770.0, 13.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955849380000, MOVE,
+ generateMotionArgs(downTime, toNs(104ms), MOVE,
{{1433.0, 751.0, 45.0}, {1072.0, 769.0, 13.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955859046000, MOVE,
+ generateMotionArgs(downTime, toNs(112ms), MOVE,
{{1433.0, 751.0, 43.0}, {1072.0, 768.0, 13.0}}));
argsList = mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955869823000, MOVE,
+ generateMotionArgs(downTime, toNs(120ms), MOVE,
{{1433.0, 751.0, 45.0}, {1072.0, 767.0, 13.0}}));
ASSERT_EQ(1u, argsList.size());
ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, argsList[0].action);
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955875641000, MOVE,
+ generateMotionArgs(downTime, toNs(128ms), MOVE,
{{1433.0, 751.0, 43.0}, {1072.0, 766.0, 13.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955882693000, MOVE,
+ generateMotionArgs(downTime, toNs(136ms), MOVE,
{{1433.0, 750.0, 44.0}, {1072.0, 765.0, 13.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955892324000, MOVE,
+ generateMotionArgs(downTime, toNs(144ms), MOVE,
{{1433.0, 750.0, 42.0}, {1072.0, 763.0, 14.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955899425000, MOVE,
+ generateMotionArgs(downTime, toNs(152ms), MOVE,
{{1434.0, 750.0, 44.0}, {1073.0, 761.0, 14.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955909400000, MOVE,
+ generateMotionArgs(downTime, toNs(160ms), MOVE,
{{1435.0, 750.0, 43.0}, {1073.0, 759.0, 15.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955915885000, MOVE,
+ generateMotionArgs(downTime, toNs(168ms), MOVE,
{{1436.0, 750.0, 45.0}, {1074.0, 757.0, 15.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955925607000, MOVE,
+ generateMotionArgs(downTime, toNs(176ms), MOVE,
{{1436.0, 750.0, 44.0}, {1074.0, 755.0, 15.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955932580000, MOVE,
+ generateMotionArgs(downTime, toNs(184ms), MOVE,
{{1436.0, 750.0, 45.0}, {1074.0, 753.0, 15.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955942231000, MOVE,
+ generateMotionArgs(downTime, toNs(192ms), MOVE,
{{1436.0, 749.0, 44.0}, {1074.0, 751.0, 15.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955949204000, MOVE,
+ generateMotionArgs(downTime, toNs(200ms), MOVE,
{{1435.0, 748.0, 45.0}, {1074.0, 749.0, 15.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955959103000, MOVE,
+ generateMotionArgs(downTime, toNs(208ms), MOVE,
{{1434.0, 746.0, 44.0}, {1074.0, 747.0, 14.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955965884000, MOVE,
+ generateMotionArgs(downTime, toNs(216ms), MOVE,
{{1433.0, 744.0, 44.0}, {1075.0, 745.0, 14.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955975649000, MOVE,
+ generateMotionArgs(downTime, toNs(224ms), MOVE,
{{1431.0, 741.0, 43.0}, {1075.0, 742.0, 13.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955982537000, MOVE,
+ generateMotionArgs(downTime, toNs(232ms), MOVE,
{{1428.0, 738.0, 43.0}, {1076.0, 739.0, 12.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955992284000, MOVE,
+ generateMotionArgs(downTime, toNs(240ms), MOVE,
{{1400.0, 726.0, 54.0}, {1076.0, 739.0, 13.0}}));
argsList = mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955999348000, POINTER_1_UP,
+ generateMotionArgs(downTime, toNs(248ms), POINTER_1_UP,
{{1362.0, 716.0, 55.0}, {1076.0, 739.0, 13.0}}));
ASSERT_TRUE(argsList.empty());
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255955999348000, MOVE, {{1362.0, 716.0, 55.0}}));
+ generateMotionArgs(downTime, toNs(256ms), MOVE, {{1362.0, 716.0, 55.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956008885000, MOVE, {{1347.0, 707.0, 54.0}}));
+ generateMotionArgs(downTime, toNs(264ms), MOVE, {{1347.0, 707.0, 54.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956015791000, MOVE, {{1340.0, 698.0, 54.0}}));
+ generateMotionArgs(downTime, toNs(272ms), MOVE, {{1340.0, 698.0, 54.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956025804000, MOVE, {{1338.0, 694.0, 55.0}}));
+ generateMotionArgs(downTime, toNs(280ms), MOVE, {{1338.0, 694.0, 55.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956032314000, MOVE, {{1336.0, 690.0, 53.0}}));
+ generateMotionArgs(downTime, toNs(288ms), MOVE, {{1336.0, 690.0, 53.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956042329000, MOVE, {{1334.0, 685.0, 47.0}}));
+ generateMotionArgs(downTime, toNs(296ms), MOVE, {{1334.0, 685.0, 47.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956048979000, MOVE, {{1333.0, 679.0, 46.0}}));
+ generateMotionArgs(downTime, toNs(304ms), MOVE, {{1333.0, 679.0, 46.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956058813000, MOVE, {{1332.0, 672.0, 45.0}}));
+ generateMotionArgs(downTime, toNs(312ms), MOVE, {{1332.0, 672.0, 45.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956065592000, MOVE, {{1333.0, 666.0, 40.0}}));
+ generateMotionArgs(downTime, toNs(320ms), MOVE, {{1333.0, 666.0, 40.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956075276000, MOVE, {{1336.0, 661.0, 24.0}}));
+ generateMotionArgs(downTime, toNs(328ms), MOVE, {{1336.0, 661.0, 24.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956082198000, MOVE, {{1338.0, 656.0, 16.0}}));
+ generateMotionArgs(downTime, toNs(336ms), MOVE, {{1338.0, 656.0, 16.0}}));
mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956092059000, MOVE, {{1341.0, 649.0, 1.0}}));
+ generateMotionArgs(downTime, toNs(344ms), MOVE, {{1341.0, 649.0, 1.0}}));
argsList = mPalmRejector->processMotion(
- generateMotionArgs(downTime, 255956098764000, UP, {{1341.0, 649.0, 1.0}}));
+ generateMotionArgs(downTime, toNs(352ms), UP, {{1341.0, 649.0, 1.0}}));
ASSERT_TRUE(argsList.empty());
}
@@ -845,7 +980,7 @@
ASSERT_EQ(2u, argsList.size());
// First event - cancel pointer 1
ASSERT_EQ(POINTER_1_UP, argsList[0].action);
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
// Second event - send MOVE for the remaining pointer
ASSERT_EQ(MOVE, argsList[1].action);
ASSERT_EQ(0, argsList[1].flags);
@@ -886,7 +1021,7 @@
// Cancel all
ASSERT_EQ(CANCEL, argsList[0].action);
ASSERT_EQ(2u, argsList[0].pointerCount);
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
// Future move events are ignored
argsList = mPalmRejector->processMotion(
@@ -932,7 +1067,7 @@
{{1414.0, 702.0, 41.0}, {1059.0, 731.0, 12.0}}));
ASSERT_EQ(1u, argsList.size());
ASSERT_EQ(CANCEL, argsList[0].action) << MotionEvent::actionToString(argsList[0].action);
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
// Future move events should not go to the listener.
argsList = mPalmRejector->processMotion(
@@ -966,7 +1101,7 @@
{{1417.0, 685.0, 41.0}, {1060, 700, 10.0}}));
ASSERT_EQ(2u, argsList.size());
ASSERT_EQ(POINTER_1_UP, argsList[0].action);
- ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+ ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
ASSERT_EQ(MOVE, argsList[1].action) << MotionEvent::actionToString(argsList[1].action);
ASSERT_EQ(0, argsList[1].flags);
diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp
index 4d1de96..f5b360f 100644
--- a/services/sensorservice/AidlSensorHalWrapper.cpp
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -23,6 +23,7 @@
#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
+#include <aidl/sensors/convert.h>
using ::aidl::android::hardware::sensors::AdditionalInfo;
using ::aidl::android::hardware::sensors::DynamicSensorInfo;
@@ -34,469 +35,16 @@
using ::android::AidlMessageQueue;
using ::android::hardware::EventFlag;
using ::android::hardware::sensors::V2_1::implementation::MAX_RECEIVE_BUFFER_EVENT_COUNT;
+using ::android::hardware::sensors::implementation::convertToStatus;
+using ::android::hardware::sensors::implementation::convertToSensor;
+using ::android::hardware::sensors::implementation::convertToSensorEvent;
+using ::android::hardware::sensors::implementation::convertFromSensorEvent;
+
namespace android {
namespace {
-status_t convertToStatus(ndk::ScopedAStatus status) {
- if (status.isOk()) {
- return OK;
- } else {
- switch (status.getExceptionCode()) {
- case EX_ILLEGAL_ARGUMENT: {
- return BAD_VALUE;
- }
- case EX_SECURITY: {
- return PERMISSION_DENIED;
- }
- case EX_UNSUPPORTED_OPERATION: {
- return INVALID_OPERATION;
- }
- case EX_SERVICE_SPECIFIC: {
- switch (status.getServiceSpecificError()) {
- case ISensors::ERROR_BAD_VALUE: {
- return BAD_VALUE;
- }
- case ISensors::ERROR_NO_MEMORY: {
- return NO_MEMORY;
- }
- default: {
- return UNKNOWN_ERROR;
- }
- }
- }
- default: {
- return UNKNOWN_ERROR;
- }
- }
- }
-}
-
-void convertToSensor(const SensorInfo &src, sensor_t *dst) {
- dst->name = strdup(src.name.c_str());
- dst->vendor = strdup(src.vendor.c_str());
- dst->version = src.version;
- dst->handle = src.sensorHandle;
- dst->type = (int)src.type;
- dst->maxRange = src.maxRange;
- dst->resolution = src.resolution;
- dst->power = src.power;
- dst->minDelay = src.minDelayUs;
- dst->fifoReservedEventCount = src.fifoReservedEventCount;
- dst->fifoMaxEventCount = src.fifoMaxEventCount;
- dst->stringType = strdup(src.typeAsString.c_str());
- dst->requiredPermission = strdup(src.requiredPermission.c_str());
- dst->maxDelay = src.maxDelayUs;
- dst->flags = src.flags;
- dst->reserved[0] = dst->reserved[1] = 0;
-}
-
-void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
- *dst = {.version = sizeof(sensors_event_t),
- .sensor = src.sensorHandle,
- .type = (int32_t)src.sensorType,
- .reserved0 = 0,
- .timestamp = src.timestamp};
-
- switch (src.sensorType) {
- case SensorType::META_DATA: {
- // Legacy HALs expect the handle reference in the meta data field.
- // Copy it over from the handle of the event.
- dst->meta_data.what = (int32_t)src.payload.get<Event::EventPayload::meta>().what;
- dst->meta_data.sensor = src.sensorHandle;
- // Set the sensor handle to 0 to maintain compatibility.
- dst->sensor = 0;
- break;
- }
-
- case SensorType::ACCELEROMETER:
- case SensorType::MAGNETIC_FIELD:
- case SensorType::ORIENTATION:
- case SensorType::GYROSCOPE:
- case SensorType::GRAVITY:
- case SensorType::LINEAR_ACCELERATION: {
- dst->acceleration.x = src.payload.get<Event::EventPayload::vec3>().x;
- dst->acceleration.y = src.payload.get<Event::EventPayload::vec3>().y;
- dst->acceleration.z = src.payload.get<Event::EventPayload::vec3>().z;
- dst->acceleration.status = (int32_t)src.payload.get<Event::EventPayload::vec3>().status;
- break;
- }
-
- case SensorType::GAME_ROTATION_VECTOR: {
- dst->data[0] = src.payload.get<Event::EventPayload::vec4>().x;
- dst->data[1] = src.payload.get<Event::EventPayload::vec4>().y;
- dst->data[2] = src.payload.get<Event::EventPayload::vec4>().z;
- dst->data[3] = src.payload.get<Event::EventPayload::vec4>().w;
- break;
- }
-
- case SensorType::ROTATION_VECTOR:
- case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
- dst->data[0] = src.payload.get<Event::EventPayload::data>().values[0];
- dst->data[1] = src.payload.get<Event::EventPayload::data>().values[1];
- dst->data[2] = src.payload.get<Event::EventPayload::data>().values[2];
- dst->data[3] = src.payload.get<Event::EventPayload::data>().values[3];
- dst->data[4] = src.payload.get<Event::EventPayload::data>().values[4];
- break;
- }
-
- case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
- case SensorType::GYROSCOPE_UNCALIBRATED:
- case SensorType::ACCELEROMETER_UNCALIBRATED: {
- dst->uncalibrated_gyro.x_uncalib = src.payload.get<Event::EventPayload::uncal>().x;
- dst->uncalibrated_gyro.y_uncalib = src.payload.get<Event::EventPayload::uncal>().y;
- dst->uncalibrated_gyro.z_uncalib = src.payload.get<Event::EventPayload::uncal>().z;
- dst->uncalibrated_gyro.x_bias = src.payload.get<Event::EventPayload::uncal>().xBias;
- dst->uncalibrated_gyro.y_bias = src.payload.get<Event::EventPayload::uncal>().yBias;
- dst->uncalibrated_gyro.z_bias = src.payload.get<Event::EventPayload::uncal>().zBias;
- break;
- }
-
- case SensorType::HINGE_ANGLE:
- case SensorType::DEVICE_ORIENTATION:
- case SensorType::LIGHT:
- case SensorType::PRESSURE:
- case SensorType::PROXIMITY:
- case SensorType::RELATIVE_HUMIDITY:
- case SensorType::AMBIENT_TEMPERATURE:
- case SensorType::SIGNIFICANT_MOTION:
- case SensorType::STEP_DETECTOR:
- case SensorType::TILT_DETECTOR:
- case SensorType::WAKE_GESTURE:
- case SensorType::GLANCE_GESTURE:
- case SensorType::PICK_UP_GESTURE:
- case SensorType::WRIST_TILT_GESTURE:
- case SensorType::STATIONARY_DETECT:
- case SensorType::MOTION_DETECT:
- case SensorType::HEART_BEAT:
- case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
- dst->data[0] = src.payload.get<Event::EventPayload::scalar>();
- break;
- }
-
- case SensorType::STEP_COUNTER: {
- dst->u64.step_counter = src.payload.get<Event::EventPayload::stepCount>();
- break;
- }
-
- case SensorType::HEART_RATE: {
- dst->heart_rate.bpm = src.payload.get<Event::EventPayload::heartRate>().bpm;
- dst->heart_rate.status =
- (int8_t)src.payload.get<Event::EventPayload::heartRate>().status;
- break;
- }
-
- case SensorType::POSE_6DOF: { // 15 floats
- for (size_t i = 0; i < 15; ++i) {
- dst->data[i] = src.payload.get<Event::EventPayload::pose6DOF>().values[i];
- }
- break;
- }
-
- case SensorType::DYNAMIC_SENSOR_META: {
- dst->dynamic_sensor_meta.connected =
- src.payload.get<Event::EventPayload::dynamic>().connected;
- dst->dynamic_sensor_meta.handle =
- src.payload.get<Event::EventPayload::dynamic>().sensorHandle;
- dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later
-
- memcpy(dst->dynamic_sensor_meta.uuid,
- src.payload.get<Event::EventPayload::dynamic>().uuid.values.data(), 16);
-
- break;
- }
-
- case SensorType::ADDITIONAL_INFO: {
- const AdditionalInfo &srcInfo = src.payload.get<Event::EventPayload::additional>();
-
- additional_info_event_t *dstInfo = &dst->additional_info;
- dstInfo->type = (int32_t)srcInfo.type;
- dstInfo->serial = srcInfo.serial;
-
- switch (srcInfo.payload.getTag()) {
- case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
- const auto &values =
- srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
- .values;
- CHECK_EQ(values.size() * sizeof(int32_t), sizeof(dstInfo->data_int32));
- memcpy(dstInfo->data_int32, values.data(), sizeof(dstInfo->data_int32));
- break;
- }
- case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
- const auto &values =
- srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
- .values;
- CHECK_EQ(values.size() * sizeof(float), sizeof(dstInfo->data_float));
- memcpy(dstInfo->data_float, values.data(), sizeof(dstInfo->data_float));
- break;
- }
- default: {
- ALOGE("Invalid sensor additional info tag: %d", (int)srcInfo.payload.getTag());
- }
- }
- break;
- }
-
- case SensorType::HEAD_TRACKER: {
- const auto &ht = src.payload.get<Event::EventPayload::headTracker>();
- dst->head_tracker.rx = ht.rx;
- dst->head_tracker.ry = ht.ry;
- dst->head_tracker.rz = ht.rz;
- dst->head_tracker.vx = ht.vx;
- dst->head_tracker.vy = ht.vy;
- dst->head_tracker.vz = ht.vz;
- dst->head_tracker.discontinuity_count = ht.discontinuityCount;
- break;
- }
-
- case SensorType::ACCELEROMETER_LIMITED_AXES:
- case SensorType::GYROSCOPE_LIMITED_AXES:
- dst->limited_axes_imu.x = src.payload.get<Event::EventPayload::limitedAxesImu>().x;
- dst->limited_axes_imu.y = src.payload.get<Event::EventPayload::limitedAxesImu>().y;
- dst->limited_axes_imu.z = src.payload.get<Event::EventPayload::limitedAxesImu>().z;
- dst->limited_axes_imu.x_supported =
- src.payload.get<Event::EventPayload::limitedAxesImu>().xSupported;
- dst->limited_axes_imu.y_supported =
- src.payload.get<Event::EventPayload::limitedAxesImu>().ySupported;
- dst->limited_axes_imu.z_supported =
- src.payload.get<Event::EventPayload::limitedAxesImu>().zSupported;
- break;
-
- case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
- case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
- dst->limited_axes_imu_uncalibrated.x_uncalib =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().x;
- dst->limited_axes_imu_uncalibrated.y_uncalib =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().y;
- dst->limited_axes_imu_uncalibrated.z_uncalib =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().z;
- dst->limited_axes_imu_uncalibrated.x_bias =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xBias;
- dst->limited_axes_imu_uncalibrated.y_bias =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().yBias;
- dst->limited_axes_imu_uncalibrated.z_bias =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zBias;
- dst->limited_axes_imu_uncalibrated.x_supported =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xSupported;
- dst->limited_axes_imu_uncalibrated.y_supported =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().ySupported;
- dst->limited_axes_imu_uncalibrated.z_supported =
- src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zSupported;
- break;
-
- case SensorType::HEADING:
- dst->heading.heading = src.payload.get<Event::EventPayload::heading>().heading;
- dst->heading.accuracy = src.payload.get<Event::EventPayload::heading>().accuracy;
- break;
-
- default: {
- CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
- memcpy(dst->data, src.payload.get<Event::EventPayload::data>().values.data(),
- 16 * sizeof(float));
- break;
- }
- }
-}
-
-void convertFromSensorEvent(const sensors_event_t &src, Event *dst) {
- *dst = {
- .timestamp = src.timestamp,
- .sensorHandle = src.sensor,
- .sensorType = (SensorType)src.type,
- };
-
- switch (dst->sensorType) {
- case SensorType::META_DATA: {
- Event::EventPayload::MetaData meta;
- meta.what = (Event::EventPayload::MetaData::MetaDataEventType)src.meta_data.what;
- // Legacy HALs contain the handle reference in the meta data field.
- // Copy that over to the handle of the event. In legacy HALs this
- // field was expected to be 0.
- dst->sensorHandle = src.meta_data.sensor;
- dst->payload.set<Event::EventPayload::Tag::meta>(meta);
- break;
- }
-
- case SensorType::ACCELEROMETER:
- case SensorType::MAGNETIC_FIELD:
- case SensorType::ORIENTATION:
- case SensorType::GYROSCOPE:
- case SensorType::GRAVITY:
- case SensorType::LINEAR_ACCELERATION: {
- Event::EventPayload::Vec3 vec3;
- vec3.x = src.acceleration.x;
- vec3.y = src.acceleration.y;
- vec3.z = src.acceleration.z;
- vec3.status = (SensorStatus)src.acceleration.status;
- dst->payload.set<Event::EventPayload::Tag::vec3>(vec3);
- break;
- }
-
- case SensorType::GAME_ROTATION_VECTOR: {
- Event::EventPayload::Vec4 vec4;
- vec4.x = src.data[0];
- vec4.y = src.data[1];
- vec4.z = src.data[2];
- vec4.w = src.data[3];
- dst->payload.set<Event::EventPayload::Tag::vec4>(vec4);
- break;
- }
-
- case SensorType::ROTATION_VECTOR:
- case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
- Event::EventPayload::Data data;
- memcpy(data.values.data(), src.data, 5 * sizeof(float));
- dst->payload.set<Event::EventPayload::Tag::data>(data);
- break;
- }
-
- case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
- case SensorType::GYROSCOPE_UNCALIBRATED:
- case SensorType::ACCELEROMETER_UNCALIBRATED: {
- Event::EventPayload::Uncal uncal;
- uncal.x = src.uncalibrated_gyro.x_uncalib;
- uncal.y = src.uncalibrated_gyro.y_uncalib;
- uncal.z = src.uncalibrated_gyro.z_uncalib;
- uncal.xBias = src.uncalibrated_gyro.x_bias;
- uncal.yBias = src.uncalibrated_gyro.y_bias;
- uncal.zBias = src.uncalibrated_gyro.z_bias;
- dst->payload.set<Event::EventPayload::Tag::uncal>(uncal);
- break;
- }
-
- case SensorType::DEVICE_ORIENTATION:
- case SensorType::LIGHT:
- case SensorType::PRESSURE:
- case SensorType::PROXIMITY:
- case SensorType::RELATIVE_HUMIDITY:
- case SensorType::AMBIENT_TEMPERATURE:
- case SensorType::SIGNIFICANT_MOTION:
- case SensorType::STEP_DETECTOR:
- case SensorType::TILT_DETECTOR:
- case SensorType::WAKE_GESTURE:
- case SensorType::GLANCE_GESTURE:
- case SensorType::PICK_UP_GESTURE:
- case SensorType::WRIST_TILT_GESTURE:
- case SensorType::STATIONARY_DETECT:
- case SensorType::MOTION_DETECT:
- case SensorType::HEART_BEAT:
- case SensorType::LOW_LATENCY_OFFBODY_DETECT:
- case SensorType::HINGE_ANGLE: {
- dst->payload.set<Event::EventPayload::Tag::scalar>((float)src.data[0]);
- break;
- }
-
- case SensorType::STEP_COUNTER: {
- dst->payload.set<Event::EventPayload::Tag::stepCount>(src.u64.step_counter);
- break;
- }
-
- case SensorType::HEART_RATE: {
- Event::EventPayload::HeartRate heartRate;
- heartRate.bpm = src.heart_rate.bpm;
- heartRate.status = (SensorStatus)src.heart_rate.status;
- dst->payload.set<Event::EventPayload::Tag::heartRate>(heartRate);
- break;
- }
-
- case SensorType::POSE_6DOF: { // 15 floats
- Event::EventPayload::Pose6Dof pose6DOF;
- for (size_t i = 0; i < 15; ++i) {
- pose6DOF.values[i] = src.data[i];
- }
- dst->payload.set<Event::EventPayload::Tag::pose6DOF>(pose6DOF);
- break;
- }
-
- case SensorType::DYNAMIC_SENSOR_META: {
- DynamicSensorInfo dynamic;
- dynamic.connected = src.dynamic_sensor_meta.connected;
- dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
-
- memcpy(dynamic.uuid.values.data(), src.dynamic_sensor_meta.uuid, 16);
- dst->payload.set<Event::EventPayload::Tag::dynamic>(dynamic);
- break;
- }
-
- case SensorType::ADDITIONAL_INFO: {
- AdditionalInfo info;
- const additional_info_event_t &srcInfo = src.additional_info;
- info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type;
- info.serial = srcInfo.serial;
-
- AdditionalInfo::AdditionalInfoPayload::Int32Values data;
- CHECK_EQ(data.values.size() * sizeof(int32_t), sizeof(srcInfo.data_int32));
- memcpy(data.values.data(), srcInfo.data_int32, sizeof(srcInfo.data_int32));
- info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(data);
-
- dst->payload.set<Event::EventPayload::Tag::additional>(info);
- break;
- }
-
- case SensorType::HEAD_TRACKER: {
- Event::EventPayload::HeadTracker headTracker;
- headTracker.rx = src.head_tracker.rx;
- headTracker.ry = src.head_tracker.ry;
- headTracker.rz = src.head_tracker.rz;
- headTracker.vx = src.head_tracker.vx;
- headTracker.vy = src.head_tracker.vy;
- headTracker.vz = src.head_tracker.vz;
- headTracker.discontinuityCount = src.head_tracker.discontinuity_count;
-
- dst->payload.set<Event::EventPayload::Tag::headTracker>(headTracker);
- break;
- }
-
- case SensorType::ACCELEROMETER_LIMITED_AXES:
- case SensorType::GYROSCOPE_LIMITED_AXES: {
- Event::EventPayload::LimitedAxesImu limitedAxesImu;
- limitedAxesImu.x = src.limited_axes_imu.x;
- limitedAxesImu.y = src.limited_axes_imu.y;
- limitedAxesImu.z = src.limited_axes_imu.z;
- limitedAxesImu.xSupported = src.limited_axes_imu.x_supported;
- limitedAxesImu.ySupported = src.limited_axes_imu.y_supported;
- limitedAxesImu.zSupported = src.limited_axes_imu.z_supported;
- dst->payload.set<Event::EventPayload::Tag::limitedAxesImu>(limitedAxesImu);
- break;
- }
-
- case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
- case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED: {
- Event::EventPayload::LimitedAxesImuUncal limitedAxesImuUncal;
- limitedAxesImuUncal.x = src.limited_axes_imu_uncalibrated.x_uncalib;
- limitedAxesImuUncal.y = src.limited_axes_imu_uncalibrated.y_uncalib;
- limitedAxesImuUncal.z = src.limited_axes_imu_uncalibrated.z_uncalib;
- limitedAxesImuUncal.xBias = src.limited_axes_imu_uncalibrated.x_bias;
- limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
- limitedAxesImuUncal.zBias = src.limited_axes_imu_uncalibrated.z_bias;
- limitedAxesImuUncal.xSupported = src.limited_axes_imu_uncalibrated.x_supported;
- limitedAxesImuUncal.ySupported = src.limited_axes_imu_uncalibrated.y_supported;
- limitedAxesImuUncal.zSupported = src.limited_axes_imu_uncalibrated.z_supported;
- dst->payload.set<Event::EventPayload::Tag::limitedAxesImuUncal>(limitedAxesImuUncal);
- break;
- }
-
- case SensorType::HEADING: {
- Event::EventPayload::Heading heading;
- heading.heading = src.heading.heading;
- heading.accuracy = src.heading.accuracy;
- dst->payload.set<Event::EventPayload::heading>(heading);
- break;
- }
-
- default: {
- CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
- Event::EventPayload::Data data;
- memcpy(data.values.data(), src.data, 16 * sizeof(float));
- dst->payload.set<Event::EventPayload::Tag::data>(data);
- break;
- }
- }
-}
-
void serviceDied(void *cookie) {
ALOGW("Sensors HAL died, attempting to reconnect.");
((AidlSensorHalWrapper *)cookie)->prepareForReconnect();
@@ -726,7 +274,7 @@
.type = type,
.format = format,
.size = static_cast<int32_t>(memory->size),
- .memoryHandle = makeToAidl(memory->handle),
+ .memoryHandle = dupToAidl(memory->handle),
};
return convertToStatus(mSensors->registerDirectChannel(mem, channelHandle));
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 3c4f8d9..a2042d6 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -75,6 +75,7 @@
static_libs: [
"libaidlcommonsupport",
"android.hardware.sensors@1.0-convert",
+ "android.hardware.sensors-V1-convert",
"android.hardware.sensors-V1-ndk",
],
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 948692b..e0a4f03 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1328,6 +1328,7 @@
mSensors.getUserDebugSensors() : mSensors.getUserSensors();
Vector<Sensor> accessibleSensorList;
+ resetTargetSdkVersionCache(opPackageName);
bool isCapped = isRateCappedBasedOnPermission(opPackageName);
for (size_t i = 0; i < initialSensorList.size(); i++) {
Sensor sensor = initialSensorList[i];
@@ -1367,6 +1368,7 @@
if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {
return nullptr;
}
+ resetTargetSdkVersionCache(opPackageName);
Mutex::Autolock _l(mLock);
// To create a client in DATA_INJECTION mode to inject data, SensorService should already be
@@ -1402,6 +1404,7 @@
sp<ISensorEventConnection> SensorService::createSensorDirectConnection(
const String16& opPackageName, uint32_t size, int32_t type, int32_t format,
const native_handle *resource) {
+ resetTargetSdkVersionCache(opPackageName);
ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
// No new direct connections are allowed when sensor privacy is enabled
@@ -1643,14 +1646,6 @@
checkWakeLockStateLocked(&connLock);
}
- {
- Mutex::Autolock packageLock(sPackageTargetVersionLock);
- auto iter = sPackageTargetVersion.find(c->mOpPackageName);
- if (iter != sPackageTargetVersion.end()) {
- sPackageTargetVersion.erase(iter);
- }
- }
-
SensorDevice& dev(SensorDevice::getInstance());
dev.notifyConnectionDestroyed(c);
}
@@ -2091,6 +2086,14 @@
return targetSdkVersion;
}
+void SensorService::resetTargetSdkVersionCache(const String16& opPackageName) {
+ Mutex::Autolock packageLock(sPackageTargetVersionLock);
+ auto iter = sPackageTargetVersion.find(opPackageName);
+ if (iter != sPackageTargetVersion.end()) {
+ sPackageTargetVersion.erase(iter);
+ }
+}
+
void SensorService::checkWakeLockState() {
ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
checkWakeLockStateLocked(&connLock);
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 234dc9c..4ba3c51 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -377,6 +377,7 @@
const String16& opPackageName);
static bool hasPermissionForSensor(const Sensor& sensor);
static int getTargetSdkVersion(const String16& opPackageName);
+ static void resetTargetSdkVersionCache(const String16& opPackageName);
// SensorService acquires a partial wakelock for delivering events from wake up sensors. This
// method checks whether all the events from these wake up sensors have been delivered to the
// corresponding applications, if yes the wakelock is released.
diff --git a/services/sensorservice/aidl/Android.bp b/services/sensorservice/aidl/Android.bp
new file mode 100644
index 0000000..34d1de7
--- /dev/null
+++ b/services/sensorservice/aidl/Android.bp
@@ -0,0 +1,44 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library {
+ name: "libsensorserviceaidl",
+ srcs: [
+ "EventQueue.cpp",
+ "DirectReportChannel.cpp",
+ "SensorManager.cpp",
+ "utils.cpp",
+ ],
+ host_supported: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ header_libs: ["jni_headers"],
+ shared_libs: [
+ "libbase",
+ "libutils",
+ "libcutils",
+ "libbinder_ndk",
+ "libsensor",
+ "android.frameworks.sensorservice-V1-ndk",
+ "android.hardware.sensors-V1-ndk",
+ ],
+ export_include_dirs: [
+ "include/",
+ ],
+ static_libs: [
+ "android.hardware.sensors-V1-convert",
+ ],
+
+ export_header_lib_headers: ["jni_headers"],
+ local_include_dirs: [
+ "include/sensorserviceaidl/",
+ ],
+}
diff --git a/services/sensorservice/aidl/DirectReportChannel.cpp b/services/sensorservice/aidl/DirectReportChannel.cpp
new file mode 100644
index 0000000..cab53c1
--- /dev/null
+++ b/services/sensorservice/aidl/DirectReportChannel.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DirectReportChannel.h"
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+DirectReportChannel::DirectReportChannel(::android::SensorManager& manager, int channelId)
+ : mManager(manager), mId(channelId) {}
+
+DirectReportChannel::~DirectReportChannel() {
+ mManager.destroyDirectChannel(mId);
+}
+
+ndk::ScopedAStatus DirectReportChannel::configure(
+ int32_t sensorHandle, ::aidl::android::hardware::sensors::ISensors::RateLevel rate,
+ int32_t* _aidl_return) {
+ int token = mManager.configureDirectChannel(mId, sensorHandle, static_cast<int>(rate));
+ if (token <= 0) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(token);
+ }
+ *_aidl_return = token;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/DirectReportChannel.h b/services/sensorservice/aidl/DirectReportChannel.h
new file mode 100644
index 0000000..d9ea73d
--- /dev/null
+++ b/services/sensorservice/aidl/DirectReportChannel.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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 <aidl/android/frameworks/sensorservice/BnDirectReportChannel.h>
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <sensor/SensorManager.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+class DirectReportChannel final
+ : public ::aidl::android::frameworks::sensorservice::BnDirectReportChannel {
+public:
+ DirectReportChannel(::android::SensorManager& manager, int channelId);
+ ~DirectReportChannel();
+
+ ndk::ScopedAStatus configure(int32_t sensorHandle,
+ ::aidl::android::hardware::sensors::ISensors::RateLevel rate,
+ int32_t* _aidl_return) override;
+
+private:
+ ::android::SensorManager& mManager;
+ const int mId;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/EventQueue.cpp b/services/sensorservice/aidl/EventQueue.cpp
new file mode 100644
index 0000000..c394709
--- /dev/null
+++ b/services/sensorservice/aidl/EventQueue.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventQueue.h"
+#include "utils.h"
+
+#include <android-base/logging.h>
+#include <utils/Looper.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+using ::aidl::android::frameworks::sensorservice::IEventQueueCallback;
+using ::aidl::android::hardware::sensors::Event;
+
+class EventQueueLooperCallback : public ::android::LooperCallback {
+public:
+ EventQueueLooperCallback(sp<::android::SensorEventQueue> queue,
+ std::shared_ptr<IEventQueueCallback> callback)
+ : mQueue(queue), mCallback(callback) {}
+
+ int handleEvent(int /* fd */, int /* events */, void* /* data */) {
+ ASensorEvent event;
+ ssize_t actual;
+
+ auto internalQueue = mQueue.promote();
+ if (internalQueue == nullptr) {
+ return 1;
+ }
+
+ while ((actual = internalQueue->read(&event, 1)) > 0) {
+ internalQueue->sendAck(&event, actual);
+ ndk::ScopedAStatus ret = mCallback->onEvent(convertEvent(event));
+ if (!ret.isOk()) {
+ LOG(ERROR) << "Failed to envoke EventQueueCallback: " << ret;
+ }
+ }
+
+ return 1; // continue to receive callbacks
+ }
+
+private:
+ wp<::android::SensorEventQueue> mQueue;
+ std::shared_ptr<IEventQueueCallback> mCallback;
+};
+
+EventQueue::EventQueue(std::shared_ptr<IEventQueueCallback> callback, sp<::android::Looper> looper,
+ sp<::android::SensorEventQueue> internalQueue)
+ : mLooper(looper), mInternalQueue(internalQueue) {
+ mLooper->addFd(internalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT,
+ new EventQueueLooperCallback(internalQueue, callback), nullptr);
+}
+
+EventQueue::~EventQueue() {
+ mLooper->removeFd(mInternalQueue->getFd());
+}
+
+ndk::ScopedAStatus EventQueue::enableSensor(int32_t in_sensorHandle, int32_t in_samplingPeriodUs,
+ int64_t in_maxBatchReportLatencyUs) {
+ return convertResult(mInternalQueue->enableSensor(in_sensorHandle, in_samplingPeriodUs,
+ in_maxBatchReportLatencyUs, 0));
+}
+
+ndk::ScopedAStatus EventQueue::disableSensor(int32_t in_sensorHandle) {
+ return convertResult(mInternalQueue->disableSensor(in_sensorHandle));
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/EventQueue.h b/services/sensorservice/aidl/EventQueue.h
new file mode 100644
index 0000000..0ae1eba
--- /dev/null
+++ b/services/sensorservice/aidl/EventQueue.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 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 "SensorManagerAidl.h"
+
+#include <aidl/android/frameworks/sensorservice/BnEventQueue.h>
+#include <sensor/SensorManager.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+struct EventQueue final : public aidl::android::frameworks::sensorservice::BnEventQueue {
+ EventQueue(
+ std::shared_ptr<aidl::android::frameworks::sensorservice::IEventQueueCallback> callback,
+ sp<::android::Looper> looper, sp<::android::SensorEventQueue> internalQueue);
+ ~EventQueue();
+
+ ndk::ScopedAStatus enableSensor(int32_t in_sensorHandle, int32_t in_samplingPeriodUs,
+ int64_t in_maxBatchReportLatencyUs) override;
+ ndk::ScopedAStatus disableSensor(int32_t sensorHandle) override;
+
+private:
+ friend class EventQueueLooperCallback;
+ sp<::android::Looper> mLooper;
+ sp<::android::SensorEventQueue> mInternalQueue;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/SensorManager.cpp b/services/sensorservice/aidl/SensorManager.cpp
new file mode 100644
index 0000000..9b03344
--- /dev/null
+++ b/services/sensorservice/aidl/SensorManager.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+// LOG_TAG defined via build flag.
+#ifndef LOG_TAG
+#define LOG_TAG "AidlSensorManager"
+#endif
+
+#include "DirectReportChannel.h"
+#include "EventQueue.h"
+#include "SensorManagerAidl.h"
+#include "utils.h"
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder.h>
+#include <sched.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+using ::aidl::android::frameworks::sensorservice::IDirectReportChannel;
+using ::aidl::android::frameworks::sensorservice::IEventQueue;
+using ::aidl::android::frameworks::sensorservice::IEventQueueCallback;
+using ::aidl::android::frameworks::sensorservice::ISensorManager;
+using ::aidl::android::hardware::common::Ashmem;
+using ::aidl::android::hardware::sensors::ISensors;
+using ::aidl::android::hardware::sensors::SensorInfo;
+using ::aidl::android::hardware::sensors::SensorType;
+using ::android::frameworks::sensorservice::implementation::SensorManagerAidl;
+
+static const char* POLL_THREAD_NAME = "aidl_ssvc_poll";
+
+SensorManagerAidl::SensorManagerAidl(JavaVM* vm)
+ : mLooper(new Looper(false)), mStopThread(true), mJavaVm(vm) {}
+SensorManagerAidl::~SensorManagerAidl() {
+ // Stops pollAll inside the thread.
+ std::lock_guard<std::mutex> lock(mThreadMutex);
+
+ mStopThread = true;
+ if (mLooper != nullptr) {
+ mLooper->wake();
+ }
+ if (mPollThread.joinable()) {
+ mPollThread.join();
+ }
+}
+
+ndk::ScopedAStatus createDirectChannel(::android::SensorManager& manager, size_t size, int type,
+ const native_handle_t* handle,
+ std::shared_ptr<IDirectReportChannel>* chan) {
+ int channelId = manager.createDirectChannel(size, type, handle);
+ if (channelId < 0) {
+ return convertResult(channelId);
+ }
+ if (channelId == 0) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+ }
+ *chan = ndk::SharedRefBase::make<DirectReportChannel>(manager, channelId);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createAshmemDirectChannel(
+ const Ashmem& in_mem, int64_t in_size,
+ std::shared_ptr<IDirectReportChannel>* _aidl_return) {
+ if (in_size > in_mem.size || in_size < ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE);
+ }
+ native_handle_t* handle = native_handle_create(1, 0);
+ handle->data[0] = dup(in_mem.fd.get());
+
+ auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_ASHMEM,
+ handle, _aidl_return);
+ int result = native_handle_close(handle);
+ CHECK(result == 0) << "Failed to close the native_handle_t: " << result;
+ result = native_handle_delete(handle);
+ CHECK(result == 0) << "Failed to delete the native_handle_t: " << result;
+
+ return status;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createGrallocDirectChannel(
+ const ndk::ScopedFileDescriptor& in_mem, int64_t in_size,
+ std::shared_ptr<IDirectReportChannel>* _aidl_return) {
+ native_handle_t* handle = native_handle_create(1, 0);
+ handle->data[0] = dup(in_mem.get());
+
+ auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_GRALLOC,
+ handle, _aidl_return);
+ int result = native_handle_close(handle);
+ CHECK(result == 0) << "Failed to close the native_handle_t: " << result;
+ result = native_handle_delete(handle);
+ CHECK(result == 0) << "Failed to delete the native_handle_t: " << result;
+
+ return status;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createEventQueue(
+ const std::shared_ptr<IEventQueueCallback>& in_callback,
+ std::shared_ptr<IEventQueue>* _aidl_return) {
+ if (in_callback == nullptr) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE);
+ }
+
+ sp<::android::Looper> looper = getLooper();
+ if (looper == nullptr) {
+ LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue cannot initialize looper";
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+ }
+
+ String8 package(String8::format("aidl_client_pid_%d", AIBinder_getCallingPid()));
+ sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(package);
+ if (internalQueue == nullptr) {
+ LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue returns nullptr.";
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+ }
+
+ *_aidl_return = ndk::SharedRefBase::make<EventQueue>(in_callback, looper, internalQueue);
+
+ return ndk::ScopedAStatus::ok();
+}
+
+SensorInfo convertSensor(Sensor src) {
+ SensorInfo dst;
+ dst.sensorHandle = src.getHandle();
+ dst.name = src.getName();
+ dst.vendor = src.getVendor();
+ dst.version = src.getVersion();
+ dst.type = static_cast<SensorType>(src.getType());
+ dst.typeAsString = src.getStringType();
+ // maxRange uses maxValue because ::android::Sensor wraps the
+ // internal sensor_t in this way.
+ dst.maxRange = src.getMaxValue();
+ dst.resolution = src.getResolution();
+ dst.power = src.getPowerUsage();
+ dst.minDelayUs = src.getMinDelay();
+ dst.fifoReservedEventCount = src.getFifoReservedEventCount();
+ dst.fifoMaxEventCount = src.getFifoMaxEventCount();
+ dst.requiredPermission = src.getRequiredPermission();
+ dst.maxDelayUs = src.getMaxDelay();
+ dst.flags = src.getFlags();
+ return dst;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::getDefaultSensor(SensorType in_type,
+ SensorInfo* _aidl_return) {
+ ::android::Sensor const* sensor =
+ getInternalManager().getDefaultSensor(static_cast<int>(in_type));
+ if (!sensor) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_NOT_EXIST);
+ }
+ *_aidl_return = convertSensor(*sensor);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SensorManagerAidl::getSensorList(std::vector<SensorInfo>* _aidl_return) {
+ Sensor const* const* list;
+ _aidl_return->clear();
+ ssize_t count = getInternalManager().getSensorList(&list);
+ if (count < 0 || list == nullptr) {
+ LOG(ERROR) << "SensorMAanger::getSensorList failed with count: " << count;
+ return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+ }
+ _aidl_return->reserve(static_cast<size_t>(count));
+ for (ssize_t i = 0; i < count; ++i) {
+ _aidl_return->push_back(convertSensor(*list[i]));
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+::android::SensorManager& SensorManagerAidl::getInternalManager() {
+ std::lock_guard<std::mutex> lock(mInternalManagerMutex);
+ if (mInternalManager == nullptr) {
+ mInternalManager = &::android::SensorManager::getInstanceForPackage(
+ String16(ISensorManager::descriptor));
+ }
+ return *mInternalManager;
+}
+
+/* One global looper for all event queues created from this SensorManager. */
+sp<Looper> SensorManagerAidl::getLooper() {
+ std::lock_guard<std::mutex> lock(mThreadMutex);
+
+ if (!mPollThread.joinable()) {
+ // if thread not initialized, start thread
+ mStopThread = false;
+ std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] {
+ struct sched_param p = {};
+ p.sched_priority = 10;
+ if (sched_setscheduler(0 /* current thread*/, SCHED_FIFO, &p) != 0) {
+ LOG(ERROR) << "Could not use SCHED_FIFO for looper thread: " << strerror(errno);
+ }
+
+ // set looper
+ Looper::setForThread(looper);
+
+ // 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,
+ .group = nullptr};
+ JNIEnv* env;
+ if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) {
+ LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
+ }
+
+ 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) << POLL_THREAD_NAME << " is terminated.";
+ }};
+ mPollThread = std::move(pollThread);
+ }
+ return mLooper;
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp
new file mode 100644
index 0000000..0d6e476
--- /dev/null
+++ b/services/sensorservice/aidl/fuzzer/Android.bp
@@ -0,0 +1,52 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_fuzz {
+ name: "libsensorserviceaidl_fuzzer",
+ defaults: [
+ "service_fuzzer_defaults",
+ ],
+ host_supported: true,
+ static_libs: [
+ "libsensorserviceaidl",
+ "libpermission",
+ "android.frameworks.sensorservice-V1-ndk",
+ "android.hardware.sensors-V1-convert",
+ "android.hardware.sensors-V1-ndk",
+ "android.hardware.common-V2-ndk",
+ "libsensor",
+ "libfakeservicemanager",
+ "libcutils",
+ "liblog",
+ ],
+ srcs: [
+ "fuzzer.cpp",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-sensors@google.com",
+ "devinmoore@google.com",
+ ],
+ },
+ sanitize: {
+ misc_undefined: [
+ "signed-integer-overflow",
+ "unsigned-integer-overflow",
+ ],
+ diag: {
+ misc_undefined: [
+ "signed-integer-overflow",
+ "unsigned-integer-overflow",
+ ],
+ },
+ address: true,
+ integer_overflow: true,
+ },
+
+}
diff --git a/services/sensorservice/aidl/fuzzer/fuzzer.cpp b/services/sensorservice/aidl/fuzzer/fuzzer.cpp
new file mode 100644
index 0000000..1b63d76
--- /dev/null
+++ b/services/sensorservice/aidl/fuzzer/fuzzer.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <ServiceManager.h>
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <fuzzbinder/random_binder.h>
+#include <sensorserviceaidl/SensorManagerAidl.h>
+
+using android::fuzzService;
+using android::frameworks::sensorservice::implementation::SensorManagerAidl;
+using ndk::SharedRefBase;
+
+[[clang::no_destroy]] static std::once_flag gSmOnce;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ static android::sp<android::ServiceManager> fakeServiceManager = new android::ServiceManager();
+ std::call_once(gSmOnce, [&] { setDefaultServiceManager(fakeServiceManager); });
+ fakeServiceManager->clear();
+
+ FuzzedDataProvider fdp(data, size);
+ android::sp<android::IBinder> binder = android::getRandomBinder(&fdp);
+ if (binder == nullptr) {
+ // Nothing to do if we get a null binder. It will cause SensorManager to
+ // hang while trying to get sensorservice.
+ return 0;
+ }
+
+ CHECK(android::NO_ERROR == fakeServiceManager->addService(android::String16("sensorservice"),
+ binder));
+
+ std::shared_ptr<SensorManagerAidl> sensorService =
+ ndk::SharedRefBase::make<SensorManagerAidl>(nullptr);
+
+ fuzzService(sensorService->asBinder().get(), std::move(fdp));
+
+ return 0;
+}
diff --git a/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h b/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h
new file mode 100644
index 0000000..c77ee88
--- /dev/null
+++ b/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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 <aidl/android/frameworks/sensorservice/BnSensorManager.h>
+#include <jni.h>
+#include <sensor/SensorManager.h>
+#include <utils/Looper.h>
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+class SensorManagerAidl : public ::aidl::android::frameworks::sensorservice::BnSensorManager {
+public:
+ explicit SensorManagerAidl(JavaVM* vm);
+ ~SensorManagerAidl();
+
+ ::ndk::ScopedAStatus createAshmemDirectChannel(
+ const ::aidl::android::hardware::common::Ashmem& in_mem, int64_t in_size,
+ std::shared_ptr<::aidl::android::frameworks::sensorservice::IDirectReportChannel>*
+ _aidl_return) override;
+ ::ndk::ScopedAStatus createEventQueue(
+ const std::shared_ptr<::aidl::android::frameworks::sensorservice::IEventQueueCallback>&
+ in_callback,
+ std::shared_ptr<::aidl::android::frameworks::sensorservice::IEventQueue>* _aidl_return)
+ override;
+ ::ndk::ScopedAStatus createGrallocDirectChannel(
+ const ::ndk::ScopedFileDescriptor& in_buffer, int64_t in_size,
+ std::shared_ptr<::aidl::android::frameworks::sensorservice::IDirectReportChannel>*
+ _aidl_return) override;
+ ::ndk::ScopedAStatus getDefaultSensor(
+ ::aidl::android::hardware::sensors::SensorType in_type,
+ ::aidl::android::hardware::sensors::SensorInfo* _aidl_return) override;
+ ::ndk::ScopedAStatus getSensorList(
+ std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) override;
+
+private:
+ // Block until ::android::SensorManager is initialized.
+ ::android::SensorManager& getInternalManager();
+ sp<Looper> getLooper();
+
+ std::mutex mInternalManagerMutex;
+ ::android::SensorManager* mInternalManager = nullptr; // does not own
+ sp<Looper> mLooper;
+
+ volatile bool mStopThread;
+ std::mutex mThreadMutex; // protects mPollThread
+ std::thread mPollThread;
+
+ JavaVM* mJavaVm;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/utils.cpp b/services/sensorservice/aidl/utils.cpp
new file mode 100644
index 0000000..beb38b9
--- /dev/null
+++ b/services/sensorservice/aidl/utils.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+
+#include <aidl/android/frameworks/sensorservice/ISensorManager.h>
+#include <aidl/sensors/convert.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+ndk::ScopedAStatus convertResult(status_t src) {
+ using ::aidl::android::frameworks::sensorservice::ISensorManager;
+
+ int err = 0;
+ switch (src) {
+ case OK:
+ return ndk::ScopedAStatus::ok();
+ case NAME_NOT_FOUND:
+ err = ISensorManager::RESULT_NOT_EXIST;
+ break;
+ case NO_MEMORY:
+ err = ISensorManager::RESULT_NO_MEMORY;
+ break;
+ case NO_INIT:
+ err = ISensorManager::RESULT_NO_INIT;
+ break;
+ case PERMISSION_DENIED:
+ err = ISensorManager::RESULT_PERMISSION_DENIED;
+ break;
+ case BAD_VALUE:
+ err = ISensorManager::RESULT_BAD_VALUE;
+ break;
+ case INVALID_OPERATION:
+ err = ISensorManager::RESULT_INVALID_OPERATION;
+ break;
+ default:
+ err = ISensorManager::RESULT_UNKNOWN_ERROR;
+ }
+ return ndk::ScopedAStatus::fromServiceSpecificError(err);
+}
+
+::aidl::android::hardware::sensors::Event convertEvent(const ::ASensorEvent& src) {
+ ::aidl::android::hardware::sensors::Event dst;
+ ::android::hardware::sensors::implementation::
+ convertFromASensorEvent(src, &dst);
+ return dst;
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/utils.h b/services/sensorservice/aidl/utils.h
new file mode 100644
index 0000000..06ba59e
--- /dev/null
+++ b/services/sensorservice/aidl/utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 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 <aidl/android/hardware/sensors/Event.h>
+#include <sensor/Sensor.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+::ndk::ScopedAStatus convertResult(status_t status);
+::aidl::android::hardware::sensors::Event convertEvent(const ::ASensorEvent& event);
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/hidl/utils.cpp b/services/sensorservice/hidl/utils.cpp
index 2f9e922..5fa594d 100644
--- a/services/sensorservice/hidl/utils.cpp
+++ b/services/sensorservice/hidl/utils.cpp
@@ -76,8 +76,8 @@
::android::hardware::sensors::V1_0::Event convertEvent(const ::ASensorEvent& src) {
::android::hardware::sensors::V1_0::Event dst;
- ::android::hardware::sensors::V1_0::implementation::convertFromSensorEvent(
- reinterpret_cast<const sensors_event_t&>(src), &dst);
+ ::android::hardware::sensors::V1_0::implementation::convertFromASensorEvent(
+ src, &dst);
return dst;
}
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
index 7fea616..7d358e1 100644
--- a/services/stats/Android.bp
+++ b/services/stats/Android.bp
@@ -13,10 +13,13 @@
"StatsAidl.cpp",
"StatsHal.cpp",
],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
shared_libs: [
"android.frameworks.stats@1.0",
- "android.frameworks.stats-V1-ndk",
+ "android.frameworks.stats-V2-ndk",
"libbinder_ndk",
"libhidlbase",
"liblog",
@@ -29,10 +32,12 @@
],
export_shared_lib_headers: [
"android.frameworks.stats@1.0",
- "android.frameworks.stats-V1-ndk",
+ "android.frameworks.stats-V2-ndk",
],
local_include_dirs: [
"include/stats",
],
- vintf_fragments: ["android.frameworks.stats@1.0-service.xml"]
+ vintf_fragments: [
+ "android.frameworks.stats-service.xml",
+ ],
}
diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp
index a3b68f1..410a5af 100644
--- a/services/stats/StatsAidl.cpp
+++ b/services/stats/StatsAidl.cpp
@@ -30,14 +30,14 @@
StatsHal::StatsHal() {}
ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
- std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
-1, "Not a valid vendor atom ID");
}
- if (reverseDomainName.length() > 50) {
- ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
+ if (vendorAtom.reverseDomainName.length() > 50) {
+ ALOGE("Vendor atom reverse domain name %s is too long.",
+ vendorAtom.reverseDomainName.c_str());
return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
-1, "Vendor atom reverse domain name is too long");
}
@@ -62,6 +62,90 @@
AStatsEvent_writeString(event,
atomValue.get<VendorAtomValue::stringValue>().c_str());
break;
+ case VendorAtomValue::boolValue:
+ AStatsEvent_writeBool(event,
+ atomValue.get<VendorAtomValue::boolValue>());
+ break;
+ case VendorAtomValue::repeatedIntValue: {
+ const std::optional<std::vector<int>>& repeatedIntValue =
+ atomValue.get<VendorAtomValue::repeatedIntValue>();
+ if (!repeatedIntValue) {
+ AStatsEvent_writeInt32Array(event, {}, 0);
+ break;
+ }
+ AStatsEvent_writeInt32Array(event, repeatedIntValue->data(),
+ repeatedIntValue->size());
+ break;
+ }
+ case VendorAtomValue::repeatedLongValue: {
+ const std::optional<std::vector<int64_t>>& repeatedLongValue =
+ atomValue.get<VendorAtomValue::repeatedLongValue>();
+ if (!repeatedLongValue) {
+ AStatsEvent_writeInt64Array(event, {}, 0);
+ break;
+ }
+ AStatsEvent_writeInt64Array(event, repeatedLongValue->data(),
+ repeatedLongValue->size());
+ break;
+ }
+ case VendorAtomValue::repeatedFloatValue: {
+ const std::optional<std::vector<float>>& repeatedFloatValue =
+ atomValue.get<VendorAtomValue::repeatedFloatValue>();
+ if (!repeatedFloatValue) {
+ AStatsEvent_writeFloatArray(event, {}, 0);
+ break;
+ }
+ AStatsEvent_writeFloatArray(event, repeatedFloatValue->data(),
+ repeatedFloatValue->size());
+ break;
+ }
+ case VendorAtomValue::repeatedStringValue: {
+ const std::optional<std::vector<std::optional<std::string>>>& repeatedStringValue =
+ atomValue.get<VendorAtomValue::repeatedStringValue>();
+ if (!repeatedStringValue) {
+ AStatsEvent_writeStringArray(event, {}, 0);
+ break;
+ }
+ const std::vector<std::optional<std::string>>& repeatedStringVector =
+ *repeatedStringValue;
+ const char* cStringArray[repeatedStringVector.size()];
+
+ for (int i = 0; i < repeatedStringVector.size(); ++i) {
+ cStringArray[i] = repeatedStringVector[i].has_value()
+ ? repeatedStringVector[i]->c_str()
+ : "";
+ }
+
+ AStatsEvent_writeStringArray(event, cStringArray, repeatedStringVector.size());
+ break;
+ }
+ case VendorAtomValue::repeatedBoolValue: {
+ const std::optional<std::vector<bool>>& repeatedBoolValue =
+ atomValue.get<VendorAtomValue::repeatedBoolValue>();
+ if (!repeatedBoolValue) {
+ AStatsEvent_writeBoolArray(event, {}, 0);
+ break;
+ }
+ const std::vector<bool>& repeatedBoolVector = *repeatedBoolValue;
+ bool boolArray[repeatedBoolValue->size()];
+
+ for (int i = 0; i < repeatedBoolVector.size(); ++i) {
+ boolArray[i] = repeatedBoolVector[i];
+ }
+
+ AStatsEvent_writeBoolArray(event, boolArray, repeatedBoolVector.size());
+ break;
+ }
+ case VendorAtomValue::byteArrayValue: {
+ const std::optional<std::vector<uint8_t>>& byteArrayValue =
+ atomValue.get<VendorAtomValue::byteArrayValue>();
+ if (!byteArrayValue) {
+ AStatsEvent_writeByteArray(event, {}, 0);
+ break;
+ }
+ AStatsEvent_writeByteArray(event, byteArrayValue->data(), byteArrayValue->size());
+ break;
+ }
}
}
AStatsEvent_build(event);
diff --git a/services/stats/StatsHal.cpp b/services/stats/StatsHal.cpp
index ae0a984..d27d989 100644
--- a/services/stats/StatsHal.cpp
+++ b/services/stats/StatsHal.cpp
@@ -112,13 +112,13 @@
}
hardware::Return<void> StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
- std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
return hardware::Void();
}
- if (reverseDomainName.length() > 50) {
- ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
+ if (vendorAtom.reverseDomainName.size() > 50) {
+ ALOGE("Vendor atom reverse domain name %s is too long.",
+ vendorAtom.reverseDomainName.c_str());
return hardware::Void();
}
AStatsEvent* event = AStatsEvent_obtain();
diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats-service.xml
similarity index 93%
rename from services/stats/android.frameworks.stats@1.0-service.xml
rename to services/stats/android.frameworks.stats-service.xml
index c564b7b..7e2635e 100644
--- a/services/stats/android.frameworks.stats@1.0-service.xml
+++ b/services/stats/android.frameworks.stats-service.xml
@@ -11,7 +11,7 @@
<hal format="aidl">
<name>android.frameworks.stats</name>
- <version>1</version>
+ <version>2</version>
<fqname>IStats/default</fqname>
</hal>
</manifest>
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index 16cb41b..5e84be1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -56,6 +56,9 @@
// similar requests if needed.
virtual void createClientCompositionCache(uint32_t cacheSize) = 0;
+ // Sends the brightness setting to HWC
+ virtual void applyDisplayBrightness(const bool applyImmediately) = 0;
+
protected:
~Display() = default;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index db2fd1b..2203639 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -27,6 +27,7 @@
#include <compositionengine/LayerFE.h>
#include <renderengine/LayerSettings.h>
#include <ui/Fence.h>
+#include <ui/FenceTime.h>
#include <ui/GraphicTypes.h>
#include <ui/LayerStack.h>
#include <ui/Region.h>
@@ -311,6 +312,8 @@
const Region& flashRegion,
std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
virtual void setExpensiveRenderingExpected(bool enabled) = 0;
+ virtual void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) = 0;
+ virtual bool isPowerHintSessionEnabled() = 0;
virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 61a0e6a..33a10a3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -72,6 +72,7 @@
const compositionengine::DisplayColorProfileCreationArgs&) override;
void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override;
void createClientCompositionCache(uint32_t cacheSize) override;
+ void applyDisplayBrightness(const bool applyImmediately) override;
// Internal helpers used by chooseCompositionStrategy()
using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
@@ -89,6 +90,8 @@
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
private:
+ bool isPowerHintSessionEnabled() override;
+ void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) override;
DisplayId mId;
bool mIsDisconnected = false;
Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 31c51e6..df721cd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -140,6 +140,8 @@
std::vector<LayerFE*> &outLayerFEs) override;
void appendRegionFlashRequests(const Region&, std::vector<LayerFE::LayerSettings>&) override;
void setExpensiveRenderingExpected(bool enabled) override;
+ void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) override;
+ bool isPowerHintSessionEnabled() override;
void dumpBase(std::string&) const;
// Implemented by the final implementation for the final state it uses.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2bfd3cf..24a7744 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -115,7 +115,7 @@
// Renders the cached set with the supplied output composition state.
void render(renderengine::RenderEngine& re, TexturePool& texturePool,
- const OutputCompositionState& outputState);
+ const OutputCompositionState& outputState, bool deviceHandlesColorTransform);
void dump(std::string& result) const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 92cc484..f934cb2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -106,7 +106,8 @@
// Renders the newest cached sets with the supplied output composition state
void renderCachedSets(const OutputCompositionState& outputState,
- std::optional<std::chrono::steady_clock::time_point> renderDeadline);
+ std::optional<std::chrono::steady_clock::time_point> renderDeadline,
+ bool deviceHandlesColorTransform);
void setTexturePoolEnabled(bool enabled) { mTexturePool.setEnabled(enabled); }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index b7ebca6..c968df7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -65,7 +65,8 @@
// Rendering a pending cached set is optional: if the renderDeadline is not far enough in the
// future then the planner may opt to skip rendering the cached set.
void renderCachedSets(const OutputCompositionState& outputState,
- std::optional<std::chrono::steady_clock::time_point> renderDeadline);
+ std::optional<std::chrono::steady_clock::time_point> renderDeadline,
+ bool deviceHandlesColorTransform);
void setTexturePoolEnabled(bool enabled) { mFlattener.setTexturePoolEnabled(enabled); }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index 72e6f3b..7e99ec2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -41,6 +41,7 @@
MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
+ MOCK_METHOD1(applyDisplayBrightness, void(const bool));
MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index cb9fbad..2a04949 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -133,6 +133,8 @@
MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
MOCK_METHOD1(setTreat170mAsSrgb, void(bool));
+ MOCK_METHOD(void, setHintSessionGpuFence, (std::unique_ptr<FenceTime> && gpuFence));
+ MOCK_METHOD(bool, isPowerHintSessionEnabled, ());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index b79b46b..1ec6449 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -203,6 +203,24 @@
setReleasedLayers(std::move(releasedLayers));
}
+void Display::applyDisplayBrightness(const bool applyImmediately) {
+ auto& hwc = getCompositionEngine().getHwComposer();
+ const auto halDisplayId = HalDisplayId::tryCast(*getDisplayId());
+ if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
+ physicalDisplayId && getState().displayBrightness) {
+ const status_t result =
+ hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
+ getState().displayBrightnessNits,
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = applyImmediately})
+ .get();
+ ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
+ getName().c_str(), result, strerror(-result));
+ }
+ // Clear out the display brightness now that it's been communicated to composer.
+ editState().displayBrightness.reset();
+}
+
void Display::beginFrame() {
Output::beginFrame();
@@ -212,20 +230,7 @@
return;
}
- auto& hwc = getCompositionEngine().getHwComposer();
- if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
- physicalDisplayId && getState().displayBrightness) {
- const status_t result =
- hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
- getState().displayBrightnessNits,
- Hwc2::Composer::DisplayBrightnessOptions{
- .applyImmediately = false})
- .get();
- ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
- getName().c_str(), result, strerror(-result));
- }
- // Clear out the display brightness now that it's been communicated to composer.
- editState().displayBrightness.reset();
+ applyDisplayBrightness(false);
}
bool Display::chooseCompositionStrategy(
@@ -243,11 +248,14 @@
return false;
}
+ const nsecs_t startTime = systemTime();
+
// Get any composition changes requested by the HWC device, and apply them.
std::optional<android::HWComposer::DeviceRequestedChanges> changes;
auto& hwc = getCompositionEngine().getHwComposer();
+ const bool requiresClientComposition = anyLayersRequireClientComposition();
if (status_t result =
- hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
+ hwc.getDeviceCompositionChanges(*halDisplayId, requiresClientComposition,
getState().earliestPresentTime,
getState().previousPresentFence,
getState().expectedPresentTime, outChanges);
@@ -257,6 +265,11 @@
return false;
}
+ if (isPowerHintSessionEnabled()) {
+ mPowerAdvisor->setHwcValidateTiming(mId, startTime, systemTime());
+ mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition);
+ }
+
return true;
}
@@ -356,9 +369,24 @@
}
auto& hwc = getCompositionEngine().getHwComposer();
+
+ const nsecs_t startTime = systemTime();
+
+ if (isPowerHintSessionEnabled()) {
+ if (!getCompositionEngine().getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
+ getState().previousPresentFence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
+ mPowerAdvisor->setHwcPresentDelayedTime(mId, getState().earliestPresentTime);
+ }
+ }
+
hwc.presentAndGetReleaseFences(*halDisplayIdOpt, getState().earliestPresentTime,
getState().previousPresentFence);
+ if (isPowerHintSessionEnabled()) {
+ mPowerAdvisor->setHwcPresentTiming(mId, startTime, systemTime());
+ }
+
fences.presentFence = hwc.getPresentFence(*halDisplayIdOpt);
// TODO(b/121291683): Change HWComposer call to return entire map
@@ -384,6 +412,14 @@
}
}
+bool Display::isPowerHintSessionEnabled() {
+ return mPowerAdvisor != nullptr && mPowerAdvisor->usePowerHintSession();
+}
+
+void Display::setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) {
+ mPowerAdvisor->setGpuFenceTime(mId, std::move(gpuFence));
+}
+
void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs,
GpuCompositionResult&& result) {
// We only need to actually compose the display if:
@@ -396,6 +432,13 @@
}
impl::Output::finishFrame(refreshArgs, std::move(result));
+
+ if (isPowerHintSessionEnabled()) {
+ auto& hwc = getCompositionEngine().getHwComposer();
+ if (auto halDisplayId = HalDisplayId::tryCast(mId)) {
+ mPowerAdvisor->setSkippedValidate(mId, hwc.getValidateSkipped(*halDisplayId));
+ }
+ }
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index c3385a8..b724daa 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -586,8 +586,29 @@
// Remove the transparent area from the visible region
if (!layerFEState->isOpaque) {
if (tr.preserveRects()) {
- // transform the transparent region
- transparentRegion = tr.transform(layerFEState->transparentRegionHint);
+ // Clip the transparent region to geomLayerBounds first
+ // The transparent region may be influenced by applications, for
+ // instance, by overriding ViewGroup#gatherTransparentRegion with a
+ // custom view. Once the layer stack -> display mapping is known, we
+ // must guard against very wrong inputs to prevent underflow or
+ // overflow errors. We do this here by constraining the transparent
+ // region to be within the pre-transform layer bounds, since the
+ // layer bounds are expected to play nicely with the full
+ // transform.
+ const Region clippedTransparentRegionHint =
+ layerFEState->transparentRegionHint.intersect(
+ Rect(layerFEState->geomLayerBounds));
+
+ if (clippedTransparentRegionHint.isEmpty()) {
+ if (!layerFEState->transparentRegionHint.isEmpty()) {
+ ALOGD("Layer: %s had an out of bounds transparent region",
+ layerFE->getDebugName());
+ layerFEState->transparentRegionHint.dump("transparentRegionHint");
+ }
+ transparentRegion.clear();
+ } else {
+ transparentRegion = tr.transform(clippedTransparentRegionHint);
+ }
} else {
// transformation too complex, can't do the
// transparent region optimization.
@@ -1099,6 +1120,10 @@
return;
}
+ if (isPowerHintSessionEnabled()) {
+ // get fence end time to know when gpu is complete in display
+ setHintSessionGpuFence(std::make_unique<FenceTime>(new Fence(dup(optReadyFence->get()))));
+ }
// swap buffers (presentation)
mRenderSurface->queueBuffer(std::move(*optReadyFence));
}
@@ -1218,7 +1243,8 @@
ATRACE_NAME("ClientCompositionCacheHit");
outputCompositionState.reusedClientComposition = true;
setExpensiveRenderingExpected(false);
- return base::unique_fd();
+ // b/239944175 pass the fence associated with the buffer.
+ return base::unique_fd(std::move(fd));
}
ATRACE_NAME("ClientCompositionCacheMiss");
mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
@@ -1403,6 +1429,14 @@
// The base class does nothing with this call.
}
+void Output::setHintSessionGpuFence(std::unique_ptr<FenceTime>&&) {
+ // The base class does nothing with this call.
+}
+
+bool Output::isPowerHintSessionEnabled() {
+ return false;
+}
+
void Output::postFramebuffer() {
ATRACE_CALL();
ALOGV(__FUNCTION__);
@@ -1460,7 +1494,8 @@
void Output::renderCachedSets(const CompositionRefreshArgs& refreshArgs) {
if (mPlanner) {
- mPlanner->renderCachedSets(getState(), refreshArgs.scheduledFrameTime);
+ mPlanner->renderCachedSets(getState(), refreshArgs.scheduledFrameTime,
+ getState().usesDeviceComposition || getSkipColorTransform());
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 641b806..d6f02ee 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -159,7 +159,8 @@
}
void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& texturePool,
- const OutputCompositionState& outputState) {
+ const OutputCompositionState& outputState,
+ bool deviceHandlesColorTransform) {
ATRACE_CALL();
const Rect& viewport = outputState.layerStackSpace.getContent();
const ui::Dataspace& outputDataspace = outputState.dataspace;
@@ -170,6 +171,8 @@
.physicalDisplay = outputState.framebufferSpace.getContent(),
.clip = viewport,
.outputDataspace = outputDataspace,
+ .colorTransform = outputState.colorTransformMatrix,
+ .deviceHandlesColorTransform = deviceHandlesColorTransform,
.orientation = orientation,
.targetLuminanceNits = outputState.displayBrightnessNits,
};
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 1062b70..9175dd0 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -99,7 +99,8 @@
void Flattener::renderCachedSets(
const OutputCompositionState& outputState,
- std::optional<std::chrono::steady_clock::time_point> renderDeadline) {
+ std::optional<std::chrono::steady_clock::time_point> renderDeadline,
+ bool deviceHandlesColorTransform) {
ATRACE_CALL();
if (!mNewCachedSet) {
@@ -136,7 +137,7 @@
}
}
- mNewCachedSet->render(mRenderEngine, mTexturePool, outputState);
+ mNewCachedSet->render(mRenderEngine, mTexturePool, outputState, deviceHandlesColorTransform);
}
void Flattener::dumpLayers(std::string& result) const {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index c8413eb..54133d9 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -201,11 +201,11 @@
finalPlan);
}
-void Planner::renderCachedSets(
- const OutputCompositionState& outputState,
- std::optional<std::chrono::steady_clock::time_point> renderDeadline) {
+void Planner::renderCachedSets(const OutputCompositionState& outputState,
+ std::optional<std::chrono::steady_clock::time_point> renderDeadline,
+ bool deviceHandlesColorTransform) {
ATRACE_CALL();
- mFlattener.renderCachedSets(outputState, renderDeadline);
+ mFlattener.renderCachedSets(outputState, renderDeadline, deviceHandlesColorTransform);
}
void Planner::dump(const Vector<String16>& args, std::string& result) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 0e5a7b6..344fea3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -169,6 +169,7 @@
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mPowerAdvisor, usePowerHintSession()).WillRepeatedly(Return(false));
}
DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 9b12b08..d7704a8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -137,6 +137,7 @@
MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (PhysicalDisplayId), (const, override));
MOCK_METHOD(Hwc2::AidlTransform, getPhysicalDisplayOrientation, (PhysicalDisplayId),
(const, override));
+ MOCK_METHOD(bool, getValidateSkipped, (HalDisplayId), (const, override));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index 50adcfb..c8bd5e4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -38,11 +38,33 @@
MOCK_METHOD(bool, usePowerHintSession, (), (override));
MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
- MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
- MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
- (override));
+ MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDuration), (override));
+ MOCK_METHOD(void, sendActualWorkDuration, (), (override));
+ MOCK_METHOD(void, sendPredictedWorkDuration, (), (override));
MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
+ MOCK_METHOD(void, setGpuFenceTime,
+ (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
+ MOCK_METHOD(void, setHwcValidateTiming,
+ (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime),
+ (override));
+ MOCK_METHOD(void, setHwcPresentTiming,
+ (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime),
+ (override));
+ MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
+ MOCK_METHOD(void, setRequiresClientComposition,
+ (DisplayId displayId, bool requiresClientComposition), (override));
+ MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
+ MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime),
+ (override));
+ MOCK_METHOD(void, setHwcPresentDelayedTime,
+ (DisplayId displayId,
+ std::chrono::steady_clock::time_point earliestFrameStartTime));
+ MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override));
+ MOCK_METHOD(void, setCommitStart, (nsecs_t commitStartTime), (override));
+ MOCK_METHOD(void, setCompositeEnd, (nsecs_t compositeEndtime), (override));
+ MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override));
+ MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (int64_t targetDuration), (override));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 063726b..cf12890 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -1505,6 +1505,8 @@
static const Region kTransparentRegionHint;
static const Region kTransparentRegionHintTwo;
static const Region kTransparentRegionHintTwo90Rotation;
+ static const Region kTransparentRegionHintNegative;
+ static const Region kTransparentRegionHintNegativeIntersectsBounds;
StrictMock<OutputPartialMock> mOutput;
LayerFESet mGeomSnapshots;
@@ -1528,6 +1530,10 @@
Region(Rect(25, 20, 50, 75));
const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHintTwo90Rotation =
Region(Rect(125, 25, 180, 50));
+const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHintNegative =
+ Region(Rect(INT32_MIN, INT32_MIN, INT32_MIN + 100, INT32_MIN + 200));
+const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHintNegativeIntersectsBounds =
+ Region(Rect(INT32_MIN, INT32_MIN, 100, 100));
TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) {
EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
@@ -1997,6 +2003,41 @@
RegionEq(kTransparentRegionHintTwo90Rotation));
}
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, transparentRegionExcludesOutputLayer) {
+ mLayer.layerFEState.isOpaque = false;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerBounds = kFullBoundsNoRotation.bounds().toFloatRect();
+ mLayer.layerFEState.transparentRegionHint = kFullBoundsNoRotation;
+
+ EXPECT_CALL(mOutput, ensureOutputLayer(_, _)).Times(0);
+}
+
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, transparentRegionIgnoredWhenOutsideBounds) {
+ mLayer.layerFEState.isOpaque = false;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.geomLayerBounds = kFullBoundsNoRotation.bounds().toFloatRect();
+ mLayer.layerFEState.transparentRegionHint = kTransparentRegionHintNegative;
+
+ EXPECT_CALL(mOutput, ensureOutputLayer(_, _)).Times(0);
+}
+
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, transparentRegionClipsWhenOutsideBounds) {
+ mLayer.layerFEState.isOpaque = false;
+ mLayer.layerFEState.contentDirty = true;
+ mLayer.layerFEState.compositionType =
+ aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
+ mLayer.layerFEState.transparentRegionHint = kTransparentRegionHintNegativeIntersectsBounds;
+
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
+ EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+ .WillOnce(Return(&mLayer.outputLayer));
+ ensureOutputLayerIfVisible();
+
+ // Check that the blocking region clips an out-of-bounds transparent region.
+ EXPECT_THAT(mLayer.outputLayerState.outputSpaceBlockingRegionHint,
+ RegionEq(kTransparentRegionHint));
+}
+
/*
* Output::present()
*/
@@ -3319,6 +3360,9 @@
MOCK_METHOD2(appendRegionFlashRequests,
void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
+ MOCK_METHOD(void, setHintSessionGpuFence, (std::unique_ptr<FenceTime> && gpuFence),
+ (override));
+ MOCK_METHOD(bool, isPowerHintSessionEnabled, (), (override));
};
OutputComposeSurfacesTest() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 8a99e4e..0e9db36 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -376,7 +376,7 @@
.WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
mOutputState.isSecure = false;
- cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -429,7 +429,7 @@
.WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
mOutputState.isSecure = true;
- cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -477,7 +477,58 @@
.WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
mOutputState.isSecure = true;
- cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
+ expectReadyBuffer(cachedSet);
+
+ EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
+ EXPECT_EQ(Rect(kOutputSize.width, kOutputSize.height), cachedSet.getTextureBounds());
+
+ // Now check that appending a new cached set properly cleans up RenderEngine resources.
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+ cachedSet.append(CachedSet(layer3));
+}
+
+TEST_F(CachedSetTest, renderWhitePointNoColorTransform) {
+ // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
+ // This is a duplicate of the "renderWhitePoint" test, but setting "deviceHandlesColorTransform"
+ // to false, in the render call.
+
+ CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE1 = mTestLayers[1]->layerFE;
+ CachedSet::Layer& layer2 = *mTestLayers[2]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE2 = mTestLayers[2]->layerFE;
+
+ CachedSet cachedSet(layer1);
+ cachedSet.append(CachedSet(layer2));
+
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1;
+ clientCompList1.push_back({});
+
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2;
+ clientCompList2.push_back({});
+
+ mOutputState.displayBrightnessNits = 400.f;
+
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<renderengine::LayerSettings>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+ EXPECT_EQ(mOutputState.displayBrightnessNits, displaySettings.targetLuminanceNits);
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ };
+
+ EXPECT_CALL(*layerFE1,
+ prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq(
+ mOutputState.displayBrightnessNits)))
+ .WillOnce(Return(clientCompList1));
+ EXPECT_CALL(*layerFE2,
+ prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq(
+ mOutputState.displayBrightnessNits)))
+ .WillOnce(Return(clientCompList2));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ mOutputState.isSecure = true;
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState, false);
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -527,7 +578,7 @@
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -767,7 +818,7 @@
};
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
}
TEST_F(CachedSetTest, addHolePunch_noBuffer) {
@@ -829,7 +880,7 @@
};
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
}
TEST_F(CachedSetTest, append_removesHolePunch) {
@@ -969,7 +1020,7 @@
};
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
}
} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 50e3a28..96021ec 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -159,13 +159,13 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// same geometry, update the internal layer stack
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
}
void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) {
@@ -177,7 +177,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -187,7 +187,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
const auto buffer = layers[0]->getOutputLayer()->getState().overrideInfo.buffer;
EXPECT_NE(nullptr, buffer);
@@ -222,7 +222,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
}
TEST_F(FlattenerTest, flattenLayers_ActiveLayersWithLowFpsAreFlattened) {
@@ -284,7 +284,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -389,7 +389,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -428,7 +428,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -437,7 +437,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_NE(nullptr, overrideBuffer2);
@@ -452,7 +452,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_NE(nullptr, overrideBuffer2);
@@ -461,7 +461,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -505,7 +505,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -521,7 +521,7 @@
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
mOutputState.framebufferSpace.setOrientation(ui::ROTATION_90);
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -534,7 +534,7 @@
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
mOutputState.framebufferSpace.setOrientation(ui::ROTATION_180);
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -550,7 +550,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -562,7 +562,7 @@
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
mOutputState.framebufferSpace.setOrientation(ui::ROTATION_270);
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -603,7 +603,7 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -616,7 +616,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -669,7 +669,7 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -682,7 +682,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -743,7 +743,7 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer0);
@@ -753,7 +753,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer0); // got overridden
EXPECT_EQ(nullptr, overrideBuffer1); // did not
@@ -815,7 +815,7 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer0);
@@ -825,7 +825,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer0); // got overridden
EXPECT_EQ(nullptr, overrideBuffer1); // did not
@@ -871,7 +871,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -881,7 +881,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
EXPECT_EQ(nullptr, overrideBuffer3);
@@ -917,7 +917,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -928,7 +928,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
}
@@ -971,7 +971,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -981,7 +981,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, blurOverrideBuffer);
EXPECT_NE(nullptr, overrideBuffer3);
@@ -1020,7 +1020,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
const auto& cachedSet = mFlattener->getNewCachedSetForTesting();
ASSERT_NE(std::nullopt, cachedSet);
@@ -1034,7 +1034,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer2, overrideBuffer1);
EXPECT_EQ(nullptr, blurOverrideBuffer);
@@ -1063,7 +1063,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -1071,12 +1071,12 @@
// Simulate attempting to render prior to merging the new cached set with the layer stack.
// Here we should not try to re-render.
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We provide the override buffer now that it's rendered
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer2, overrideBuffer1);
@@ -1120,7 +1120,8 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
mFlattener->renderCachedSets(mOutputState,
std::chrono::steady_clock::now() -
- (kCachedSetRenderDuration + 10ms));
+ (kCachedSetRenderDuration + 10ms),
+ true);
}
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
@@ -1128,7 +1129,8 @@
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState,
std::chrono::steady_clock::now() -
- (kCachedSetRenderDuration + 10ms));
+ (kCachedSetRenderDuration + 10ms),
+ true);
}
TEST_F(FlattenerTest, flattenLayers_skipsBT601_625) {
@@ -1162,7 +1164,7 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1175,7 +1177,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -1213,7 +1215,7 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1226,7 +1228,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -1264,7 +1266,7 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1277,7 +1279,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -1318,7 +1320,7 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1332,7 +1334,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -1371,7 +1373,7 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1384,7 +1386,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mOutputState, std::nullopt);
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a915b61..26fbd55 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -104,7 +104,7 @@
mCompositionDisplay->getRenderSurface()->initialize();
- setPowerMode(args.initialPowerMode);
+ if (args.initialPowerMode.has_value()) setPowerMode(args.initialPowerMode.value());
// initialize the display orientation transform.
setProjection(ui::ROTATION_0, Rect::INVALID_RECT, Rect::INVALID_RECT);
@@ -173,20 +173,31 @@
}
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
+ if (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON) {
+ if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+ getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+ mBrightness = *mStagedBrightness;
+ }
+ mStagedBrightness = std::nullopt;
+ getCompositionDisplay()->applyDisplayBrightness(true);
+ }
+
mPowerMode = mode;
- getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF);
+
+ getCompositionDisplay()->setCompositionEnabled(mPowerMode.has_value() &&
+ *mPowerMode != hal::PowerMode::OFF);
}
void DisplayDevice::enableLayerCaching(bool enable) {
getCompositionDisplay()->setLayerCachingEnabled(enable);
}
-hal::PowerMode DisplayDevice::getPowerMode() const {
+std::optional<hal::PowerMode> DisplayDevice::getPowerMode() const {
return mPowerMode;
}
bool DisplayDevice::isPoweredOn() const {
- return mPowerMode != hal::PowerMode::OFF;
+ return mPowerMode && *mPowerMode != hal::PowerMode::OFF;
}
void DisplayDevice::setActiveMode(DisplayModeId id) {
@@ -211,6 +222,7 @@
to_string(getId()).c_str());
return BAD_VALUE;
}
+ mNumModeSwitchesInPolicy++;
mUpcomingActiveMode = info;
ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue());
return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(),
@@ -324,8 +336,10 @@
}
void DisplayDevice::persistBrightness(bool needsComposite) {
- if (needsComposite && mStagedBrightness && mBrightness != *mStagedBrightness) {
- getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+ if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+ if (needsComposite) {
+ getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+ }
mBrightness = *mStagedBrightness;
}
mStagedBrightness = std::nullopt;
@@ -372,7 +386,7 @@
}
result += "\n powerMode="s;
- result += to_string(mPowerMode);
+ result += mPowerMode.has_value() ? to_string(mPowerMode.value()) : "OFF(reset)";
result += '\n';
if (mRefreshRateConfigs) {
@@ -537,6 +551,27 @@
mDesiredActiveModeChanged = false;
}
+status_t DisplayDevice::setRefreshRatePolicy(
+ const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
+ const auto oldPolicy = mRefreshRateConfigs->getCurrentPolicy();
+ const status_t setPolicyResult = overridePolicy
+ ? mRefreshRateConfigs->setOverridePolicy(policy)
+ : mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
+
+ if (setPolicyResult == OK) {
+ const int numModeChanges = mNumModeSwitchesInPolicy.exchange(0);
+
+ ALOGI("Display %s policy changed\n"
+ "Previous: {%s}\n"
+ "Current: {%s}\n"
+ "%d mode changes were performed under the previous policy",
+ to_string(getId()).c_str(), oldPolicy.toString().c_str(),
+ policy ? policy->toString().c_str() : "null", numModeChanges);
+ }
+
+ return setPolicyResult;
+}
+
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index d5d87b4..fc24a9c 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -181,7 +181,7 @@
/* ------------------------------------------------------------------------
* Display power mode management.
*/
- hardware::graphics::composer::hal::PowerMode getPowerMode() const;
+ std::optional<hardware::graphics::composer::hal::PowerMode> getPowerMode() const;
void setPowerMode(hardware::graphics::composer::hal::PowerMode mode);
bool isPoweredOn() const;
@@ -249,6 +249,10 @@
nsecs_t getVsyncPeriodFromHWC() const;
nsecs_t getRefreshTimestamp() const;
+ status_t setRefreshRatePolicy(
+ const std::optional<scheduler::RefreshRateConfigs::Policy>& policy,
+ bool overridePolicy);
+
// release HWC resources (if any) for removable displays
void disconnect();
@@ -277,8 +281,8 @@
static ui::Transform::RotationFlags sPrimaryDisplayRotationFlags;
- hardware::graphics::composer::hal::PowerMode mPowerMode =
- hardware::graphics::composer::hal::PowerMode::OFF;
+ // allow initial power mode as null.
+ std::optional<hardware::graphics::composer::hal::PowerMode> mPowerMode;
DisplayModePtr mActiveMode;
std::optional<float> mStagedBrightness = std::nullopt;
float mBrightness = -1.f;
@@ -303,6 +307,8 @@
TracedOrdinal<bool> mDesiredActiveModeChanged
GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
+
+ std::atomic_int mNumModeSwitchesInPolicy = 0;
};
struct DisplayDeviceState {
@@ -360,8 +366,7 @@
HdrCapabilities hdrCapabilities;
int32_t supportedPerFrameMetadata{0};
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
- hardware::graphics::composer::hal::PowerMode initialPowerMode{
- hardware::graphics::composer::hal::PowerMode::ON};
+ std::optional<hardware::graphics::composer::hal::PowerMode> initialPowerMode;
bool isPrimary{false};
DisplayModes supportedModes;
DisplayModeId activeModeId;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0da8ece..a6aee1f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -738,6 +738,13 @@
});
}
+bool HWComposer::getValidateSkipped(HalDisplayId displayId) const {
+ if (mDisplayData.count(displayId) == 0) {
+ return false;
+ }
+ return mDisplayData.at(displayId).validateWasSkipped;
+}
+
status_t HWComposer::setBootDisplayMode(PhysicalDisplayId displayId,
hal::HWConfigId displayModeId) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 4c0ecd8..92a8f30 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -199,6 +199,9 @@
PhysicalDisplayId, float brightness, float brightnessNits,
const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
+ // Get whether the display skipped validation on the latest present
+ virtual bool getValidateSkipped(HalDisplayId displayId) const = 0;
+
// Events handling ---------------------------------------------------------
// Returns stable display ID (and display name on connection of new or previously disconnected
@@ -397,6 +400,8 @@
status_t setActiveColorMode(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent) override;
+ bool getValidateSkipped(HalDisplayId displayId) const override;
+
// Composer 2.4
ui::DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index b5678b4..a0350b7 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -187,7 +187,7 @@
if (!mSupportsPowerHint.has_value()) {
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
- mSupportsPowerHint = halWrapper->supportsPowerHintSession();
+ mSupportsPowerHint = halWrapper && halWrapper->supportsPowerHintSession();
}
return *mSupportsPowerHint;
}
@@ -196,7 +196,7 @@
return mPowerHintSessionRunning;
}
-void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) {
+void PowerAdvisor::setTargetWorkDuration(int64_t targetDuration) {
if (!usePowerHintSession()) {
ALOGV("Power hint session target duration cannot be set, skipping");
return;
@@ -205,26 +205,45 @@
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper != nullptr) {
- halWrapper->setTargetWorkDuration(targetDurationNanos - kTargetSafetyMargin.count());
+ halWrapper->setTargetWorkDuration(targetDuration);
}
}
}
-void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) {
+void PowerAdvisor::sendActualWorkDuration() {
if (!mBootFinished || !usePowerHintSession()) {
ALOGV("Actual work duration power hint cannot be sent, skipping");
return;
}
- {
+ const std::optional<nsecs_t> actualDuration = estimateWorkDuration(false);
+ if (actualDuration.has_value()) {
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper != nullptr) {
- halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos);
+ halWrapper->sendActualWorkDuration(*actualDuration + kTargetSafetyMargin.count(),
+ systemTime());
}
}
}
-// needs to be set after the flag is known but before PowerAdvisor enters onBootFinished
+void PowerAdvisor::sendPredictedWorkDuration() {
+ if (!mBootFinished || !usePowerHintSession()) {
+ ALOGV("Actual work duration power hint cannot be sent, skipping");
+ return;
+ }
+
+ const std::optional<nsecs_t> predictedDuration = estimateWorkDuration(true);
+
+ if (predictedDuration.has_value()) {
+ std::lock_guard lock(mPowerHalMutex);
+ HalWrapper* const halWrapper = getPowerHal();
+ if (halWrapper != nullptr) {
+ halWrapper->sendActualWorkDuration(*predictedDuration + kTargetSafetyMargin.count(),
+ systemTime());
+ }
+ }
+}
+
void PowerAdvisor::enablePowerHint(bool enabled) {
mPowerHintEnabled = enabled;
}
@@ -244,6 +263,302 @@
return mPowerHintSessionRunning;
}
+void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) {
+ DisplayTimingData& displayData = mDisplayTimingData[displayId];
+ if (displayData.gpuEndFenceTime) {
+ nsecs_t signalTime = displayData.gpuEndFenceTime->getSignalTime();
+ if (signalTime != Fence::SIGNAL_TIME_INVALID && signalTime != Fence::SIGNAL_TIME_PENDING) {
+ for (auto&& [_, otherDisplayData] : mDisplayTimingData) {
+ // If the previous display started before us but ended after we should have
+ // started, then it likely delayed our start time and we must compensate for that.
+ // Displays finishing earlier should have already made their way through this call
+ // and swapped their timing into "lastValid" from "latest", so we check that here.
+ if (!otherDisplayData.lastValidGpuStartTime.has_value()) continue;
+ if ((*otherDisplayData.lastValidGpuStartTime < *displayData.gpuStartTime) &&
+ (*otherDisplayData.lastValidGpuEndTime > *displayData.gpuStartTime)) {
+ displayData.lastValidGpuStartTime = *otherDisplayData.lastValidGpuEndTime;
+ break;
+ }
+ }
+ displayData.lastValidGpuStartTime = displayData.gpuStartTime;
+ displayData.lastValidGpuEndTime = signalTime;
+ }
+ }
+ displayData.gpuEndFenceTime = std::move(fenceTime);
+ displayData.gpuStartTime = systemTime();
+}
+
+void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
+ nsecs_t validateEndTime) {
+ DisplayTimingData& displayData = mDisplayTimingData[displayId];
+ displayData.hwcValidateStartTime = validateStartTime;
+ displayData.hwcValidateEndTime = validateEndTime;
+}
+
+void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
+ nsecs_t presentEndTime) {
+ DisplayTimingData& displayData = mDisplayTimingData[displayId];
+ displayData.hwcPresentStartTime = presentStartTime;
+ displayData.hwcPresentEndTime = presentEndTime;
+}
+
+void PowerAdvisor::setSkippedValidate(DisplayId displayId, bool skipped) {
+ mDisplayTimingData[displayId].skippedValidate = skipped;
+}
+
+void PowerAdvisor::setRequiresClientComposition(DisplayId displayId,
+ bool requiresClientComposition) {
+ mDisplayTimingData[displayId].usedClientComposition = requiresClientComposition;
+}
+
+void PowerAdvisor::setExpectedPresentTime(nsecs_t expectedPresentTime) {
+ mExpectedPresentTimes.append(expectedPresentTime);
+}
+
+void PowerAdvisor::setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) {
+ mLastSfPresentEndTime = presentEndTime;
+ mLastPresentFenceTime = presentFenceTime;
+}
+
+void PowerAdvisor::setFrameDelay(nsecs_t frameDelayDuration) {
+ mFrameDelayDuration = frameDelayDuration;
+}
+
+void PowerAdvisor::setHwcPresentDelayedTime(
+ DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) {
+ mDisplayTimingData[displayId].hwcPresentDelayedTime =
+ (earliestFrameStartTime - std::chrono::steady_clock::now()).count() + systemTime();
+}
+
+void PowerAdvisor::setCommitStart(nsecs_t commitStartTime) {
+ mCommitStartTimes.append(commitStartTime);
+}
+
+void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) {
+ mLastPostcompDuration = compositeEnd - mLastSfPresentEndTime;
+}
+
+void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) {
+ mDisplayIds = displayIds;
+}
+
+void PowerAdvisor::setTotalFrameTargetWorkDuration(nsecs_t targetDuration) {
+ mTotalFrameTargetDuration = targetDuration;
+}
+
+std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds(
+ std::optional<nsecs_t> DisplayTimingData::*sortBy) {
+ std::vector<DisplayId> sortedDisplays;
+ std::copy_if(mDisplayIds.begin(), mDisplayIds.end(), std::back_inserter(sortedDisplays),
+ [&](DisplayId id) {
+ return mDisplayTimingData.count(id) &&
+ (mDisplayTimingData[id].*sortBy).has_value();
+ });
+ std::sort(sortedDisplays.begin(), sortedDisplays.end(), [&](DisplayId idA, DisplayId idB) {
+ return *(mDisplayTimingData[idA].*sortBy) < *(mDisplayTimingData[idB].*sortBy);
+ });
+ return sortedDisplays;
+}
+
+std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) {
+ if (earlyHint && (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull())) {
+ return std::nullopt;
+ }
+
+ // Tracks when we finish presenting to hwc
+ nsecs_t estimatedEndTime = mCommitStartTimes[0];
+
+ // How long we spent this frame not doing anything, waiting for fences or vsync
+ nsecs_t idleDuration = 0;
+
+ // Most recent previous gpu end time in the current frame, probably from a prior display, used
+ // as the start time for the next gpu operation if it ran over time since it probably blocked
+ std::optional<nsecs_t> previousValidGpuEndTime;
+
+ // The currently estimated gpu end time for the frame,
+ // used to accumulate gpu time as we iterate over the active displays
+ std::optional<nsecs_t> estimatedGpuEndTime;
+
+ // If we're predicting at the start of the frame, we use last frame as our reference point
+ // If we're predicting at the end of the frame, we use the current frame as a reference point
+ nsecs_t referenceFrameStartTime = (earlyHint ? mCommitStartTimes[-1] : mCommitStartTimes[0]);
+
+ // When the prior frame should be presenting to the display
+ // If we're predicting at the start of the frame, we use last frame's expected present time
+ // If we're predicting at the end of the frame, the present fence time is already known
+ nsecs_t lastFramePresentTime = (earlyHint ? mExpectedPresentTimes[-1] : mLastPresentFenceTime);
+
+ // The timing info for the previously calculated display, if there was one
+ std::optional<DisplayTimeline> previousDisplayReferenceTiming;
+ std::vector<DisplayId>&& displayIds =
+ getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime);
+ DisplayTimeline referenceTiming, estimatedTiming;
+
+ // Iterate over the displays that use hwc in the same order they are presented
+ for (DisplayId displayId : displayIds) {
+ if (mDisplayTimingData.count(displayId) == 0) {
+ continue;
+ }
+
+ auto& displayData = mDisplayTimingData.at(displayId);
+
+ // mLastPresentFenceTime should always be the time of the reference frame, since it will be
+ // the previous frame's present fence if called at the start, and current frame's if called
+ // at the end
+ referenceTiming = displayData.calculateDisplayTimeline(mLastPresentFenceTime);
+
+ // If this is the first display, include the duration before hwc present starts
+ if (!previousDisplayReferenceTiming.has_value()) {
+ estimatedEndTime += referenceTiming.hwcPresentStartTime - referenceFrameStartTime;
+ } else { // Otherwise add the time since last display's hwc present finished
+ estimatedEndTime += referenceTiming.hwcPresentStartTime -
+ previousDisplayReferenceTiming->hwcPresentEndTime;
+ }
+
+ // Late hint can re-use reference timing here since it's estimating its own reference frame
+ estimatedTiming = earlyHint
+ ? referenceTiming.estimateTimelineFromReference(lastFramePresentTime,
+ estimatedEndTime)
+ : referenceTiming;
+
+ // Update predicted present finish time with this display's present time
+ estimatedEndTime = estimatedTiming.hwcPresentEndTime;
+
+ // Track how long we spent waiting for the fence, can be excluded from the timing estimate
+ idleDuration += estimatedTiming.probablyWaitsForPresentFence
+ ? lastFramePresentTime - estimatedTiming.presentFenceWaitStartTime
+ : 0;
+
+ // Track how long we spent waiting to present, can be excluded from the timing estimate
+ idleDuration += earlyHint ? 0 : referenceTiming.hwcPresentDelayDuration;
+
+ // Estimate the reference frame's gpu timing
+ auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime);
+ if (gpuTiming.has_value()) {
+ previousValidGpuEndTime = gpuTiming->startTime + gpuTiming->duration;
+
+ // Estimate the prediction frame's gpu end time from the reference frame
+ estimatedGpuEndTime =
+ std::max(estimatedTiming.hwcPresentStartTime, estimatedGpuEndTime.value_or(0)) +
+ gpuTiming->duration;
+ }
+ previousDisplayReferenceTiming = referenceTiming;
+ }
+ ATRACE_INT64("Idle duration", idleDuration);
+
+ nsecs_t estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime;
+
+ // Don't count time spent idly waiting in the estimate as we could do more work in that time
+ estimatedEndTime -= idleDuration;
+ estimatedFlingerEndTime -= idleDuration;
+
+ // We finish the frame when both present and the gpu are done, so wait for the later of the two
+ // Also add the frame delay duration since the target did not move while we were delayed
+ nsecs_t totalDuration = mFrameDelayDuration +
+ std::max(estimatedEndTime, estimatedGpuEndTime.value_or(0)) - mCommitStartTimes[0];
+
+ // We finish SurfaceFlinger when post-composition finishes, so add that in here
+ nsecs_t flingerDuration =
+ estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0];
+
+ // Combine the two timings into a single normalized one
+ nsecs_t combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);
+
+ return std::make_optional(combinedDuration);
+}
+
+nsecs_t PowerAdvisor::combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration) {
+ nsecs_t targetDuration;
+ {
+ std::lock_guard lock(mPowerHalMutex);
+ targetDuration = *getPowerHal()->getTargetWorkDuration();
+ }
+ if (!mTotalFrameTargetDuration.has_value()) return flingerDuration;
+
+ // Normalize total to the flinger target (vsync period) since that's how often we actually send
+ // hints
+ nsecs_t normalizedTotalDuration = (targetDuration * totalDuration) / *mTotalFrameTargetDuration;
+ return std::max(flingerDuration, normalizedTotalDuration);
+}
+
+PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference(
+ nsecs_t fenceTime, nsecs_t displayStartTime) {
+ DisplayTimeline estimated;
+ estimated.hwcPresentStartTime = displayStartTime;
+
+ // We don't predict waiting for vsync alignment yet
+ estimated.hwcPresentDelayDuration = 0;
+
+ // How long we expect to run before we start waiting for the fence
+ // For now just re-use last frame's post-present duration and assume it will not change much
+ // Excludes time spent waiting for vsync since that's not going to be consistent
+ estimated.presentFenceWaitStartTime = estimated.hwcPresentStartTime +
+ (presentFenceWaitStartTime - (hwcPresentStartTime + hwcPresentDelayDuration));
+ estimated.probablyWaitsForPresentFence = fenceTime > estimated.presentFenceWaitStartTime;
+ estimated.hwcPresentEndTime = postPresentFenceHwcPresentDuration +
+ (estimated.probablyWaitsForPresentFence ? fenceTime
+ : estimated.presentFenceWaitStartTime);
+ return estimated;
+}
+
+PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline(
+ nsecs_t fenceTime) {
+ DisplayTimeline timeline;
+ // How long between calling hwc present and trying to wait on the fence
+ const nsecs_t fenceWaitStartDelay =
+ (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated)
+ .count();
+
+ // Did our reference frame wait for an appropriate vsync before calling into hwc
+ const bool waitedOnHwcPresentTime = hwcPresentDelayedTime.has_value() &&
+ *hwcPresentDelayedTime > *hwcPresentStartTime &&
+ *hwcPresentDelayedTime < *hwcPresentEndTime;
+
+ // Use validate start here if we skipped it because we did validate + present together
+ timeline.hwcPresentStartTime = skippedValidate ? *hwcValidateStartTime : *hwcPresentStartTime;
+
+ // Use validate end here if we skipped it because we did validate + present together
+ timeline.hwcPresentEndTime = skippedValidate ? *hwcValidateEndTime : *hwcPresentEndTime;
+
+ // How long hwc present was delayed waiting for the next appropriate vsync
+ timeline.hwcPresentDelayDuration =
+ (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0);
+ // When we started waiting for the present fence after calling into hwc present
+ timeline.presentFenceWaitStartTime =
+ timeline.hwcPresentStartTime + timeline.hwcPresentDelayDuration + fenceWaitStartDelay;
+ timeline.probablyWaitsForPresentFence = fenceTime > timeline.presentFenceWaitStartTime &&
+ fenceTime < timeline.hwcPresentEndTime;
+
+ // How long we ran after we finished waiting for the fence but before hwc present finished
+ timeline.postPresentFenceHwcPresentDuration = timeline.hwcPresentEndTime -
+ (timeline.probablyWaitsForPresentFence ? fenceTime
+ : timeline.presentFenceWaitStartTime);
+ return timeline;
+}
+
+std::optional<PowerAdvisor::GpuTimeline> PowerAdvisor::DisplayTimingData::estimateGpuTiming(
+ std::optional<nsecs_t> previousEnd) {
+ if (!(usedClientComposition && lastValidGpuStartTime.has_value() && gpuEndFenceTime)) {
+ return std::nullopt;
+ }
+ const nsecs_t latestGpuStartTime = std::max(previousEnd.value_or(0), *gpuStartTime);
+ const nsecs_t latestGpuEndTime = gpuEndFenceTime->getSignalTime();
+ nsecs_t gpuDuration = 0;
+ if (latestGpuEndTime != Fence::SIGNAL_TIME_INVALID &&
+ latestGpuEndTime != Fence::SIGNAL_TIME_PENDING) {
+ // If we know how long the most recent gpu duration was, use that
+ gpuDuration = latestGpuEndTime - latestGpuStartTime;
+ } else if (lastValidGpuEndTime.has_value()) {
+ // If we don't have the fence data, use the most recent information we do have
+ gpuDuration = *lastValidGpuEndTime - *lastValidGpuStartTime;
+ if (latestGpuEndTime == Fence::SIGNAL_TIME_PENDING) {
+ // If pending but went over the previous duration, use current time as the end
+ gpuDuration = std::max(gpuDuration, systemTime() - latestGpuStartTime);
+ }
+ }
+ return GpuTimeline{.duration = gpuDuration, .startTime = latestGpuStartTime};
+}
+
class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
public:
HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
@@ -325,6 +640,9 @@
}
mSupportsPowerHint = checkPowerHintSessionSupported();
+
+ // Currently set to 0 to disable rate limiter by default
+ mAllowedActualDeviation = base::GetIntProperty<nsecs_t>("debug.sf.allowed_actual_deviation", 0);
}
AidlPowerHalWrapper::~AidlPowerHalWrapper() {
@@ -332,7 +650,7 @@
mPowerHintSession->close();
mPowerHintSession = nullptr;
}
-};
+}
std::unique_ptr<PowerAdvisor::HalWrapper> AidlPowerHalWrapper::connect() {
// This only waits if the service is actually declared
@@ -370,7 +688,7 @@
return ret.isOk();
}
-// only version 2+ of the aidl supports power hint sessions, hidl has no support
+// Only version 2+ of the aidl supports power hint sessions, hidl has no support
bool AidlPowerHalWrapper::supportsPowerHintSession() {
return mSupportsPowerHint;
}
@@ -424,30 +742,14 @@
return isPowerHintSessionRunning();
}
-bool AidlPowerHalWrapper::shouldSetTargetDuration(int64_t targetDurationNanos) {
- if (targetDurationNanos <= 0) {
- return false;
- }
- // report if the change in target from our last submission to now exceeds the threshold
- return abs(1.0 -
- static_cast<double>(mLastTargetDurationSent) /
- static_cast<double>(targetDurationNanos)) >= kAllowedTargetDeviationPercent;
-}
-
-void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDurationNanos) {
+void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDuration) {
ATRACE_CALL();
- mTargetDuration = targetDurationNanos;
- if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
- if (!sNormalizeTarget && isPowerHintSessionRunning() &&
- shouldSetTargetDuration(targetDurationNanos)) {
- if (mLastActualDurationSent.has_value()) {
- // update the error term here since we are actually sending an update to powerhal
- if (sTraceHintSessionData)
- ATRACE_INT64("Target error term", targetDurationNanos - *mLastActualDurationSent);
- }
- ALOGV("Sending target time: %" PRId64 "ns", targetDurationNanos);
- mLastTargetDurationSent = targetDurationNanos;
- auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
+ mTargetDuration = targetDuration;
+ if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration);
+ if (isPowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) {
+ ALOGV("Sending target time: %" PRId64 "ns", targetDuration);
+ mLastTargetDurationSent = targetDuration;
+ auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration);
if (!ret.isOk()) {
ALOGW("Failed to set power hint target work duration with error: %s",
ret.exceptionMessage().c_str());
@@ -456,8 +758,8 @@
}
}
-bool AidlPowerHalWrapper::shouldReportActualDurationsNow() {
- // report if we have never reported before or are approaching a stale session
+bool AidlPowerHalWrapper::shouldReportActualDurations() {
+ // Report if we have never reported before or are approaching a stale session
if (!mLastActualDurationSent.has_value() ||
(systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
return true;
@@ -466,65 +768,42 @@
if (!mActualDuration.has_value()) {
return false;
}
-
- // duration of most recent timing
- const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
- // duration of the last timing actually reported to the powerhal
- const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
-
- // report if the change in duration from then to now exceeds the threshold
- return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
- kAllowedActualDeviationPercent;
+ // Report if the change in actual duration exceeds the threshold
+ return abs(*mActualDuration - *mLastActualDurationSent) > mAllowedActualDeviation;
}
-void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDurationNanos,
- nsecs_t timeStampNanos) {
+void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDuration, nsecs_t timestamp) {
ATRACE_CALL();
- if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
+ if (actualDuration < 0 || !isPowerHintSessionRunning()) {
ALOGV("Failed to send actual work duration, skipping");
return;
}
- nsecs_t reportedDuration = actualDurationNanos;
+ const nsecs_t reportedDuration = actualDuration;
- // normalize the sent values to a pre-set target
- if (sNormalizeTarget) {
- reportedDuration += mLastTargetDurationSent - mTargetDuration;
- } else {
- // when target duration change is within deviation and not updated, adjust the actual
- // duration proportionally based on the difference, e.g. if new target is 5ms longer than
- // last reported but actual duration is the same as last target, we want to report a smaller
- // actual work duration now to indicate that we are overshooting
- if (mLastTargetDurationSent != kDefaultTarget.count() && mTargetDuration != 0) {
- reportedDuration =
- static_cast<int64_t>(static_cast<long double>(mLastTargetDurationSent) /
- mTargetDuration * actualDurationNanos);
- mActualDuration = reportedDuration;
- }
- }
mActualDuration = reportedDuration;
WorkDuration duration;
duration.durationNanos = reportedDuration;
- duration.timeStampNanos = timeStampNanos;
+ duration.timeStampNanos = timestamp;
mPowerHintQueue.push_back(duration);
if (sTraceHintSessionData) {
- ATRACE_INT64("Measured duration", actualDurationNanos);
- ATRACE_INT64("Target error term", mTargetDuration - actualDurationNanos);
+ ATRACE_INT64("Measured duration", actualDuration);
+ ATRACE_INT64("Target error term", actualDuration - mTargetDuration);
ATRACE_INT64("Reported duration", reportedDuration);
ATRACE_INT64("Reported target", mLastTargetDurationSent);
- ATRACE_INT64("Reported target error term", mLastTargetDurationSent - reportedDuration);
+ ATRACE_INT64("Reported target error term", reportedDuration - mLastTargetDurationSent);
}
ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
" with error: %" PRId64,
- reportedDuration, mLastTargetDurationSent, mLastTargetDurationSent - reportedDuration);
+ reportedDuration, mLastTargetDurationSent, reportedDuration - mLastTargetDurationSent);
// This rate limiter queues similar duration reports to the powerhal into
// batches to avoid excessive binder calls. The criteria to send a given batch
// are outlined in shouldReportActualDurationsNow()
- if (shouldReportActualDurationsNow()) {
+ if (shouldReportActualDurations()) {
ALOGV("Sending hint update batch");
mLastActualReportTimestamp = systemTime();
auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
@@ -534,8 +813,8 @@
mShouldReconnectHal = true;
}
mPowerHintQueue.clear();
- // we save the non-normalized value here to detect % changes
- mLastActualDurationSent = reportedDuration;
+ // We save the actual duration here for rate limiting
+ mLastActualDurationSent = actualDuration;
}
}
@@ -551,76 +830,73 @@
return mTargetDuration;
}
+void AidlPowerHalWrapper::setAllowedActualDeviation(nsecs_t allowedDeviation) {
+ mAllowedActualDeviation = allowedDeviation;
+}
+
const bool AidlPowerHalWrapper::sTraceHintSessionData =
base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
-const bool AidlPowerHalWrapper::sNormalizeTarget =
- base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), false);
-
PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
- static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
- static bool sHasHal = true;
-
- if (!sHasHal) {
+ if (!mHasHal) {
return nullptr;
}
- // grab old hint session values before we destroy any existing wrapper
+ // Grab old hint session values before we destroy any existing wrapper
std::vector<int32_t> oldPowerHintSessionThreadIds;
std::optional<int64_t> oldTargetWorkDuration;
- if (sHalWrapper != nullptr) {
- oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds();
- oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration();
+ if (mHalWrapper != nullptr) {
+ oldPowerHintSessionThreadIds = mHalWrapper->getPowerHintSessionThreadIds();
+ oldTargetWorkDuration = mHalWrapper->getTargetWorkDuration();
}
// If we used to have a HAL, but it stopped responding, attempt to reconnect
if (mReconnectPowerHal) {
- sHalWrapper = nullptr;
+ mHalWrapper = nullptr;
mReconnectPowerHal = false;
}
- if (sHalWrapper != nullptr) {
- auto wrapper = sHalWrapper.get();
- // if the wrapper is fine, return it, but if it indicates a reconnect, remake it
+ if (mHalWrapper != nullptr) {
+ auto wrapper = mHalWrapper.get();
+ // If the wrapper is fine, return it, but if it indicates a reconnect, remake it
if (!wrapper->shouldReconnectHAL()) {
return wrapper;
}
ALOGD("Reconnecting Power HAL");
- sHalWrapper = nullptr;
+ mHalWrapper = nullptr;
}
- // at this point, we know for sure there is no running session
+ // At this point, we know for sure there is no running session
mPowerHintSessionRunning = false;
// First attempt to connect to the AIDL Power HAL
- sHalWrapper = AidlPowerHalWrapper::connect();
+ mHalWrapper = AidlPowerHalWrapper::connect();
// If that didn't succeed, attempt to connect to the HIDL Power HAL
- if (sHalWrapper == nullptr) {
- sHalWrapper = HidlPowerHalWrapper::connect();
+ if (mHalWrapper == nullptr) {
+ mHalWrapper = HidlPowerHalWrapper::connect();
} else {
ALOGD("Successfully connecting AIDL Power HAL");
- // if AIDL, pass on any existing hint session values
- // thread ids always safe to set
- sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
- // only set duration and start if duration is defined
+ // If AIDL, pass on any existing hint session values
+ mHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
+ // Only set duration and start if duration is defined
if (oldTargetWorkDuration.has_value()) {
- sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
- // only start if possible to run and both threadids and duration are defined
+ mHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
+ // Only start if possible to run and both threadids and duration are defined
if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
- mPowerHintSessionRunning = sHalWrapper->startPowerHintSession();
+ mPowerHintSessionRunning = mHalWrapper->startPowerHintSession();
}
}
}
// If we make it to this point and still don't have a HAL, it's unlikely we
// will, so stop trying
- if (sHalWrapper == nullptr) {
- sHasHal = false;
+ if (mHalWrapper == nullptr) {
+ mHasHal = false;
}
- return sHalWrapper.get();
+ return mHalWrapper.get();
}
} // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 7c10e19..6e25f78 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -18,11 +18,15 @@
#include <atomic>
#include <chrono>
+#include <unordered_map>
#include <unordered_set>
+#include <ui/DisplayId.h>
+#include <ui/FenceTime.h>
#include <utils/Mutex.h>
#include <android/hardware/power/IPower.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <ui/DisplayIdentification.h>
#include "../Scheduler/OneShotTimer.h"
@@ -44,13 +48,50 @@
virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
virtual bool isUsingExpensiveRendering() = 0;
virtual void notifyDisplayUpdateImminent() = 0;
+ // Checks both if it supports and if it's enabled
virtual bool usePowerHintSession() = 0;
virtual bool supportsPowerHintSession() = 0;
virtual bool isPowerHintSessionRunning() = 0;
- virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0;
- virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) = 0;
+ // Sends a power hint that updates to the target work duration for the frame
+ virtual void setTargetWorkDuration(nsecs_t targetDuration) = 0;
+ // Sends a power hint for the actual known work duration at the end of the frame
+ virtual void sendActualWorkDuration() = 0;
+ // Sends a power hint for the upcoming frame predicted from previous frame timing
+ virtual void sendPredictedWorkDuration() = 0;
+ // Sets whether the power hint session is enabled
virtual void enablePowerHint(bool enabled) = 0;
+ // Initializes the power hint session
virtual bool startPowerHintSession(const std::vector<int32_t>& threadIds) = 0;
+ // Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time
+ virtual void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) = 0;
+ // Reports the start and end times of a hwc validate call this frame for a given display
+ virtual void setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
+ nsecs_t validateEndTime) = 0;
+ // Reports the start and end times of a hwc present call this frame for a given display
+ virtual void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
+ nsecs_t presentEndTime) = 0;
+ // Reports the expected time that the current frame will present to the display
+ virtual void setExpectedPresentTime(nsecs_t expectedPresentTime) = 0;
+ // Reports the most recent present fence time and end time once known
+ virtual void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) = 0;
+ // Reports whether a display used client composition this frame
+ virtual void setRequiresClientComposition(DisplayId displayId,
+ bool requiresClientComposition) = 0;
+ // Reports whether a given display skipped validation this frame
+ virtual void setSkippedValidate(DisplayId displayId, bool skipped) = 0;
+ // Reports when a hwc present is delayed, and the time that it will resume
+ virtual void setHwcPresentDelayedTime(
+ DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) = 0;
+ // Reports the start delay for SurfaceFlinger this frame
+ virtual void setFrameDelay(nsecs_t frameDelayDuration) = 0;
+ // Reports the SurfaceFlinger commit start time this frame
+ virtual void setCommitStart(nsecs_t commitStartTime) = 0;
+ // Reports the SurfaceFlinger composite end time this frame
+ virtual void setCompositeEnd(nsecs_t compositeEndTime) = 0;
+ // Reports the list of the currently active displays
+ virtual void setDisplays(std::vector<DisplayId>& displayIds) = 0;
+ // Sets the target duration for the entire pipeline including the gpu
+ virtual void setTotalFrameTargetWorkDuration(nsecs_t targetDuration) = 0;
};
namespace impl {
@@ -70,12 +111,11 @@
virtual void restartPowerHintSession() = 0;
virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0;
virtual bool startPowerHintSession() = 0;
- virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0;
- virtual void sendActualWorkDuration(int64_t actualDurationNanos,
- nsecs_t timeStampNanos) = 0;
+ virtual void setTargetWorkDuration(nsecs_t targetDuration) = 0;
+ virtual void sendActualWorkDuration(nsecs_t actualDuration, nsecs_t timestamp) = 0;
virtual bool shouldReconnectHAL() = 0;
virtual std::vector<int32_t> getPowerHintSessionThreadIds() = 0;
- virtual std::optional<int64_t> getTargetWorkDuration() = 0;
+ virtual std::optional<nsecs_t> getTargetWorkDuration() = 0;
};
PowerAdvisor(SurfaceFlinger& flinger);
@@ -89,26 +129,43 @@
bool usePowerHintSession() override;
bool supportsPowerHintSession() override;
bool isPowerHintSessionRunning() override;
- void setTargetWorkDuration(int64_t targetDurationNanos) override;
- void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) override;
+ void setTargetWorkDuration(nsecs_t targetDuration) override;
+ void sendActualWorkDuration() override;
+ void sendPredictedWorkDuration() override;
void enablePowerHint(bool enabled) override;
bool startPowerHintSession(const std::vector<int32_t>& threadIds) override;
+ void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime);
+ void setHwcValidateTiming(DisplayId displayId, nsecs_t valiateStartTime,
+ nsecs_t validateEndTime) override;
+ void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
+ nsecs_t presentEndTime) override;
+ void setSkippedValidate(DisplayId displayId, bool skipped) override;
+ void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) override;
+ void setExpectedPresentTime(nsecs_t expectedPresentTime) override;
+ void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) override;
+ void setHwcPresentDelayedTime(
+ DisplayId displayId,
+ std::chrono::steady_clock::time_point earliestFrameStartTime) override;
+
+ void setFrameDelay(nsecs_t frameDelayDuration) override;
+ void setCommitStart(nsecs_t commitStartTime) override;
+ void setCompositeEnd(nsecs_t compositeEndTime) override;
+ void setDisplays(std::vector<DisplayId>& displayIds) override;
+ void setTotalFrameTargetWorkDuration(nsecs_t targetDuration) override;
private:
+ friend class PowerAdvisorTest;
+
+ // Tracks if powerhal exists
+ bool mHasHal = true;
+ // Holds the hal wrapper for getPowerHal
+ std::unique_ptr<HalWrapper> mHalWrapper GUARDED_BY(mPowerHalMutex) = nullptr;
+
HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
bool mReconnectPowerHal GUARDED_BY(mPowerHalMutex) = false;
std::mutex mPowerHalMutex;
std::atomic_bool mBootFinished = false;
- std::optional<bool> mPowerHintEnabled;
- std::optional<bool> mSupportsPowerHint;
- bool mPowerHintSessionRunning = false;
-
- // An adjustable safety margin which moves the "target" earlier to allow flinger to
- // go a bit over without dropping a frame, especially since we can't measure
- // the exact time HWC finishes composition so "actual" durations are measured
- // from the end of present() instead, which is a bit later.
- static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 2ms;
std::unordered_set<DisplayId> mExpensiveDisplays;
bool mNotifiedExpensiveRendering = false;
@@ -117,6 +174,110 @@
std::atomic_bool mSendUpdateImminent = true;
std::atomic<nsecs_t> mLastScreenUpdatedTime = 0;
std::optional<scheduler::OneShotTimer> mScreenUpdateTimer;
+
+ // Higher-level timing data used for estimation
+ struct DisplayTimeline {
+ // The start of hwc present, or the start of validate if it happened there instead
+ nsecs_t hwcPresentStartTime = -1;
+ // The end of hwc present or validate, whichever one actually presented
+ nsecs_t hwcPresentEndTime = -1;
+ // How long the actual hwc present was delayed after hwcPresentStartTime
+ nsecs_t hwcPresentDelayDuration = 0;
+ // When we think we started waiting for the present fence after calling into hwc present and
+ // after potentially waiting for the earliest present time
+ nsecs_t presentFenceWaitStartTime = -1;
+ // How long we ran after we finished waiting for the fence but before hwc present finished
+ nsecs_t postPresentFenceHwcPresentDuration = 0;
+ // Are we likely to have waited for the present fence during composition
+ bool probablyWaitsForPresentFence = false;
+ // Estimate one frame's timeline from that of a previous frame
+ DisplayTimeline estimateTimelineFromReference(nsecs_t fenceTime, nsecs_t displayStartTime);
+ };
+
+ struct GpuTimeline {
+ nsecs_t duration = 0;
+ nsecs_t startTime = -1;
+ };
+
+ // Power hint session data recorded from the pipeline
+ struct DisplayTimingData {
+ std::unique_ptr<FenceTime> gpuEndFenceTime;
+ std::optional<nsecs_t> gpuStartTime;
+ std::optional<nsecs_t> lastValidGpuEndTime;
+ std::optional<nsecs_t> lastValidGpuStartTime;
+ std::optional<nsecs_t> hwcPresentStartTime;
+ std::optional<nsecs_t> hwcPresentEndTime;
+ std::optional<nsecs_t> hwcValidateStartTime;
+ std::optional<nsecs_t> hwcValidateEndTime;
+ std::optional<nsecs_t> hwcPresentDelayedTime;
+ bool usedClientComposition = false;
+ bool skippedValidate = false;
+ // Calculate high-level timing milestones from more granular display timing data
+ DisplayTimeline calculateDisplayTimeline(nsecs_t fenceTime);
+ // Estimate the gpu duration for a given display from previous gpu timing data
+ std::optional<GpuTimeline> estimateGpuTiming(std::optional<nsecs_t> previousEnd);
+ };
+
+ template <class T, size_t N>
+ class RingBuffer {
+ std::array<T, N> elements = {};
+ size_t mIndex = 0;
+ size_t numElements = 0;
+
+ public:
+ void append(T item) {
+ mIndex = (mIndex + 1) % N;
+ numElements = std::min(N, numElements + 1);
+ elements[mIndex] = item;
+ }
+ bool isFull() const { return numElements == N; }
+ // Allows access like [0] == current, [-1] = previous, etc..
+ T& operator[](int offset) {
+ size_t positiveOffset =
+ static_cast<size_t>((offset % static_cast<int>(N)) + static_cast<int>(N));
+ return elements[(mIndex + positiveOffset) % N];
+ }
+ };
+
+ // Filter and sort the display ids by a given property
+ std::vector<DisplayId> getOrderedDisplayIds(std::optional<nsecs_t> DisplayTimingData::*sortBy);
+ // Estimates a frame's total work duration including gpu time.
+ // Runs either at the beginning or end of a frame, using the most recent data available
+ std::optional<nsecs_t> estimateWorkDuration(bool earlyHint);
+ // There are two different targets and actual work durations we care about,
+ // this normalizes them together and takes the max of the two
+ nsecs_t combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration);
+
+ std::unordered_map<DisplayId, DisplayTimingData> mDisplayTimingData;
+
+ // Current frame's delay
+ nsecs_t mFrameDelayDuration = 0;
+ // Last frame's post-composition duration
+ nsecs_t mLastPostcompDuration = 0;
+ // Buffer of recent commit start times
+ RingBuffer<nsecs_t, 2> mCommitStartTimes;
+ // Buffer of recent expected present times
+ RingBuffer<nsecs_t, 2> mExpectedPresentTimes;
+ // Most recent present fence time, set at the end of the frame once known
+ nsecs_t mLastPresentFenceTime = -1;
+ // Most recent present fence time, set at the end of the frame once known
+ nsecs_t mLastSfPresentEndTime = -1;
+ // Target for the entire pipeline including gpu
+ std::optional<nsecs_t> mTotalFrameTargetDuration;
+ // Updated list of display IDs
+ std::vector<DisplayId> mDisplayIds;
+
+ std::optional<bool> mPowerHintEnabled;
+ std::optional<bool> mSupportsPowerHint;
+ bool mPowerHintSessionRunning = false;
+
+ // An adjustable safety margin which pads the "actual" value sent to PowerHAL,
+ // encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error
+ static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 1ms;
+
+ // How long we expect hwc to run after the present call until it waits for the fence
+ static constexpr const std::chrono::nanoseconds kFenceWaitStartDelayValidated = 150us;
+ static constexpr const std::chrono::nanoseconds kFenceWaitStartDelaySkippedValidate = 250us;
};
class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
@@ -133,50 +294,50 @@
void restartPowerHintSession() override;
void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
bool startPowerHintSession() override;
- void setTargetWorkDuration(int64_t targetDurationNanos) override;
- void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override;
+ void setTargetWorkDuration(nsecs_t targetDuration) override;
+ void sendActualWorkDuration(nsecs_t actualDuration, nsecs_t timestamp) override;
bool shouldReconnectHAL() override;
std::vector<int32_t> getPowerHintSessionThreadIds() override;
- std::optional<int64_t> getTargetWorkDuration() override;
+ std::optional<nsecs_t> getTargetWorkDuration() override;
private:
+ friend class AidlPowerHalWrapperTest;
+
bool checkPowerHintSessionSupported();
void closePowerHintSession();
- bool shouldReportActualDurationsNow();
- bool shouldSetTargetDuration(int64_t targetDurationNanos);
+ bool shouldReportActualDurations();
+
+ // Used for testing
+ void setAllowedActualDeviation(nsecs_t);
const sp<hardware::power::IPower> mPowerHal = nullptr;
bool mHasExpensiveRendering = false;
bool mHasDisplayUpdateImminent = false;
// Used to indicate an error state and need for reconstruction
bool mShouldReconnectHal = false;
- // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
+
+ // Power hint session data
+
+ // Concurrent access for this is protected by mPowerHalMutex
sp<hardware::power::IPowerHintSession> mPowerHintSession = nullptr;
// Queue of actual durations saved to report
std::vector<hardware::power::WorkDuration> mPowerHintQueue;
- // The latest un-normalized values we have received for target and actual
- int64_t mTargetDuration = kDefaultTarget.count();
- std::optional<int64_t> mActualDuration;
+ // The latest values we have received for target and actual
+ nsecs_t mTargetDuration = kDefaultTarget.count();
+ std::optional<nsecs_t> mActualDuration;
// The list of thread ids, stored so we can restart the session from this class if needed
std::vector<int32_t> mPowerHintThreadIds;
- bool mSupportsPowerHint;
+ bool mSupportsPowerHint = false;
// Keep track of the last messages sent for rate limiter change detection
- std::optional<int64_t> mLastActualDurationSent;
- // timestamp of the last report we sent, used to avoid stale sessions
- int64_t mLastActualReportTimestamp = 0;
- int64_t mLastTargetDurationSent = kDefaultTarget.count();
- // Whether to normalize all the actual values as error terms relative to a constant target
- // This saves a binder call by not setting the target, and should not affect the pid values
- static const bool sNormalizeTarget;
+ std::optional<nsecs_t> mLastActualDurationSent;
+ // Timestamp of the last report we sent, used to avoid stale sessions
+ nsecs_t mLastActualReportTimestamp = 0;
+ nsecs_t mLastTargetDurationSent = kDefaultTarget.count();
+ // Max amount the error term can vary without causing an actual value report
+ nsecs_t mAllowedActualDeviation = -1;
// Whether we should emit ATRACE_INT data for hint sessions
static const bool sTraceHintSessionData;
-
- // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
- static constexpr double kAllowedActualDeviationPercent = 0.1;
- // Max percent the target duration can vary without causing a report (eg: 0.1 = 10%)
- static constexpr double kAllowedTargetDeviationPercent = 0.1;
- // Target used for init and normalization, the actual value does not really matter
- static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
+ static constexpr const std::chrono::nanoseconds kDefaultTarget = 16ms;
// Amount of time after the last message was sent before the session goes stale
// actually 100ms but we use 80 here to ideally avoid going stale
static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 38662bd..0c4b012 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -81,6 +81,7 @@
namespace android {
namespace {
constexpr int kDumpTableRowLength = 159;
+const ui::Transform kIdentityTransform;
} // namespace
using namespace ftl::flag_operators;
@@ -2164,7 +2165,8 @@
if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) {
WindowInfo info;
if (useDrawing) {
- info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true);
+ info = fillInputInfo(
+ InputDisplayArgs{.transform = &kIdentityTransform, .isSecure = true});
} else {
info = state.inputInfo;
}
@@ -2371,7 +2373,7 @@
}
}
-WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure) {
+WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
mDrawingState.inputInfo.ownerUid = mOwnerUid;
@@ -2380,12 +2382,21 @@
mDrawingState.inputInfo.displayId = getLayerStack().id;
}
+ const ui::Transform& displayTransform =
+ displayArgs.transform != nullptr ? *displayArgs.transform : kIdentityTransform;
+
WindowInfo info = mDrawingState.inputInfo;
info.id = sequence;
info.displayId = getLayerStack().id;
fillInputFrameInfo(info, displayTransform);
+ if (displayArgs.transform == nullptr) {
+ // Do not let the window receive touches if it is not associated with a valid display
+ // transform. We still allow the window to receive keys and prevent ANRs.
+ info.inputConfig |= WindowInfo::InputConfig::NOT_TOUCHABLE;
+ }
+
// For compatibility reasons we let layers which can receive input
// receive input before they have actually submitted a buffer. Because
// of this we use canReceiveInput instead of isVisible to check the
@@ -2403,7 +2414,7 @@
// If the window will be blacked out on a display because the display does not have the secure
// flag and the layer has the secure flag set, then drop input.
- if (!displayIsSecure && isSecure()) {
+ if (!displayArgs.isSecure && isSecure()) {
info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 24abad9..c547da0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -844,7 +844,11 @@
bool getPremultipledAlpha() const;
void setInputInfo(const gui::WindowInfo& info);
- gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure);
+ struct InputDisplayArgs {
+ const ui::Transform* transform = nullptr;
+ bool isSecure = false;
+ };
+ gui::WindowInfo fillInputInfo(const InputDisplayArgs& displayArgs);
/**
* Returns whether this layer has an explicitly set input-info.
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index d4435c2..a9180d4 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -16,9 +16,10 @@
#include <algorithm>
-#include "RefreshRateOverlay.h"
+#include "BackgroundExecutor.h"
#include "Client.h"
#include "Layer.h"
+#include "RefreshRateOverlay.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
@@ -56,6 +57,14 @@
} // namespace
+SurfaceControlHolder::~SurfaceControlHolder() {
+ // Hand the sp<SurfaceControl> to the helper thread to release the last
+ // reference. This makes sure that the SurfaceControl is destructed without
+ // SurfaceFlinger::mStateLock held.
+ BackgroundExecutor::getInstance().sendCallbacks(
+ {[sc = std::move(mSurfaceControl)]() mutable { sc.clear(); }});
+}
+
void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color,
SkCanvas& canvas) {
const SkRect rect = [&]() {
@@ -210,21 +219,27 @@
return buffers;
}
+std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder() {
+ sp<SurfaceControl> surfaceControl =
+ SurfaceComposerClient::getDefault()
+ ->createSurface(String8("RefreshRateOverlay"), kBufferWidth, kBufferHeight,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+ return std::make_unique<SurfaceControlHolder>(std::move(surfaceControl));
+}
+
RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner)
: mFpsRange(fpsRange),
mShowSpinner(showSpinner),
- mSurfaceControl(SurfaceComposerClient::getDefault()
- ->createSurface(String8("RefreshRateOverlay"), kBufferWidth,
- kBufferHeight, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceBufferState)) {
+ mSurfaceControl(createSurfaceControlHolder()) {
if (!mSurfaceControl) {
ALOGE("%s: Failed to create buffer state layer", __func__);
return;
}
- createTransaction(mSurfaceControl)
- .setLayer(mSurfaceControl, INT32_MAX - 2)
- .setTrustedOverlay(mSurfaceControl, true)
+ createTransaction(mSurfaceControl->get())
+ .setLayer(mSurfaceControl->get(), INT32_MAX - 2)
+ .setTrustedOverlay(mSurfaceControl->get(), true)
.apply();
}
@@ -233,7 +248,7 @@
if (!mSurfaceControl) return kNoBuffers;
const auto transformHint =
- static_cast<ui::Transform::RotationFlags>(mSurfaceControl->getTransformHint());
+ static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint());
// Tell SurfaceFlinger about the pre-rotation on the buffer.
const auto transform = [&] {
@@ -247,7 +262,9 @@
}
}();
- createTransaction(mSurfaceControl).setTransform(mSurfaceControl, transform).apply();
+ createTransaction(mSurfaceControl->get())
+ .setTransform(mSurfaceControl->get(), transform)
+ .apply();
BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint});
if (it == mBufferCache.end()) {
@@ -289,21 +306,21 @@
Rect frame((3 * width) >> 4, height >> 5);
frame.offsetBy(width >> 5, height >> 4);
- createTransaction(mSurfaceControl)
- .setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
- frame.getHeight() / static_cast<float>(kBufferHeight))
- .setPosition(mSurfaceControl, frame.left, frame.top)
+ createTransaction(mSurfaceControl->get())
+ .setMatrix(mSurfaceControl->get(), frame.getWidth() / static_cast<float>(kBufferWidth),
+ 0, 0, frame.getHeight() / static_cast<float>(kBufferHeight))
+ .setPosition(mSurfaceControl->get(), frame.left, frame.top)
.apply();
}
void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
- createTransaction(mSurfaceControl).setLayerStack(mSurfaceControl, stack).apply();
+ createTransaction(mSurfaceControl->get()).setLayerStack(mSurfaceControl->get(), stack).apply();
}
void RefreshRateOverlay::changeRefreshRate(Fps fps) {
mCurrentFps = fps;
const auto buffer = getOrCreateBuffers(fps)[mFrame];
- createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
+ createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply();
}
void RefreshRateOverlay::animate() {
@@ -312,7 +329,7 @@
const auto& buffers = getOrCreateBuffers(*mCurrentFps);
mFrame = (mFrame + 1) % buffers.size();
const auto buffer = buffers[mFrame];
- createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
+ createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply();
}
} // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index a465a36..a2966e6 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -33,6 +33,20 @@
class GraphicBuffer;
class SurfaceControl;
+class SurfaceFlinger;
+
+// Helper class to delete the SurfaceControl on a helper thread as
+// SurfaceControl assumes its destruction happens without SurfaceFlinger::mStateLock held.
+class SurfaceControlHolder {
+public:
+ explicit SurfaceControlHolder(sp<SurfaceControl> sc) : mSurfaceControl(std::move(sc)){};
+ ~SurfaceControlHolder();
+
+ const sp<SurfaceControl>& get() const { return mSurfaceControl; }
+
+private:
+ sp<SurfaceControl> mSurfaceControl;
+};
class RefreshRateOverlay {
public:
@@ -75,7 +89,7 @@
const FpsRange mFpsRange; // For color interpolation.
const bool mShowSpinner;
- const sp<SurfaceControl> mSurfaceControl;
+ const std::unique_ptr<SurfaceControlHolder> mSurfaceControl;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 747032b..4af1f5c 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -188,10 +188,10 @@
VSyncSource::VSyncData DispSyncSource::getLatestVSyncData() const {
std::lock_guard lock(mVsyncMutex);
- nsecs_t expectedPresentTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
+ nsecs_t expectedPresentationTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
- nsecs_t deadline = expectedPresentTime - mWorkDuration.get().count() - mReadyDuration.count();
- return {expectedPresentTime, deadline};
+ nsecs_t deadline = expectedPresentationTime - mReadyDuration.count();
+ return {expectedPresentationTime, deadline};
}
void DispSyncSource::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index ca83496..a48c921 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -40,22 +40,26 @@
struct RefreshRateScore {
DisplayModeIterator modeIt;
- float score;
+ float overallScore;
+ struct {
+ float modeBelowThreshold;
+ float modeAboveThreshold;
+ } fixedRateBelowThresholdLayersScore;
};
template <typename Iterator>
const DisplayModePtr& getMaxScoreRefreshRate(Iterator begin, Iterator end) {
const auto it =
std::max_element(begin, end, [](RefreshRateScore max, RefreshRateScore current) {
- const auto& [modeIt, score] = current;
+ const auto& [modeIt, overallScore, _] = current;
std::string name = to_string(modeIt->second->getFps());
- ALOGV("%s scores %.2f", name.c_str(), score);
+ ALOGV("%s scores %.2f", name.c_str(), overallScore);
- ATRACE_INT(name.c_str(), static_cast<int>(std::round(score * 100)));
+ ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100)));
constexpr float kEpsilon = 0.0001f;
- return score > max.score * (1 + kEpsilon);
+ return overallScore > max.overallScore * (1 + kEpsilon);
});
return it->modeIt->second;
@@ -151,31 +155,6 @@
return {quotient, remainder};
}
-bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, Fps refreshRate) const {
- using namespace fps_approx_ops;
-
- switch (layer.vote) {
- case LayerVoteType::ExplicitExactOrMultiple:
- case LayerVoteType::Heuristic:
- if (mConfig.frameRateMultipleThreshold != 0 &&
- refreshRate >= Fps::fromValue(mConfig.frameRateMultipleThreshold) &&
- layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2)) {
- // Don't vote high refresh rates past the threshold for layers with a low desired
- // refresh rate. For example, desired 24 fps with 120 Hz threshold means no vote for
- // 120 Hz, but desired 60 fps should have a vote.
- return false;
- }
- break;
- case LayerVoteType::ExplicitDefault:
- case LayerVoteType::ExplicitExact:
- case LayerVoteType::Max:
- case LayerVoteType::Min:
- case LayerVoteType::NoVote:
- break;
- }
- return true;
-}
-
float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer,
Fps refreshRate) const {
constexpr float kScoreForFractionalPairs = .8f;
@@ -240,10 +219,6 @@
float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate,
bool isSeamlessSwitch) const {
- if (!isVoteAllowed(layer, refreshRate)) {
- return 0;
- }
-
// Slightly prefer seamless switches.
constexpr float kSeamedSwitchPenalty = 0.95f;
const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
@@ -300,6 +275,7 @@
auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
GlobalSignals signals) const
-> std::pair<DisplayModePtr, GlobalSignals> {
+ using namespace fps_approx_ops;
ATRACE_CALL();
ALOGV("%s: %zu layers", __func__, layers.size());
@@ -409,7 +385,7 @@
const auto weight = layer.weight;
- for (auto& [modeIt, score] : scores) {
+ for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
const auto& [id, mode] = *modeIt;
const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup();
@@ -451,18 +427,92 @@
continue;
}
- const auto layerScore =
+ const float layerScore =
calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch);
- ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
- to_string(mode->getFps()).c_str(), layerScore);
+ const float weightedLayerScore = weight * layerScore;
- score += weight * layerScore;
+ // Layer with fixed source has a special consideration which depends on the
+ // mConfig.frameRateMultipleThreshold. We don't want these layers to score
+ // refresh rates above the threshold, but we also don't want to favor the lower
+ // ones by having a greater number of layers scoring them. Instead, we calculate
+ // the score independently for these layers and later decide which
+ // refresh rates to add it. For example, desired 24 fps with 120 Hz threshold should not
+ // score 120 Hz, but desired 60 fps should contribute to the score.
+ const bool fixedSourceLayer = [](LayerVoteType vote) {
+ switch (vote) {
+ case LayerVoteType::ExplicitExactOrMultiple:
+ case LayerVoteType::Heuristic:
+ return true;
+ case LayerVoteType::NoVote:
+ case LayerVoteType::Min:
+ case LayerVoteType::Max:
+ case LayerVoteType::ExplicitDefault:
+ case LayerVoteType::ExplicitExact:
+ return false;
+ }
+ }(layer.vote);
+ const bool layerBelowThreshold = mConfig.frameRateMultipleThreshold != 0 &&
+ layer.desiredRefreshRate <
+ Fps::fromValue(mConfig.frameRateMultipleThreshold / 2);
+ if (fixedSourceLayer && layerBelowThreshold) {
+ const bool modeAboveThreshold =
+ mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold);
+ if (modeAboveThreshold) {
+ ALOGV("%s gives %s fixed source (above threshold) score of %.4f",
+ formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
+ layerScore);
+ fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore;
+ } else {
+ ALOGV("%s gives %s fixed source (below threshold) score of %.4f",
+ formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
+ layerScore);
+ fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore;
+ }
+ } else {
+ ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
+ to_string(mode->getFps()).c_str(), layerScore);
+ overallScore += weightedLayerScore;
+ }
}
}
- // Now that we scored all the refresh rates we need to pick the one that got the highest score.
- // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max,
- // or the lower otherwise.
+ // We want to find the best refresh rate without the fixed source layers,
+ // so we could know whether we should add the modeAboveThreshold scores or not.
+ // If the best refresh rate is already above the threshold, it means that
+ // some non-fixed source layers already scored it, so we can just add the score
+ // for all fixed source layers, even the ones that are above the threshold.
+ const bool maxScoreAboveThreshold = [&] {
+ if (mConfig.frameRateMultipleThreshold == 0 || scores.empty()) {
+ return false;
+ }
+
+ const auto maxScoreIt =
+ std::max_element(scores.begin(), scores.end(),
+ [](RefreshRateScore max, RefreshRateScore current) {
+ const auto& [modeIt, overallScore, _] = current;
+ return overallScore > max.overallScore;
+ });
+ ALOGV("%s is the best refresh rate without fixed source layers. It is %s the threshold for "
+ "refresh rate multiples",
+ to_string(maxScoreIt->modeIt->second->getFps()).c_str(),
+ maxScoreAboveThreshold ? "above" : "below");
+ return maxScoreIt->modeIt->second->getFps() >=
+ Fps::fromValue(mConfig.frameRateMultipleThreshold);
+ }();
+
+ // Now we can add the fixed rate layers score
+ for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
+ overallScore += fixedRateBelowThresholdLayersScore.modeBelowThreshold;
+ if (maxScoreAboveThreshold) {
+ overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold;
+ }
+ ALOGV("%s adjusted overallScore is %.4f", to_string(modeIt->second->getFps()).c_str(),
+ overallScore);
+ }
+
+ // Now that we scored all the refresh rates we need to pick the one that got the highest
+ // overallScore. In case of a tie we will pick the higher refresh rate if any of the layers
+ // wanted Max, or the lower otherwise.
const DisplayModePtr& bestRefreshRate = maxVoteLayers > 0
? getMaxScoreRefreshRate(scores.rbegin(), scores.rend())
: getMaxScoreRefreshRate(scores.begin(), scores.end());
@@ -471,7 +521,7 @@
// If we never scored any layers, then choose the rate from the primary
// range instead of picking a random score from the app range.
if (std::all_of(scores.begin(), scores.end(),
- [](RefreshRateScore score) { return score.score == 0; })) {
+ [](RefreshRateScore score) { return score.overallScore == 0; })) {
const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
ALOGV("layers not scored - choose %s", to_string(max->getFps()).c_str());
return {max, kNoSignals};
@@ -575,7 +625,7 @@
continue;
}
- for (auto& [_, score] : scores) {
+ for (auto& [_, score, _1] : scores) {
score = 0;
}
@@ -587,7 +637,7 @@
LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
layer->vote != LayerVoteType::ExplicitExact);
- for (auto& [modeIt, score] : scores) {
+ for (auto& [modeIt, score, _] : scores) {
constexpr bool isSeamlessSwitch = true;
const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(),
isSeamlessSwitch);
@@ -605,7 +655,7 @@
// If we never scored any layers, we don't have a preferred frame rate
if (std::all_of(scores.begin(), scores.end(),
- [](RefreshRateScore score) { return score.score == 0; })) {
+ [](RefreshRateScore score) { return score.overallScore == 0; })) {
continue;
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 05a8692..a79002e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -353,9 +353,6 @@
const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
- // Returns whether the layer is allowed to vote for the given refresh rate.
- bool isVoteAllowed(const LayerRequirement&, Fps) const;
-
// calculates a score for a layer. Used to determine the display refresh rate
// and the frame rate override for certains applications.
float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate,
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 37f0fec..727cb08 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -25,6 +25,7 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
+#include <ftl/fake_guard.h>
#include <gui/WindowInfo.h>
#include <system/window.h>
#include <ui/DisplayStatInfo.h>
@@ -94,9 +95,13 @@
}
void Scheduler::setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs> configs) {
+ // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer.
{
- // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer.
- std::scoped_lock lock(mRefreshRateConfigsLock);
+ // mRefreshRateConfigsLock is not locked here to avoid the deadlock
+ // as the callback can attempt to acquire the lock before stopIdleTimer can finish
+ // the execution. It's safe to FakeGuard as main thread is the only thread that
+ // writes to the mRefreshRateConfigs.
+ ftl::FakeGuard guard(mRefreshRateConfigsLock);
if (mRefreshRateConfigs) {
mRefreshRateConfigs->stopIdleTimer();
mRefreshRateConfigs->clearIdleTimerCallbacks();
@@ -554,11 +559,12 @@
}
}
-void Scheduler::setDisplayPowerState(bool normal) {
+void Scheduler::setDisplayPowerMode(hal::PowerMode powerMode) {
{
std::lock_guard<std::mutex> lock(mPolicyLock);
- mPolicy.isDisplayPowerStateNormal = normal;
+ mPolicy.displayPowerMode = powerMode;
}
+ mVsyncSchedule->getController().setDisplayPowerMode(powerMode);
if (mDisplayPowerTimer) {
mDisplayPowerTimer->reset();
@@ -706,7 +712,8 @@
// If Display Power is not in normal operation we want to be in performance mode. When coming
// back to normal mode, a grace period is given with DisplayPowerTimer.
if (mDisplayPowerTimer &&
- (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) {
+ (mPolicy.displayPowerMode != hal::PowerMode::ON ||
+ mPolicy.displayPowerTimer == TimerState::Reset)) {
constexpr GlobalSignals kNoSignals;
return {configs->getMaxRefreshRateByPolicy(), kNoSignals};
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0c72124..a8043bf 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -186,7 +186,7 @@
// Indicates that touch interaction is taking place.
void onTouchHint();
- void setDisplayPowerState(bool normal);
+ void setDisplayPowerMode(hal::PowerMode powerMode);
VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); }
@@ -325,7 +325,7 @@
TimerState idleTimer = TimerState::Reset;
TouchState touch = TouchState::Inactive;
TimerState displayPowerTimer = TimerState::Expired;
- bool isDisplayPowerStateNormal = true;
+ hal::PowerMode displayPowerMode = hal::PowerMode::ON;
// Chosen display mode.
DisplayModePtr mode;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 665a7ee..e23945d 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -147,6 +147,11 @@
return false;
}
+ if (mDisplayPowerMode == hal::PowerMode::DOZE ||
+ mDisplayPowerMode == hal::PowerMode::DOZE_SUSPEND) {
+ return true;
+ }
+
if (!mLastHwVsync && !HwcVsyncPeriod) {
return false;
}
@@ -207,6 +212,11 @@
return mMoreSamplesNeeded;
}
+void VSyncReactor::setDisplayPowerMode(hal::PowerMode powerMode) {
+ std::scoped_lock lock(mMutex);
+ mDisplayPowerMode = powerMode;
+}
+
void VSyncReactor::dump(std::string& result) const {
std::lock_guard lock(mMutex);
StringAppendF(&result, "VsyncReactor in use\n");
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 6a1950a..4501487 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -49,6 +49,8 @@
bool addHwVsyncTimestamp(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
bool* periodFlushed) final;
+ void setDisplayPowerMode(hal::PowerMode powerMode) final;
+
void dump(std::string& result) const final;
private:
@@ -73,6 +75,8 @@
std::optional<nsecs_t> mPeriodTransitioningTo GUARDED_BY(mMutex);
std::optional<nsecs_t> mLastHwVsync GUARDED_BY(mMutex);
+ hal::PowerMode mDisplayPowerMode GUARDED_BY(mMutex) = hal::PowerMode::ON;
+
const bool mSupportKernelIdleTimer = false;
};
diff --git a/services/surfaceflinger/Scheduler/VsyncController.h b/services/surfaceflinger/Scheduler/VsyncController.h
index 59f6537..726a420 100644
--- a/services/surfaceflinger/Scheduler/VsyncController.h
+++ b/services/surfaceflinger/Scheduler/VsyncController.h
@@ -18,7 +18,10 @@
#include <cstddef>
#include <memory>
+#include <mutex>
+#include <DisplayHardware/HWComposer.h>
+#include <DisplayHardware/Hal.h>
#include <ui/FenceTime.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
@@ -70,6 +73,13 @@
*/
virtual void setIgnorePresentFences(bool ignore) = 0;
+ /*
+ * Sets the primary display power mode to the controller.
+ *
+ * \param [in] powerMode
+ */
+ virtual void setDisplayPowerMode(hal::PowerMode powerMode) = 0;
+
virtual void dump(std::string& result) const = 0;
protected:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e9fbf6e..e228468 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -328,8 +328,9 @@
mCompositionEngine(mFactory.createCompositionEngine()),
mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
- mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
+ mInternalDisplayDensity(
+ getDensityFromProperty("ro.sf.lcd_density", !mEmulatedDisplayDensity)),
mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
@@ -444,6 +445,11 @@
}
mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
+
+ // Power hint session mode, representing which hint(s) to send: early, late, or both)
+ mPowerHintSessionMode =
+ {.late = base::GetBoolProperty("debug.sf.send_late_power_session_hint"s, true),
+ .early = base::GetBoolProperty("debug.sf.send_early_power_session_hint"s, false)};
}
LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
@@ -1999,12 +2005,6 @@
bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
FTL_FAKE_GUARD(kMainThreadContext) {
- // we set this once at the beginning of commit to ensure consistency throughout the whole frame
- mPowerHintSessionData.sessionEnabled = mPowerAdvisor->usePowerHintSession();
- if (mPowerHintSessionData.sessionEnabled) {
- mPowerHintSessionData.commitStart = systemTime();
- }
-
// calculate the expected present time once and use the cached
// value throughout this frame to make sure all layers are
// seeing this same value.
@@ -2018,10 +2018,6 @@
const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
mScheduledPresentTime = expectedVsyncTime;
- if (mPowerHintSessionData.sessionEnabled) {
- mPowerAdvisor->setTargetWorkDuration(mExpectedPresentTime -
- mPowerHintSessionData.commitStart);
- }
const auto vsyncIn = [&] {
if (!ATRACE_ENABLED()) return 0.f;
return (mExpectedPresentTime - systemTime()) / 1e6f;
@@ -2097,6 +2093,32 @@
}
}
+ // Save this once per commit + composite to ensure consistency
+ // TODO (b/240619471): consider removing active display check once AOD is fixed
+ const auto activeDisplay =
+ FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(mActiveDisplayToken));
+ mPowerHintSessionEnabled = mPowerAdvisor->usePowerHintSession() && activeDisplay &&
+ activeDisplay->getPowerMode() == hal::PowerMode::ON;
+ if (mPowerHintSessionEnabled) {
+ const auto& display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
+ // get stable vsync period from display mode
+ const nsecs_t vsyncPeriod = display->getActiveMode()->getVsyncPeriod();
+ mPowerAdvisor->setCommitStart(frameTime);
+ mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime);
+ const nsecs_t idealSfWorkDuration =
+ mVsyncModulator->getVsyncConfig().sfWorkDuration.count();
+ // Frame delay is how long we should have minus how long we actually have
+ mPowerAdvisor->setFrameDelay(idealSfWorkDuration - (mExpectedPresentTime - frameTime));
+ mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration);
+ mPowerAdvisor->setTargetWorkDuration(vsyncPeriod);
+
+ // Send early hint here to make sure there's not another frame pending
+ if (mPowerHintSessionMode.early) {
+ // Send a rough prediction for this frame based on last frame's timing info
+ mPowerAdvisor->sendPredictedWorkDuration();
+ }
+ }
+
if (mTracingEnabledChanged) {
mLayerTracingEnabled = mLayerTracing.isEnabled();
mTracingEnabledChanged = false;
@@ -2173,16 +2195,15 @@
FTL_FAKE_GUARD(kMainThreadContext) {
ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
- if (mPowerHintSessionData.sessionEnabled) {
- mPowerHintSessionData.compositeStart = systemTime();
- }
-
compositionengine::CompositionRefreshArgs refreshArgs;
const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
refreshArgs.outputs.reserve(displays.size());
+ std::vector<DisplayId> displayIds;
for (const auto& [_, display] : displays) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
+ displayIds.push_back(display->getId());
}
+ mPowerAdvisor->setDisplays(displayIds);
mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
if (auto layerFE = layer->getCompositionEngineLayerFE())
refreshArgs.layers.push_back(layerFE);
@@ -2230,12 +2251,17 @@
mCompositionEngine->present(refreshArgs);
- if (mPowerHintSessionData.sessionEnabled) {
- mPowerHintSessionData.presentEnd = systemTime();
- }
-
mTimeStats->recordFrameDuration(frameTime, systemTime());
+ // Send a power hint hint after presentation is finished
+ if (mPowerHintSessionEnabled) {
+ mPowerAdvisor->setSfPresentTiming(mPreviousPresentFences[0].fenceTime->getSignalTime(),
+ systemTime());
+ if (mPowerHintSessionMode.late) {
+ mPowerAdvisor->sendActualWorkDuration();
+ }
+ }
+
if (mScheduler->onPostComposition(presentTime)) {
scheduleComposite(FrameHint::kNone);
}
@@ -2280,11 +2306,8 @@
scheduleCommit(FrameHint::kNone);
}
- // calculate total render time for performance hinting if adpf cpu hint is enabled,
- if (mPowerHintSessionData.sessionEnabled) {
- const nsecs_t flingerDuration =
- (mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart);
- mPowerAdvisor->sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
+ if (mPowerHintSessionEnabled) {
+ mPowerAdvisor->setCompositeEnd(systemTime());
}
}
@@ -2878,7 +2901,8 @@
ALOGV("Display Orientation: %s", toCString(creationArgs.physicalOrientation));
// virtual displays are always considered enabled
- creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF;
+ creationArgs.initialPowerMode =
+ state.isVirtual() ? std::make_optional(hal::PowerMode::ON) : std::nullopt;
sp<DisplayDevice> display = getFactory().createDisplayDevice(creationArgs);
@@ -3321,11 +3345,11 @@
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
- // Do not create WindowInfos for windows on displays that cannot receive input.
- if (const auto opt = displayInputInfos.get(layer->getLayerStack())) {
- const auto& info = opt->get();
- outWindowInfos.push_back(layer->fillInputInfo(info.transform, info.isSecure));
- }
+ const auto opt = displayInputInfos.get(layer->getLayerStack(),
+ [](const auto& info) -> Layer::InputDisplayArgs {
+ return {&info.transform, info.isSecure};
+ });
+ outWindowInfos.push_back(layer->fillInputInfo(opt.value_or(Layer::InputDisplayArgs{})));
});
sNumWindowInfos = outWindowInfos.size();
@@ -4859,8 +4883,8 @@
const auto displayId = display->getPhysicalId();
ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str());
- const hal::PowerMode currentMode = display->getPowerMode();
- if (mode == currentMode) {
+ std::optional<hal::PowerMode> currentMode = display->getPowerMode();
+ if (currentMode.has_value() && mode == *currentMode) {
return;
}
@@ -4876,7 +4900,7 @@
mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
}
const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
- if (currentMode == hal::PowerMode::OFF) {
+ if (*currentMode == hal::PowerMode::OFF) {
// Turn on the display
if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
onActiveDisplayChangedLocked(display);
@@ -4907,7 +4931,7 @@
if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
}
- if (isDisplayActiveLocked(display) && currentMode != hal::PowerMode::DOZE_SUSPEND) {
+ if (isDisplayActiveLocked(display) && *currentMode != hal::PowerMode::DOZE_SUSPEND) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
@@ -4921,7 +4945,7 @@
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(displayId, mode);
- if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) {
+ if (isDisplayActiveLocked(display) && *currentMode == hal::PowerMode::DOZE_SUSPEND) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, refreshRate);
}
@@ -4940,7 +4964,7 @@
if (isDisplayActiveLocked(display)) {
mTimeStats->setPowerMode(mode);
mRefreshRateStats->setPowerMode(mode);
- mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
+ mScheduler->setDisplayPowerMode(mode);
}
ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str());
@@ -4993,6 +5017,25 @@
const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
+ // Traversal of drawing state must happen on the main thread.
+ // Otherwise, SortedVector may have shared ownership during concurrent
+ // traversals, which can result in use-after-frees.
+ std::string compositionLayers;
+ mScheduler
+ ->schedule([&] {
+ StringAppendF(&compositionLayers, "Composition layers\n");
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ auto* compositionState = layer->getCompositionState();
+ if (!compositionState || !compositionState->isVisible) return;
+
+ android::base::StringAppendF(&compositionLayers, "* Layer %p (%s)\n", layer,
+ layer->getDebugName() ? layer->getDebugName()
+ : "<unknown>");
+ compositionState->dump(compositionLayers);
+ });
+ })
+ .get();
+
bool dumpLayers = true;
{
TimedLock lock(mStateLock, s2ns(1), __func__);
@@ -5005,7 +5048,7 @@
(it->second)(args, asProto, result);
dumpLayers = false;
} else if (!asProto) {
- dumpAllLocked(args, result);
+ dumpAllLocked(args, compositionLayers, result);
}
}
@@ -5304,7 +5347,8 @@
result.append(future.get());
}
-void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
+void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& compositionLayers,
+ std::string& result) const {
const bool colorize = !args.empty() && args[0] == String16("--color");
Colorizer colorizer(colorize);
@@ -5355,18 +5399,7 @@
StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load());
colorizer.reset(result);
- {
- StringAppendF(&result, "Composition layers\n");
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- auto* compositionState = layer->getCompositionState();
- if (!compositionState || !compositionState->isVisible) return;
-
- android::base::StringAppendF(&result, "* Layer %p (%s)\n", layer,
- layer->getDebugName() ? layer->getDebugName()
- : "<unknown>");
- compositionState->dump(result);
- });
- }
+ result.append(compositionLayers);
colorizer.bold(result);
StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size());
@@ -6631,8 +6664,13 @@
1 /* layerCount */, usage, "screenshot");
const status_t bufferStatus = buffer->initCheck();
- LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
- bufferStatus);
+ if (bufferStatus != OK) {
+ // Animations may end up being really janky, but don't crash here.
+ // Otherwise an irreponsible process may cause an SF crash by allocating
+ // too much.
+ ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus);
+ return ftl::yield<FenceResult>(base::unexpected(bufferStatus)).share();
+ }
const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
renderengine::impl::ExternalTexture::Usage::
@@ -6906,9 +6944,7 @@
return NO_ERROR;
}
- status_t setPolicyResult = overridePolicy
- ? display->refreshRateConfigs().setOverridePolicy(policy)
- : display->refreshRateConfigs().setDisplayManagerPolicy(*policy);
+ const status_t setPolicyResult = display->setRefreshRatePolicy(policy, overridePolicy);
if (setPolicyResult < 0) {
return BAD_VALUE;
}
@@ -7564,7 +7600,7 @@
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
+ if ((uid != AID_GRAPHICS) && (uid != AID_SYSTEM) &&
!PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 46f0e6b..02846fe 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1085,7 +1085,8 @@
/*
* Debugging & dumpsys
*/
- void dumpAllLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
+ void dumpAllLocked(const DumpArgs& args, const std::string& compositionLayers,
+ std::string& result) const REQUIRES(mStateLock);
void appendSfConfigString(std::string& result) const;
void listLayersLocked(std::string& result) const;
@@ -1374,8 +1375,8 @@
sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter;
ui::DisplayPrimaries mInternalDisplayPrimaries;
- const float mInternalDisplayDensity;
const float mEmulatedDisplayDensity;
+ const float mInternalDisplayDensity;
// Should only be accessed by the main thread.
sp<os::IInputFlinger> mInputFlinger;
@@ -1436,12 +1437,12 @@
return mScheduler->getLayerFramerate(now, id);
}
+ bool mPowerHintSessionEnabled;
+
struct {
- bool sessionEnabled = false;
- nsecs_t commitStart;
- nsecs_t compositeStart;
- nsecs_t presentEnd;
- } mPowerHintSessionData GUARDED_BY(kMainThreadContext);
+ bool late = false;
+ bool early = false;
+ } mPowerHintSessionMode;
nsecs_t mAnimationTransactionTimeout = s2ns(5);
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index ceddf27..507601b 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -63,7 +63,7 @@
"android.hardware.graphics.composer@2.1",
],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.common-V4-ndk",
"android.hardware.graphics.common@1.2",
"libandroid",
"libbase",
diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
index 9ab35d7..53de4a6 100644
--- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -52,6 +52,8 @@
void verifyAndClearExpectations();
void sendActualWorkDurationGroup(std::vector<WorkDuration> durations,
std::chrono::nanoseconds sleepBeforeLastSend);
+ std::chrono::nanoseconds mAllowedDeviation;
+ std::chrono::nanoseconds mStaleTimeout;
};
void AidlPowerHalWrapperTest::SetUp() {
@@ -59,6 +61,9 @@
mMockSession = new NiceMock<MockIPowerHintSession>();
ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok()));
mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
+ mWrapper->setAllowedActualDeviation(std::chrono::nanoseconds{10ms}.count());
+ mAllowedDeviation = std::chrono::nanoseconds{mWrapper->mAllowedActualDeviation};
+ mStaleTimeout = AidlPowerHalWrapper::kStaleTimeout;
}
void AidlPowerHalWrapperTest::verifyAndClearExpectations() {
@@ -76,6 +81,7 @@
mWrapper->sendActualWorkDuration(duration.durationNanos, duration.timeStampNanos);
}
}
+
WorkDuration toWorkDuration(std::chrono::nanoseconds durationNanos, int64_t timeStampNanos) {
WorkDuration duration;
duration.durationNanos = durationNanos.count();
@@ -83,6 +89,10 @@
return duration;
}
+WorkDuration toWorkDuration(std::pair<std::chrono::nanoseconds, nsecs_t> timePair) {
+ return toWorkDuration(timePair.first, timePair.second);
+}
+
std::string printWorkDurations(const ::std::vector<WorkDuration>& durations) {
std::ostringstream os;
for (auto duration : durations) {
@@ -112,7 +122,7 @@
EXPECT_FALSE(mWrapper->startPowerHintSession());
}
-TEST_F(AidlPowerHalWrapperTest, restartNewPoserHintSessionWithNewThreadIds) {
+TEST_F(AidlPowerHalWrapperTest, restartNewPowerHintSessionWithNewThreadIds) {
ASSERT_TRUE(mWrapper->supportsPowerHintSession());
std::vector<int32_t> threadIds = {1, 2};
@@ -149,12 +159,8 @@
std::chrono::nanoseconds base = 100ms;
// test cases with target work duration and whether it should update hint against baseline 100ms
- const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases = {{0ms, false},
- {-1ms, false},
- {200ms, true},
- {2ms, true},
- {91ms, false},
- {109ms, false}};
+ const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases =
+ {{0ms, true}, {-1ms, true}, {200ms, true}, {2ms, true}, {100ms, false}, {109ms, true}};
for (const auto& test : testCases) {
// reset to 100ms baseline
@@ -200,21 +206,21 @@
// 100ms
const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
testCases = {{{{-1ms, 100}}, false},
- {{{91ms, 100}}, false},
- {{{109ms, 100}}, false},
+ {{{100ms - (mAllowedDeviation / 2), 100}}, false},
+ {{{100ms + (mAllowedDeviation / 2), 100}}, false},
+ {{{100ms + (mAllowedDeviation + 1ms), 100}}, true},
+ {{{100ms - (mAllowedDeviation + 1ms), 100}}, true},
{{{100ms, 100}, {200ms, 200}}, true},
{{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}};
for (const auto& test : testCases) {
// reset actual duration
- sendActualWorkDurationGroup({base}, 80ms);
+ sendActualWorkDurationGroup({base}, mStaleTimeout);
auto raw = test.first;
std::vector<WorkDuration> durations(raw.size());
std::transform(raw.begin(), raw.end(), durations.begin(),
- [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
- return toWorkDuration(d.first, d.second);
- });
+ [](auto d) { return toWorkDuration(d); });
EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
.Times(test.second ? 1 : 0);
sendActualWorkDurationGroup(durations, 0ms);
@@ -222,40 +228,6 @@
}
}
-TEST_F(AidlPowerHalWrapperTest, sendAdjustedActualWorkDuration) {
- ASSERT_TRUE(mWrapper->supportsPowerHintSession());
-
- std::vector<int32_t> threadIds = {1, 2};
- mWrapper->setPowerHintSessionThreadIds(threadIds);
- EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
- .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
- ASSERT_TRUE(mWrapper->startPowerHintSession());
- verifyAndClearExpectations();
-
- std::chrono::nanoseconds lastTarget = 100ms;
- EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(lastTarget.count())).Times(1);
- mWrapper->setTargetWorkDuration(lastTarget.count());
- std::chrono::nanoseconds newTarget = 105ms;
- mWrapper->setTargetWorkDuration(newTarget.count());
- EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(newTarget.count())).Times(0);
- std::chrono::nanoseconds actual = 21ms;
- // 100 / 105 * 21ms = 20ms
- std::chrono::nanoseconds expectedActualSent = 20ms;
- std::vector<WorkDuration> expectedDurations = {toWorkDuration(expectedActualSent, 1)};
-
- EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
- .WillOnce(DoAll(
- [expectedDurations](const ::std::vector<WorkDuration>& durationsSent) {
- EXPECT_EQ(expectedDurations, durationsSent)
- << base::StringPrintf("actual sent: %s vs expected: %s",
- printWorkDurations(durationsSent).c_str(),
- printWorkDurations(expectedDurations)
- .c_str());
- },
- Return(Status::ok())));
- mWrapper->sendActualWorkDuration(actual.count(), 1);
-}
-
TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
ASSERT_TRUE(mWrapper->supportsPowerHintSession());
@@ -269,22 +241,23 @@
auto base = toWorkDuration(100ms, 0);
// test cases with actual work durations and whether it should update hint against baseline
// 100ms
- const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
- testCases = {{{{91ms, 100}}, true}, {{{109ms, 100}}, true}};
+ const std::vector<std::tuple<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>,
+ std::chrono::nanoseconds, bool>>
+ testCases = {{{{100ms, 100}}, mStaleTimeout, true},
+ {{{100ms + (mAllowedDeviation / 2), 100}}, mStaleTimeout, true},
+ {{{100ms, 100}}, mStaleTimeout / 2, false}};
for (const auto& test : testCases) {
// reset actual duration
- sendActualWorkDurationGroup({base}, 80ms);
+ sendActualWorkDurationGroup({base}, mStaleTimeout);
- auto raw = test.first;
+ auto raw = std::get<0>(test);
std::vector<WorkDuration> durations(raw.size());
std::transform(raw.begin(), raw.end(), durations.begin(),
- [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
- return toWorkDuration(d.first, d.second);
- });
+ [](auto d) { return toWorkDuration(d); });
EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
- .Times(test.second ? 1 : 0);
- sendActualWorkDurationGroup(durations, 80ms);
+ .Times(std::get<2>(test) ? 1 : 0);
+ sendActualWorkDurationGroup(durations, std::get<1>(test));
verifyAndClearExpectations();
}
}
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 7823363..339d746 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -24,6 +24,7 @@
filegroup {
name: "libsurfaceflinger_mock_sources",
srcs: [
+ "mock/DisplayHardware/MockAidlPowerHalWrapper.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockHWC2.cpp",
"mock/DisplayHardware/MockIPower.cpp",
@@ -95,6 +96,7 @@
"LayerTest.cpp",
"LayerTestUtils.cpp",
"MessageQueueTest.cpp",
+ "PowerAdvisorTest.cpp",
"SurfaceFlinger_CreateDisplayTest.cpp",
"SurfaceFlinger_DestroyDisplayTest.cpp",
"SurfaceFlinger_DisplayModeSwitching.cpp",
@@ -136,7 +138,7 @@
static_libs: [
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
- "android.hardware.graphics.common-V3-ndk",
+ "android.hardware.graphics.common-V4-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index ec27eda..67ace1a 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -292,9 +292,10 @@
TEST_F(DispSyncSourceTest, getLatestVsyncData) {
const nsecs_t now = systemTime();
- const nsecs_t vsyncInternalDuration = mWorkDuration.count() + mReadyDuration.count();
+ const nsecs_t expectedPresentationTime =
+ now + mWorkDuration.count() + mReadyDuration.count() + 1;
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_))
- .WillOnce(Return(now + vsyncInternalDuration + 1));
+ .WillOnce(Return(expectedPresentationTime));
{
InSequence seq;
EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
@@ -306,10 +307,8 @@
EXPECT_TRUE(mDispSyncSource);
const auto vsyncData = mDispSyncSource->getLatestVSyncData();
- ASSERT_GT(vsyncData.deadlineTimestamp, now);
- ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
- EXPECT_EQ(vsyncData.deadlineTimestamp,
- vsyncData.expectedPresentationTime - vsyncInternalDuration);
+ ASSERT_EQ(vsyncData.expectedPresentationTime, expectedPresentationTime);
+ EXPECT_EQ(vsyncData.deadlineTimestamp, expectedPresentationTime - mReadyDuration.count());
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
new file mode 100644
index 0000000..8711a42
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "PowerAdvisorTest"
+
+#include <DisplayHardware/PowerAdvisor.h>
+#include <compositionengine/Display.h>
+#include <ftl/fake_guard.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <ui/DisplayId.h>
+#include <chrono>
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockAidlPowerHalWrapper.h"
+
+using namespace android;
+using namespace android::Hwc2::mock;
+using namespace android::hardware::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+namespace android::Hwc2::impl {
+
+class PowerAdvisorTest : public testing::Test {
+public:
+ void SetUp() override;
+ void startPowerHintSession();
+ void fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod);
+ void setExpectedTiming(nsecs_t startTime, nsecs_t vsyncPeriod);
+ nsecs_t getFenceWaitDelayDuration(bool skipValidate);
+
+protected:
+ TestableSurfaceFlinger mFlinger;
+ std::unique_ptr<PowerAdvisor> mPowerAdvisor;
+ NiceMock<MockAidlPowerHalWrapper>* mMockAidlWrapper;
+ nsecs_t kErrorMargin = std::chrono::nanoseconds(1ms).count();
+};
+
+void PowerAdvisorTest::SetUp() FTL_FAKE_GUARD(mPowerAdvisor->mPowerHalMutex) {
+ std::unique_ptr<MockAidlPowerHalWrapper> mockAidlWrapper =
+ std::make_unique<NiceMock<MockAidlPowerHalWrapper>>();
+ mPowerAdvisor = std::make_unique<PowerAdvisor>(*mFlinger.flinger());
+ ON_CALL(*mockAidlWrapper.get(), supportsPowerHintSession()).WillByDefault(Return(true));
+ ON_CALL(*mockAidlWrapper.get(), startPowerHintSession()).WillByDefault(Return(true));
+ mPowerAdvisor->mHalWrapper = std::move(mockAidlWrapper);
+ mMockAidlWrapper =
+ reinterpret_cast<NiceMock<MockAidlPowerHalWrapper>*>(mPowerAdvisor->mHalWrapper.get());
+}
+
+void PowerAdvisorTest::startPowerHintSession() {
+ const std::vector<int32_t> threadIds = {1, 2, 3};
+ mPowerAdvisor->enablePowerHint(true);
+ mPowerAdvisor->startPowerHintSession(threadIds);
+}
+
+void PowerAdvisorTest::setExpectedTiming(nsecs_t totalFrameTarget, nsecs_t expectedPresentTime) {
+ mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTarget);
+ mPowerAdvisor->setExpectedPresentTime(expectedPresentTime);
+}
+
+void PowerAdvisorTest::fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod) {
+ mPowerAdvisor->setCommitStart(startTime);
+ mPowerAdvisor->setFrameDelay(0);
+ mPowerAdvisor->setTargetWorkDuration(vsyncPeriod);
+}
+
+nsecs_t PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) {
+ return (skipValidate ? PowerAdvisor::kFenceWaitStartDelaySkippedValidate
+ : PowerAdvisor::kFenceWaitStartDelayValidated)
+ .count();
+}
+
+namespace {
+
+TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) {
+ mPowerAdvisor->onBootFinished();
+ startPowerHintSession();
+
+ std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
+
+ // 60hz
+ const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60;
+ const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count();
+ const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count();
+
+ nsecs_t startTime = 100;
+
+ // advisor only starts on frame 2 so do an initial no-op frame
+ fakeBasicFrameTiming(startTime, vsyncPeriod);
+ setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+ mPowerAdvisor->setDisplays(displayIds);
+ mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+ mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
+
+ // increment the frame
+ startTime += vsyncPeriod;
+
+ const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration;
+ EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1);
+
+ fakeBasicFrameTiming(startTime, vsyncPeriod);
+ setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+ mPowerAdvisor->setDisplays(displayIds);
+ mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000);
+ mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000);
+ mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+ mPowerAdvisor->sendActualWorkDuration();
+}
+
+TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) {
+ mPowerAdvisor->onBootFinished();
+ startPowerHintSession();
+
+ std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
+
+ // 60hz
+ const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60;
+ const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count();
+ const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count();
+ const nsecs_t hwcBlockedDuration = std::chrono::nanoseconds(500us).count();
+
+ nsecs_t startTime = 100;
+
+ // advisor only starts on frame 2 so do an initial no-op frame
+ fakeBasicFrameTiming(startTime, vsyncPeriod);
+ setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+ mPowerAdvisor->setDisplays(displayIds);
+ mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+ mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
+
+ // increment the frame
+ startTime += vsyncPeriod;
+
+ const nsecs_t expectedDuration = kErrorMargin + presentDuration +
+ getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration;
+ EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1);
+
+ fakeBasicFrameTiming(startTime, vsyncPeriod);
+ setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+ mPowerAdvisor->setDisplays(displayIds);
+ mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000);
+ mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 3000000);
+ // now report the fence as having fired during the display HWC time
+ mPowerAdvisor->setSfPresentTiming(startTime + 2000000 + hwcBlockedDuration,
+ startTime + presentDuration);
+ mPowerAdvisor->sendActualWorkDuration();
+}
+
+TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) {
+ mPowerAdvisor->onBootFinished();
+ startPowerHintSession();
+
+ std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0),
+ GpuVirtualDisplayId(1)};
+
+ // 60hz
+ const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60;
+ // make present duration much later than the hwc display by itself will account for
+ const nsecs_t presentDuration = std::chrono::nanoseconds(10ms).count();
+ const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count();
+
+ nsecs_t startTime = 100;
+
+ // advisor only starts on frame 2 so do an initial no-op frame
+ fakeBasicFrameTiming(startTime, vsyncPeriod);
+ setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+ mPowerAdvisor->setDisplays(displayIds);
+ mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+ mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
+
+ // increment the frame
+ startTime += vsyncPeriod;
+
+ const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration;
+ EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1);
+
+ fakeBasicFrameTiming(startTime, vsyncPeriod);
+ setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+ mPowerAdvisor->setDisplays(displayIds);
+
+ // don't report timing for the gpu displays since they don't use hwc
+ mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000);
+ mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000);
+ mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+ mPowerAdvisor->sendActualWorkDuration();
+}
+
+} // namespace
+} // namespace android::Hwc2::impl
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index fcde532..188fd58 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -564,9 +564,10 @@
TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60,
{.frameRateMultipleThreshold = 120});
- std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
+ auto& lr3 = layers[2];
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -639,6 +640,48 @@
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.name = "90Hz ExplicitExactOrMultiple";
EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 24_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Max;
+ lr2.name = "Max";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 24_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 120_Hz;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "120Hz ExplicitDefault";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 24_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 120_Hz;
+ lr2.vote = LayerVoteType::ExplicitExact;
+ lr2.name = "120Hz ExplicitExact";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 10_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 120_Hz;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "120Hz ExplicitExact";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 30_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 30_Hz;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.name = "30Hz ExplicitExactOrMultiple";
+ lr3.vote = LayerVoteType::Heuristic;
+ lr3.desiredRefreshRate = 120_Hz;
+ lr3.name = "120Hz Heuristic";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index aab2795..93c809e 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -159,8 +159,8 @@
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
- constexpr bool kPowerStateNormal = true;
- mScheduler->setDisplayPowerState(kPowerStateNormal);
+ constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
+ mScheduler->setDisplayPowerMode(kPowerModeOn);
constexpr uint32_t kDisplayArea = 999'999;
mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
@@ -226,8 +226,8 @@
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
- constexpr bool kPowerStateNormal = true;
- mScheduler->setDisplayPowerState(kPowerStateNormal);
+ constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
+ mScheduler->setDisplayPowerMode(kPowerModeOn);
constexpr uint32_t kDisplayArea = 999'999;
mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
index 8de9e4b..2c9888d 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -74,6 +74,7 @@
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+ mFlinger.setPowerHintSessionMode(true, true);
mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
static constexpr bool kIsPrimary = true;
FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary)
@@ -96,6 +97,7 @@
.setNativeWindow(mNativeWindow)
.setPowerMode(hal::PowerMode::ON)
.inject();
+ mFlinger.mutableActiveDisplayToken() = mDisplay->getDisplayToken();
}
void SurfaceFlingerPowerHintTest::setupScheduler() {
@@ -142,10 +144,30 @@
std::this_thread::sleep_for(mockHwcRunTime);
return hardware::graphics::composer::V2_1::Error::NONE;
});
- EXPECT_CALL(*mPowerAdvisor,
- sendActualWorkDuration(Gt(mockHwcRunTime.count()),
- Gt(now + mockHwcRunTime.count())))
+ EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(1);
+ static constexpr bool kVsyncId = 123; // arbitrary
+ mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
+}
+
+TEST_F(SurfaceFlingerPowerHintTest, inactiveOnDisplayDoze) {
+ ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
+
+ mDisplay->setPowerMode(hal::PowerMode::DOZE);
+
+ const std::chrono::nanoseconds mockVsyncPeriod = 15ms;
+ EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(0);
+
+ const nsecs_t now = systemTime();
+ const std::chrono::nanoseconds mockHwcRunTime = 20ms;
+ EXPECT_CALL(*mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc))
.Times(1);
+ EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _))
+ .WillOnce([mockHwcRunTime] {
+ std::this_thread::sleep_for(mockHwcRunTime);
+ return hardware::graphics::composer::V2_1::Error::NONE;
+ });
+ EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(0);
static constexpr bool kVsyncId = 123; // arbitrary
mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index f1a69fb..283f9ca 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -330,6 +330,10 @@
layer->mDrawingParent = drawingParent;
}
+ void setPowerHintSessionMode(bool early, bool late) {
+ mFlinger->mPowerHintSessionMode = {.late = late, .early = early};
+ }
+
/* ------------------------------------------------------------------------
* Forwarding for functions being tested
*/
@@ -741,6 +745,7 @@
mHwcDisplayId(hwcDisplayId) {
mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
+ mCreationArgs.initialPowerMode = hal::PowerMode::ON;
}
sp<IBinder> token() const { return mDisplayToken; }
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 4eb9055..30a3f9a 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -349,6 +349,23 @@
}
}
+TEST_F(VSyncReactorTest, addHwVsyncTimestampDozePreempt) {
+ bool periodFlushed = false;
+ nsecs_t const newPeriod = 4000;
+
+ mReactor.startPeriodTransition(newPeriod);
+
+ auto time = 0;
+ // If the power mode is not DOZE or DOZE_SUSPEND, it is still collecting timestamps.
+ EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ // Set power mode to DOZE to trigger period flushing.
+ mReactor.setDisplayPowerMode(hal::PowerMode::DOZE);
+ EXPECT_FALSE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+}
+
TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsHwVsync) {
auto time = 0;
bool periodFlushed = false;
diff --git a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp
similarity index 65%
copy from libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
copy to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp
index fc2542b..5049b1d 100644
--- a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-parcelable GenericDataParcelable {
- int data;
- float majorVersion;
- float minorVersion;
- IBinder binder;
- ParcelFileDescriptor fileDescriptor;
- int[] array;
-}
\ No newline at end of file
+#include "MockAidlPowerHalWrapper.h"
+#include "MockIPower.h"
+
+namespace android::Hwc2::mock {
+
+MockAidlPowerHalWrapper::MockAidlPowerHalWrapper()
+ : AidlPowerHalWrapper(sp<testing::NiceMock<MockIPower>>::make()){};
+MockAidlPowerHalWrapper::~MockAidlPowerHalWrapper() = default;
+
+} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h
new file mode 100644
index 0000000..657ced3
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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 <gmock/gmock.h>
+
+#include "DisplayHardware/PowerAdvisor.h"
+
+namespace android {
+namespace hardware {
+namespace power {
+class IPower;
+}
+} // namespace hardware
+} // namespace android
+
+namespace android::Hwc2::mock {
+
+class MockAidlPowerHalWrapper : public Hwc2::impl::AidlPowerHalWrapper {
+public:
+ MockAidlPowerHalWrapper();
+ ~MockAidlPowerHalWrapper() override;
+ MOCK_METHOD(bool, setExpensiveRendering, (bool enabled), (override));
+ MOCK_METHOD(bool, notifyDisplayUpdateImminent, (), (override));
+ MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
+ MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
+ MOCK_METHOD(void, restartPowerHintSession, (), (override));
+ MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
+ (override));
+ MOCK_METHOD(bool, startPowerHintSession, (), (override));
+ MOCK_METHOD(void, setTargetWorkDuration, (nsecs_t targetDuration), (override));
+ MOCK_METHOD(void, sendActualWorkDuration, (nsecs_t actualDuration, nsecs_t timestamp),
+ (override));
+ MOCK_METHOD(bool, shouldReconnectHAL, (), (override));
+};
+
+} // namespace android::Hwc2::mock
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index c598cbc..aede250 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -36,11 +36,33 @@
MOCK_METHOD(bool, usePowerHintSession, (), (override));
MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
- MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
- MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
- (override));
+ MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDuration), (override));
+ MOCK_METHOD(void, sendActualWorkDuration, (), (override));
+ MOCK_METHOD(void, sendPredictedWorkDuration, (), (override));
MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
+ MOCK_METHOD(void, setGpuFenceTime,
+ (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
+ MOCK_METHOD(void, setHwcValidateTiming,
+ (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime),
+ (override));
+ MOCK_METHOD(void, setHwcPresentTiming,
+ (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime),
+ (override));
+ MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
+ MOCK_METHOD(void, setRequiresClientComposition,
+ (DisplayId displayId, bool requiresClientComposition), (override));
+ MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
+ MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime),
+ (override));
+ MOCK_METHOD(void, setHwcPresentDelayedTime,
+ (DisplayId displayId,
+ std::chrono::steady_clock::time_point earliestFrameStartTime));
+ MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override));
+ MOCK_METHOD(void, setCommitStart, (nsecs_t commitStartTime), (override));
+ MOCK_METHOD(void, setCompositeEnd, (nsecs_t compositeEndtime), (override));
+ MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override));
+ MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (int64_t targetDuration), (override));
};
} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h
index 314f681..4ef91da 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h
@@ -31,6 +31,7 @@
MOCK_METHOD3(addHwVsyncTimestamp, bool(nsecs_t, std::optional<nsecs_t>, bool*));
MOCK_METHOD1(startPeriodTransition, void(nsecs_t));
MOCK_METHOD1(setIgnorePresentFences, void(bool));
+ MOCK_METHOD(void, setDisplayPowerMode, (hal::PowerMode), (override));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
deleted file mode 100644
index 80e9a3c..0000000
--- a/services/vr/hardware_composer/Android.bp
+++ /dev/null
@@ -1,134 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_library_shared {
- name: "libvr_hwc-hal",
-
- system_ext_specific: true,
-
- srcs: [
- "impl/vr_hwc.cpp",
- "impl/vr_composer_client.cpp",
- ],
-
- static_libs: [
- "libbroadcastring",
- "libdisplay",
- ],
-
- shared_libs: [
- "android.frameworks.vr.composer@2.0",
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.composer@2.2",
- "android.hardware.graphics.composer@2.3",
- "android.hardware.graphics.composer@2.1-resources",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.graphics.mapper@4.0",
- "libbase",
- "libbufferhubqueue",
- "libbinder",
- "libcutils",
- "libfmq",
- "libhardware",
- "libhidlbase",
- "liblog",
- "libsync",
- "libui",
- "libutils",
- "libpdx_default_transport",
- ],
-
- header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
- "android.hardware.graphics.composer@2.3-hal",
- ],
-
- export_header_lib_headers: [
- "android.hardware.graphics.composer@2.3-hal",
- ],
-
- export_static_lib_headers: [
- "libdisplay",
- ],
-
- export_shared_lib_headers: [
- "android.frameworks.vr.composer@2.0",
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.composer@2.2",
- "android.hardware.graphics.composer@2.3",
- ],
-
- export_include_dirs: ["."],
-
- cflags: [
- "-DLOG_TAG=\"vr_hwc\"",
- "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
- "-Wall",
- "-Werror",
- "-Wno-error=unused-private-field",
- // Warnings in vr_hwc.cpp to be fixed after sync of goog/master.
- "-Wno-sign-compare",
- "-Wno-unused-parameter",
- ],
-
-}
-
-cc_library_static {
- name: "libvr_hwc-impl",
- srcs: [
- "vr_composer.cpp",
- ],
- static_libs: [
- "libvr_hwc-binder",
- ],
- shared_libs: [
- "libbase",
- "libbinder",
- "liblog",
- "libui",
- "libutils",
- "libvr_hwc-hal",
- ],
- export_shared_lib_headers: [
- "libvr_hwc-hal",
- ],
- cflags: [
- "-DLOG_TAG=\"vr_hwc\"",
- "-Wall",
- "-Werror",
- ],
-}
-
-cc_test {
- name: "vr_hwc_test",
- gtest: true,
- srcs: ["tests/vr_composer_test.cpp"],
- static_libs: [
- "libgtest",
- "libvr_hwc-impl",
- // NOTE: This needs to be included after the *-impl lib otherwise the
- // symbols in the *-binder library get optimized out.
- "libvr_hwc-binder",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- // warnings in vr_composer_test.cpp to be fixed after merge of goog/master
- "-Wno-sign-compare",
- "-Wno-unused-parameter",
- ],
- shared_libs: [
- "libbase",
- "libbinder",
- "liblog",
- "libui",
- "libutils",
- ],
-}
diff --git a/services/vr/hardware_composer/aidl/Android.bp b/services/vr/hardware_composer/aidl/Android.bp
deleted file mode 100644
index fa71ed7..0000000
--- a/services/vr/hardware_composer/aidl/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_library_static {
- name: "libvr_hwc-binder",
- srcs: [
- "android/dvr/IVrComposer.aidl",
- "android/dvr/IVrComposerCallback.aidl",
- "android/dvr/parcelable_composer_frame.cpp",
- "android/dvr/parcelable_composer_layer.cpp",
- "android/dvr/parcelable_unique_fd.cpp",
- ],
- aidl: {
- local_include_dirs: ["."],
- export_aidl_headers: true,
- },
- export_include_dirs: ["."],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- shared_libs: [
- "libbinder",
- "libui",
- "libutils",
- "libvr_hwc-hal",
- ],
-}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
deleted file mode 100644
index be1ec5b..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-package android.dvr;
-
-import android.dvr.IVrComposerCallback;
-
-/**
- * Service interface exposed by VR HWC exposed to system apps which allows one
- * system app to connect to get SurfaceFlinger's outputs (all displays). This
- * is active when SurfaceFlinger is in VR mode, where all 2D output is
- * redirected to VR HWC.
- *
- * @hide */
-interface IVrComposer
-{
- const String SERVICE_NAME = "vr_hwc";
-
- /**
- * 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/aidl/android/dvr/IVrComposerCallback.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
deleted file mode 100644
index aa70de1..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-package android.dvr;
-
-import android.dvr.ParcelableComposerFrame;
-import android.dvr.ParcelableUniqueFd;
-
-/**
- * A system app will implement and register this callback with VRComposer
- * to receive the layers SurfaceFlinger presented when in VR mode.
- *
- * @hide */
-interface IVrComposerCallback {
- /**
- * Called by the VR HWC service when a new frame is ready to be presented.
- *
- * @param frame The new frame VR HWC wants to present.
- * @return A fence FD used to signal when the previous frame is no longer
- * used by the client. This may be an invalid fence (-1) if the client is not
- * using the previous frame, in which case the previous frame may be re-used
- * at any point in time.
- */
- ParcelableUniqueFd onNewFrame(in ParcelableComposerFrame frame);
-}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
deleted file mode 100644
index 84abc19..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package android.dvr;
-
-parcelable ParcelableComposerFrame cpp_header "android/dvr/parcelable_composer_frame.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
deleted file mode 100644
index a200345..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package android.dvr;
-
-parcelable ParcelableComposerLayer cpp_header "android/dvr/parcelable_composer_layer.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
deleted file mode 100644
index eee9d13..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package android.dvr;
-
-parcelable ParcelableUniqueFd cpp_header "android/dvr/parcelable_unique_fd.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
deleted file mode 100644
index db7d5dc..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "aidl/android/dvr/parcelable_composer_frame.h"
-
-#include <binder/Parcel.h>
-
-#include "aidl/android/dvr/parcelable_composer_layer.h"
-
-namespace android {
-namespace dvr {
-
-ParcelableComposerFrame::ParcelableComposerFrame() {}
-
-ParcelableComposerFrame::ParcelableComposerFrame(
- const ComposerView::Frame& frame)
- : frame_(frame) {}
-
-ParcelableComposerFrame::~ParcelableComposerFrame() {}
-
-status_t ParcelableComposerFrame::writeToParcel(Parcel* parcel) const {
- status_t ret = parcel->writeUint64(frame_.display_id);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(frame_.display_width);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(frame_.display_height);
- if (ret != OK) return ret;
-
- ret = parcel->writeBool(frame_.removed);
- if (ret != OK) return ret;
-
- ret = parcel->writeUint32(static_cast<uint32_t>(frame_.active_config));
- if (ret != OK) return ret;
-
- ret = parcel->writeUint32(static_cast<uint32_t>(frame_.color_mode));
- if (ret != OK) return ret;
-
- ret = parcel->writeUint32(static_cast<uint32_t>(frame_.power_mode));
- if (ret != OK) return ret;
-
- ret = parcel->writeUint32(static_cast<uint32_t>(frame_.vsync_enabled));
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(frame_.color_transform_hint);
- if (ret != OK) return ret;
-
- for(size_t i = 0; i < 16; i++) {
- ret = parcel->writeFloat(frame_.color_transform[i]);
- if (ret != OK) return ret;
- }
-
- std::vector<ParcelableComposerLayer> layers;
- for (size_t i = 0; i < frame_.layers.size(); ++i)
- layers.push_back(ParcelableComposerLayer(frame_.layers[i]));
-
- ret = parcel->writeParcelableVector(layers);
-
- return ret;
-}
-
-status_t ParcelableComposerFrame::readFromParcel(const Parcel* parcel) {
- status_t ret = parcel->readUint64(&frame_.display_id);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&frame_.display_width);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&frame_.display_height);
- if (ret != OK) return ret;
-
- ret = parcel->readBool(&frame_.removed);
- if (ret != OK) return ret;
-
- uint32_t value;
- ret = parcel->readUint32(&value);
- if (ret != OK) return ret;
- frame_.active_config = static_cast<Config>(value);
-
- ret = parcel->readUint32(&value);
- if (ret != OK) return ret;
- frame_.color_mode = static_cast<ColorMode>(value);
-
- ret = parcel->readUint32(&value);
- if (ret != OK) return ret;
- frame_.power_mode = static_cast<IComposerClient::PowerMode>(value);
-
- ret = parcel->readUint32(&value);
- if (ret != OK) return ret;
- frame_.vsync_enabled = static_cast<IComposerClient::Vsync>(value);
-
- ret = parcel->readInt32(&frame_.color_transform_hint);
- if (ret != OK) return ret;
-
- for(size_t i = 0; i < 16; i++) {
- ret = parcel->readFloat(&frame_.color_transform[i]);
- if (ret != OK) return ret;
- }
-
- std::vector<ParcelableComposerLayer> layers;
- ret = parcel->readParcelableVector(&layers);
- if (ret != OK) return ret;
-
- frame_.layers.clear();
- for (size_t i = 0; i < layers.size(); ++i)
- frame_.layers.push_back(layers[i].layer());
-
- return ret;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
deleted file mode 100644
index a82df7f..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
-
-#include <binder/Parcelable.h>
-#include <impl/vr_hwc.h>
-
-namespace android {
-namespace dvr {
-
-class ParcelableComposerFrame : public Parcelable {
- public:
- ParcelableComposerFrame();
- explicit ParcelableComposerFrame(const ComposerView::Frame& frame);
- ~ParcelableComposerFrame() override;
-
- ComposerView::Frame frame() const { return frame_; }
-
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
-
- private:
- ComposerView::Frame frame_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
deleted file mode 100644
index c3621eb..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-#include "aidl/android/dvr/parcelable_composer_layer.h"
-
-#include <binder/Parcel.h>
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/GraphicBufferMapper.h>
-
-namespace android {
-namespace dvr {
-
-ParcelableComposerLayer::ParcelableComposerLayer() {}
-
-ParcelableComposerLayer::ParcelableComposerLayer(
- const ComposerView::ComposerLayer& layer) : layer_(layer) {}
-
-ParcelableComposerLayer::~ParcelableComposerLayer() {}
-
-status_t ParcelableComposerLayer::writeToParcel(Parcel* parcel) const {
- status_t ret = parcel->writeUint64(layer_.id);
- if (ret != OK) return ret;
-
- ret = parcel->write(*layer_.buffer);
- if (ret != OK) return ret;
-
- ret = parcel->writeBool(layer_.fence->isValid());
- if (ret != OK) return ret;
-
- if (layer_.fence->isValid()) {
- ret = parcel->writeFileDescriptor(layer_.fence->dup(), true);
- if (ret != OK) return ret;
- }
-
- ret = parcel->writeInt32(layer_.display_frame.left);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(layer_.display_frame.top);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(layer_.display_frame.right);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(layer_.display_frame.bottom);
- if (ret != OK) return ret;
-
- ret = parcel->writeFloat(layer_.crop.left);
- if (ret != OK) return ret;
-
- ret = parcel->writeFloat(layer_.crop.top);
- if (ret != OK) return ret;
-
- ret = parcel->writeFloat(layer_.crop.right);
- if (ret != OK) return ret;
-
- ret = parcel->writeFloat(layer_.crop.bottom);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(static_cast<int32_t>(layer_.blend_mode));
- if (ret != OK) return ret;
-
- ret = parcel->writeFloat(layer_.alpha);
- if (ret != OK) return ret;
-
- ret = parcel->writeUint32(layer_.type);
- if (ret != OK) return ret;
-
- ret = parcel->writeUint32(layer_.app_id);
- if (ret != OK) return ret;
-
- ret = parcel->writeUint32(layer_.z_order);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(layer_.cursor_x);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(layer_.cursor_y);
- if (ret != OK) return ret;
-
- uint32_t color = layer_.color.r |
- (static_cast<uint32_t>(layer_.color.g) << 8) |
- (static_cast<uint32_t>(layer_.color.b) << 16) |
- (static_cast<uint32_t>(layer_.color.a) << 24);
- ret = parcel->writeUint32(color);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(layer_.dataspace);
- if (ret != OK) return ret;
-
- ret = parcel->writeInt32(layer_.transform);
- if (ret != OK) return ret;
-
- ret = parcel->writeUint32(static_cast<uint32_t>(layer_.visible_regions.size()));
- if (ret != OK) return ret;
-
- for (auto& rect: layer_.visible_regions) {
- ret = parcel->writeInt32(rect.left);
- ret = parcel->writeInt32(rect.top);
- ret = parcel->writeInt32(rect.right);
- ret = parcel->writeInt32(rect.bottom);
- if (ret != OK) return ret;
- }
-
- ret = parcel->writeUint32(static_cast<uint32_t>(layer_.damaged_regions.size()));
- if (ret != OK) return ret;
-
- for (auto& rect: layer_.damaged_regions) {
- ret = parcel->writeInt32(rect.left);
- ret = parcel->writeInt32(rect.top);
- ret = parcel->writeInt32(rect.right);
- ret = parcel->writeInt32(rect.bottom);
- if (ret != OK) return ret;
- }
-
- return OK;
-}
-
-status_t ParcelableComposerLayer::readFromParcel(const Parcel* parcel) {
- status_t ret = parcel->readUint64(&layer_.id);
- if (ret != OK) return ret;
-
- layer_.buffer = new GraphicBuffer();
- ret = parcel->read(*layer_.buffer);
- if (ret != OK) {
- layer_.buffer.clear();
- return ret;
- }
-
- bool has_fence = 0;
- ret = parcel->readBool(&has_fence);
- if (ret != OK) return ret;
-
- if (has_fence)
- layer_.fence = new Fence(dup(parcel->readFileDescriptor()));
- else
- layer_.fence = new Fence();
-
- ret = parcel->readInt32(&layer_.display_frame.left);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&layer_.display_frame.top);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&layer_.display_frame.right);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&layer_.display_frame.bottom);
- if (ret != OK) return ret;
-
- ret = parcel->readFloat(&layer_.crop.left);
- if (ret != OK) return ret;
-
- ret = parcel->readFloat(&layer_.crop.top);
- if (ret != OK) return ret;
-
- ret = parcel->readFloat(&layer_.crop.right);
- if (ret != OK) return ret;
-
- ret = parcel->readFloat(&layer_.crop.bottom);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(reinterpret_cast<int32_t*>(&layer_.blend_mode));
- if (ret != OK) return ret;
-
- ret = parcel->readFloat(&layer_.alpha);
- if (ret != OK) return ret;
-
- ret = parcel->readUint32(&layer_.type);
- if (ret != OK) return ret;
-
- ret = parcel->readUint32(&layer_.app_id);
- if (ret != OK) return ret;
-
- ret = parcel->readUint32(&layer_.z_order);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&layer_.cursor_x);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&layer_.cursor_y);
- if (ret != OK) return ret;
-
- uint32_t color;
- ret = parcel->readUint32(&color);
- if (ret != OK) return ret;
- layer_.color.r = color & 0xFF;
- layer_.color.g = (color >> 8) & 0xFF;
- layer_.color.b = (color >> 16) & 0xFF;
- layer_.color.a = (color >> 24) & 0xFF;
-
- ret = parcel->readInt32(&layer_.dataspace);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&layer_.transform);
- if (ret != OK) return ret;
-
- uint32_t size;
- ret = parcel->readUint32(&size);
- if (ret != OK) return ret;
-
- for(size_t i = 0; i < size; i++) {
- hwc_rect_t rect;
- ret = parcel->readInt32(&rect.left);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&rect.top);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&rect.right);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&rect.bottom);
- if (ret != OK) return ret;
-
- layer_.visible_regions.push_back(rect);
- }
-
- ret = parcel->readUint32(&size);
- if (ret != OK) return ret;
-
- for(size_t i = 0; i < size; i++) {
- hwc_rect_t rect;
- ret = parcel->readInt32(&rect.left);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&rect.top);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&rect.right);
- if (ret != OK) return ret;
-
- ret = parcel->readInt32(&rect.bottom);
- if (ret != OK) return ret;
-
- layer_.damaged_regions.push_back(rect);
- }
-
- return OK;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
deleted file mode 100644
index 6d2ac09..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
-
-#include <binder/Parcelable.h>
-#include <impl/vr_hwc.h>
-
-#include <memory>
-
-namespace android {
-namespace dvr {
-
-class ParcelableComposerLayer : public Parcelable {
- public:
- ParcelableComposerLayer();
- explicit ParcelableComposerLayer(const ComposerView::ComposerLayer& layer);
- ~ParcelableComposerLayer() override;
-
- ComposerView::ComposerLayer layer() const { return layer_; }
-
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
-
- private:
- ComposerView::ComposerLayer layer_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
deleted file mode 100644
index 9486f3c..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "android/dvr/parcelable_unique_fd.h"
-
-#include <binder/Parcel.h>
-
-namespace android {
-namespace dvr {
-
-ParcelableUniqueFd::ParcelableUniqueFd() {}
-
-ParcelableUniqueFd::ParcelableUniqueFd(const base::unique_fd& fence)
- : fence_(dup(fence.get())) {}
-
-ParcelableUniqueFd::~ParcelableUniqueFd() {}
-
-status_t ParcelableUniqueFd::writeToParcel(Parcel* parcel) const {
- status_t ret = parcel->writeBool(fence_.get() >= 0);
- if (ret != OK) return ret;
-
- if (fence_.get() >= 0)
- ret = parcel->writeUniqueFileDescriptor(fence_);
-
- return ret;
-}
-
-status_t ParcelableUniqueFd::readFromParcel(const Parcel* parcel) {
- bool has_fence = 0;
- status_t ret = parcel->readBool(&has_fence);
- if (ret != OK) return ret;
-
- if (has_fence)
- ret = parcel->readUniqueFileDescriptor(&fence_);
-
- return ret;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
deleted file mode 100644
index c4216f6..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
-
-#include <android-base/unique_fd.h>
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace dvr {
-
-// Provide a wrapper to serialized base::unique_fd. The wrapper also handles the
-// case where the FD is invalid (-1), unlike FileDescriptor which expects a
-// valid FD.
-class ParcelableUniqueFd : public Parcelable {
- public:
- ParcelableUniqueFd();
- explicit ParcelableUniqueFd(const base::unique_fd& fence);
- ~ParcelableUniqueFd() override;
-
- void set_fence(const base::unique_fd& fence) {
- fence_.reset(dup(fence.get()));
- }
- base::unique_fd fence() const { return base::unique_fd(dup(fence_.get())); }
-
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
-
- private:
- base::unique_fd fence_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
deleted file mode 100644
index dd1603d..0000000
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ /dev/null
@@ -1,123 +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.
- */
-
-#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
-#include <hardware/gralloc.h>
-#include <hardware/gralloc1.h>
-#include <log/log.h>
-
-#include <memory>
-
-#include "impl/vr_hwc.h"
-#include "impl/vr_composer_client.h"
-
-namespace android {
-namespace dvr {
-
-using android::frameworks::vr::composer::V2_0::IVrComposerClient;
-
-VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
- : ComposerClient(&hal), mVrHal(hal) {
- if (!init()) {
- LOG_ALWAYS_FATAL("failed to initialize VrComposerClient");
- }
-}
-
-VrComposerClient::~VrComposerClient() {}
-
-std::unique_ptr<ComposerCommandEngine>
-VrComposerClient::createCommandEngine() {
- return std::make_unique<VrCommandEngine>(*this);
-}
-
-VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client)
- : ComposerCommandEngine(client.mHal, client.mResources.get()),
- mVrHal(client.mVrHal) {}
-
-VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
-
-bool VrComposerClient::VrCommandEngine::executeCommand(
- hardware::graphics::composer::V2_1::IComposerClient::Command command,
- uint16_t length) {
- IVrComposerClient::VrCommand vrCommand =
- static_cast<IVrComposerClient::VrCommand>(command);
- switch (vrCommand) {
- case IVrComposerClient::VrCommand::SET_LAYER_INFO:
- return executeSetLayerInfo(length);
- case IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA:
- return executeSetClientTargetMetadata(length);
- case IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA:
- return executeSetLayerBufferMetadata(length);
- default:
- return ComposerCommandEngine::executeCommand(command, length);
- }
-}
-
-bool VrComposerClient::VrCommandEngine::executeSetLayerInfo(uint16_t length) {
- if (length != 2) {
- return false;
- }
-
- auto err = mVrHal.setLayerInfo(mCurrentDisplay, mCurrentLayer, read(), read());
- if (err != Error::NONE) {
- mWriter->setError(getCommandLoc(), err);
- }
-
- return true;
-}
-
-bool VrComposerClient::VrCommandEngine::executeSetClientTargetMetadata(
- uint16_t length) {
- if (length != 7)
- return false;
-
- auto err = mVrHal.setClientTargetMetadata(mCurrentDisplay, readBufferMetadata());
- if (err != Error::NONE)
- mWriter->setError(getCommandLoc(), err);
-
- return true;
-}
-
-bool VrComposerClient::VrCommandEngine::executeSetLayerBufferMetadata(
- uint16_t length) {
- if (length != 7)
- return false;
-
- auto err = mVrHal.setLayerBufferMetadata(mCurrentDisplay, mCurrentLayer,
- readBufferMetadata());
- if (err != Error::NONE)
- mWriter->setError(getCommandLoc(), err);
-
- return true;
-}
-
-IVrComposerClient::BufferMetadata
-VrComposerClient::VrCommandEngine::readBufferMetadata() {
- IVrComposerClient::BufferMetadata metadata = {
- .width = read(),
- .height = read(),
- .stride = read(),
- .layerCount = read(),
- .format =
- static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(
- readSigned()),
- .usage = read64(),
- };
- return metadata;
-}
-
-} // 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
deleted file mode 100644
index 1b2b5f4..0000000
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
-
-#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
-#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
-#include <composer-hal/2.1/ComposerClient.h>
-#include <composer-hal/2.1/ComposerCommandEngine.h>
-#include <composer-hal/2.2/ComposerClient.h>
-#include <composer-hal/2.3/ComposerClient.h>
-
-namespace android {
-namespace dvr {
-
-class VrHwc;
-
-using hardware::graphics::composer::V2_1::hal::ComposerCommandEngine;
-using hardware::graphics::composer::V2_3::hal::ComposerHal;
-using hardware::graphics::composer::V2_3::hal::detail::ComposerClientImpl;
-
-using ComposerClient = ComposerClientImpl<IVrComposerClient, ComposerHal>;
-
-class VrComposerClient : public ComposerClient {
- public:
- explicit VrComposerClient(android::dvr::VrHwc& hal);
- virtual ~VrComposerClient();
-
- private:
- class VrCommandEngine : public ComposerCommandEngine {
- public:
- explicit VrCommandEngine(VrComposerClient& client);
- ~VrCommandEngine() override;
-
- bool executeCommand(
- hardware::graphics::composer::V2_1::IComposerClient::Command command,
- uint16_t length) override;
-
- private:
- bool executeSetLayerInfo(uint16_t length);
- bool executeSetClientTargetMetadata(uint16_t length);
- bool executeSetLayerBufferMetadata(uint16_t length);
-
- IVrComposerClient::BufferMetadata readBufferMetadata();
-
- android::dvr::VrHwc& mVrHal;
-
- VrCommandEngine(const VrCommandEngine&) = delete;
- void operator=(const VrCommandEngine&) = delete;
- };
-
- VrComposerClient(const VrComposerClient&) = delete;
- void operator=(const VrComposerClient&) = delete;
-
- std::unique_ptr<ComposerCommandEngine> createCommandEngine() override;
- dvr::VrHwc& mVrHal;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
deleted file mode 100644
index e530b16..0000000
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ /dev/null
@@ -1,1178 +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.
- */
-#include "impl/vr_hwc.h"
-
-#include "android-base/stringprintf.h"
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
-#include <private/dvr/display_client.h>
-#include <ui/Fence.h>
-#include <utils/Trace.h>
-
-#include <mutex>
-
-#include "vr_composer_client.h"
-
-using namespace android::hardware::graphics::common::V1_0;
-using namespace android::hardware::graphics::composer::V2_3;
-
-using android::base::StringPrintf;
-using android::hardware::hidl_handle;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using android::hardware::Void;
-
-namespace types = android::hardware::graphics::common;
-
-namespace android {
-namespace dvr {
-namespace {
-
-const Display kDefaultDisplayId = 1;
-const Config kDefaultConfigId = 1;
-
-sp<GraphicBuffer> CreateGraphicBuffer(
- const native_handle_t* handle,
- const IVrComposerClient::BufferMetadata& metadata) {
- sp<GraphicBuffer> buffer = new GraphicBuffer(
- handle, GraphicBuffer::CLONE_HANDLE, metadata.width, metadata.height,
- static_cast<int32_t>(metadata.format), metadata.layerCount,
- metadata.usage, metadata.stride);
- if (buffer->initCheck() != OK) {
- ALOGE("Failed to create graphic buffer");
- return nullptr;
- }
-
- return buffer;
-}
-
-void GetPrimaryDisplaySize(int32_t* width, int32_t* height) {
- *width = 1080;
- *height = 1920;
-
- 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;
- }
-
- auto status = display_client->GetDisplayMetrics();
- if (!status) {
- ALOGE("Could not get display metrics from display service : %s(%d)",
- status.GetErrorMessage().c_str(), status.error());
- return;
- }
-
- *width = status.get().display_width;
- *height = status.get().display_height;
-}
-
-} // namespace
-
-HwcDisplay::HwcDisplay(int32_t width, int32_t height)
- : width_(width), height_(height) {}
-
-HwcDisplay::~HwcDisplay() {}
-
-bool HwcDisplay::SetClientTarget(const native_handle_t* handle,
- base::unique_fd fence) {
- if (handle)
- buffer_ = CreateGraphicBuffer(handle, buffer_metadata_);
-
- fence_ = new Fence(fence.release());
- return true;
-}
-
-void HwcDisplay::SetClientTargetMetadata(
- const IVrComposerClient::BufferMetadata& metadata) {
- buffer_metadata_ = metadata;
-}
-
-HwcLayer* HwcDisplay::CreateLayer() {
- uint64_t layer_id = layer_ids_++;
- layers_.push_back(HwcLayer(layer_id));
- return &layers_.back();
-}
-
-HwcLayer* HwcDisplay::GetLayer(Layer id) {
- for (size_t i = 0; i < layers_.size(); ++i)
- if (layers_[i].info.id == id)
- return &layers_[i];
-
- return nullptr;
-}
-
-bool HwcDisplay::DestroyLayer(Layer id) {
- for (auto it = layers_.begin(); it != layers_.end(); ++it) {
- if (it->info.id == id) {
- layers_.erase(it);
- return true;
- }
- }
-
- return false;
-}
-
-void HwcDisplay::GetChangedCompositionTypes(
- std::vector<Layer>* layer_ids,
- std::vector<IComposerClient::Composition>* types) {
- std::sort(layers_.begin(), layers_.end(),
- [](const auto& lhs, const auto& rhs) {
- return lhs.info.z_order < rhs.info.z_order;
- });
-
- const size_t no_layer = std::numeric_limits<size_t>::max();
- size_t first_client_layer = no_layer, last_client_layer = no_layer;
- for (size_t i = 0; i < layers_.size(); ++i) {
- switch (layers_[i].composition_type) {
- case IComposerClient::Composition::SOLID_COLOR:
- case IComposerClient::Composition::CURSOR:
- case IComposerClient::Composition::SIDEBAND:
- if (first_client_layer == no_layer)
- first_client_layer = i;
-
- last_client_layer = i;
- break;
- default:
- break;
- }
- }
-
- for (size_t i = 0; i < layers_.size(); ++i) {
- if (i >= first_client_layer && i <= last_client_layer) {
- if (layers_[i].composition_type != IComposerClient::Composition::CLIENT) {
- layer_ids->push_back(layers_[i].info.id);
- types->push_back(IComposerClient::Composition::CLIENT);
- layers_[i].composition_type = IComposerClient::Composition::CLIENT;
- }
-
- continue;
- }
-
- if (layers_[i].composition_type != IComposerClient::Composition::DEVICE) {
- layer_ids->push_back(layers_[i].info.id);
- types->push_back(IComposerClient::Composition::DEVICE);
- layers_[i].composition_type = IComposerClient::Composition::DEVICE;
- }
- }
-}
-
-Error HwcDisplay::GetFrame(
- std::vector<ComposerView::ComposerLayer>* out_frames) {
- bool queued_client_target = false;
- std::vector<ComposerView::ComposerLayer> frame;
- for (const auto& layer : layers_) {
- if (layer.composition_type == IComposerClient::Composition::CLIENT) {
- if (queued_client_target)
- continue;
-
- if (!buffer_.get()) {
- ALOGE("Client composition requested but no client target buffer");
- return Error::BAD_LAYER;
- }
-
- ComposerView::ComposerLayer client_target_layer = {
- .buffer = buffer_,
- .fence = fence_.get() ? fence_ : new Fence(-1),
- .display_frame = {0, 0, static_cast<int32_t>(buffer_->getWidth()),
- static_cast<int32_t>(buffer_->getHeight())},
- .crop = {0.0f, 0.0f, static_cast<float>(buffer_->getWidth()),
- static_cast<float>(buffer_->getHeight())},
- .blend_mode = IComposerClient::BlendMode::NONE,
- };
-
- frame.push_back(client_target_layer);
- queued_client_target = true;
- } else {
- if (!layer.info.buffer.get() || !layer.info.fence.get()) {
- ALOGV("Layer requested without valid buffer");
- continue;
- }
-
- frame.push_back(layer.info);
- }
- }
-
- out_frames->swap(frame);
- return Error::NONE;
-}
-
-std::vector<Layer> HwcDisplay::UpdateLastFrameAndGetLastFrameLayers() {
- std::vector<Layer> last_frame_layers;
- last_frame_layers.swap(last_frame_layers_ids_);
-
- for (const auto& layer : layers_)
- last_frame_layers_ids_.push_back(layer.info.id);
-
- return last_frame_layers;
-}
-
-void HwcDisplay::SetColorTransform(const float* matrix, int32_t hint) {
- color_transform_hint_ = hint;
- if (matrix)
- memcpy(color_transform_, matrix, sizeof(color_transform_));
-}
-
-void HwcDisplay::dumpDebugInfo(std::string* result) const {
- if (!result) {
- return;
- }
- *result += StringPrintf("HwcDisplay: width: %d, height: %d, layers size: %zu, colormode: %d\
- , config: %d\n", width_, height_, layers_.size(), color_mode_, active_config_);
- *result += StringPrintf("HwcDisplay buffer metadata: width: %d, height: %d, stride: %d,\
- layerCount: %d, pixelFormat: %d\n", buffer_metadata_.width, buffer_metadata_.height,
- buffer_metadata_.stride, buffer_metadata_.layerCount, buffer_metadata_.format);
- for (const auto& layer : layers_) {
- layer.dumpDebugInfo(result);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// VrHwcClient
-
-VrHwc::VrHwc() {
- vsync_callback_ = new VsyncCallback;
-}
-
-VrHwc::~VrHwc() {
- vsync_callback_->SetEventCallback(nullptr);
-}
-
-bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
-
-void VrHwc::registerEventCallback(EventCallback* callback) {
- std::unique_lock<std::mutex> lock(mutex_);
- event_callback_ = callback;
- int32_t width, height;
- GetPrimaryDisplaySize(&width, &height);
- // Create the primary display late to avoid initialization issues between
- // VR HWC and SurfaceFlinger.
- displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
-
- // Surface flinger will make calls back into vr_hwc when it receives the
- // onHotplug() call, so it's important to release mutex_ here.
- lock.unlock();
- event_callback_->onHotplug(kDefaultDisplayId,
- hardware::graphics::composer::V2_1::
- IComposerCallback::Connection::CONNECTED);
- lock.lock();
- UpdateVsyncCallbackEnabledLocked();
-}
-
-void VrHwc::unregisterEventCallback() {
- std::lock_guard<std::mutex> guard(mutex_);
- event_callback_ = nullptr;
- UpdateVsyncCallbackEnabledLocked();
-}
-
-uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
-
-Error VrHwc::destroyVirtualDisplay(Display display) {
- std::lock_guard<std::mutex> guard(mutex_);
- if (display == kDefaultDisplayId || displays_.erase(display) == 0)
- return Error::BAD_DISPLAY;
- ComposerView::Frame frame;
- frame.display_id = display;
- frame.removed = true;
- if (observer_)
- observer_->OnNewFrame(frame);
- return Error::NONE;
-}
-
-Error VrHwc::createLayer(Display display, Layer* outLayer) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* layer = display_ptr->CreateLayer();
- *outLayer = layer->info.id;
- return Error::NONE;
-}
-
-Error VrHwc::destroyLayer(Display display, Layer layer) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr) {
- return Error::BAD_DISPLAY;
- }
-
- return display_ptr->DestroyLayer(layer) ? Error::NONE : Error::BAD_LAYER;
-}
-
-Error VrHwc::getActiveConfig(Display display, Config* outConfig) {
- std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
- return Error::BAD_DISPLAY;
- *outConfig = kDefaultConfigId;
- return Error::NONE;
-}
-
-Error VrHwc::getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute,
- int32_t* outValue) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr) {
- return Error::BAD_DISPLAY;
- }
- if (config != kDefaultConfigId) {
- return Error::BAD_CONFIG;
- }
-
- switch (attribute) {
- case IComposerClient::Attribute::WIDTH:
- *outValue = display_ptr->width();
- break;
- case IComposerClient::Attribute::HEIGHT:
- *outValue = display_ptr->height();
- break;
- case IComposerClient::Attribute::VSYNC_PERIOD:
- {
- 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:
- {
- 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;
- }
-
- return Error::NONE;
-}
-
-Error VrHwc::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) {
- std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
- return Error::BAD_DISPLAY;
- std::vector<Config> configs(1, kDefaultConfigId);
- *outConfigs = hidl_vec<Config>(configs);
- return Error::NONE;
-}
-
-Error VrHwc::getDisplayName(Display /* display */, hidl_string* outName) {
- *outName = hidl_string();
- return Error::NONE;
-}
-
-Error VrHwc::getDisplayType(Display display,
- IComposerClient::DisplayType* outType) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr) {
- *outType = IComposerClient::DisplayType::INVALID;
- return Error::BAD_DISPLAY;
- }
-
- if (display == kDefaultDisplayId)
- *outType = IComposerClient::DisplayType::PHYSICAL;
- else
- *outType = IComposerClient::DisplayType::VIRTUAL;
-
- return Error::NONE;
-}
-
-Error VrHwc::getDozeSupport(Display display, bool* outSupport) {
- *outSupport = false;
- std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
- return Error::BAD_DISPLAY;
- return Error::NONE;
-}
-
-Error VrHwc::setActiveConfig(Display display, Config config) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
- if (config != kDefaultConfigId)
- return Error::BAD_CONFIG;
-
- display_ptr->set_active_config(config);
- return Error::NONE;
-}
-
-Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- if (enabled != IComposerClient::Vsync::ENABLE &&
- enabled != IComposerClient::Vsync::DISABLE) {
- return Error::BAD_PARAMETER;
- }
-
- Error set_vsync_result = Error::NONE;
- if (display == kDefaultDisplayId) {
- sp<IVsyncService> vsync_service = interface_cast<IVsyncService>(
- defaultServiceManager()->getService(
- String16(IVsyncService::GetServiceName())));
- if (vsync_service == nullptr) {
- ALOGE("Failed to get vsync service");
- return Error::NO_RESOURCES;
- }
-
- if (enabled == IComposerClient::Vsync::ENABLE) {
- ALOGI("Enable vsync");
- display_ptr->set_vsync_enabled(true);
- status_t result = vsync_service->registerCallback(vsync_callback_);
- if (result != OK) {
- ALOGE("%s service registerCallback() failed: %s (%d)",
- IVsyncService::GetServiceName(), strerror(-result), result);
- set_vsync_result = Error::NO_RESOURCES;
- }
- } else if (enabled == IComposerClient::Vsync::DISABLE) {
- ALOGI("Disable vsync");
- display_ptr->set_vsync_enabled(false);
- status_t result = vsync_service->unregisterCallback(vsync_callback_);
- if (result != OK) {
- ALOGE("%s service unregisterCallback() failed: %s (%d)",
- IVsyncService::GetServiceName(), strerror(-result), result);
- set_vsync_result = Error::NO_RESOURCES;
- }
- }
-
- UpdateVsyncCallbackEnabledLocked();
- }
-
- return set_vsync_result;
-}
-
-Error VrHwc::setColorTransform(Display display, const float* matrix,
- int32_t hint) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- display_ptr->SetColorTransform(matrix, hint);
- return Error::NONE;
-}
-
-Error VrHwc::setClientTarget(Display display, buffer_handle_t target,
- int32_t acquireFence, int32_t /* dataspace */,
- const std::vector<hwc_rect_t>& /* damage */) {
- base::unique_fd fence(acquireFence);
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- if (target == nullptr)
- return Error::NONE;
-
- if (!display_ptr->SetClientTarget(target, std::move(fence)))
- return Error::BAD_PARAMETER;
-
- return Error::NONE;
-}
-
-Error VrHwc::setOutputBuffer(Display display, buffer_handle_t /* buffer */,
- int32_t releaseFence) {
- base::unique_fd fence(releaseFence);
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- // TODO(dnicoara): Is it necessary to do anything here?
- return Error::NONE;
-}
-
-Error VrHwc::validateDisplay(
- Display display, std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* /* outDisplayRequestMask */,
- std::vector<Layer>* /* outRequestedLayers */,
- std::vector<uint32_t>* /* outRequestMasks */) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- display_ptr->GetChangedCompositionTypes(outChangedLayers,
- outCompositionTypes);
- return Error::NONE;
-}
-
-Error VrHwc::acceptDisplayChanges(Display /* display */) { return Error::NONE; }
-
-Error VrHwc::presentDisplay(Display display, int32_t* outPresentFence,
- std::vector<Layer>* outLayers,
- std::vector<int32_t>* outReleaseFences) {
- *outPresentFence = -1;
- outLayers->clear();
- outReleaseFences->clear();
-
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
-
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- ComposerView::Frame frame;
- std::vector<Layer> last_frame_layers;
- Error status = display_ptr->GetFrame(&frame.layers);
- frame.display_id = display;
- frame.display_width = display_ptr->width();
- frame.display_height = display_ptr->height();
- frame.active_config = display_ptr->active_config();
- frame.power_mode = display_ptr->power_mode();
- frame.vsync_enabled = display_ptr->vsync_enabled() ?
- IComposerClient::Vsync::ENABLE : IComposerClient::Vsync::DISABLE;
- frame.color_transform_hint = display_ptr->color_transform_hint();
- frame.color_mode = display_ptr->color_mode();
- memcpy(frame.color_transform, display_ptr->color_transform(),
- sizeof(frame.color_transform));
- if (status != Error::NONE)
- return status;
-
- last_frame_layers = display_ptr->UpdateLastFrameAndGetLastFrameLayers();
-
- base::unique_fd fence;
- if (observer_)
- fence = observer_->OnNewFrame(frame);
-
- if (fence.get() < 0)
- return Error::NONE;
-
- *outPresentFence = dup(fence.get());
- outLayers->swap(last_frame_layers);
- for (size_t i = 0; i < outLayers->size(); ++i)
- outReleaseFences->push_back(dup(fence.get()));
-
- return Error::NONE;
-}
-
-Error VrHwc::setLayerCursorPosition(Display display, Layer layer, int32_t x,
- int32_t y) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.cursor_x = x;
- hwc_layer->info.cursor_y = y;
- return Error::NONE;
-}
-
-Error VrHwc::setLayerBuffer(Display display, Layer layer,
- buffer_handle_t buffer, int32_t acquireFence) {
- base::unique_fd fence(acquireFence);
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.buffer = CreateGraphicBuffer(
- buffer, hwc_layer->buffer_metadata);
- hwc_layer->info.fence = new Fence(fence.release());
-
- return Error::NONE;
-}
-
-Error VrHwc::setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<hwc_rect_t>& damage) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.damaged_regions = damage;
- return Error::NONE;
-}
-
-Error VrHwc::setLayerBlendMode(Display display, Layer layer, int32_t mode) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.blend_mode =
- static_cast<ComposerView::ComposerLayer::BlendMode>(mode);
-
- return Error::NONE;
-}
-
-Error VrHwc::setLayerColor(Display display, Layer layer,
- IComposerClient::Color color) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.color = color;
- return Error::NONE;
-}
-
-Error VrHwc::setLayerCompositionType(Display display, Layer layer,
- int32_t type) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->composition_type = static_cast<HwcLayer::Composition>(type);
-
- return Error::NONE;
-}
-
-Error VrHwc::setLayerDataspace(Display display, Layer layer,
- int32_t dataspace) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.dataspace = dataspace;
- return Error::NONE;
-}
-
-Error VrHwc::setLayerDisplayFrame(Display display, Layer layer,
- const hwc_rect_t& frame) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.display_frame =
- {frame.left, frame.top, frame.right, frame.bottom};
-
- return Error::NONE;
-}
-
-Error VrHwc::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.alpha = alpha;
-
- return Error::NONE;
-}
-
-Error VrHwc::setLayerSidebandStream(Display display, Layer /* layer */,
- buffer_handle_t /* stream */) {
- std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
- return Error::BAD_DISPLAY;
- return Error::NONE;
-}
-
-Error VrHwc::setLayerSourceCrop(Display display, Layer layer,
- const hwc_frect_t& crop) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.crop = {crop.left, crop.top, crop.right, crop.bottom};
-
- return Error::NONE;
-}
-
-Error VrHwc::setLayerTransform(Display display, Layer layer,
- int32_t transform) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.transform = transform;
- return Error::NONE;
-}
-
-Error VrHwc::setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<hwc_rect_t>& visible) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.visible_regions = visible;
- return Error::NONE;
-}
-
-Error VrHwc::setLayerZOrder(Display display, Layer layer, uint32_t z) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.z_order = z;
-
- return Error::NONE;
-}
-
-Error VrHwc::setLayerInfo(Display display, Layer layer, uint32_t type,
- uint32_t appId) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->info.type = type;
- hwc_layer->info.app_id = appId;
-
- return Error::NONE;
-}
-
-Error VrHwc::setClientTargetMetadata(
- Display display, const IVrComposerClient::BufferMetadata& metadata) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- display_ptr->SetClientTargetMetadata(metadata);
-
- return Error::NONE;
-}
-
-Error VrHwc::setLayerBufferMetadata(
- Display display, Layer layer,
- const IVrComposerClient::BufferMetadata& metadata) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
- if (!hwc_layer)
- return Error::BAD_LAYER;
-
- hwc_layer->buffer_metadata = metadata;
-
- return Error::NONE;
-}
-
-Return<void> VrHwc::getCapabilities(getCapabilities_cb hidl_cb) {
- hidl_cb(hidl_vec<Capability>());
- return Void();
-}
-
-Return<void> VrHwc::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
- std::string result;
-
- {
- std::lock_guard<std::mutex> guard(mutex_);
- result = "\nVrHwc states:\n";
- for (const auto& pair : displays_) {
- result += StringPrintf("Display id: %lu\n", (unsigned long)pair.first);
- pair.second->dumpDebugInfo(&result);
- }
- result += "\n";
- }
-
- hidl_cb(hidl_string(result));
- return Void();
-}
-
-Return<void> VrHwc::createClient(createClient_cb hidl_cb) {
- std::lock_guard<std::mutex> guard(mutex_);
-
- Error status = Error::NONE;
- sp<VrComposerClient> client;
- if (!client_.promote().get()) {
- client = new VrComposerClient(*this);
- } else {
- ALOGE("Already have a client");
- status = Error::NO_RESOURCES;
- }
-
- client_ = client;
- hidl_cb(status, client);
- return Void();
-}
-
-Return<void> VrHwc::createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) {
- std::lock_guard<std::mutex> guard(mutex_);
-
- Error status = Error::NONE;
- sp<VrComposerClient> client;
- if (!client_.promote().get()) {
- client = new VrComposerClient(*this);
- } else {
- ALOGE("Already have a client");
- status = Error::NO_RESOURCES;
- }
-
- client_ = client;
- hidl_cb(status, client);
- return Void();
-}
-
-void VrHwc::ForceDisplaysRefresh() {
- std::lock_guard<std::mutex> guard(mutex_);
- if (event_callback_ != nullptr) {
- for (const auto& pair : displays_)
- event_callback_->onRefresh(pair.first);
- }
-}
-
-void VrHwc::RegisterObserver(Observer* observer) {
- std::lock_guard<std::mutex> guard(mutex_);
- if (observer_)
- ALOGE("Overwriting observer");
- else
- observer_ = observer;
-}
-
-void VrHwc::UnregisterObserver(Observer* observer) {
- std::lock_guard<std::mutex> guard(mutex_);
- if (observer != observer_)
- ALOGE("Trying to unregister unknown observer");
- else
- observer_ = nullptr;
-}
-
-HwcDisplay* VrHwc::FindDisplay(Display display) {
- auto iter = displays_.find(display);
- return iter == displays_.end() ? nullptr : iter->second.get();
-}
-
-void VrHwc::UpdateVsyncCallbackEnabledLocked() {
- auto primary_display = FindDisplay(kDefaultDisplayId);
- LOG_ALWAYS_FATAL_IF(event_callback_ != nullptr && primary_display == nullptr,
- "Should have created the primary display by now");
- bool send_vsync =
- event_callback_ != nullptr && primary_display->vsync_enabled();
- vsync_callback_->SetEventCallback(send_vsync ? event_callback_ : nullptr);
-}
-
-Return<void> VrHwc::debug(const hidl_handle& fd,
- const hidl_vec<hidl_string>& args) {
- std::string result;
-
- {
- std::lock_guard<std::mutex> guard(mutex_);
- for (const auto& pair : displays_) {
- result += StringPrintf("Display id: %d\n", static_cast<int>(pair.first));
- pair.second->dumpDebugInfo(&result);
- }
- result += "\n";
- }
-
- FILE* out = fdopen(dup(fd->data[0]), "w");
- fprintf(out, "%s", result.c_str());
- fclose(out);
-
- return Void();
-}
-
-void HwcLayer::dumpDebugInfo(std::string* result) const {
- if (!result) {
- return;
- }
- *result += StringPrintf("Layer: composition_type: %d, type: %d, app_id: %d, z_order: %d,\
- cursor_x: %d, cursor_y: %d, color(rgba): (%d,%d,%d,%d), dataspace: %d, transform: %d,\
- display_frame(LTRB): (%d,%d,%d,%d), crop(LTRB): (%.1f,%.1f,%.1f,%.1f), blend_mode: %d\n",
- composition_type, info.type, info.app_id, info.z_order, info.cursor_x, info.cursor_y,
- info.color.r, info.color.g, info.color.b, info.color.a, info.dataspace, info.transform,
- info.display_frame.left, info.display_frame.top, info.display_frame.right,
- info.display_frame.bottom, info.crop.left, info.crop.top, info.crop.right,
- info.crop.bottom, info.blend_mode);
- *result += StringPrintf("Layer buffer metadata: width: %d, height: %d, stride: %d, layerCount: %d\
- , pixelFormat: %d\n", buffer_metadata.width, buffer_metadata.height, buffer_metadata.stride,
- buffer_metadata.layerCount, buffer_metadata.format);
-}
-
-status_t VrHwc::VsyncCallback::onVsync(int64_t vsync_timestamp) {
- ATRACE_NAME("vr_hwc onVsync");
- std::lock_guard<std::mutex> guard(mutex_);
- if (callback_ != nullptr)
- callback_->onVsync(kDefaultDisplayId, vsync_timestamp);
- return OK;
-}
-
-void VrHwc::VsyncCallback::SetEventCallback(EventCallback* callback) {
- std::lock_guard<std::mutex> guard(mutex_);
- callback_ = callback;
-}
-
-// composer::V2_2::ComposerHal
-Error VrHwc::setReadbackBuffer(Display display,
- const native_handle_t* bufferHandle,
- android::base::unique_fd fenceFd) {
- return Error::NONE;
-}
-
-Error VrHwc::getReadbackBufferFence(Display display,
- android::base::unique_fd* outFenceFd) {
- return Error::NONE;
-}
-
-Error VrHwc::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
- types::V1_1::PixelFormat* format,
- Display* outDisplay) {
- *format = types::V1_1::PixelFormat::RGBA_8888;
- *outDisplay = display_count_;
- displays_[display_count_].reset(new HwcDisplay(width, height));
- display_count_++;
- return Error::NONE;
-}
-
-Error VrHwc::setPowerMode_2_2(Display display,
- IComposerClient::PowerMode mode) {
- bool dozeSupported = false;
-
- Error dozeSupportError = getDozeSupport(display, &dozeSupported);
-
- if (dozeSupportError != Error::NONE)
- return dozeSupportError;
-
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- if (mode < IComposerClient::PowerMode::OFF ||
- mode > IComposerClient::PowerMode::DOZE_SUSPEND) {
- return Error::BAD_PARAMETER;
- }
-
- if (!dozeSupported && (mode == IComposerClient::PowerMode::DOZE ||
- mode == IComposerClient::PowerMode::DOZE_SUSPEND)) {
- return Error::UNSUPPORTED;
- }
-
- display_ptr->set_power_mode(mode);
- return Error::NONE;
-}
-
-Error VrHwc::setLayerFloatColor(Display display, Layer layer,
- IComposerClient::FloatColor color) {
- return Error::NONE;
-}
-
-Error VrHwc::getRenderIntents(Display display, types::V1_1::ColorMode mode,
- std::vector<RenderIntent>* outIntents) {
- return Error::NONE;
-}
-
-std::array<float, 16> VrHwc::getDataspaceSaturationMatrix(
- types::V1_1::Dataspace dataspace) {
- return {};
-}
-
-// composer::V2_3::ComposerHal
-Error VrHwc::getHdrCapabilities_2_3(Display /*display*/,
- hidl_vec<Hdr>* /*outTypes*/,
- float* outMaxLuminance,
- float* outMaxAverageLuminance,
- float* outMinLuminance) {
- *outMaxLuminance = 0;
- *outMaxAverageLuminance = 0;
- *outMinLuminance = 0;
- return Error::NONE;
-}
-
-Error VrHwc::setLayerPerFrameMetadata_2_3(
- Display display, Layer layer,
- const std::vector<IComposerClient::PerFrameMetadata>& metadata) {
- return Error::NONE;
-}
-
-Error VrHwc::getPerFrameMetadataKeys_2_3(
- Display display,
- std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) {
- return Error::NONE;
-}
-
-Error VrHwc::setColorMode_2_3(Display display, ColorMode mode,
- RenderIntent intent) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3)
- return Error::BAD_PARAMETER;
-
- display_ptr->set_color_mode(mode);
- return Error::NONE;
-}
-
-Error VrHwc::getRenderIntents_2_3(Display display, ColorMode mode,
- std::vector<RenderIntent>* outIntents) {
- return Error::NONE;
-}
-
-Error VrHwc::getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) {
- return Error::NONE;
-}
-
-Error VrHwc::getClientTargetSupport_2_3(Display display, uint32_t width,
- uint32_t height, PixelFormat format,
- Dataspace dataspace) {
- return Error::NONE;
-}
-
-Error VrHwc::getReadbackBufferAttributes_2_3(Display display,
- PixelFormat* outFormat,
- Dataspace* outDataspace) {
- return Error::NONE;
-}
-
-Error VrHwc::getDisplayIdentificationData(Display display, uint8_t* outPort,
- std::vector<uint8_t>* outData) {
- 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 Error::BAD_CONFIG;
- }
- auto edid_data = display_client->GetConfigurationData(
- display::ConfigFileType::kDeviceEdid);
- auto display_identification_port =
- display_client->GetDisplayIdentificationPort();
- *outPort = display_identification_port.get();
-
- std::copy(edid_data.get().begin(), edid_data.get().end(),
- std::back_inserter(*outData));
- return Error::NONE;
-}
-
-Error VrHwc::setLayerColorTransform(Display display, Layer layer,
- const float* matrix) {
- return Error::NONE;
-}
-
-Error VrHwc::getDisplayedContentSamplingAttributes(
- Display display, PixelFormat& format, Dataspace& dataspace,
- hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
- return Error::NONE;
-}
-
-Error VrHwc::setDisplayedContentSamplingEnabled(
- Display display, IComposerClient::DisplayedContentSampling enable,
- hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
- uint64_t maxFrames) {
- return Error::NONE;
-}
-
-Error VrHwc::getDisplayedContentSample(Display display, uint64_t maxFrames,
- uint64_t timestamp, uint64_t& frameCount,
- hidl_vec<uint64_t>& sampleComponent0,
- hidl_vec<uint64_t>& sampleComponent1,
- hidl_vec<uint64_t>& sampleComponent2,
- hidl_vec<uint64_t>& sampleComponent3) {
- return Error::NONE;
-}
-
-Error VrHwc::getDisplayCapabilities(
- Display display,
- std::vector<IComposerClient::DisplayCapability>* outCapabilities) {
- return Error::NONE;
-}
-
-Error VrHwc::setLayerPerFrameMetadataBlobs(
- Display display, Layer layer,
- std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) {
- return Error::NONE;
-}
-
-Error VrHwc::getDisplayBrightnessSupport(Display display, bool* outSupport) {
- return Error::NONE;
-}
-
-Error VrHwc::setDisplayBrightness(Display display, float brightness) {
- return Error::NONE;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
deleted file mode 100644
index 3e3a630..0000000
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ /dev/null
@@ -1,410 +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.
- */
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H
-
-#include <android-base/unique_fd.h>
-#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
-#include <android/hardware/graphics/composer/2.3/IComposer.h>
-#include <composer-hal/2.3/ComposerHal.h>
-#include <private/dvr/vsync_service.h>
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/StrongPointer.h>
-
-#include <mutex>
-#include <unordered_map>
-
-using namespace android::frameworks::vr::composer::V2_0;
-using namespace android::hardware::graphics::common::V1_0;
-using namespace android::hardware::graphics::composer::V2_3;
-
-using android::hardware::hidl_bitfield;
-using android::hardware::hidl_handle;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using android::hardware::Void;
-using android::hardware::graphics::composer::V2_1::Config;
-using android::hardware::graphics::composer::V2_1::Display;
-using android::hardware::graphics::composer::V2_1::Error;
-using android::hardware::graphics::composer::V2_1::Layer;
-using android::hardware::graphics::composer::V2_3::IComposerClient;
-
-namespace android {
-
-class Fence;
-
-namespace dvr {
-
-class VrComposerClient;
-
-using android::hardware::graphics::composer::V2_3::hal::ComposerHal;
-
-namespace types = android::hardware::graphics::common;
-
-using types::V1_1::RenderIntent;
-using types::V1_2::ColorMode;
-using types::V1_2::Dataspace;
-using types::V1_2::Hdr;
-using types::V1_2::PixelFormat;
-
-class ComposerView {
- public:
- struct ComposerLayer {
- using Recti = hardware::graphics::composer::V2_3::IComposerClient::Rect;
- using Rectf = hardware::graphics::composer::V2_3::IComposerClient::FRect;
- using BlendMode =
- hardware::graphics::composer::V2_3::IComposerClient::BlendMode;
-
- Layer id;
- sp<GraphicBuffer> buffer;
- sp<Fence> fence;
- Recti display_frame;
- Rectf crop;
- BlendMode blend_mode;
- float alpha;
- uint32_t type;
- uint32_t app_id;
- uint32_t z_order;
- int32_t cursor_x;
- int32_t cursor_y;
- IComposerClient::Color color;
- int32_t dataspace;
- int32_t transform;
- std::vector<hwc_rect_t> visible_regions;
- std::vector<hwc_rect_t> damaged_regions;
- };
-
- struct Frame {
- Display display_id;
- // This is set to true to notify the upper layer that the display is
- // being removed, or left false in the case of a normal frame. The upper
- // layer tracks display IDs and will handle new ones showing up.
- bool removed = false;
- int32_t display_width;
- int32_t display_height;
- Config active_config;
- ColorMode color_mode;
- IComposerClient::PowerMode power_mode;
- IComposerClient::Vsync vsync_enabled;
- float color_transform[16];
- int32_t color_transform_hint;
- std::vector<ComposerLayer> layers;
- };
-
- class Observer {
- public:
- virtual ~Observer() {}
-
- // Returns a list of layers that need to be shown together. Layers are
- // returned in z-order, with the lowest layer first.
- virtual base::unique_fd OnNewFrame(const Frame& frame) = 0;
- };
-
- virtual ~ComposerView() {}
-
- virtual void ForceDisplaysRefresh() = 0;
- virtual void RegisterObserver(Observer* observer) = 0;
- virtual void UnregisterObserver(Observer* observer) = 0;
-};
-
-struct HwcLayer {
- using Composition =
- hardware::graphics::composer::V2_3::IComposerClient::Composition;
-
- explicit HwcLayer(Layer new_id) { info.id = new_id; }
-
- void dumpDebugInfo(std::string* result) const;
-
- Composition composition_type;
- ComposerView::ComposerLayer info;
- IVrComposerClient::BufferMetadata buffer_metadata;
-};
-
-class HwcDisplay {
- public:
- HwcDisplay(int32_t width, int32_t height);
- ~HwcDisplay();
-
- int32_t width() const { return width_; }
- int32_t height() const { return height_; }
-
- HwcLayer* CreateLayer();
- bool DestroyLayer(Layer id);
- HwcLayer* GetLayer(Layer id);
-
- bool SetClientTarget(const native_handle_t* handle, base::unique_fd fence);
- void SetClientTargetMetadata(
- const IVrComposerClient::BufferMetadata& metadata);
-
- void GetChangedCompositionTypes(
- std::vector<Layer>* layer_ids,
- std::vector<IComposerClient::Composition>* composition);
-
- Error GetFrame(std::vector<ComposerView::ComposerLayer>* out_frame);
-
- std::vector<Layer> UpdateLastFrameAndGetLastFrameLayers();
-
- Config active_config() const { return active_config_; }
- void set_active_config(Config config) { active_config_ = config; }
-
- ColorMode color_mode() const { return color_mode_; }
- void set_color_mode(ColorMode mode) { color_mode_ = mode; }
-
- IComposerClient::PowerMode power_mode() const { return power_mode_; }
- void set_power_mode(IComposerClient::PowerMode mode) { power_mode_ = mode; }
-
- bool vsync_enabled() const { return vsync_enabled_; }
- void set_vsync_enabled(bool vsync) {vsync_enabled_ = vsync;}
-
- const float* color_transform() const { return color_transform_; }
- int32_t color_transform_hint() const { return color_transform_hint_; }
- void SetColorTransform(const float* matrix, int32_t hint);
-
- void dumpDebugInfo(std::string* result) const;
-
- private:
- // The client target buffer and the associated fence.
- sp<GraphicBuffer> buffer_;
- IVrComposerClient::BufferMetadata buffer_metadata_;
- sp<Fence> fence_;
-
- // List of currently active layers.
- std::vector<HwcLayer> layers_;
-
- std::vector<Layer> last_frame_layers_ids_;
-
- // Layer ID generator.
- uint64_t layer_ids_ = 1;
-
- int32_t width_;
- int32_t height_;
-
- Config active_config_;
- ColorMode color_mode_;
- IComposerClient::PowerMode power_mode_;
- bool vsync_enabled_ = false;
- float color_transform_[16];
- int32_t color_transform_hint_;
-
- HwcDisplay(const HwcDisplay&) = delete;
- void operator=(const HwcDisplay&) = delete;
-};
-
-class VrHwc : public IComposer, public ComposerHal, public ComposerView {
- public:
- VrHwc();
- ~VrHwc() override;
-
- Error setLayerInfo(Display display, Layer layer, uint32_t type,
- uint32_t appId);
- Error setClientTargetMetadata(
- Display display, const IVrComposerClient::BufferMetadata& metadata);
- Error setLayerBufferMetadata(
- Display display, Layer layer,
- const IVrComposerClient::BufferMetadata& metadata);
-
- // composer::V2_1::ComposerHal
- bool hasCapability(hwc2_capability_t capability) override;
-
- std::string dumpDebugInfo() override { return {}; }
-
- void registerEventCallback(ComposerHal::EventCallback* callback) override;
- void unregisterEventCallback() override;
-
- uint32_t getMaxVirtualDisplayCount() override;
- Error destroyVirtualDisplay(Display display) override;
-
- Error createLayer(Display display, Layer* outLayer) override;
- Error destroyLayer(Display display, Layer layer) override;
-
- Error getActiveConfig(Display display, Config* outConfig) override;
- Error getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute,
- int32_t* outValue) override;
- Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
- Error getDisplayName(Display display, hidl_string* outName) override;
- Error getDisplayType(Display display,
- IComposerClient::DisplayType* outType) override;
- Error getDozeSupport(Display display, bool* outSupport) override;
-
- Error setActiveConfig(Display display, Config config) override;
- Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
-
- Error setColorTransform(Display display, const float* matrix,
- int32_t hint) override;
- Error setClientTarget(Display display, buffer_handle_t target,
- int32_t acquireFence, int32_t dataspace,
- const std::vector<hwc_rect_t>& damage) override;
- Error setOutputBuffer(Display display, buffer_handle_t buffer,
- int32_t releaseFence) override;
- Error validateDisplay(
- Display display, std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks) override;
- Error acceptDisplayChanges(Display display) override;
- Error presentDisplay(Display display, int32_t* outPresentFence,
- std::vector<Layer>* outLayers,
- std::vector<int32_t>* outReleaseFences) override;
-
- Error setLayerCursorPosition(Display display, Layer layer, int32_t x,
- int32_t y) override;
- Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
- int32_t acquireFence) override;
- Error setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<hwc_rect_t>& damage) override;
- Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
- Error setLayerColor(Display display, Layer layer,
- IComposerClient::Color color) override;
- Error setLayerCompositionType(Display display, Layer layer,
- int32_t type) override;
- Error setLayerDataspace(Display display, Layer layer,
- int32_t dataspace) override;
- Error setLayerDisplayFrame(Display display, Layer layer,
- const hwc_rect_t& frame) override;
- Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
- Error setLayerSidebandStream(Display display, Layer layer,
- buffer_handle_t stream) override;
- Error setLayerSourceCrop(Display display, Layer layer,
- const hwc_frect_t& crop) override;
- Error setLayerTransform(Display display, Layer layer,
- int32_t transform) override;
- Error setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<hwc_rect_t>& visible) override;
- Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
-
- // composer::V2_2::ComposerHal
- Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
- android::base::unique_fd fenceFd) override;
- Error getReadbackBufferFence(Display display,
- android::base::unique_fd* outFenceFd) override;
- Error createVirtualDisplay_2_2(uint32_t width, uint32_t height,
- types::V1_1::PixelFormat* format,
- Display* outDisplay) override;
- Error setPowerMode_2_2(Display display,
- IComposerClient::PowerMode mode) override;
- Error setLayerFloatColor(Display display, Layer layer,
- IComposerClient::FloatColor color) override;
- Error getRenderIntents(Display display, types::V1_1::ColorMode mode,
- std::vector<RenderIntent>* outIntents) override;
- std::array<float, 16> getDataspaceSaturationMatrix(
- types::V1_1::Dataspace dataspace) override;
-
- // composer::V2_3::ComposerHal
- Error getHdrCapabilities_2_3(Display display, hidl_vec<Hdr>* outTypes,
- float* outMaxLuminance,
- float* outMaxAverageLuminance,
- float* outMinLuminance) override;
- Error setLayerPerFrameMetadata_2_3(
- Display display, Layer layer,
- const std::vector<IComposerClient::PerFrameMetadata>& metadata) override;
- Error getPerFrameMetadataKeys_2_3(
- Display display,
- std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override;
- Error setColorMode_2_3(Display display, ColorMode mode,
- RenderIntent intent) override;
- Error getRenderIntents_2_3(Display display, ColorMode mode,
- std::vector<RenderIntent>* outIntents) override;
- Error getColorModes_2_3(Display display,
- hidl_vec<ColorMode>* outModes) override;
- Error getClientTargetSupport_2_3(Display display, uint32_t width,
- uint32_t height, PixelFormat format,
- Dataspace dataspace) override;
- Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat,
- Dataspace* outDataspace) override;
- Error getDisplayIdentificationData(Display display, uint8_t* outPort,
- std::vector<uint8_t>* outData) override;
- Error setLayerColorTransform(Display display, Layer layer,
- const float* matrix) override;
- Error getDisplayedContentSamplingAttributes(
- Display display, PixelFormat& format, Dataspace& dataspace,
- hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask)
- override;
- Error setDisplayedContentSamplingEnabled(
- Display display, IComposerClient::DisplayedContentSampling enable,
- hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
- uint64_t maxFrames) override;
- Error getDisplayedContentSample(
- Display display, uint64_t maxFrames, uint64_t timestamp,
- uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
- hidl_vec<uint64_t>& sampleComponent1,
- hidl_vec<uint64_t>& sampleComponent2,
- hidl_vec<uint64_t>& sampleComponent3) override;
- Error getDisplayCapabilities(Display display,
- std::vector<IComposerClient::DisplayCapability>*
- outCapabilities) override;
- Error setLayerPerFrameMetadataBlobs(
- Display display, Layer layer,
- std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) override;
- Error getDisplayBrightnessSupport(Display display, bool* outSupport) override;
- Error setDisplayBrightness(Display display, float brightness) override;
-
- // IComposer:
- Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
- Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
- Return<void> createClient(createClient_cb hidl_cb) override;
- Return<void> createClient_2_3(
- IComposer::createClient_2_3_cb hidl_cb) override;
-
- // ComposerView:
- void ForceDisplaysRefresh() override;
- void RegisterObserver(Observer* observer) override;
- void UnregisterObserver(Observer* observer) override;
-
- Return<void> debug(const hidl_handle& fd,
- const hidl_vec<hidl_string>& args) override;
-
- private:
- class VsyncCallback : public BnVsyncCallback {
- public:
- status_t onVsync(int64_t vsync_timestamp) override;
- void SetEventCallback(EventCallback* callback);
- private:
- std::mutex mutex_;
- EventCallback* callback_;
- };
-
- HwcDisplay* FindDisplay(Display display);
-
- // Re-evaluate whether or not we should start making onVsync() callbacks to
- // the client. We need enableCallback(true) to have been called, and
- // setVsyncEnabled() to have been called for the primary display. The caller
- // must have mutex_ locked already.
- void UpdateVsyncCallbackEnabledLocked();
-
- wp<VrComposerClient> client_;
-
- // Guard access to internal state from binder threads.
- std::mutex mutex_;
-
- std::unordered_map<Display, std::unique_ptr<HwcDisplay>> displays_;
- Display display_count_ = 2;
-
- EventCallback* event_callback_ = nullptr;
- Observer* observer_ = nullptr;
-
- sp<VsyncCallback> vsync_callback_;
-
- VrHwc(const VrHwc&) = delete;
- void operator=(const VrHwc&) = delete;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
deleted file mode 100644
index 2e70928..0000000
--- a/services/vr/hardware_composer/tests/vr_composer_test.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-#include <android/dvr/BnVrComposerCallback.h>
-#include <binder/IServiceManager.h>
-#include <gtest/gtest.h>
-#include <sys/eventfd.h>
-#include <vr_composer.h>
-
-namespace android {
-namespace dvr {
-namespace {
-
-const char kVrDisplayName[] = "VrDisplay_Test";
-
-class TestComposerView : public ComposerView {
- public:
- TestComposerView() {}
- ~TestComposerView() override = default;
-
- size_t display_refresh_count() const { return display_refresh_count_; }
-
- void ForceDisplaysRefresh() override { display_refresh_count_++; }
- void RegisterObserver(Observer* observer) override {}
- void UnregisterObserver(Observer* observer) override {}
-
- TestComposerView(const TestComposerView&) = delete;
- void operator=(const TestComposerView&) = delete;
-
- private:
- size_t display_refresh_count_ = 0;
-};
-
-class TestComposerCallback : public BnVrComposerCallback {
- public:
- TestComposerCallback() {}
- ~TestComposerCallback() override = default;
-
- ComposerView::Frame last_frame() const { return last_frame_; }
-
- binder::Status onNewFrame(
- const ParcelableComposerFrame& frame,
- ParcelableUniqueFd* /* fence */) override {
- last_frame_ = frame.frame();
- return binder::Status::ok();
- }
-
- private:
- ComposerView::Frame last_frame_;
-
- TestComposerCallback(const TestComposerCallback&) = delete;
- void operator=(const TestComposerCallback&) = delete;
-};
-
-class TestComposerCallbackWithFence : public TestComposerCallback {
- public:
- ~TestComposerCallbackWithFence() override = default;
-
- binder::Status onNewFrame(
- const ParcelableComposerFrame& frame,
- ParcelableUniqueFd* fence) override {
- binder::Status status = TestComposerCallback::onNewFrame(frame, fence);
-
- base::unique_fd fd(eventfd(0, 0));
- EXPECT_LE(0, fd.get());
- fence->set_fence(fd);
-
- return status;
- }
-};
-
-sp<GraphicBuffer> CreateBuffer() {
- return new GraphicBuffer(600, 400, PIXEL_FORMAT_RGBA_8888,
- GraphicBuffer::USAGE_HW_TEXTURE);
-}
-
-} // namespace
-
-class VrComposerTest : public testing::Test {
- public:
- VrComposerTest() : composer_(new VrComposer(&composer_view_)) {}
- ~VrComposerTest() override = default;
-
- sp<IVrComposer> GetComposerProxy() const {
- sp<IServiceManager> sm(defaultServiceManager());
- return interface_cast<IVrComposer>(sm->getService(String16(kVrDisplayName)));
- }
-
- void SetUp() override {
- sp<IServiceManager> sm(defaultServiceManager());
- EXPECT_EQ(OK,
- sm->addService(String16(kVrDisplayName), composer_, false));
- }
-
- protected:
- TestComposerView composer_view_;
- sp<VrComposer> composer_;
-
- VrComposerTest(const VrComposerTest&) = delete;
- void operator=(const VrComposerTest&) = delete;
-};
-
-TEST_F(VrComposerTest, TestWithoutObserver) {
- sp<IVrComposer> composer = GetComposerProxy();
- ComposerView::Frame frame;
-
- base::unique_fd fence = composer_->OnNewFrame(frame);
- ASSERT_EQ(-1, fence.get());
-}
-
-TEST_F(VrComposerTest, TestWithObserver) {
- sp<IVrComposer> composer = GetComposerProxy();
- sp<TestComposerCallback> callback = new TestComposerCallback();
- ASSERT_EQ(0, composer_view_.display_refresh_count());
- ASSERT_TRUE(composer->registerObserver(callback).isOk());
- ASSERT_EQ(1, composer_view_.display_refresh_count());
-
- ComposerView::Frame frame;
- base::unique_fd fence = composer_->OnNewFrame(frame);
- ASSERT_EQ(-1, fence.get());
-}
-
-TEST_F(VrComposerTest, TestWithOneLayer) {
- sp<IVrComposer> composer = GetComposerProxy();
- sp<TestComposerCallback> callback = new TestComposerCallbackWithFence();
- ASSERT_TRUE(composer->registerObserver(callback).isOk());
-
- ComposerView::Frame frame;
- frame.display_id = 1;
- frame.removed = false;
- frame.display_width = 600;
- frame.display_height = 400;
- frame.layers.push_back(ComposerView::ComposerLayer{
- .id = 1,
- .buffer = CreateBuffer(),
- .fence = new Fence(eventfd(0, 0)),
- .display_frame = {0, 0, 600, 400},
- .crop = {0.0f, 0.0f, 600.0f, 400.0f},
- .blend_mode = IComposerClient::BlendMode::NONE,
- .alpha = 1.0f,
- .type = 1,
- .app_id = 1,
- });
- base::unique_fd fence = composer_->OnNewFrame(frame);
- ASSERT_LE(0, fence.get());
-
- ComposerView::Frame received_frame = callback->last_frame();
- ASSERT_EQ(frame.display_id, received_frame.display_id);
- ASSERT_EQ(frame.display_width, received_frame.display_width);
- ASSERT_EQ(frame.display_height, received_frame.display_height);
- ASSERT_EQ(frame.removed, received_frame.removed);
- ASSERT_EQ(1u, received_frame.layers.size());
- ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id);
- ASSERT_NE(nullptr, received_frame.layers[0].buffer.get());
- ASSERT_TRUE(received_frame.layers[0].fence->isValid());
- ASSERT_EQ(frame.layers[0].display_frame.left,
- received_frame.layers[0].display_frame.left);
- ASSERT_EQ(frame.layers[0].display_frame.top,
- received_frame.layers[0].display_frame.top);
- ASSERT_EQ(frame.layers[0].display_frame.right,
- received_frame.layers[0].display_frame.right);
- ASSERT_EQ(frame.layers[0].display_frame.bottom,
- received_frame.layers[0].display_frame.bottom);
- ASSERT_EQ(frame.layers[0].crop.left, received_frame.layers[0].crop.left);
- ASSERT_EQ(frame.layers[0].crop.top, received_frame.layers[0].crop.top);
- ASSERT_EQ(frame.layers[0].crop.right, received_frame.layers[0].crop.right);
- ASSERT_EQ(frame.layers[0].crop.bottom, received_frame.layers[0].crop.bottom);
- ASSERT_EQ(frame.layers[0].blend_mode, received_frame.layers[0].blend_mode);
- ASSERT_EQ(frame.layers[0].alpha, received_frame.layers[0].alpha);
- ASSERT_EQ(frame.layers[0].type, received_frame.layers[0].type);
- ASSERT_EQ(frame.layers[0].app_id, received_frame.layers[0].app_id);
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
deleted file mode 100644
index d93f370..0000000
--- a/services/vr/hardware_composer/vr_composer.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#include "vr_composer.h"
-
-#include <binder/IPCThreadState.h>
-#include <binder/PermissionCache.h>
-
-namespace android {
-namespace dvr {
-namespace {
-
-bool CheckPermission() {
- const android::IPCThreadState* ipc = android::IPCThreadState::self();
- const pid_t pid = ipc->getCallingPid();
- const uid_t uid = ipc->getCallingUid();
- const bool permission = PermissionCache::checkPermission(
- String16("android.permission.RESTRICTED_VR_ACCESS"), pid, uid);
- if (!permission)
- ALOGE("permission denied to pid=%d uid=%u", pid, uid);
-
- return permission;
-}
-
-} // namespace
-
-VrComposer::VrComposer(ComposerView* composer_view)
- : composer_view_(composer_view) {
- composer_view_->RegisterObserver(this);
-}
-
-VrComposer::~VrComposer() {
- composer_view_->UnregisterObserver(this);
-}
-
-binder::Status VrComposer::registerObserver(
- const sp<IVrComposerCallback>& callback) {
- {
- std::lock_guard<std::mutex> guard(mutex_);
-
- if (!CheckPermission())
- return binder::Status::fromStatusT(PERMISSION_DENIED);
-
- if (callback_.get()) {
- ALOGE("Failed to register callback, already registered");
- return binder::Status::fromStatusT(ALREADY_EXISTS);
- }
-
- callback_ = callback;
- IInterface::asBinder(callback_)->linkToDeath(this);
- }
-
- // Don't take the lock to force display refresh otherwise it could end in a
- // deadlock since HWC calls this with new frames and it has a lock of its own
- // to serialize access to the display information.
- composer_view_->ForceDisplaysRefresh();
- 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_);
-
- if (!callback_.get())
- return base::unique_fd();
-
- ParcelableComposerFrame parcelable_frame(frame);
- ParcelableUniqueFd fence;
- binder::Status ret = callback_->onNewFrame(parcelable_frame, &fence);
- if (!ret.isOk())
- ALOGE("Failed to send new frame: %s", ret.toString8().string());
-
- return fence.fence();
-}
-
-void VrComposer::binderDied(const wp<IBinder>& /* who */) {
- std::lock_guard<std::mutex> guard(mutex_);
-
- callback_ = nullptr;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
deleted file mode 100644
index 1273352..0000000
--- a/services/vr/hardware_composer/vr_composer.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
-
-#include <android/dvr/BnVrComposer.h>
-#include <impl/vr_hwc.h>
-
-namespace android {
-namespace dvr {
-
-class VrComposerCallback;
-
-// Implementation of the IVrComposer service used to notify VR Window Manager
-// when SurfaceFlinger presents 2D UI changes.
-//
-// VR HWC updates the presented frame via the ComposerView::Observer interface.
-// On notification |callback_| is called to update VR Window Manager.
-// NOTE: If VR Window Manager isn't connected, the notification is a no-op.
-class VrComposer
- : public BnVrComposer,
- public ComposerView::Observer,
- public IBinder::DeathRecipient {
- public:
- explicit VrComposer(ComposerView* composer_view);
- ~VrComposer() override;
-
- // BnVrComposer:
- binder::Status registerObserver(
- const sp<IVrComposerCallback>& callback) override;
-
- binder::Status clearObserver() override;
-
- // ComposerView::Observer:
- base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
-
- private:
- // IBinder::DeathRecipient:
- void binderDied(const wp<IBinder>& who) override;
-
- std::mutex mutex_;
-
- sp<IVrComposerCallback> callback_;
-
- ComposerView* composer_view_; // Not owned.
-
- VrComposer(const VrComposer&) = delete;
- void operator=(const VrComposer&) = delete;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h
index ba98696..40cf9fb 100644
--- a/vulkan/include/vulkan/vk_android_native_buffer.h
+++ b/vulkan/include/vulkan/vk_android_native_buffer.h
@@ -49,7 +49,13 @@
* in VkBindImageMemorySwapchainInfoKHR will be additionally chained to the
* pNext chain of VkBindImageMemoryInfo and passed down to the driver.
*/
-#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 8
+/*
+ * NOTE ON VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 9
+ *
+ * This version of the extension is largely designed to clean up the mix of
+ * GrallocUsage and GrallocUsage2
+ */
+#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 9
#define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer"
#define VK_ANDROID_NATIVE_BUFFER_ENUM(type, id) \
@@ -61,6 +67,8 @@
VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 1)
#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID \
VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 2)
+#define VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID \
+ VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 3)
/* clang-format off */
typedef enum VkSwapchainImageUsageFlagBitsANDROID {
@@ -90,6 +98,7 @@
* format: gralloc format requested when the buffer was allocated
* usage: gralloc usage requested when the buffer was allocated
* usage2: gralloc usage requested when the buffer was allocated
+ * usage3: gralloc usage requested when the buffer was allocated
*/
typedef struct {
VkStructureType sType;
@@ -98,7 +107,8 @@
int stride;
int format;
int usage; /* DEPRECATED in SPEC_VERSION 6 */
- VkNativeBufferUsage2ANDROID usage2; /* ADDED in SPEC_VERSION 6 */
+ VkNativeBufferUsage2ANDROID usage2; /* DEPRECATED in SPEC_VERSION 9 */
+ uint64_t usage3; /* ADDED in SPEC_VERSION 9 */
} VkNativeBufferANDROID;
/*
@@ -127,6 +137,21 @@
VkBool32 sharedImage;
} VkPhysicalDevicePresentationPropertiesANDROID;
+/*
+ * struct VkGrallocUsageInfoANDROID
+ *
+ * sType: VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID
+ * pNext: NULL or a pointer to a structure extending this structure
+ * format: value specifying the format the image will be created with
+ * imageUsage: bitmask of VkImageUsageFlagBits describing intended usage
+ */
+typedef struct {
+ VkStructureType sType;
+ const void* pNext;
+ VkFormat format;
+ VkImageUsageFlags imageUsage;
+} VkGrallocUsageInfoANDROID;
+
/* DEPRECATED in SPEC_VERSION 6 */
typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsageANDROID)(
VkDevice device,
@@ -134,7 +159,7 @@
VkImageUsageFlags imageUsage,
int* grallocUsage);
-/* ADDED in SPEC_VERSION 6 */
+/* DEPRECATED in SPEC_VERSION 9 */
typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage2ANDROID)(
VkDevice device,
VkFormat format,
@@ -143,6 +168,12 @@
uint64_t* grallocConsumerUsage,
uint64_t* grallocProducerUsage);
+/* ADDED in SPEC_VERSION 9 */
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage3ANDROID)(
+ VkDevice device,
+ const VkGrallocUsageInfoANDROID* grallocUsageInfo,
+ uint64_t* grallocUsage);
+
typedef VkResult (VKAPI_PTR *PFN_vkAcquireImageANDROID)(
VkDevice device,
VkImage image,
@@ -167,7 +198,7 @@
int* grallocUsage
);
-/* ADDED in SPEC_VERSION 6 */
+/* DEPRECATED in SPEC_VERSION 9 */
VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage2ANDROID(
VkDevice device,
VkFormat format,
@@ -177,6 +208,13 @@
uint64_t* grallocProducerUsage
);
+/* ADDED in SPEC_VERSION 9 */
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage3ANDROID(
+ VkDevice device,
+ const VkGrallocUsageInfoANDROID* grallocUsageInfo,
+ uint64_t* grallocUsage
+);
+
VKAPI_ATTR VkResult VKAPI_CALL vkAcquireImageANDROID(
VkDevice device,
VkImage image,
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index df70bf4..a9706bc 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -682,6 +682,7 @@
"vkGetPhysicalDeviceMemoryProperties2",
"vkGetPhysicalDeviceMemoryProperties2KHR",
"vkGetPhysicalDeviceMultisamplePropertiesEXT",
+ "vkGetPhysicalDeviceOpticalFlowImageFormatsNV",
"vkGetPhysicalDevicePresentRectanglesKHR",
"vkGetPhysicalDeviceProperties",
"vkGetPhysicalDeviceProperties2",
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 7664518..a99355f 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -1027,6 +1027,51 @@
}
}
+VkResult GetAndroidNativeBufferSpecVersion9Support(
+ VkPhysicalDevice physicalDevice,
+ bool& support) {
+ support = false;
+
+ const InstanceData& data = GetData(physicalDevice);
+
+ // Call to get propertyCount
+ uint32_t propertyCount = 0;
+ ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
+ VkResult result = data.driver.EnumerateDeviceExtensionProperties(
+ physicalDevice, nullptr, &propertyCount, nullptr);
+ ATRACE_END();
+
+ if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
+ return result;
+ }
+
+ // Call to enumerate properties
+ std::vector<VkExtensionProperties> properties(propertyCount);
+ ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
+ result = data.driver.EnumerateDeviceExtensionProperties(
+ physicalDevice, nullptr, &propertyCount, properties.data());
+ ATRACE_END();
+
+ if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
+ return result;
+ }
+
+ for (uint32_t i = 0; i < propertyCount; i++) {
+ auto& prop = properties[i];
+
+ if (strcmp(prop.extensionName,
+ VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0)
+ continue;
+
+ if (prop.specVersion >= 9) {
+ support = true;
+ return result;
+ }
+ }
+
+ return result;
+}
+
VkResult EnumerateDeviceExtensionProperties(
VkPhysicalDevice physicalDevice,
const char* pLayerName,
@@ -1061,6 +1106,49 @@
VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
}
+ // Conditionally add VK_EXT_IMAGE_COMPRESSION_CONTROL* if feature and ANB
+ // support is provided by the driver
+ VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT
+ swapchainCompFeats = {};
+ swapchainCompFeats.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT;
+ swapchainCompFeats.pNext = nullptr;
+ swapchainCompFeats.imageCompressionControlSwapchain = false;
+ VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompFeats = {};
+ imageCompFeats.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT;
+ imageCompFeats.pNext = &swapchainCompFeats;
+ imageCompFeats.imageCompressionControl = false;
+
+ VkPhysicalDeviceFeatures2 feats2 = {};
+ feats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ feats2.pNext = &imageCompFeats;
+
+ const auto& driver = GetData(physicalDevice).driver;
+ if (driver.GetPhysicalDeviceFeatures2 ||
+ driver.GetPhysicalDeviceFeatures2KHR) {
+ GetPhysicalDeviceFeatures2(physicalDevice, &feats2);
+ }
+
+ bool anb9 = false;
+ VkResult result =
+ GetAndroidNativeBufferSpecVersion9Support(physicalDevice, anb9);
+
+ if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
+ return result;
+ }
+
+ if (anb9 && imageCompFeats.imageCompressionControl) {
+ loader_extensions.push_back(
+ {VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME,
+ VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION});
+ }
+ if (anb9 && swapchainCompFeats.imageCompressionControlSwapchain) {
+ loader_extensions.push_back(
+ {VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME,
+ VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION});
+ }
+
// enumerate our extensions first
if (!pLayerName && pProperties) {
uint32_t count = std::min(
@@ -1078,7 +1166,7 @@
}
ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
- VkResult result = data.driver.EnumerateDeviceExtensionProperties(
+ result = data.driver.EnumerateDeviceExtensionProperties(
physicalDevice, pLayerName, pPropertyCount, pProperties);
ATRACE_END();
@@ -1254,15 +1342,18 @@
return VK_ERROR_INCOMPATIBLE_DRIVER;
}
- // sanity check ANDROID_native_buffer implementation, whose set of
+ // Confirming ANDROID_native_buffer implementation, whose set of
// entrypoints varies according to the spec version.
if ((wrapper.GetHalExtensions()[ProcHook::ANDROID_native_buffer]) &&
!data->driver.GetSwapchainGrallocUsageANDROID &&
- !data->driver.GetSwapchainGrallocUsage2ANDROID) {
- ALOGE("Driver's implementation of ANDROID_native_buffer is broken;"
- " must expose at least one of "
- "vkGetSwapchainGrallocUsageANDROID or "
- "vkGetSwapchainGrallocUsage2ANDROID");
+ !data->driver.GetSwapchainGrallocUsage2ANDROID &&
+ !data->driver.GetSwapchainGrallocUsage3ANDROID) {
+ ALOGE(
+ "Driver's implementation of ANDROID_native_buffer is broken;"
+ " must expose at least one of "
+ "vkGetSwapchainGrallocUsageANDROID or "
+ "vkGetSwapchainGrallocUsage2ANDROID or "
+ "vkGetSwapchainGrallocUsage3ANDROID");
data->driver.DestroyDevice(dev, pAllocator);
FreeDeviceData(data, data_allocator);
@@ -1441,10 +1532,89 @@
if (driver.GetPhysicalDeviceFeatures2) {
driver.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+ } else {
+ driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+ }
+
+ // Conditionally add imageCompressionControlSwapchain if
+ // imageCompressionControl is supported Check for imageCompressionControl in
+ // the pChain
+ bool imageCompressionControl = false;
+ bool imageCompressionControlInChain = false;
+ bool imageCompressionControlSwapchainInChain = false;
+ VkPhysicalDeviceFeatures2* pFeats = pFeatures;
+ while (pFeats) {
+ switch (pFeats->sType) {
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT: {
+ const VkPhysicalDeviceImageCompressionControlFeaturesEXT*
+ compressionFeat = reinterpret_cast<
+ const VkPhysicalDeviceImageCompressionControlFeaturesEXT*>(
+ pFeats);
+ imageCompressionControl =
+ compressionFeat->imageCompressionControl;
+ imageCompressionControlInChain = true;
+ } break;
+
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: {
+ VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*
+ compressionFeat = reinterpret_cast<
+ VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*>(
+ pFeats);
+ compressionFeat->imageCompressionControlSwapchain = false;
+ imageCompressionControlSwapchainInChain = true;
+ } break;
+
+ default:
+ break;
+ }
+ pFeats = reinterpret_cast<VkPhysicalDeviceFeatures2*>(pFeats->pNext);
+ }
+
+ if (!imageCompressionControlSwapchainInChain) {
return;
}
- driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+ // If not in pchain, explicitly query for imageCompressionControl
+ if (!imageCompressionControlInChain) {
+ VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompFeats = {};
+ imageCompFeats.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT;
+ imageCompFeats.pNext = nullptr;
+ imageCompFeats.imageCompressionControl = false;
+
+ VkPhysicalDeviceFeatures2 feats2 = {};
+ feats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ feats2.pNext = &imageCompFeats;
+
+ if (driver.GetPhysicalDeviceFeatures2) {
+ driver.GetPhysicalDeviceFeatures2(physicalDevice, &feats2);
+ } else {
+ driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, &feats2);
+ }
+
+ imageCompressionControl = imageCompFeats.imageCompressionControl;
+ }
+
+ // Only enumerate imageCompressionControlSwapchin if imageCompressionControl
+ if (imageCompressionControl) {
+ pFeats = pFeatures;
+ while (pFeats) {
+ switch (pFeats->sType) {
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: {
+ VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*
+ compressionFeat = reinterpret_cast<
+ VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*>(
+ pFeats);
+ compressionFeat->imageCompressionControlSwapchain = true;
+ } break;
+
+ default:
+ break;
+ }
+ pFeats =
+ reinterpret_cast<VkPhysicalDeviceFeatures2*>(pFeats->pNext);
+ }
+ }
}
void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 14c516b..4d2bbd6 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -107,6 +107,8 @@
VkPhysicalDevice physicalDevice,
VkPhysicalDevicePresentationPropertiesANDROID* presentation_properties);
+bool GetAndroidNativeBufferSpecVersion9Support(VkPhysicalDevice physicalDevice);
+
VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
const char* pName);
VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device,
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index b436db1..de98aa7 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -496,6 +496,13 @@
nullptr,
},
{
+ "vkGetSwapchainGrallocUsage3ANDROID",
+ ProcHook::DEVICE,
+ ProcHook::ANDROID_native_buffer,
+ nullptr,
+ nullptr,
+ },
+ {
"vkGetSwapchainGrallocUsageANDROID",
ProcHook::DEVICE,
ProcHook::ANDROID_native_buffer,
@@ -664,6 +671,7 @@
INIT_PROC(false, dev, GetDeviceQueue2);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID);
+ INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage3ANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, QueueSignalReleaseImageANDROID);
// clang-format on
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 079f9cc..2f60086 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -123,6 +123,7 @@
PFN_vkGetDeviceQueue2 GetDeviceQueue2;
PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID;
+ PFN_vkGetSwapchainGrallocUsage3ANDROID GetSwapchainGrallocUsage3ANDROID;
PFN_vkAcquireImageANDROID AcquireImageANDROID;
PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
// clang-format on
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index f49e8f3..b189c68 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -178,6 +178,7 @@
vkGetImageSparseMemoryRequirements;
vkGetImageSparseMemoryRequirements2; # introduced=28
vkGetImageSubresourceLayout;
+ vkGetImageSubresourceLayout2EXT; # introduced=UpsideDownCake
vkGetInstanceProcAddr;
vkGetMemoryAndroidHardwareBufferANDROID; # introduced=28
vkGetPhysicalDeviceExternalBufferProperties; # introduced=28
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 6af2cc1..e9935e5 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -508,6 +508,10 @@
case VK_FORMAT_R8_UNORM:
native_format = android::PIXEL_FORMAT_R_8;
break;
+ // TODO: Do we need to query for VK_EXT_rgba10x6_formats here?
+ case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
+ native_format = android::PIXEL_FORMAT_RGBA_10101010;
+ break;
default:
ALOGV("unsupported swapchain format %d", format);
break;
@@ -715,6 +719,17 @@
capabilities->minImageExtent = VkExtent2D{1, 1};
capabilities->maxImageExtent = VkExtent2D{4096, 4096};
+ if (capabilities->maxImageExtent.height <
+ capabilities->currentExtent.height) {
+ capabilities->maxImageExtent.height =
+ capabilities->currentExtent.height;
+ }
+
+ if (capabilities->maxImageExtent.width <
+ capabilities->currentExtent.width) {
+ capabilities->maxImageExtent.width = capabilities->currentExtent.width;
+ }
+
capabilities->maxImageArrayLayers = 1;
capabilities->supportedTransforms = kSupportedTransforms;
@@ -743,7 +758,6 @@
const InstanceData& instance_data = GetData(pdev);
- bool wide_color_support = false;
uint64_t consumer_usage = 0;
bool colorspace_ext =
instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
@@ -754,27 +768,15 @@
if (!surfaceless_enabled) {
return VK_ERROR_SURFACE_LOST_KHR;
}
- // Support for VK_GOOGLE_surfaceless_query. The EGL loader
- // unconditionally supports wide color formats, even if they will cause
- // a SurfaceFlinger fallback. Based on that, wide_color_support will be
- // set to true in this case.
- wide_color_support = true;
+ // Support for VK_GOOGLE_surfaceless_query.
// TODO(b/203826952): research proper value; temporarily use the
// values seen on Pixel
consumer_usage = AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY;
} else {
Surface& surface = *SurfaceFromHandle(surface_handle);
- int err = native_window_get_wide_color_support(surface.window.get(),
- &wide_color_support);
- if (err) {
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- ALOGV("wide_color_support is: %d", wide_color_support);
-
consumer_usage = surface.consumer_usage;
}
- wide_color_support = wide_color_support && colorspace_ext;
AHardwareBuffer_Desc desc = {};
desc.width = 1;
@@ -787,17 +789,15 @@
std::vector<VkSurfaceFormatKHR> all_formats = {
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
- // Also allow to use PASS_THROUGH + HAL_DATASPACE_ARBITRARY
- {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT},
- {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT},
};
if (colorspace_ext) {
all_formats.emplace_back(VkSurfaceFormatKHR{
+ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ all_formats.emplace_back(VkSurfaceFormatKHR{
+ VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT});
- }
-
- if (wide_color_support) {
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
all_formats.emplace_back(VkSurfaceFormatKHR{
@@ -812,17 +812,21 @@
if (AHardwareBuffer_isSupported(&desc)) {
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
- all_formats.emplace_back(VkSurfaceFormatKHR{
- VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ if (colorspace_ext) {
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_R5G6B5_UNORM_PACK16,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ }
}
desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
if (AHardwareBuffer_isSupported(&desc)) {
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
- all_formats.emplace_back(VkSurfaceFormatKHR{
- VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_PASS_THROUGH_EXT});
- if (wide_color_support) {
+ if (colorspace_ext) {
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT});
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT});
@@ -837,10 +841,10 @@
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
- all_formats.emplace_back(
- VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
- VK_COLOR_SPACE_PASS_THROUGH_EXT});
- if (wide_color_support) {
+ if (colorspace_ext) {
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT});
all_formats.emplace_back(
VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
@@ -849,9 +853,26 @@
desc.format = AHARDWAREBUFFER_FORMAT_R8_UNORM;
if (AHardwareBuffer_isSupported(&desc)) {
+ if (colorspace_ext) {
+ all_formats.emplace_back(VkSurfaceFormatKHR{
+ VK_FORMAT_R8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ }
+ }
+
+ // TODO query VK_EXT_rgba10x6_formats support
+ desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM;
+ if (AHardwareBuffer_isSupported(&desc)) {
all_formats.emplace_back(
- VkSurfaceFormatKHR{VK_FORMAT_R8_UNORM,
- VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+ if (colorspace_ext) {
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
+ }
}
// NOTE: Any new formats that are added must be coordinated across different
@@ -929,25 +950,87 @@
return GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,
pSurfaceInfo->surface,
pSurfaceFormatCount, nullptr);
- } else {
- // temp vector for forwarding; we'll marshal it into the pSurfaceFormats
- // after the call.
- std::vector<VkSurfaceFormatKHR> surface_formats(*pSurfaceFormatCount);
- VkResult result = GetPhysicalDeviceSurfaceFormatsKHR(
- physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount,
- surface_formats.data());
+ }
- if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
- // marshal results individually due to stride difference.
- // completely ignore any chained extension structs.
- uint32_t formats_to_marshal = *pSurfaceFormatCount;
- for (uint32_t i = 0u; i < formats_to_marshal; i++) {
- pSurfaceFormats[i].surfaceFormat = surface_formats[i];
- }
- }
+ // temp vector for forwarding; we'll marshal it into the pSurfaceFormats
+ // after the call.
+ std::vector<VkSurfaceFormatKHR> surface_formats(*pSurfaceFormatCount);
+ VkResult result = GetPhysicalDeviceSurfaceFormatsKHR(
+ physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount,
+ surface_formats.data());
+ if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
return result;
}
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ // marshal results individually due to stride difference.
+ uint32_t formats_to_marshal = *pSurfaceFormatCount;
+ for (uint32_t i = 0u; i < formats_to_marshal; i++) {
+ pSurfaceFormats[i].surfaceFormat = surface_formats[i];
+
+ // Query the compression properties for the surface format
+ VkSurfaceFormat2KHR* pSurfaceFormat = &pSurfaceFormats[i];
+ while (pSurfaceFormat->pNext) {
+ pSurfaceFormat =
+ reinterpret_cast<VkSurfaceFormat2KHR*>(pSurfaceFormat->pNext);
+ switch (pSurfaceFormat->sType) {
+ case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: {
+ VkImageCompressionPropertiesEXT* surfaceCompressionProps =
+ reinterpret_cast<VkImageCompressionPropertiesEXT*>(
+ pSurfaceFormat);
+
+ if (surfaceCompressionProps &&
+ driver.GetPhysicalDeviceImageFormatProperties2KHR) {
+ VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
+ imageFormatInfo.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+ imageFormatInfo.format =
+ pSurfaceFormats[i].surfaceFormat.format;
+ imageFormatInfo.pNext = nullptr;
+
+ VkImageCompressionControlEXT compressionControl = {};
+ compressionControl.sType =
+ VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT;
+ compressionControl.pNext = imageFormatInfo.pNext;
+
+ imageFormatInfo.pNext = &compressionControl;
+
+ VkImageCompressionPropertiesEXT compressionProps = {};
+ compressionProps.sType =
+ VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT;
+ compressionProps.pNext = nullptr;
+
+ VkImageFormatProperties2KHR imageFormatProps = {};
+ imageFormatProps.sType =
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
+ imageFormatProps.pNext = &compressionProps;
+
+ VkResult compressionRes =
+ driver.GetPhysicalDeviceImageFormatProperties2KHR(
+ physicalDevice, &imageFormatInfo,
+ &imageFormatProps);
+ if (compressionRes == VK_SUCCESS) {
+ surfaceCompressionProps->imageCompressionFlags =
+ compressionProps.imageCompressionFlags;
+ surfaceCompressionProps
+ ->imageCompressionFixedRateFlags =
+ compressionProps.imageCompressionFixedRateFlags;
+ } else {
+ return compressionRes;
+ }
+ }
+ } break;
+
+ default:
+ // Ignore all other extension structs
+ break;
+ }
+ }
+ }
+
+ return result;
}
VKAPI_ATTR
@@ -1360,8 +1443,48 @@
num_images = 1;
}
+ void* usage_info_pNext = nullptr;
+ VkImageCompressionControlEXT image_compression = {};
uint64_t native_usage = 0;
- if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
+ if (dispatch.GetSwapchainGrallocUsage3ANDROID) {
+ ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID");
+ VkGrallocUsageInfoANDROID gralloc_usage_info = {};
+ gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID;
+ gralloc_usage_info.format = create_info->imageFormat;
+ gralloc_usage_info.imageUsage = create_info->imageUsage;
+
+ // Look through the pNext chain for an image compression control struct
+ // if one is found AND the appropriate extensions are enabled,
+ // append it to be the gralloc usage pNext chain
+ const VkSwapchainCreateInfoKHR* create_infos = create_info;
+ while (create_infos->pNext) {
+ create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
+ create_infos->pNext);
+ switch (create_infos->sType) {
+ case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+ const VkImageCompressionControlEXT* compression_infos =
+ reinterpret_cast<const VkImageCompressionControlEXT*>(
+ create_infos);
+ image_compression = *compression_infos;
+ image_compression.pNext = nullptr;
+ usage_info_pNext = &image_compression;
+ } break;
+
+ default:
+ // Ignore all other info structs
+ break;
+ }
+ }
+ gralloc_usage_info.pNext = usage_info_pNext;
+
+ result = dispatch.GetSwapchainGrallocUsage3ANDROID(
+ device, &gralloc_usage_info, &native_usage);
+ ATRACE_END();
+ if (result != VK_SUCCESS) {
+ ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;
ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
result = dispatch.GetSwapchainGrallocUsage2ANDROID(
@@ -1373,7 +1496,7 @@
return VK_ERROR_SURFACE_LOST_KHR;
}
native_usage =
- convertGralloc1ToBufferUsage(consumer_usage, producer_usage);
+ convertGralloc1ToBufferUsage(producer_usage, consumer_usage);
} else if (dispatch.GetSwapchainGrallocUsageANDROID) {
ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
int32_t legacy_usage = 0;
@@ -1427,7 +1550,7 @@
#pragma clang diagnostic ignored "-Wold-style-cast"
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID,
#pragma clang diagnostic pop
- .pNext = nullptr,
+ .pNext = usage_info_pNext,
.usage = swapchain_image_usage,
};
VkNativeBufferANDROID image_native_buffer = {
@@ -1485,6 +1608,7 @@
android_convertGralloc0To1Usage(int(img.buffer->usage),
&image_native_buffer.usage2.producer,
&image_native_buffer.usage2.consumer);
+ image_native_buffer.usage3 = img.buffer->usage;
ATRACE_BEGIN("CreateImage");
result =
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 3c91150..f998b1a 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -948,6 +948,17 @@
return VK_SUCCESS;
}
+VkResult GetSwapchainGrallocUsage3ANDROID(
+ VkDevice,
+ const VkGrallocUsageInfoANDROID* grallocUsageInfo,
+ uint64_t* grallocUsage) {
+ // The null driver never reads or writes the gralloc buffer
+ ALOGV("TODO: vk%s - grallocUsageInfo->format:%i", __FUNCTION__,
+ grallocUsageInfo->format);
+ *grallocUsage = 0;
+ return VK_SUCCESS;
+}
+
VkResult AcquireImageANDROID(VkDevice,
VkImage,
int fence,
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index f6dcf09..0cb7bd3 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -261,6 +261,7 @@
{"vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetRenderAreaGranularity>(GetRenderAreaGranularity))},
{"vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSemaphoreCounterValue>(GetSemaphoreCounterValue))},
{"vkGetSwapchainGrallocUsage2ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID>(GetSwapchainGrallocUsage2ANDROID))},
+ {"vkGetSwapchainGrallocUsage3ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage3ANDROID>(GetSwapchainGrallocUsage3ANDROID))},
{"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
{"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
{"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkMapMemory>(MapMemory))},
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 3e003e3..5c7fea0 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -209,6 +209,7 @@
VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsage3ANDROID(VkDevice device, const VkGrallocUsageInfoANDROID* grallocUsageInfo, uint64_t* grallocUsage);
VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 4176509..c25c6cb 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -69,6 +69,7 @@
_OPTIONAL_COMMANDS = [
'vkGetSwapchainGrallocUsageANDROID',
'vkGetSwapchainGrallocUsage2ANDROID',
+ 'vkGetSwapchainGrallocUsage3ANDROID',
]
# Dict for mapping dispatch table to a type.
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index da6b00a..0284192 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -731,7 +731,7 @@
visitor->Visit("vulkanMemoryModelAvailabilityVisibilityChains", &features->vulkanMemoryModelAvailabilityVisibilityChains) &&
visitor->Visit("shaderOutputViewportIndex", &features->shaderOutputViewportIndex) &&
visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer) &&
- visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer);
+ visitor->Visit("subgroupBroadcastDynamicId", &features->subgroupBroadcastDynamicId);
}
template <typename Visitor>