Merge "Map the hwc-id -> SF-id in getPreferredBootDisplayMode and SF-Id -> HWC id in setUserPreferredDisplayMode"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index bb1d206..08a3d9a 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -246,7 +246,7 @@
{ OPT, "events/gpu_mem/gpu_mem_total/enable" },
{ OPT, "events/fastrpc/fastrpc_dma_stat/enable" },
} },
- { "thermal", "Thermal event", 0, {
+ { "thermal", "Thermal event", ATRACE_TAG_THERMAL, {
{ REQ, "events/thermal/thermal_temperature/enable" },
{ OPT, "events/thermal/cdev_update/enable" },
} },
diff --git a/cmds/dumpstate/DumpPool.cpp b/cmds/dumpstate/DumpPool.cpp
index c2c8a72..4d3a67b 100644
--- a/cmds/dumpstate/DumpPool.cpp
+++ b/cmds/dumpstate/DumpPool.cpp
@@ -33,6 +33,20 @@
const std::string DumpPool::PREFIX_TMPFILE_NAME = "dump-tmp.";
+
+void WaitForTask(std::future<std::string> future, const std::string& title, int out_fd) {
+ DurationReporter duration_reporter("Wait for " + title, true);
+
+ std::string result = future.get();
+ if (result.empty()) {
+ return;
+ }
+ DumpFileToFd(out_fd, title, result);
+ if (unlink(result.c_str())) {
+ MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
+ }
+}
+
DumpPool::DumpPool(const std::string& tmp_root) : tmp_root_(tmp_root), shutdown_(false),
log_duration_(true) {
assert(!tmp_root.empty());
@@ -40,31 +54,10 @@
}
DumpPool::~DumpPool() {
- shutdown();
-}
-
-void DumpPool::start(int thread_counts) {
- assert(thread_counts > 0);
- assert(threads_.empty());
- if (thread_counts > MAX_THREAD_COUNT) {
- thread_counts = MAX_THREAD_COUNT;
- }
- MYLOGI("Start thread pool:%d", thread_counts);
- shutdown_ = false;
- for (int i = 0; i < thread_counts; i++) {
- threads_.emplace_back(std::thread([=]() {
- setThreadName(pthread_self(), i + 1);
- loop();
- }));
- }
-}
-
-void DumpPool::shutdown() {
std::unique_lock lock(lock_);
if (shutdown_ || threads_.empty()) {
return;
}
- futures_map_.clear();
while (!tasks_.empty()) tasks_.pop();
shutdown_ = true;
@@ -76,27 +69,22 @@
}
threads_.clear();
deleteTempFiles(tmp_root_);
- MYLOGI("shutdown thread pool");
+ MYLOGI("shutdown thread pool\n");
}
-void DumpPool::waitForTask(const std::string& task_name, const std::string& title,
- int out_fd) {
- DurationReporter duration_reporter("Wait for " + task_name, true);
- auto iterator = futures_map_.find(task_name);
- if (iterator == futures_map_.end()) {
- MYLOGW("Task %s does not exist", task_name.c_str());
- return;
+void DumpPool::start(int thread_counts) {
+ assert(thread_counts > 0);
+ assert(threads_.empty());
+ if (thread_counts > MAX_THREAD_COUNT) {
+ thread_counts = MAX_THREAD_COUNT;
}
- Future future = iterator->second;
- futures_map_.erase(iterator);
-
- std::string result = future.get();
- if (result.empty()) {
- return;
- }
- DumpFileToFd(out_fd, title, result);
- if (unlink(result.c_str())) {
- MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
+ MYLOGI("Start thread pool:%d\n", thread_counts);
+ shutdown_ = false;
+ for (int i = 0; i < thread_counts; i++) {
+ threads_.emplace_back(std::thread([=]() {
+ setThreadName(pthread_self(), i + 1);
+ loop();
+ }));
}
}
diff --git a/cmds/dumpstate/DumpPool.h b/cmds/dumpstate/DumpPool.h
index 0c3c2cc..9fb0fcc 100644
--- a/cmds/dumpstate/DumpPool.h
+++ b/cmds/dumpstate/DumpPool.h
@@ -18,7 +18,6 @@
#define FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
#include <future>
-#include <map>
#include <queue>
#include <string>
@@ -32,8 +31,26 @@
class DumpPoolTest;
/*
+ * Waits until the task is finished. Dumps the task results to the specified
+ * out_fd.
+ *
+ * |future| The task future.
+ * |title| Dump title string to the out_fd, an empty string for nothing.
+ * |out_fd| The target file to dump the result from the task.
+ */
+void WaitForTask(std::future<std::string> future, const std::string& title, int out_fd);
+
+/*
+ * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
+ */
+
+inline void WaitForTask(std::future<std::string> future) {
+ WaitForTask(std::move(future), "", STDOUT_FILENO);
+}
+
+/*
* A thread pool with the fixed number of threads to execute multiple dump tasks
- * simultaneously for the dumpstate. The dump task is a callable function. It
+ * simultaneously for dumpstate. The dump task is a callable function. It
* could include a file descriptor as a parameter to redirect dump results, if
* it needs to output results to the bugreport. This can avoid messing up
* bugreport's results when multiple dump tasks are running at the same time.
@@ -44,13 +61,16 @@
* }
* ...
* DumpPool pool(tmp_root);
- * pool.enqueueTaskWithFd("TaskName", &DumpFoo, std::placeholders::_1);
+ * auto task = pool.enqueueTaskWithFd("TaskName", &DumpFoo, std::placeholders::_1);
* ...
- * pool.waitForTask("TaskName");
+ * WaitForTask(task);
*
* DumpFoo is a callable function included a out_fd parameter. Using the
* enqueueTaskWithFd method in DumpPool to enqueue the task to the pool. The
* std::placeholders::_1 is a placeholder for DumpPool to pass a fd argument.
+ *
+ * std::futures returned by `enqueueTask*()` must all have their `get` methods
+ * called, or have been destroyed before the DumpPool itself is destroyed.
*/
class DumpPool {
friend class android::os::dumpstate::DumpPoolTest;
@@ -63,6 +83,12 @@
* files.
*/
explicit DumpPool(const std::string& tmp_root);
+
+ /*
+ * Will waits until all threads exit the loop. Destroying DumpPool before destroying the
+ * associated std::futures created by `enqueueTask*` will cause an abort on Android because
+ * Android is built with `-fno-exceptions`.
+ */
~DumpPool();
/*
@@ -73,68 +99,47 @@
void start(int thread_counts = MAX_THREAD_COUNT);
/*
- * Requests to shutdown the pool and waits until all threads exit the loop.
- */
- void shutdown();
-
- /*
* Adds a task into the queue of the thread pool.
*
- * |task_name| The name of the task. It's also the title of the
+ * |duration_title| The name of the task. It's also the title of the
* DurationReporter log.
* |f| Callable function to execute the task.
* |args| A list of arguments.
*
* TODO(b/164369078): remove this api to have just one enqueueTask for consistency.
*/
- template<class F, class... Args> void enqueueTask(const std::string& task_name, F&& f,
- Args&&... args) {
+ template<class F, class... Args>
+ std::future<std::string> enqueueTask(const std::string& duration_title, F&& f, Args&&... args) {
std::function<void(void)> func = std::bind(std::forward<F>(f),
std::forward<Args>(args)...);
- futures_map_[task_name] = post(task_name, func);
+ auto future = post(duration_title, func);
if (threads_.empty()) {
start();
}
+ return future;
}
/*
* Adds a task into the queue of the thread pool. The task takes a file
* descriptor as a parameter to redirect dump results to a temporary file.
*
- * |task_name| The name of the task. It's also the title of the
- * DurationReporter log.
+ * |duration_title| The title of the DurationReporter log.
* |f| Callable function to execute the task.
* |args| A list of arguments. A placeholder std::placeholders::_1 as a fd
* argument needs to be included here.
*/
- template<class F, class... Args> void enqueueTaskWithFd(const std::string& task_name, F&& f,
- Args&&... args) {
+ template<class F, class... Args> std::future<std::string> enqueueTaskWithFd(
+ const std::string& duration_title, F&& f, Args&&... args) {
std::function<void(int)> func = std::bind(std::forward<F>(f),
std::forward<Args>(args)...);
- futures_map_[task_name] = post(task_name, func);
+ auto future = post(duration_title, func);
if (threads_.empty()) {
start();
}
+ return future;
}
/*
- * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
- */
- void waitForTask(const std::string& task_name) {
- waitForTask(task_name, "", STDOUT_FILENO);
- }
-
- /*
- * Waits until the task is finished. Dumps the task results to the specified
- * out_fd.
- *
- * |task_name| The name of the task.
- * |title| Dump title string to the out_fd, an empty string for nothing.
- * |out_fd| The target file to dump the result from the task.
- */
- void waitForTask(const std::string& task_name, const std::string& title, int out_fd);
-
- /*
* Deletes temporary files created by DumpPool.
*/
void deleteTempFiles();
@@ -143,22 +148,22 @@
private:
using Task = std::packaged_task<std::string()>;
- using Future = std::shared_future<std::string>;
template<class T> void invokeTask(T dump_func, const std::string& duration_title, int out_fd);
- template<class T> Future post(const std::string& task_name, T dump_func) {
+ template<class T>
+ std::future<std::string> post(const std::string& duration_title, T dump_func) {
Task packaged_task([=]() {
std::unique_ptr<TmpFile> tmp_file_ptr = createTempFile();
if (!tmp_file_ptr) {
return std::string("");
}
- invokeTask(dump_func, task_name, tmp_file_ptr->fd.get());
+ invokeTask(dump_func, duration_title, tmp_file_ptr->fd.get());
fsync(tmp_file_ptr->fd.get());
return std::string(tmp_file_ptr->path);
});
std::unique_lock lock(lock_);
- auto future = packaged_task.get_future().share();
+ auto future = packaged_task.get_future();
tasks_.push(std::move(packaged_task));
condition_variable_.notify_one();
return future;
@@ -194,7 +199,6 @@
std::vector<std::thread> threads_;
std::queue<Task> tasks_;
- std::map<std::string, Future> futures_map_;
DISALLOW_COPY_AND_ASSIGN(DumpPool);
};
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index c833d0e..aa42541 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -48,11 +48,26 @@
sigemptyset(&child_mask);
sigaddset(&child_mask, SIGCHLD);
+ // block SIGCHLD before we check if a process has exited
if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
printf("*** sigprocmask failed: %s\n", strerror(errno));
return false;
}
+ // if the child has exited already, handle and reset signals before leaving
+ pid_t child_pid = waitpid(pid, status, WNOHANG);
+ if (child_pid != pid) {
+ if (child_pid > 0) {
+ printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
+ sigprocmask(SIG_SETMASK, &old_mask, nullptr);
+ return false;
+ }
+ } else {
+ sigprocmask(SIG_SETMASK, &old_mask, nullptr);
+ return true;
+ }
+
+ // wait for a SIGCHLD
timespec ts;
ts.tv_sec = MSEC_TO_SEC(timeout_ms);
ts.tv_nsec = (timeout_ms % 1000) * 1000000;
@@ -76,7 +91,7 @@
return false;
}
- pid_t child_pid = waitpid(pid, status, WNOHANG);
+ child_pid = waitpid(pid, status, WNOHANG);
if (child_pid != pid) {
if (child_pid != -1) {
printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
@@ -232,7 +247,6 @@
dprintf(out_fd, "*** Error dumping %s (%s): %s\n", path.c_str(), title.c_str(),
strerror(err));
}
- fsync(out_fd);
return -1;
}
return DumpFileFromFdToFd(title, path, fd.get(), out_fd, PropertiesHelper::IsDryRun());
@@ -280,7 +294,6 @@
if (!title.empty()) {
dprintf(fd, "------ %s (%s) ------\n", title.c_str(), command);
- fsync(fd);
}
const std::string& logging_message = options.LoggingMessage();
@@ -299,14 +312,13 @@
// There is no title, but we should still print a dry-run message
dprintf(fd, "%s: skipped on dry run\n", command_string.c_str());
}
- fsync(fd);
return 0;
}
const char* path = args[0];
uint64_t start = Nanotime();
- pid_t pid = fork();
+ pid_t pid = vfork();
/* handle error case */
if (pid < 0) {
@@ -323,7 +335,7 @@
strerror(errno));
}
MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno));
- return -1;
+ _exit(EXIT_FAILURE);
}
if (options.ShouldCloseAllFileDescriptorsOnExec()) {
@@ -376,7 +388,6 @@
/* handle parent case */
int status;
bool ret = waitpid_with_timeout(pid, options.TimeoutInMs(), &status);
- fsync(fd);
uint64_t elapsed = Nanotime() - start;
if (!ret) {
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8ccd940..0e9ce89 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -120,6 +120,7 @@
using android::os::dumpstate::DumpPool;
using android::os::dumpstate::PropertiesHelper;
using android::os::dumpstate::TaskQueue;
+using android::os::dumpstate::WaitForTask;
// Keep in sync with
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -218,9 +219,9 @@
RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, __VA_ARGS__); \
RETURN_IF_USER_DENIED_CONSENT();
-#define WAIT_TASK_WITH_CONSENT_CHECK(task_name, pool_ptr) \
+#define WAIT_TASK_WITH_CONSENT_CHECK(future) \
RETURN_IF_USER_DENIED_CONSENT(); \
- pool_ptr->waitForTask(task_name); \
+ WaitForTask(future); \
RETURN_IF_USER_DENIED_CONSENT();
static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
@@ -1549,15 +1550,18 @@
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;
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.
ds.dump_pool_->start(/* thread_counts = */2);
- ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
- ds.dump_pool_->enqueueTask(DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
- ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
- ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
+ dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+ dump_incident_report = ds.dump_pool_->enqueueTask(
+ DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
+ dump_board = ds.dump_pool_->enqueueTaskWithFd(
+ DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+ dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
}
// Dump various things. Note that anything that takes "long" (i.e. several seconds) should
@@ -1582,7 +1586,6 @@
DumpFile("BUDDYINFO", "/proc/buddyinfo");
DumpExternalFragmentationInfo();
- DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
RunCommand("PROCESSES AND THREADS",
@@ -1592,7 +1595,7 @@
CommandOptions::AS_ROOT);
if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_HALS_TASK, ds.dump_pool_);
+ WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_hals));
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_HALS_TASK, DumpHals);
}
@@ -1689,7 +1692,7 @@
ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_BOARD_TASK, ds.dump_pool_);
+ WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_board));
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
}
@@ -1718,7 +1721,7 @@
ds.AddDir("/data/misc/bluetooth/logs", true);
if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_CHECKINS_TASK, ds.dump_pool_);
+ WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_checkins));
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_CHECKINS_TASK, DumpCheckins);
}
@@ -1752,7 +1755,7 @@
dump_frozen_cgroupfs();
if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, 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,
DumpIncidentReport);
@@ -1777,6 +1780,7 @@
time_t logcat_ts = time(nullptr);
/* collect stack traces from Dalvik and native processes (needs root) */
+ std::future<std::string> dump_traces;
if (dump_pool_) {
RETURN_IF_USER_DENIED_CONSENT();
// One thread is enough since we only need to enqueue DumpTraces here.
@@ -1784,7 +1788,8 @@
// DumpTraces takes long time, post it to the another thread in the
// pool, if pool is available
- dump_pool_->enqueueTask(DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
+ dump_traces = dump_pool_->enqueueTask(
+ DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_TRACES_TASK, ds.DumpTraces,
&dump_traces_path);
@@ -1833,12 +1838,11 @@
if (dump_pool_) {
RETURN_IF_USER_DENIED_CONSENT();
- dump_pool_->waitForTask(DUMP_TRACES_TASK);
+ WaitForTask(std::move(dump_traces));
- // Current running thread in the pool is the root user also. Shutdown
- // the pool and restart later to ensure all threads in the pool could
- // drop the root user.
- dump_pool_->shutdown();
+ // Current running thread in the pool is the root user also. Delete
+ // the pool and make a new one later to ensure none of threads in the pool are root.
+ dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_);
}
if (!DropRootUser()) {
return Dumpstate::RunStatus::ERROR;
@@ -1869,8 +1873,9 @@
} else {
// DumpHals takes long time, post it to the another thread in the pool,
// if pool is available.
+ std::future<std::string> dump_hals;
if (ds.dump_pool_) {
- ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+ dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
}
// Contains various system properties and process startup info.
do_dmesg();
@@ -1880,7 +1885,7 @@
DoKmsg();
// DumpHals contains unrelated hardware info (camera, NFC, biometrics, ...).
if (ds.dump_pool_) {
- ds.dump_pool_->waitForTask(DUMP_HALS_TASK);
+ WaitForTask(std::move(dump_hals));
} else {
RUN_SLOW_FUNCTION_AND_LOG(DUMP_HALS_TASK, DumpHals);
}
@@ -1914,12 +1919,14 @@
// Starts thread pool after the root user is dropped, and two additional threads
// are created for DumpHals in the DumpstateRadioCommon and DumpstateBoard.
+ std::future<std::string> dump_board;
if (ds.dump_pool_) {
ds.dump_pool_->start(/*thread_counts =*/2);
// DumpstateBoard takes long time, post it to the another thread in the pool,
// if pool is available.
- ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+ dump_board = ds.dump_pool_->enqueueTaskWithFd(
+ DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
}
DumpstateRadioCommon(include_sensitive_info);
@@ -2002,7 +2009,7 @@
printf("========================================================\n");
if (ds.dump_pool_) {
- ds.dump_pool_->waitForTask(DUMP_BOARD_TASK);
+ WaitForTask(std::move(dump_board));
} else {
RUN_SLOW_FUNCTION_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
}
@@ -3226,8 +3233,7 @@
void Dumpstate::ShutdownDumpPool() {
if (dump_pool_) {
- dump_pool_->shutdown();
- dump_pool_ = nullptr;
+ dump_pool_.reset();
}
if (zip_entry_tasks_) {
zip_entry_tasks_->run(/* do_cancel = */true);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 4a99cd8..ee6b1ae 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -478,7 +478,7 @@
// This is useful for debugging.
std::string log_path_;
- // Full path of the bugreport file, be it zip or text, inside bugreport_internal_dir_.
+ // Full path of the bugreport zip file inside bugreport_internal_dir_.
std::string path_;
// Full path of the file containing the screenshot (when requested).
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 42beb2b..70b4e5c 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -1720,14 +1720,13 @@
dprintf(out_fd, "C");
};
setLogDuration(/* log_duration = */false);
- dump_pool_->enqueueTaskWithFd(/* task_name = */"1", dump_func_1, std::placeholders::_1);
- dump_pool_->enqueueTaskWithFd(/* task_name = */"2", dump_func_2, std::placeholders::_1);
- dump_pool_->enqueueTaskWithFd(/* task_name = */"3", dump_func_3, std::placeholders::_1);
+ auto t1 = dump_pool_->enqueueTaskWithFd("", dump_func_1, std::placeholders::_1);
+ auto t2 = dump_pool_->enqueueTaskWithFd("", dump_func_2, std::placeholders::_1);
+ auto t3 = dump_pool_->enqueueTaskWithFd("", dump_func_3, std::placeholders::_1);
- dump_pool_->waitForTask("1", "", out_fd_.get());
- dump_pool_->waitForTask("2", "", out_fd_.get());
- dump_pool_->waitForTask("3", "", out_fd_.get());
- dump_pool_->shutdown();
+ WaitForTask(std::move(t1), "", out_fd_.get());
+ WaitForTask(std::move(t2), "", out_fd_.get());
+ WaitForTask(std::move(t3), "", out_fd_.get());
std::string result;
ReadFileToString(out_path_, &result);
@@ -1741,9 +1740,8 @@
run_1 = true;
};
- dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
- dump_pool_->waitForTask("1", "", out_fd_.get());
- dump_pool_->shutdown();
+ auto t1 = dump_pool_->enqueueTask(/* duration_title = */"1", dump_func_1);
+ WaitForTask(std::move(t1), "", out_fd_.get());
std::string result;
ReadFileToString(out_path_, &result);
@@ -1752,27 +1750,6 @@
EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
}
-TEST_F(DumpPoolTest, Shutdown_withoutCrash) {
- bool run_1 = false;
- auto dump_func_1 = [&]() {
- run_1 = true;
- };
- auto dump_func = []() {
- sleep(1);
- };
-
- dump_pool_->start(/* thread_counts = */1);
- dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
- dump_pool_->enqueueTask(/* task_name = */"2", dump_func);
- dump_pool_->enqueueTask(/* task_name = */"3", dump_func);
- dump_pool_->enqueueTask(/* task_name = */"4", dump_func);
- dump_pool_->waitForTask("1", "", out_fd_.get());
- dump_pool_->shutdown();
-
- EXPECT_TRUE(run_1);
- EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
-}
-
class TaskQueueTest : public DumpstateBaseTest {
public:
void SetUp() {
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 00babc3..c9f680b 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -51,6 +51,7 @@
],
static_libs: [
"libasync_safe",
+ "libext2_uuid",
],
export_shared_lib_headers: [
"libbinder",
@@ -262,6 +263,7 @@
"libasync_safe",
"libdiskusage",
"libotapreoptparameters",
+ "libext2_uuid",
],
shared_libs: [
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 4ce48d5..e7bde21 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -18,13 +18,9 @@
#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
-#include <algorithm>
#include <errno.h>
-#include <fstream>
#include <fts.h>
-#include <functional>
#include <inttypes.h>
-#include <regex>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -40,6 +36,11 @@
#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <functional>
+#include <regex>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -720,6 +721,76 @@
return error("Failed to prepare profiles for " + packageName);
}
}
+
+ // TODO(b/220095381): Due to boot time regression, we have omitted call to
+ // createAppDirectoryForSupplementalData from here temporarily (unless it's for testing)
+ if (uuid_ != nullptr && strcmp(uuid_, "TEST") == 0) {
+ auto status = createAppDirectoryForSupplementalData(uuid, packageName, userId, appId,
+ previousAppId, seInfo, flags);
+ if (!status.isOk()) {
+ return status;
+ }
+ }
+
+ return ok();
+}
+
+/**
+ * Responsible for creating /data/user/0/supplemental/<app-name> directory and other
+ * app level sub directories, such as ./shared
+ */
+binder::Status InstalldNativeService::createAppDirectoryForSupplementalData(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) {
+ int32_t supplementalUid = multiuser_get_supplemental_uid(userId, appId);
+ if (supplementalUid == -1) {
+ // There no valid supplemental process for this app. Skip creation of data directory
+ return ok();
+ }
+
+ // TODO(b/211763739): what if uuid is not nullptr or TEST?
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int i = 0; i < 2; i++) {
+ int currentFlag = storageFlags[i];
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+
+ // /data/misc_{ce,de}/<user-id>/supplemental directory gets created by vold
+ // during user creation
+
+ // Prepare the app directory
+ auto appPath = create_data_misc_supplemental_package_path(uuid_, isCeData, userId,
+ packageName.c_str());
+ if (prepare_app_dir(appPath, 0751, AID_SYSTEM)) {
+ return error("Failed to prepare " + appPath);
+ }
+
+ // Now prepare the shared directory which will be accessible by all codes
+ auto sharedPath = create_data_misc_supplemental_shared_path(uuid_, isCeData, userId,
+ packageName.c_str());
+
+ int32_t previousSupplementalUid = multiuser_get_supplemental_uid(userId, previousAppId);
+ int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
+ if (cacheGid == -1) {
+ return exception(binder::Status::EX_ILLEGAL_STATE,
+ StringPrintf("cacheGid cannot be -1 for supplemental data"));
+ }
+ auto status = createAppDataDirs(sharedPath, supplementalUid, &previousSupplementalUid,
+ cacheGid, seInfo, 0700);
+ if (!status.isOk()) {
+ return status;
+ }
+
+ // TODO(b/211763739): We also need to handle art profile creations
+
+ // TODO(b/211763739): And return the CE inode of the supplemental root directory and
+ // app directory under it so we can clear contents while CE storage is locked
+ }
+
return ok();
}
@@ -957,13 +1028,13 @@
binder::Status res = ok();
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
- if (delete_dir_contents_and_dir(path) != 0) {
+ if (rename_delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
}
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- if (delete_dir_contents_and_dir(path) != 0) {
+ if (rename_delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
if ((flags & FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
@@ -997,7 +1068,6 @@
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete contents of " + path);
}
-
path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete contents of " + path);
@@ -3190,5 +3260,22 @@
return ok();
}
+binder::Status InstalldNativeService::cleanupInvalidPackageDirs(
+ const std::optional<std::string>& uuid, int32_t userId, int32_t flags) {
+ const char* uuid_cstr = uuid ? uuid->c_str() : nullptr;
+
+ if (flags & FLAG_STORAGE_CE) {
+ auto ce_path = create_data_user_ce_path(uuid_cstr, userId);
+ cleanup_invalid_package_dirs_under_path(ce_path);
+ }
+
+ if (flags & FLAG_STORAGE_DE) {
+ auto de_path = create_data_user_de_path(uuid_cstr, userId);
+ cleanup_invalid_package_dirs_under_path(de_path);
+ }
+
+ return ok();
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 6e74884..6b4ba1f 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -47,14 +47,9 @@
int32_t flags);
binder::Status createAppData(const std::optional<std::string>& uuid,
- const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
- int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion,
- int64_t* _aidl_return);
- binder::Status createAppDataLocked(const std::optional<std::string>& uuid,
- const std::string& packageName, int32_t userId,
- int32_t flags, int32_t appId, int32_t previousAppId,
- const std::string& seInfo, int32_t targetSdkVersion,
- int64_t* _aidl_return);
+ const std::string& packageName, int32_t userId, int32_t flags,
+ int32_t appId, int32_t previousAppId, const std::string& seInfo,
+ int32_t targetSdkVersion, int64_t* _aidl_return);
binder::Status createAppData(
const android::os::CreateAppDataArgs& args,
@@ -185,6 +180,9 @@
binder::Status migrateLegacyObbData();
+ binder::Status cleanupInvalidPackageDirs(const std::optional<std::string>& uuid, int32_t userId,
+ int32_t flags);
+
private:
std::recursive_mutex mLock;
std::unordered_map<userid_t, std::weak_ptr<std::shared_mutex>> mUserIdLock;
@@ -200,6 +198,18 @@
std::unordered_map<uid_t, int64_t> mCacheQuotas;
std::string findDataMediaPath(const std::optional<std::string>& uuid, userid_t userid);
+
+ binder::Status createAppDataLocked(const std::optional<std::string>& uuid,
+ const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, int32_t previousAppId,
+ const std::string& seInfo, int32_t targetSdkVersion,
+ int64_t* _aidl_return);
+
+ binder::Status createAppDirectoryForSupplementalData(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ int32_t userId, int32_t appId,
+ int32_t previousAppId,
+ const std::string& seInfo, int32_t flags);
};
} // namespace installd
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 44c9667..afedcc6 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -126,6 +126,8 @@
void migrateLegacyObbData();
+ void cleanupInvalidPackageDirs(@nullable @utf8InCpp String uuid, int userId, int flags);
+
const int FLAG_STORAGE_DE = 0x1;
const int FLAG_STORAGE_CE = 0x2;
const int FLAG_STORAGE_EXTERNAL = 0x4;
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index c796da6..9647865 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -74,10 +74,19 @@
using android::base::ReadFully;
using android::base::StringPrintf;
using android::base::WriteFully;
+using android::base::borrowed_fd;
using android::base::unique_fd;
namespace {
+// Timeout for short operations, such as merging profiles.
+constexpr int kShortTimeoutMs = 60000; // 1 minute.
+
+// Timeout for long operations, such as compilation. This should be smaller than the Package Manager
+// watchdog (PackageManagerService.WATCHDOG_TIMEOUT, 10 minutes), so that the operation will be
+// aborted before that watchdog would take down the system server.
+constexpr int kLongTimeoutMs = 570000; // 9.5 minutes.
+
class DexOptStatus {
public:
// Check if dexopt is cancelled and fork if it is not cancelled.
@@ -486,6 +495,25 @@
}
}
+// Cleans up an output file specified by a file descriptor. This function should be called whenever
+// a subprocess that modifies a system-managed file crashes.
+// If the subprocess crashes while it's writing to the file, the file is likely corrupted, so we
+// should remove it.
+// If the subprocess times out and is killed while it's acquiring a flock on the file, there is
+// probably a deadlock, so it's also good to remove the file so that later operations won't
+// encounter the same problem. It's safe to do so because the process that is holding the flock will
+// still have access to the file until the file descriptor is closed.
+// Note that we can't do `clear_reference_profile` here even if the fd points to a reference profile
+// because that also requires a flock and is therefore likely to be stuck in the second case.
+static bool cleanup_output_fd(int fd) {
+ std::string path;
+ bool ret = remove_file_at_fd(fd, &path);
+ if (ret) {
+ LOG(INFO) << "Removed file at path " << path;
+ }
+ return ret;
+}
+
static constexpr int PROFMAN_BIN_RETURN_CODE_SUCCESS = 0;
static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 1;
static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_NOT_ENOUGH_DELTA = 2;
@@ -497,13 +525,14 @@
class RunProfman : public ExecVHelper {
public:
- void SetupArgs(const std::vector<unique_fd>& profile_fds,
- const unique_fd& reference_profile_fd,
- const std::vector<unique_fd>& apk_fds,
- const std::vector<std::string>& dex_locations,
- bool copy_and_update,
- bool for_snapshot,
- bool for_boot_image) {
+ template <typename T, typename U>
+ void SetupArgs(const std::vector<T>& profile_fds,
+ const unique_fd& reference_profile_fd,
+ const std::vector<U>& apk_fds,
+ const std::vector<std::string>& dex_locations,
+ bool copy_and_update,
+ bool for_snapshot,
+ bool for_boot_image) {
// TODO(calin): Assume for now we run in the bg compile job (which is in
// most of the invocation). With the current data flow, is not very easy or
@@ -519,11 +548,11 @@
AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
}
- for (const unique_fd& fd : profile_fds) {
+ for (const T& fd : profile_fds) {
AddArg("--profile-file-fd=" + std::to_string(fd.get()));
}
- for (const unique_fd& fd : apk_fds) {
+ for (const U& fd : apk_fds) {
AddArg("--apk-fd=" + std::to_string(fd.get()));
}
@@ -582,20 +611,14 @@
for_boot_image);
}
- void SetupCopyAndUpdate(unique_fd&& profile_fd,
- unique_fd&& reference_profile_fd,
- unique_fd&& apk_fd,
+ void SetupCopyAndUpdate(const unique_fd& profile_fd,
+ const unique_fd& reference_profile_fd,
+ const unique_fd& apk_fd,
const std::string& dex_location) {
- // The fds need to stay open longer than the scope of the function, so put them into a local
- // variable vector.
- profiles_fd_.push_back(std::move(profile_fd));
- apk_fds_.push_back(std::move(apk_fd));
- reference_profile_fd_ = std::move(reference_profile_fd);
- std::vector<std::string> dex_locations = {dex_location};
- SetupArgs(profiles_fd_,
- reference_profile_fd_,
- apk_fds_,
- dex_locations,
+ SetupArgs(std::vector<borrowed_fd>{profile_fd},
+ reference_profile_fd,
+ std::vector<borrowed_fd>{apk_fd},
+ {dex_location},
/*copy_and_update=*/true,
/*for_snapshot*/false,
/*for_boot_image*/false);
@@ -621,11 +644,6 @@
void Exec() {
ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
}
-
- private:
- unique_fd reference_profile_fd_;
- std::vector<unique_fd> profiles_fd_;
- std::vector<unique_fd> apk_fds_;
};
static int analyze_profiles(uid_t uid, const std::string& package_name,
@@ -657,13 +675,14 @@
profman_merge.Exec();
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
bool need_to_compile = false;
bool empty_profiles = false;
bool should_clear_current_profiles = false;
bool should_clear_reference_profile = false;
if (!WIFEXITED(return_code)) {
LOG(WARNING) << "profman failed for location " << location << ": " << return_code;
+ cleanup_output_fd(reference_profile_fd.get());
} else {
return_code = WEXITSTATUS(return_code);
switch (return_code) {
@@ -797,10 +816,10 @@
profman_dump.Exec();
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
- LOG(WARNING) << "profman failed for package " << pkgname << ": "
- << return_code;
+ LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code;
+ cleanup_output_fd(output_fd.get());
return false;
}
return true;
@@ -871,7 +890,11 @@
_exit(0);
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
+ if (!WIFEXITED(return_code)) {
+ cleanup_output_fd(out_fd.get());
+ return false;
+ }
return return_code == 0;
}
@@ -1521,7 +1544,7 @@
}
pipe_read.reset();
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
PLOG(ERROR) << "Error waiting for child dexoptanalyzer process";
return false;
@@ -1695,7 +1718,7 @@
}
/* parent */
- int result = wait_child(pid);
+ int result = wait_child_with_timeout(pid, kShortTimeoutMs);
cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
if (!WIFEXITED(result)) {
if ((WTERMSIG(result) == SIGKILL) && cancelled) {
@@ -1954,7 +1977,7 @@
runner.Exec(DexoptReturnCodes::kDex2oatExec);
} else {
- int res = wait_child(pid);
+ int res = wait_child_with_timeout(pid, kLongTimeoutMs);
bool cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
if (res == 0) {
LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---";
@@ -2143,7 +2166,7 @@
_exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
}
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
LOG(WARNING) << "reconcile dex failed for location " << dex_path << ": " << return_code;
} else {
@@ -2261,7 +2284,7 @@
if (!ReadFully(pipe_read, out_secondary_dex_hash->data(), out_secondary_dex_hash->size())) {
out_secondary_dex_hash->clear();
}
- return wait_child(pid) == 0;
+ return wait_child_with_timeout(pid, kShortTimeoutMs) == 0;
}
// Helper for move_ab, so that we can have common failure-case cleanup.
@@ -2591,9 +2614,10 @@
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
LOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+ cleanup_output_fd(snapshot_fd.get());
return false;
}
@@ -2700,10 +2724,11 @@
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+ cleanup_output_fd(snapshot_fd.get());
return false;
}
@@ -2774,9 +2799,9 @@
}
RunProfman args;
- args.SetupCopyAndUpdate(std::move(dex_metadata_fd),
- std::move(ref_profile_fd),
- std::move(apk_fd),
+ args.SetupCopyAndUpdate(dex_metadata_fd,
+ ref_profile_fd,
+ apk_fd,
code_path);
pid_t pid = fork();
if (pid == 0) {
@@ -2789,9 +2814,10 @@
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+ cleanup_output_fd(ref_profile_fd.get());
return false;
}
return true;
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 51f7716..e390bab 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -25,6 +25,7 @@
static_libs: [
"libasync_safe",
"libdiskusage",
+ "libext2_uuid",
"libinstalld",
"liblog",
],
@@ -53,6 +54,7 @@
static_libs: [
"libasync_safe",
"libdiskusage",
+ "libext2_uuid",
"libinstalld",
"libziparchive",
"liblog",
@@ -99,6 +101,7 @@
static_libs: [
"libasync_safe",
"libdiskusage",
+ "libext2_uuid",
"libinstalld",
"libziparchive",
"liblog",
@@ -144,6 +147,7 @@
static_libs: [
"libasync_safe",
"libdiskusage",
+ "libext2_uuid",
"libinstalld",
"liblog",
"liblogwrap",
@@ -204,6 +208,7 @@
"libutils",
],
static_libs: [
+ "libext2_uuid",
"libinstalld",
"liblog",
],
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index bb36c39..f21a304 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -50,6 +50,8 @@
namespace android {
namespace installd {
+constexpr int kTimeoutMs = 60000;
+
// TODO(calin): try to dedup this code.
#if defined(__arm__)
static const std::string kRuntimeIsa = "arm";
@@ -1073,7 +1075,7 @@
_exit(0);
}
/* parent */
- ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+ ASSERT_TRUE(WIFEXITED(wait_child_with_timeout(pid, kTimeoutMs)));
}
void mergePackageProfiles(const std::string& package_name,
@@ -1377,7 +1379,7 @@
_exit(0);
}
/* parent */
- ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+ ASSERT_TRUE(WIFEXITED(wait_child_with_timeout(pid, kTimeoutMs)));
}
protected:
std::string intial_android_profiles_dir;
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index b831515..703a096 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -74,7 +74,14 @@
}
namespace installd {
-constexpr const char* kTestUuid = "TEST";
+static constexpr const char* kTestUuid = "TEST";
+static constexpr const char* kTestPath = "/data/local/tmp/user/0";
+static constexpr const uid_t kSystemUid = 1000;
+static constexpr const int32_t kTestUserId = 0;
+static constexpr const uid_t kTestAppId = 19999;
+
+const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+const uid_t kTestAppSupplementalUid = multiuser_get_supplemental_uid(kTestUserId, kTestAppId);
#define FLAG_FORCE InstalldNativeService::FLAG_FORCE
@@ -97,7 +104,7 @@
}
static std::string get_full_path(const char* path) {
- return StringPrintf("/data/local/tmp/user/0/%s", path);
+ return StringPrintf("%s/%s", kTestPath, path);
}
static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
@@ -107,12 +114,16 @@
EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
}
-static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static int create(const char* path, uid_t owner, gid_t group, mode_t mode) {
int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
EXPECT_NE(fd, -1);
EXPECT_EQ(::fchown(fd, owner, group), 0);
EXPECT_EQ(::fchmod(fd, mode), 0);
- EXPECT_EQ(::close(fd), 0);
+ return fd;
+}
+
+static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
+ EXPECT_EQ(::close(create(path, owner, group, mode)), 0);
}
static int stat_gid(const char* path) {
@@ -127,6 +138,35 @@
return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
}
+static bool exists(const char* path) {
+ return ::access(get_full_path(path).c_str(), F_OK) == 0;
+}
+
+template <class Pred>
+static bool find_file(const char* path, Pred&& pred) {
+ bool result = false;
+ auto d = opendir(path);
+ if (d == nullptr) {
+ return result;
+ }
+ struct dirent* de;
+ while ((de = readdir(d))) {
+ const char* name = de->d_name;
+ if (pred(name, de->d_type == DT_DIR)) {
+ result = true;
+ break;
+ }
+ }
+ closedir(d);
+ return result;
+}
+
+static bool exists_renamed_deleted_dir() {
+ return find_file(kTestPath, [](const std::string& name, bool is_dir) {
+ return is_dir && is_renamed_deleted_dir(name);
+ });
+}
+
class ServiceTest : public testing::Test {
protected:
InstalldNativeService* service;
@@ -193,6 +233,134 @@
EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
}
+TEST_F(ServiceTest, DestroyUserData) {
+ LOG(INFO) << "DestroyUserData";
+
+ mkdir("com.example", 10000, 10000, 0700);
+ mkdir("com.example/foo", 10000, 10000, 0700);
+ touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("com.example/bar", 10000, 20000, 0700);
+ touch("com.example/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists("com.example/foo"));
+ EXPECT_TRUE(exists("com.example/foo/file"));
+ EXPECT_TRUE(exists("com.example/bar"));
+ EXPECT_TRUE(exists("com.example/bar/file"));
+
+ service->destroyUserData(testUuid, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE);
+
+ EXPECT_FALSE(exists("com.example/foo"));
+ EXPECT_FALSE(exists("com.example/foo/file"));
+ EXPECT_FALSE(exists("com.example/bar"));
+ EXPECT_FALSE(exists("com.example/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir());
+}
+
+TEST_F(ServiceTest, DestroyAppData) {
+ LOG(INFO) << "DestroyAppData";
+
+ mkdir("com.example", 10000, 10000, 0700);
+ mkdir("com.example/foo", 10000, 10000, 0700);
+ touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("com.example/bar", 10000, 20000, 0700);
+ touch("com.example/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists("com.example/foo"));
+ EXPECT_TRUE(exists("com.example/foo/file"));
+ EXPECT_TRUE(exists("com.example/bar"));
+ EXPECT_TRUE(exists("com.example/bar/file"));
+
+ service->destroyAppData(testUuid, "com.example", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, 0);
+
+ EXPECT_FALSE(exists("com.example/foo"));
+ EXPECT_FALSE(exists("com.example/foo/file"));
+ EXPECT_FALSE(exists("com.example/bar"));
+ EXPECT_FALSE(exists("com.example/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir());
+}
+
+TEST_F(ServiceTest, CleanupInvalidPackageDirs) {
+ LOG(INFO) << "CleanupInvalidPackageDirs";
+
+ mkdir("5b14b6458a44==deleted==", 10000, 10000, 0700);
+ mkdir("5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
+ touch("5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
+ mkdir("5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
+ touch("5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
+
+ auto fd = create("5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
+
+ mkdir("b14b6458a44NOTdeleted", 10000, 10000, 0700);
+ mkdir("b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
+ touch("b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
+ mkdir("b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
+ touch("b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
+
+ mkdir("com.example", 10000, 10000, 0700);
+ mkdir("com.example/foo", 10000, 10000, 0700);
+ touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("com.example/bar", 10000, 20000, 0700);
+ touch("com.example/bar/file", 10000, 20000, 0700);
+
+ mkdir("==deleted==", 10000, 10000, 0700);
+ mkdir("==deleted==/foo", 10000, 10000, 0700);
+ touch("==deleted==/foo/file", 10000, 20000, 0700);
+ mkdir("==deleted==/bar", 10000, 20000, 0700);
+ touch("==deleted==/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo"));
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo/file"));
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar"));
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/file"));
+ EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+
+ EXPECT_TRUE(exists("com.example/foo"));
+ EXPECT_TRUE(exists("com.example/foo/file"));
+ EXPECT_TRUE(exists("com.example/bar"));
+ EXPECT_TRUE(exists("com.example/bar/file"));
+
+ EXPECT_TRUE(exists("==deleted==/foo"));
+ EXPECT_TRUE(exists("==deleted==/foo/file"));
+ EXPECT_TRUE(exists("==deleted==/bar"));
+ EXPECT_TRUE(exists("==deleted==/bar/file"));
+
+ EXPECT_TRUE(exists_renamed_deleted_dir());
+
+ service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
+
+ EXPECT_EQ(::close(fd), 0);
+
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo"));
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo/file"));
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar"));
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/file"));
+ EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
+ EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+
+ EXPECT_TRUE(exists("com.example/foo"));
+ EXPECT_TRUE(exists("com.example/foo/file"));
+ EXPECT_TRUE(exists("com.example/bar"));
+ EXPECT_TRUE(exists("com.example/bar/file"));
+
+ EXPECT_FALSE(exists("==deleted==/foo"));
+ EXPECT_FALSE(exists("==deleted==/foo/file"));
+ EXPECT_FALSE(exists("==deleted==/bar"));
+ EXPECT_FALSE(exists("==deleted==/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir());
+}
+
TEST_F(ServiceTest, HashSecondaryDex) {
LOG(INFO) << "HashSecondaryDex";
@@ -768,5 +936,120 @@
"com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
}
+class AppSupplementalDataTest : public testing::Test {
+public:
+ void CheckFileAccess(const std::string& path, uid_t uid, mode_t mode) {
+ const auto fullPath = "/data/local/tmp/" + path;
+ ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath;
+ struct stat st;
+ ASSERT_EQ(0, stat(fullPath.c_str(), &st));
+ ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath;
+ ASSERT_EQ(uid, st.st_gid) << "For path: " << fullPath;
+ ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath;
+ }
+
+ bool exists(const char* path) { return ::access(path, F_OK) == 0; }
+
+ // Creates a default CreateAppDataArgs object
+ android::os::CreateAppDataArgs createAppDataArgs() {
+ android::os::CreateAppDataArgs args;
+ args.uuid = kTestUuid;
+ args.packageName = "com.foo";
+ args.userId = kTestUserId;
+ args.appId = kTestAppId;
+ args.seInfo = "default";
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+ return args;
+ }
+
+protected:
+ InstalldNativeService* service;
+
+ virtual void SetUp() {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
+
+ service = new InstalldNativeService();
+ clearAppData();
+ ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
+ ASSERT_TRUE(mkdirs("/data/local/tmp/user_de/0", 0700));
+ ASSERT_TRUE(mkdirs("/data/local/tmp/misc_ce/0/supplemental", 0700));
+ ASSERT_TRUE(mkdirs("/data/local/tmp/misc_de/0/supplemental", 0700));
+
+ init_globals_from_data_and_root();
+ }
+
+ virtual void TearDown() {
+ delete service;
+ clearAppData();
+ }
+
+private:
+ void clearAppData() {
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_ce", true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_de", true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
+ }
+};
+
+TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs();
+ args.packageName = "com.foo";
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
+ CheckFileAccess("misc_ce/0/supplemental/com.foo/shared", kTestAppSupplementalUid,
+ S_IFDIR | 0700);
+ CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid,
+ S_IFDIR | S_ISGID | 0771);
+
+ CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
+ CheckFileAccess("misc_de/0/supplemental/com.foo/shared", kTestAppSupplementalUid,
+ S_IFDIR | 0700);
+ CheckFileAccess("misc_de/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess("misc_de/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid,
+ S_IFDIR | S_ISGID | 0771);
+}
+
+TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs();
+ args.packageName = "com.foo";
+ args.flags = FLAG_STORAGE_CE;
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ // Only CE paths should exist
+ CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
+
+ // DE paths should not exist
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/supplemental/com.foo"));
+}
+
+TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutCeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs();
+ args.packageName = "com.foo";
+ args.flags = FLAG_STORAGE_DE;
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ // CE paths should not exist
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/supplemental/com.foo"));
+
+ // Only DE paths should exist
+ CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index ed87b67..8d1ccdc 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
@@ -555,6 +557,24 @@
EXPECT_EQ(0, MatchExtension("docx"));
}
+TEST_F(UtilsTest, TestIsRenamedDeletedDir) {
+ EXPECT_FALSE(is_renamed_deleted_dir(""));
+ EXPECT_FALSE(is_renamed_deleted_dir("1"));
+ EXPECT_FALSE(is_renamed_deleted_dir("="));
+ EXPECT_FALSE(is_renamed_deleted_dir("=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("d=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("ed=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("ted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("eted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("leted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("eleted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("deleted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("=deleted=="));
+ EXPECT_TRUE(is_renamed_deleted_dir("==deleted=="));
+ EXPECT_TRUE(is_renamed_deleted_dir("123==deleted=="));
+ EXPECT_TRUE(is_renamed_deleted_dir("5b14b6458a44==deleted=="));
+}
+
TEST_F(UtilsTest, TestRollbackPaths) {
EXPECT_EQ("/data/misc_ce/0/rollback/239/com.foo",
create_data_misc_ce_rollback_package_path(nullptr, 0, 239, "com.foo"));
@@ -638,5 +658,79 @@
ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
}
+TEST_F(UtilsTest, TestSupplementalDataPaths) {
+ // Ce data paths
+ EXPECT_EQ("/data/misc_ce/0/supplemental",
+ create_data_misc_supplemental_path(nullptr, /*isCeData=*/true, 0));
+ EXPECT_EQ("/data/misc_ce/10/supplemental",
+ create_data_misc_supplemental_path(nullptr, true, 10));
+
+ EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo",
+ create_data_misc_supplemental_package_path(nullptr, true, 0, "com.foo"));
+ EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo",
+ create_data_misc_supplemental_package_path(nullptr, true, 10, "com.foo"));
+
+ EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo/shared",
+ create_data_misc_supplemental_shared_path(nullptr, true, 0, "com.foo"));
+ EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo/shared",
+ create_data_misc_supplemental_shared_path(nullptr, true, 10, "com.foo"));
+
+ // De data paths
+ EXPECT_EQ("/data/misc_de/0/supplemental",
+ create_data_misc_supplemental_path(nullptr, /*isCeData=*/false, 0));
+ EXPECT_EQ("/data/misc_de/10/supplemental",
+ create_data_misc_supplemental_path(nullptr, false, 10));
+
+ EXPECT_EQ("/data/misc_de/0/supplemental/com.foo",
+ create_data_misc_supplemental_package_path(nullptr, false, 0, "com.foo"));
+ EXPECT_EQ("/data/misc_de/10/supplemental/com.foo",
+ create_data_misc_supplemental_package_path(nullptr, false, 10, "com.foo"));
+
+ EXPECT_EQ("/data/misc_de/0/supplemental/com.foo/shared",
+ create_data_misc_supplemental_shared_path(nullptr, false, 0, "com.foo"));
+ EXPECT_EQ("/data/misc_de/10/supplemental/com.foo/shared",
+ create_data_misc_supplemental_shared_path(nullptr, false, 10, "com.foo"));
+}
+
+TEST_F(UtilsTest, WaitChild) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child */
+ // Do nothing.
+ _exit(0);
+ }
+ /* parent */
+ int return_code = wait_child_with_timeout(pid, /*timeout_ms=*/100);
+ EXPECT_TRUE(WIFEXITED(return_code));
+ EXPECT_EQ(WEXITSTATUS(return_code), 0);
+}
+
+TEST_F(UtilsTest, WaitChildTimeout) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child */
+ sleep(1);
+ _exit(0);
+ }
+ /* parent */
+ int return_code = wait_child_with_timeout(pid, /*timeout_ms=*/1);
+ EXPECT_FALSE(WIFEXITED(return_code));
+ EXPECT_EQ(WTERMSIG(return_code), SIGKILL);
+}
+
+TEST_F(UtilsTest, RemoveFileAtFd) {
+ std::string filename = "/data/local/tmp/tempfile-XXXXXX";
+ int fd = mkstemp(filename.data());
+ ASSERT_GE(fd, 0);
+ ASSERT_EQ(access(filename.c_str(), F_OK), 0);
+
+ std::string actual_filename;
+ remove_file_at_fd(fd, &actual_filename);
+ EXPECT_NE(access(filename.c_str(), F_OK), 0);
+ EXPECT_EQ(filename, actual_filename);
+
+ close(fd);
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 0f8a732..6650b76 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -19,17 +19,21 @@
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
+#include <poll.h>
#include <stdlib.h>
#include <sys/capability.h>
+#include <sys/pidfd.h>
#include <sys/stat.h>
+#include <sys/statvfs.h>
#include <sys/wait.h>
#include <sys/xattr.h>
-#include <sys/statvfs.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
@@ -47,6 +51,7 @@
#define DEBUG_XATTRS 0
+using android::base::Dirname;
using android::base::EndsWith;
using android::base::Fdopendir;
using android::base::StringPrintf;
@@ -55,6 +60,10 @@
namespace android {
namespace installd {
+using namespace std::literals;
+
+static constexpr auto deletedSuffix = "==deleted=="sv;
+
/**
* Check that given string is valid filename, and that it attempts no
* parent or child directory traversal.
@@ -188,6 +197,43 @@
return StringPrintf("%s/user_de/%u", data.c_str(), userid);
}
+/**
+ * Create the path name where supplemental data for all apps will be stored.
+ * E.g. /data/misc_ce/0/supplemental
+ */
+std::string create_data_misc_supplemental_path(const char* uuid, bool isCeData, userid_t user) {
+ std::string data(create_data_path(uuid));
+ if (isCeData) {
+ return StringPrintf("%s/misc_ce/%d/supplemental", data.c_str(), user);
+ } else {
+ return StringPrintf("%s/misc_de/%d/supplemental", data.c_str(), user);
+ }
+}
+
+/**
+ * Create the path name where code data for all codes in a particular app will be stored.
+ * E.g. /data/misc_ce/0/supplemental/<app-name>
+ */
+std::string create_data_misc_supplemental_package_path(const char* volume_uuid, bool isCeData,
+ userid_t user, const char* package_name) {
+ check_package_name(package_name);
+ return StringPrintf("%s/%s",
+ create_data_misc_supplemental_path(volume_uuid, isCeData, user).c_str(),
+ package_name);
+}
+
+/**
+ * Create the path name where shared code data for a particular app will be stored.
+ * E.g. /data/misc_ce/0/supplemental/<app-name>/shared
+ */
+std::string create_data_misc_supplemental_shared_path(const char* volume_uuid, bool isCeData,
+ userid_t user, const char* package_name) {
+ return StringPrintf("%s/shared",
+ create_data_misc_supplemental_package_path(volume_uuid, isCeData, user,
+ package_name)
+ .c_str());
+}
+
std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
}
@@ -595,6 +641,97 @@
return res;
}
+static std::string make_unique_name(std::string_view suffix) {
+ static constexpr auto uuidStringSize = 36;
+
+ uuid_t guid;
+ uuid_generate(guid);
+
+ std::string name;
+ const auto suffixSize = suffix.size();
+ name.reserve(uuidStringSize + suffixSize);
+
+ name.resize(uuidStringSize);
+ uuid_unparse(guid, name.data());
+ name.append(suffix);
+
+ return name;
+}
+
+static int rename_delete_dir_contents(const std::string& pathname,
+ int (*exclusion_predicate)(const char*, const int),
+ bool ignore_if_missing) {
+ auto temp_dir_name = make_unique_name(deletedSuffix);
+ auto temp_dir_path =
+ base::StringPrintf("%s/%s", Dirname(pathname).c_str(), temp_dir_name.c_str());
+
+ if (::rename(pathname.c_str(), temp_dir_path.c_str())) {
+ if (ignore_if_missing && (errno == ENOENT)) {
+ return 0;
+ }
+ ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), temp_dir_path.c_str(),
+ strerror(errno));
+ return -errno;
+ }
+
+ return delete_dir_contents(temp_dir_path.c_str(), 1, exclusion_predicate, ignore_if_missing);
+}
+
+bool is_renamed_deleted_dir(const std::string& path) {
+ if (path.size() < deletedSuffix.size()) {
+ return false;
+ }
+ std::string_view pathSuffix{path.c_str() + path.size() - deletedSuffix.size()};
+ return pathSuffix == deletedSuffix;
+}
+
+int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) {
+ return rename_delete_dir_contents(pathname, nullptr, ignore_if_missing);
+}
+
+static auto open_dir(const char* dir) {
+ struct DirCloser {
+ void operator()(DIR* d) const noexcept { ::closedir(d); }
+ };
+ return std::unique_ptr<DIR, DirCloser>(::opendir(dir));
+}
+
+void cleanup_invalid_package_dirs_under_path(const std::string& pathname) {
+ auto dir = open_dir(pathname.c_str());
+ if (!dir) {
+ return;
+ }
+ int dfd = dirfd(dir.get());
+ if (dfd < 0) {
+ ALOGE("Couldn't dirfd %s: %s\n", pathname.c_str(), strerror(errno));
+ return;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir.get()))) {
+ if (de->d_type != DT_DIR) {
+ continue;
+ }
+
+ std::string name{de->d_name};
+ // always skip "." and ".."
+ if (name == "." || name == "..") {
+ continue;
+ }
+
+ if (is_renamed_deleted_dir(name) || !is_valid_filename(name) ||
+ !is_valid_package_name(name)) {
+ ALOGI("Deleting renamed or invalid data directory: %s\n", name.c_str());
+ // Deleting the content.
+ delete_dir_contents_fd(dfd, name.c_str());
+ // Deleting the directory
+ if (unlinkat(dfd, name.c_str(), AT_REMOVEDIR) < 0) {
+ ALOGE("Couldn't unlinkat %s: %s\n", name.c_str(), strerror(errno));
+ }
+ }
+ }
+}
+
int delete_dir_contents_fd(int dfd, const char *name)
{
int fd, res;
@@ -962,30 +1099,45 @@
return fs_prepare_dir(path.c_str(), 0750, uid, gid);
}
-int wait_child(pid_t pid)
-{
+static int wait_child(pid_t pid) {
int status;
- pid_t got_pid;
+ pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, /*options=*/0));
- while (1) {
- got_pid = waitpid(pid, &status, 0);
- if (got_pid == -1 && errno == EINTR) {
- printf("waitpid interrupted, retrying\n");
- } else {
- break;
- }
- }
if (got_pid != pid) {
- ALOGW("waitpid failed: wanted %d, got %d: %s\n",
- (int) pid, (int) got_pid, strerror(errno));
- return 1;
+ PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid;
+ return W_EXITCODE(/*exit_code=*/255, /*signal_number=*/0);
}
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
- return 0;
- } else {
- return status; /* always nonzero */
+ return status;
+}
+
+int wait_child_with_timeout(pid_t pid, int timeout_ms) {
+ int pidfd = pidfd_open(pid, /*flags=*/0);
+ if (pidfd < 0) {
+ PLOG(ERROR) << "pidfd_open failed for pid " << pid;
+ kill(pid, SIGKILL);
+ return wait_child(pid);
}
+
+ struct pollfd pfd;
+ pfd.fd = pidfd;
+ pfd.events = POLLIN;
+ int poll_ret = TEMP_FAILURE_RETRY(poll(&pfd, /*nfds=*/1, timeout_ms));
+
+ close(pidfd);
+
+ if (poll_ret < 0) {
+ PLOG(ERROR) << "poll failed for pid " << pid;
+ kill(pid, SIGKILL);
+ return wait_child(pid);
+ }
+ if (poll_ret == 0) {
+ LOG(WARNING) << "Child process " << pid << " timed out after " << timeout_ms
+ << "ms. Killing it";
+ kill(pid, SIGKILL);
+ return wait_child(pid);
+ }
+ return wait_child(pid);
}
/**
@@ -1198,5 +1350,27 @@
}
}
+bool remove_file_at_fd(int fd, /*out*/ std::string* path) {
+ char path_buffer[PATH_MAX + 1];
+ std::string proc_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
+ ssize_t len = readlink(proc_path.c_str(), path_buffer, PATH_MAX);
+ if (len < 0) {
+ PLOG(WARNING) << "Could not remove file at fd " << fd << ": Failed to get file path";
+ return false;
+ }
+ path_buffer[len] = '\0';
+ if (path != nullptr) {
+ *path = path_buffer;
+ }
+ if (unlink(path_buffer) != 0) {
+ if (errno == ENOENT) {
+ return true;
+ }
+ PLOG(WARNING) << "Could not remove file at path " << path_buffer;
+ return false;
+ }
+ return true;
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 549fc6c..2d00845 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -60,6 +60,13 @@
std::string create_data_user_ce_package_path_as_user_link(
const char* volume_uuid, userid_t userid, const char* package_name);
+std::string create_data_misc_supplemental_path(const char* volume_uuid, bool isCeData,
+ userid_t userid);
+std::string create_data_misc_supplemental_package_path(const char* volume_uuid, bool isCeData,
+ userid_t userid, const char* package_name);
+std::string create_data_misc_supplemental_shared_path(const char* volume_uuid, bool isCeData,
+ userid_t userid, const char* package_name);
+
std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
@@ -120,6 +127,11 @@
int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
+bool is_renamed_deleted_dir(const std::string& path);
+int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = true);
+
+void cleanup_invalid_package_dirs_under_path(const std::string& pathname);
+
int delete_dir_contents(const char *pathname,
int also_delete_dir,
int (*exclusion_predicate)(const char *name, const int is_dir),
@@ -148,7 +160,8 @@
int ensure_config_user_dirs(userid_t userid);
-int wait_child(pid_t pid);
+// Waits for a child process, or kills it if it times out. Returns the exit code.
+int wait_child_with_timeout(pid_t pid, int timeout_ms);
int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
uid_t uid, gid_t gid);
@@ -165,6 +178,10 @@
void drop_capabilities(uid_t uid);
+// Removes a file specified by a file descriptor. Returns true on success. Reports the file path to
+// `path` if present.
+bool remove_file_at_fd(int fd, /*out*/ std::string* path = nullptr);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp
index 60d6492..8c000a1 100644
--- a/cmds/installd/view_compiler.cpp
+++ b/cmds/installd/view_compiler.cpp
@@ -33,7 +33,13 @@
namespace android {
namespace installd {
-using base::unique_fd;
+namespace {
+
+using ::android::base::unique_fd;
+
+constexpr int kTimeoutMs = 300000;
+
+} // namespace
bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
int uid) {
@@ -88,7 +94,17 @@
_exit(1);
}
- return wait_child(pid) == 0;
+ int return_code = wait_child_with_timeout(pid, kTimeoutMs);
+ if (!WIFEXITED(return_code)) {
+ LOG(WARNING) << "viewcompiler failed for " << package_name << ":" << apk_path;
+ if (WTERMSIG(return_code) == SIGKILL) {
+ // If the subprocess is killed while it's writing to the file, the file is likely
+ // corrupted, so we should remove it.
+ remove_file_at_fd(outfd.get());
+ }
+ return false;
+ }
+ return WEXITSTATUS(return_code) == 0;
}
} // namespace installd
diff --git a/data/etc/android.hardware.telephony.euicc.mep.xml b/data/etc/android.hardware.telephony.euicc.mep.xml
new file mode 100644
index 0000000..f958e4b
--- /dev/null
+++ b/data/etc/android.hardware.telephony.euicc.mep.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Feature for devices with an eUICC supporting MEP(Multiple enabled profiles) -->
+<permissions>
+ <feature name="android.hardware.telephony.euicc" />
+ <feature name="android.hardware.telephony.euicc.mep" />
+</permissions>
\ No newline at end of file
diff --git a/data/etc/android.software.window_magnification.xml b/data/etc/android.software.window_magnification.xml
new file mode 100644
index 0000000..10a2de1
--- /dev/null
+++ b/data/etc/android.software.window_magnification.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the feature indicating device supports window magnifier.
+ And the hand-held and PC platform should support this.
+-->
+<permissions>
+ <feature name="android.software.window_magnification" />
+</permissions>
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index d601931..8df7fdb 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -46,6 +46,7 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
+ <feature name="android.software.window_magnification" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 68b8def..8fdd8d0 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -54,6 +54,7 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
+ <feature name="android.software.window_magnification" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/pc_core_hardware.xml b/data/etc/pc_core_hardware.xml
index b490ba0..3155710 100644
--- a/data/etc/pc_core_hardware.xml
+++ b/data/etc/pc_core_hardware.xml
@@ -49,6 +49,7 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
+ <feature name="android.software.window_magnification" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
@@ -62,4 +63,4 @@
<!-- Feature to specify if the device supports freeform. -->
<feature name="android.software.freeform_window_management" />
<feature name="android.hardware.type.pc" />
-</permissions>
\ No newline at end of file
+</permissions>
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 8c369de..59d5b10 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -54,6 +54,7 @@
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
+ <feature name="android.software.window_magnification" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 98f0eec..63aa7ff 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -76,7 +76,7 @@
* 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.
*/
-typedef void (*AChoreographer_extendedFrameCallback)(
+typedef void (*AChoreographer_vsyncCallback)(
const AChoreographerFrameCallbackData* callbackData, void* data);
/**
@@ -134,8 +134,8 @@
* Posts a callback to run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
*/
-void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer,
- AChoreographer_extendedFrameCallback callback, void* data)
+void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
+ AChoreographer_vsyncCallback callback, void* data)
__INTRODUCED_IN(33);
/**
@@ -215,7 +215,7 @@
/**
* The time in nanoseconds which the frame at given index is expected to be presented.
*/
-int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
/**
diff --git a/include/android/input.h b/include/android/input.h
index e6ad943f..fb5e204 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -808,6 +808,33 @@
};
/**
+ * Constants that identify different gesture classification types.
+ */
+enum {
+ /**
+ * Classification constant: None.
+ *
+ * No additional information is available about the current motion event stream.
+ */
+ AMOTION_EVENT_CLASSIFICATION_NONE = 0,
+ /**
+ * Classification constant: Ambiguous gesture.
+ *
+ * The user's intent with respect to the current event stream is not yet determined.
+ * Gestural actions, such as scrolling, should be inhibited until the classification resolves
+ * to another value or the event stream ends.
+ */
+ AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE = 1,
+ /**
+ * Classification constant: Deep press.
+ *
+ * The current event stream represents the user intentionally pressing harder on the screen.
+ * This classification type should be used to accelerate the long press behaviour.
+ */
+ AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS = 2,
+};
+
+/**
* Input source masks.
*
* Refer to the documentation on android.view.InputDevice for more details about input sources
@@ -1327,6 +1354,23 @@
int32_t axis, size_t pointer_index, size_t history_index);
/**
+ * Get the action button for the motion event. Returns a valid action button when the
+ * event is associated with a button press or button release action. For other actions
+ * the return value is undefined.
+ */
+int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event);
+
+/**
+ * Returns the classification for the current gesture.
+ * The classification may change as more events become available for the same gesture.
+ *
+ * @see #AMOTION_EVENT_CLASSIFICATION_NONE
+ * @see #AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE
+ * @see #AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS
+*/
+int32_t AMotionEvent_getClassification(const AInputEvent* motion_event);
+
+/**
* Creates a native AInputEvent* object that is a copy of the specified Java
* android.view.MotionEvent. The result may be used with generic and MotionEvent-specific
* AInputEvent_* functions. The object returned by this function must be disposed using
diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h
index 932af2d..708eaf5 100644
--- a/include/ftl/Flags.h
+++ b/include/ftl/Flags.h
@@ -120,10 +120,10 @@
}
/* Tests whether any of the given flags are set */
- bool any(Flags<F> f) { return (mFlags & f.mFlags) != 0; }
+ bool any(Flags<F> f) const { return (mFlags & f.mFlags) != 0; }
/* Tests whether all of the given flags are set */
- bool all(Flags<F> f) { return (mFlags & f.mFlags) == f.mFlags; }
+ bool all(Flags<F> f) const { return (mFlags & f.mFlags) == f.mFlags; }
Flags<F> operator|(Flags<F> rhs) const { return static_cast<F>(mFlags | rhs.mFlags); }
Flags<F>& operator|=(Flags<F> rhs) {
@@ -153,6 +153,10 @@
return *this;
}
+ inline Flags<F>& clear(Flags<F> f = static_cast<F>(~static_cast<U>(0))) {
+ return *this &= ~f;
+ }
+
Iterator begin() const { return Iterator(*this); }
Iterator end() const { return Iterator(); }
diff --git a/include/ftl/details/array_traits.h b/include/ftl/details/array_traits.h
index 16e63ec..5234c38 100644
--- a/include/ftl/details/array_traits.h
+++ b/include/ftl/details/array_traits.h
@@ -42,7 +42,7 @@
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
template <typename... Args>
- static pointer construct_at(const_iterator it, Args&&... args) {
+ static constexpr pointer construct_at(const_iterator it, Args&&... args) {
void* const ptr = const_cast<void*>(static_cast<const void*>(it));
if constexpr (std::is_constructible_v<value_type, Args...>) {
// TODO: Replace with std::construct_at in C++20.
@@ -52,6 +52,42 @@
return new (ptr) value_type{std::forward<Args>(args)...};
}
}
+
+ // TODO: Make constexpr in C++20.
+ template <typename... Args>
+ static reference replace_at(const_iterator it, Args&&... args) {
+ value_type element{std::forward<Args>(args)...};
+ return replace_at(it, std::move(element));
+ }
+
+ // TODO: Make constexpr in C++20.
+ static reference replace_at(const_iterator it, value_type&& value) {
+ std::destroy_at(it);
+ // This is only safe because exceptions are disabled.
+ return *construct_at(it, std::move(value));
+ }
+
+ // TODO: Make constexpr in C++20.
+ static void in_place_swap(reference a, reference b) {
+ value_type c{std::move(a)};
+ replace_at(&a, std::move(b));
+ replace_at(&b, std::move(c));
+ }
+
+ // TODO: Make constexpr in C++20.
+ static void in_place_swap_ranges(iterator first1, iterator last1, iterator first2) {
+ while (first1 != last1) {
+ in_place_swap(*first1++, *first2++);
+ }
+ }
+
+ // TODO: Replace with std::uninitialized_copy in C++20.
+ template <typename Iterator>
+ static void uninitialized_copy(Iterator first, Iterator last, const_iterator out) {
+ while (first != last) {
+ construct_at(out++, *first++);
+ }
+ }
};
// CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end.
@@ -101,33 +137,33 @@
// TODO: Replace with operator<=> in C++20.
template <template <typename, std::size_t> class Array>
struct ArrayComparators {
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator==(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator==(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator<(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator<(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator>(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator>(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return rhs < lhs;
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator!=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator!=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return !(lhs == rhs);
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator>=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator>=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return !(lhs < rhs);
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator<=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator<=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return !(lhs > rhs);
}
};
diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h
index 2effaa4..5217e76 100644
--- a/include/ftl/small_map.h
+++ b/include/ftl/small_map.h
@@ -65,6 +65,9 @@
class SmallMap final {
using Map = SmallVector<std::pair<const K, V>, N>;
+ template <typename, typename, std::size_t, typename>
+ friend class SmallMap;
+
public:
using key_type = K;
using mapped_type = V;
@@ -100,6 +103,10 @@
deduplicate();
}
+ // Copies or moves key-value pairs from a convertible map.
+ template <typename Q, typename W, std::size_t M, typename E>
+ SmallMap(SmallMap<Q, W, M, E> other) : map_(std::move(other.map_)) {}
+
size_type max_size() const { return map_.max_size(); }
size_type size() const { return map_.size(); }
bool empty() const { return map_.empty(); }
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
index 03587e3..339726e 100644
--- a/include/ftl/small_vector.h
+++ b/include/ftl/small_vector.h
@@ -37,6 +37,9 @@
// augmented by an unstable_erase operation that does not preserve order, and a replace operation
// that destructively emplaces.
//
+// Unlike std::vector, T does not require copy/move assignment, so may be an object with const data
+// members, or be const itself.
+//
// SmallVector<T, 0> is a specialization that thinly wraps std::vector.
//
// Example usage:
@@ -105,10 +108,9 @@
SmallVector(Arg&& arg, Args&&... args)
: vector_(std::in_place_type<Static>, std::forward<Arg>(arg), std::forward<Args>(args)...) {}
- // Copies at most N elements from a smaller convertible vector.
- template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>>
- SmallVector(const SmallVector<U, M>& other)
- : SmallVector(kIteratorRange, other.begin(), other.end()) {}
+ // Copies or moves elements from a smaller convertible vector.
+ template <typename U, std::size_t M, typename = std::enable_if_t<(M > 0)>>
+ SmallVector(SmallVector<U, M> other) : vector_(convert(std::move(other))) {}
void swap(SmallVector& other) { vector_.swap(other.vector_); }
@@ -235,7 +237,30 @@
}
}
+ // Extracts the elements as std::vector.
+ std::vector<T> promote() && {
+ if (dynamic()) {
+ return std::get<Dynamic>(std::move(vector_)).promote();
+ } else {
+ return {std::make_move_iterator(begin()), std::make_move_iterator(end())};
+ }
+ }
+
private:
+ template <typename, std::size_t>
+ friend class SmallVector;
+
+ template <typename U, std::size_t M>
+ static std::variant<Static, Dynamic> convert(SmallVector<U, M>&& other) {
+ using Other = SmallVector<U, M>;
+
+ if (other.dynamic()) {
+ return std::get<typename Other::Dynamic>(std::move(other.vector_));
+ } else {
+ return std::get<typename Other::Static>(std::move(other.vector_));
+ }
+ }
+
template <auto InsertStatic, auto InsertDynamic, typename... Args>
auto insert(Args&&... args) {
if (Dynamic* const vector = std::get_if<Dynamic>(&vector_)) {
@@ -267,9 +292,10 @@
// Partial specialization without static storage.
template <typename T>
class SmallVector<T, 0> final : details::ArrayTraits<T>,
+ details::ArrayComparators<SmallVector>,
details::ArrayIterators<SmallVector<T, 0>, T>,
std::vector<T> {
- using details::ArrayTraits<T>::construct_at;
+ using details::ArrayTraits<T>::replace_at;
using Iter = details::ArrayIterators<SmallVector, T>;
using Impl = std::vector<T>;
@@ -291,8 +317,30 @@
FTL_ARRAY_TRAIT(T, const_iterator);
FTL_ARRAY_TRAIT(T, const_reverse_iterator);
+ // See std::vector for underlying constructors.
using Impl::Impl;
+ // Copies and moves a vector, respectively.
+ SmallVector(const SmallVector&) = default;
+ SmallVector(SmallVector&&) = default;
+
+ // Constructs elements in place. See StaticVector for underlying constructor.
+ template <typename U, std::size_t... Sizes, typename... Types>
+ SmallVector(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list)
+ : SmallVector(SmallVector<T, sizeof...(Sizes)>(std::move(list))) {}
+
+ // Copies or moves elements from a convertible vector.
+ template <typename U, std::size_t M>
+ SmallVector(SmallVector<U, M> other) : Impl(convert(std::move(other))) {}
+
+ SmallVector& operator=(SmallVector other) {
+ // Define copy/move assignment in terms of copy/move construction.
+ swap(other);
+ return *this;
+ }
+
+ void swap(SmallVector& other) { Impl::swap(other); }
+
using Impl::empty;
using Impl::max_size;
using Impl::size;
@@ -324,10 +372,7 @@
template <typename... Args>
reference replace(const_iterator it, Args&&... args) {
- value_type element{std::forward<Args>(args)...};
- std::destroy_at(it);
- // This is only safe because exceptions are disabled.
- return *construct_at(it, std::move(element));
+ return replace_at(it, std::forward<Args>(args)...);
}
template <typename... Args>
@@ -353,7 +398,26 @@
pop_back();
}
- void swap(SmallVector& other) { Impl::swap(other); }
+ std::vector<T> promote() && { return std::move(*this); }
+
+ private:
+ template <typename U, std::size_t M>
+ static Impl convert(SmallVector<U, M>&& other) {
+ if constexpr (std::is_constructible_v<Impl, std::vector<U>&&>) {
+ return std::move(other).promote();
+ } else {
+ SmallVector vector(other.size());
+
+ // Consistently with StaticVector, T only requires copy/move construction from U, rather than
+ // copy/move assignment.
+ auto it = vector.begin();
+ for (auto& element : other) {
+ vector.replace(it++, std::move(element));
+ }
+
+ return vector;
+ }
+ }
};
template <typename>
diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h
index b7f8c29..eb83b85 100644
--- a/include/ftl/static_vector.h
+++ b/include/ftl/static_vector.h
@@ -39,6 +39,9 @@
// adheres to standard containers, except the unstable_erase operation that does not preserve order,
// and the replace operation that destructively emplaces.
//
+// Unlike std::vector, T does not require copy/move assignment, so may be an object with const data
+// members, or be const itself.
+//
// StaticVector<T, 1> is analogous to an iterable std::optional.
// StaticVector<T, 0> is an error.
//
@@ -78,7 +81,14 @@
details::ArrayComparators<StaticVector> {
static_assert(N > 0);
+ // For constructor that moves from a smaller convertible vector.
+ template <typename, std::size_t>
+ friend class StaticVector;
+
using details::ArrayTraits<T>::construct_at;
+ using details::ArrayTraits<T>::replace_at;
+ using details::ArrayTraits<T>::in_place_swap_ranges;
+ using details::ArrayTraits<T>::uninitialized_copy;
using Iter = details::ArrayIterators<StaticVector, T>;
friend Iter;
@@ -117,14 +127,18 @@
StaticVector(StaticVector&& other) { swap<true>(other); }
// Copies at most N elements from a smaller convertible vector.
- template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>>
+ template <typename U, std::size_t M>
StaticVector(const StaticVector<U, M>& other)
- : StaticVector(kIteratorRange, other.begin(), other.end()) {}
+ : StaticVector(kIteratorRange, other.begin(), other.end()) {
+ static_assert(N >= M, "Insufficient capacity");
+ }
- // Copies at most N elements from an array.
+ // Copies at most N elements from a smaller convertible array.
template <typename U, std::size_t M>
explicit StaticVector(U (&array)[M])
- : StaticVector(kIteratorRange, std::begin(array), std::end(array)) {}
+ : StaticVector(kIteratorRange, std::begin(array), std::end(array)) {
+ static_assert(N >= M, "Insufficient capacity");
+ }
// Copies at most N elements from the range [first, last).
//
@@ -139,7 +153,18 @@
template <typename Iterator>
StaticVector(IteratorRangeTag, Iterator first, Iterator last)
: size_(std::min(max_size(), static_cast<size_type>(std::distance(first, last)))) {
- std::uninitialized_copy(first, first + size_, begin());
+ uninitialized_copy(first, first + size_, begin());
+ }
+
+ // Moves at most N elements from a smaller convertible vector.
+ template <typename U, std::size_t M>
+ StaticVector(StaticVector<U, M>&& other) {
+ static_assert(N >= M, "Insufficient capacity");
+
+ // Same logic as swap<true>, though M need not be equal to N.
+ std::uninitialized_move(other.begin(), other.end(), begin());
+ std::destroy(other.begin(), other.end());
+ std::swap(size_, other.size_);
}
// Constructs at most N elements. The template arguments T and N are inferred using the
@@ -178,7 +203,9 @@
template <typename U, std::size_t Size, std::size_t... Sizes, typename... Types>
StaticVector(InitializerList<U, std::index_sequence<Size, Sizes...>, Types...>&& list)
: StaticVector(std::index_sequence<0, 0, Size>{}, std::make_index_sequence<Size>{},
- std::index_sequence<Sizes...>{}, list.tuple) {}
+ std::index_sequence<Sizes...>{}, list.tuple) {
+ static_assert(sizeof...(Sizes) < N, "Too many elements");
+ }
~StaticVector() { std::destroy(begin(), end()); }
@@ -238,10 +265,7 @@
//
template <typename... Args>
reference replace(const_iterator it, Args&&... args) {
- value_type element{std::forward<Args>(args)...};
- std::destroy_at(it);
- // This is only safe because exceptions are disabled.
- return *construct_at(it, std::move(element));
+ return replace_at(it, std::forward<Args>(args)...);
}
// Appends an element, and returns an iterator to it. If the vector is full, the element is not
@@ -380,7 +404,7 @@
}
// Swap elements [0, min).
- std::swap_ranges(begin(), begin() + min, other.begin());
+ in_place_swap_ranges(begin(), begin() + min, other.begin());
// No elements to move if sizes are equal.
if (min == max) return;
diff --git a/include/input/Input.h b/include/input/Input.h
index e421dee..b23a951 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -275,23 +275,21 @@
/**
* Classifications of the current gesture, if available.
- *
- * The following values must be kept in sync with MotionEvent.java
*/
enum class MotionClassification : uint8_t {
/**
* No classification is available.
*/
- NONE = 0,
+ NONE = AMOTION_EVENT_CLASSIFICATION_NONE,
/**
* Too early to classify the current gesture. Need more events. Look for changes in the
* upcoming motion events.
*/
- AMBIGUOUS_GESTURE = 1,
+ AMBIGUOUS_GESTURE = AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE,
/**
* The current gesture likely represents a user intentionally exerting force on the touchscreen.
*/
- DEEP_PRESS = 2,
+ DEEP_PRESS = AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS,
};
/**
@@ -816,6 +814,8 @@
static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy);
static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&,
const PointerCoords&);
+ static PointerCoords calculateTransformedCoords(uint32_t source, const ui::Transform&,
+ const PointerCoords&);
protected:
int32_t mAction;
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index 406fee0..1504715 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -27,13 +27,6 @@
#include "ParcelValTypes.h"
-using android::BAD_TYPE;
-using android::BAD_VALUE;
-using android::NO_ERROR;
-using android::Parcel;
-using android::status_t;
-using android::UNEXPECTED_NULL;
-
using android::binder::VAL_BOOLEAN;
using android::binder::VAL_INTEGER;
using android::binder::VAL_LONG;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 1821729..baa817c 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -19,6 +19,7 @@
#include <binder/ProcessState.h>
#include <android-base/result.h>
+#include <android-base/strings.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -367,8 +368,13 @@
String8 ProcessState::makeBinderThreadName() {
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
pid_t pid = getpid();
+
+ std::string_view driverName = mDriverName.c_str();
+ android::base::ConsumePrefix(&driverName, "/dev/");
+
String8 name;
- name.appendFormat("%d_%X:%s", pid, s, mDriverName.c_str());
+ name.appendFormat("%.*s:%d_%X", static_cast<int>(driverName.length()), driverName.data(), pid,
+ s);
return name;
}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 1d7de98..dbfb1c2 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -114,8 +114,8 @@
};
pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
pub use proxy::{
- get_interface, get_service, wait_for_interface, wait_for_service, DeathRecipient, SpIBinder,
- WpIBinder,
+ get_declared_instances, get_interface, get_service, is_declared, wait_for_interface,
+ wait_for_service, DeathRecipient, SpIBinder, WpIBinder,
};
pub use state::{ProcessState, ThreadState};
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 12bfde7..e3e4730 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -28,9 +28,10 @@
use std::cmp::Ordering;
use std::convert::TryInto;
-use std::ffi::{c_void, CString};
+use std::ffi::{c_void, CStr, CString};
use std::fmt;
use std::mem;
+use std::os::raw::c_char;
use std::os::unix::io::AsRawFd;
use std::ptr;
use std::sync::Arc;
@@ -778,6 +779,61 @@
}
}
+/// Check if a service is declared (e.g. in a VINTF manifest)
+pub fn is_declared(interface: &str) -> Result<bool> {
+ let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
+
+ unsafe {
+ // Safety: `interface` is a valid null-terminated C-style string and is
+ // only borrowed for the lifetime of the call. The `interface` local
+ // outlives this call as it lives for the function scope.
+ Ok(sys::AServiceManager_isDeclared(interface.as_ptr()))
+ }
+}
+
+/// Retrieve all declared instances for a particular interface
+///
+/// For instance, if 'android.foo.IFoo/foo' is declared, and 'android.foo.IFoo'
+/// is passed here, then ["foo"] would be returned.
+pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> {
+ unsafe extern "C" fn callback(instance: *const c_char, opaque: *mut c_void) {
+ // Safety: opaque was a mutable pointer created below from a Vec of
+ // CString, and outlives this callback. The null handling here is just
+ // to avoid the possibility of unwinding across C code if this crate is
+ // ever compiled with panic=unwind.
+ if let Some(instances) = opaque.cast::<Vec<CString>>().as_mut() {
+ // Safety: instance is a valid null-terminated C string with a
+ // lifetime at least as long as this function, and we immediately
+ // copy it into an owned CString.
+ instances.push(CStr::from_ptr(instance).to_owned());
+ } else {
+ eprintln!("Opaque pointer was null in get_declared_instances callback!");
+ }
+ }
+
+ let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
+ let mut instances: Vec<CString> = vec![];
+ unsafe {
+ // Safety: `interface` and `instances` are borrowed for the length of
+ // this call and both outlive the call. `interface` is guaranteed to be
+ // a valid null-terminated C-style string.
+ sys::AServiceManager_forEachDeclaredInstance(
+ interface.as_ptr(),
+ &mut instances as *mut _ as *mut c_void,
+ Some(callback),
+ );
+ }
+
+ instances
+ .into_iter()
+ .map(CString::into_string)
+ .collect::<std::result::Result<Vec<String>, _>>()
+ .map_err(|e| {
+ eprintln!("An interface instance name was not a valid UTF-8 string: {}", e);
+ StatusCode::BAD_VALUE
+ })
+}
+
/// # Safety
///
/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 50daf1c..7c5afde 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -484,6 +484,21 @@
}
#[test]
+ fn get_declared_instances() {
+ // At the time of writing this test, there is no good VINTF interface
+ // guaranteed to be on all devices. Cuttlefish has light, so this will
+ // generally test things.
+ let has_lights = binder::is_declared("android.hardware.light.ILights/default")
+ .expect("Could not check for declared interface");
+
+ 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 };
+ assert_eq!(expected_defaults, instances.iter().filter(|i| i.as_str() == "default").count());
+ }
+
+ #[test]
fn trivial_client() {
let service_name = "trivial_client_test";
let _process = ScopedServiceProcess::new(service_name);
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 1446802..38bde3a 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -26,13 +26,9 @@
static_libs: [
"libbase",
"libbinder_random_parcel",
- "libcgrouprc",
- "libcgrouprc_format",
"libcutils",
"libhidlbase",
"liblog",
- "libprocessgroup",
- "libjsoncpp",
"libutils",
],
diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp
index ee650e5..1740a2b 100644
--- a/libs/ftl/small_map_test.cpp
+++ b/libs/ftl/small_map_test.cpp
@@ -96,6 +96,33 @@
}
}
+TEST(SmallMap, Assign) {
+ {
+ // Same types; smaller capacity.
+ SmallMap map1 = ftl::init::map<char, std::string>('k', "kilo")('M', "mega")('G', "giga");
+ const SmallMap map2 = ftl::init::map('T', "tera"s)('P', "peta"s);
+
+ map1 = map2;
+ EXPECT_EQ(map1, map2);
+ }
+ {
+ // Convertible types; same capacity.
+ SmallMap map1 = ftl::init::map<char, std::string>('M', "mega")('G', "giga");
+ const SmallMap map2 = ftl::init::map('T', "tera")('P', "peta");
+
+ map1 = map2;
+ EXPECT_EQ(map1, map2);
+ }
+ {
+ // Convertible types; zero capacity.
+ SmallMap<char, std::string, 0> map1 = ftl::init::map('M', "mega")('G', "giga");
+ const SmallMap<char, std::string, 0> map2 = ftl::init::map('T', "tera")('P', "peta");
+
+ map1 = map2;
+ EXPECT_EQ(map1, map2);
+ }
+}
+
TEST(SmallMap, UniqueKeys) {
{
// Duplicate mappings are discarded.
diff --git a/libs/ftl/small_vector_test.cpp b/libs/ftl/small_vector_test.cpp
index 4237496..b662a81 100644
--- a/libs/ftl/small_vector_test.cpp
+++ b/libs/ftl/small_vector_test.cpp
@@ -138,6 +138,116 @@
}
}
+TEST(SmallVector, Copy) {
+ {
+ // Same capacity.
+ const SmallVector vector = {"snow"s, "cone"s};
+
+ SmallVector<const std::string, 2> copy(vector);
+ EXPECT_EQ(copy, vector);
+
+ // The vector is assignable even if T is const.
+ const SmallVector<std::string, 2> other = {"tiramisu"s};
+ copy = other;
+ EXPECT_EQ(copy, other);
+ }
+ {
+ // From smaller capacity.
+ const SmallVector vector = {"snow"s, "cone"s};
+
+ SmallVector<const std::string, 3> copy(vector);
+ EXPECT_EQ(copy, vector);
+
+ // The vector is assignable even if T is const.
+ const SmallVector other = {"tiramisu"s};
+ copy = other;
+ EXPECT_EQ(copy, other);
+ }
+ {
+ // To zero capacity.
+ const SmallVector vector = {"snow"s, "cone"s};
+
+ SmallVector<const std::string, 0> copy(vector);
+ EXPECT_EQ(copy, vector);
+
+ // The vector is assignable even if T is const.
+ const SmallVector other = {"tiramisu"s};
+ copy = other;
+ EXPECT_EQ(copy, other);
+ }
+ {
+ // From/to zero capacity.
+ const SmallVector<std::string, 0> vector = {"snow"s, "cone"s};
+
+ SmallVector<const std::string, 0> copy(vector);
+ EXPECT_EQ(copy, vector);
+
+ // The vector is assignable even if T is const.
+ const SmallVector<std::string, 0> other = {"tiramisu"s};
+ copy = other;
+ EXPECT_EQ(copy, other);
+ }
+}
+
+TEST(SmallVector, Move) {
+ {
+ // Same capacity.
+ SmallVector vector = {"snow"s, "cone"s};
+
+ SmallVector<const std::string, 2> move(std::move(vector));
+ EXPECT_TRUE(vector.empty());
+ EXPECT_EQ(move, (SmallVector{"snow"s, "cone"s}));
+
+ // The vector is assignable even if T is const.
+ SmallVector<std::string, 2> other = {"tiramisu"s};
+ move = std::move(other);
+ EXPECT_TRUE(other.empty());
+ EXPECT_EQ(move, (SmallVector{"tiramisu"s}));
+ }
+ {
+ // From smaller capacity.
+ SmallVector vector = {"snow"s, "cone"s};
+
+ SmallVector<const std::string, 3> move(std::move(vector));
+ EXPECT_TRUE(vector.empty());
+ EXPECT_EQ(move, (SmallVector{"snow"s, "cone"s}));
+
+ // The vector is assignable even if T is const.
+ SmallVector other = {"tiramisu"s};
+ move = std::move(other);
+ EXPECT_TRUE(other.empty());
+ EXPECT_EQ(move, (SmallVector{"tiramisu"s}));
+ }
+ {
+ // To zero capacity.
+ SmallVector vector = {"snow"s, "cone"s};
+
+ SmallVector<const std::string, 0> move(std::move(vector));
+ EXPECT_TRUE(vector.empty());
+ EXPECT_EQ(move, (SmallVector{"snow"s, "cone"s}));
+
+ // The vector is assignable even if T is const.
+ SmallVector other = {"tiramisu"s};
+ move = std::move(other);
+ EXPECT_TRUE(other.empty());
+ EXPECT_EQ(move, (SmallVector{"tiramisu"s}));
+ }
+ {
+ // From/to zero capacity.
+ SmallVector<std::string, 0> vector = {"snow"s, "cone"s};
+
+ SmallVector<const std::string, 0> move(std::move(vector));
+ EXPECT_TRUE(vector.empty());
+ EXPECT_EQ(move, (SmallVector{"snow"s, "cone"s}));
+
+ // The vector is assignable even if T is const.
+ SmallVector<std::string, 0> other = {"tiramisu"s};
+ move = std::move(other);
+ EXPECT_TRUE(other.empty());
+ EXPECT_EQ(move, (SmallVector{"tiramisu"s}));
+ }
+}
+
TEST(SmallVector, String) {
SmallVector<char, 10> chars;
char c = 'a';
@@ -366,21 +476,20 @@
bool alive = true;
};
-void swap(DestroyCounts& lhs, DestroyCounts& rhs) {
- std::swap(lhs.alive, rhs.alive);
-}
-
} // namespace
TEST(SmallVector, Destroy) {
int live = 0;
int dead = 0;
-
- { SmallVector<DestroyCounts, 3> counts; }
+ {
+ // Empty.
+ SmallVector<DestroyCounts, 3> counts;
+ }
EXPECT_EQ(0, live);
EXPECT_EQ(0, dead);
{
+ // Static.
SmallVector<DestroyCounts, 3> counts;
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
@@ -393,6 +502,7 @@
live = 0;
{
+ // Dynamic.
SmallVector<DestroyCounts, 3> counts;
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
@@ -406,12 +516,13 @@
live = dead = 0;
{
+ // Copy.
SmallVector<DestroyCounts, 2> counts;
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
- auto copy = counts;
+ const auto copy = counts;
EXPECT_TRUE(copy.dynamic());
}
EXPECT_EQ(6, live);
@@ -419,12 +530,13 @@
live = dead = 0;
{
+ // Move.
SmallVector<DestroyCounts, 2> counts;
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
- auto move = std::move(counts);
+ const auto move = std::move(counts);
EXPECT_TRUE(move.dynamic());
}
EXPECT_EQ(3, live);
@@ -432,6 +544,7 @@
live = dead = 0;
{
+ // Swap.
SmallVector<DestroyCounts, 2> counts1;
counts1.emplace_back(live, dead);
counts1.emplace_back(live, dead);
@@ -448,7 +561,10 @@
swap(counts1, counts2);
+ EXPECT_EQ(1u, counts1.size());
EXPECT_FALSE(counts1.dynamic());
+
+ EXPECT_EQ(3u, counts2.size());
EXPECT_TRUE(counts2.dynamic());
EXPECT_EQ(0, live);
@@ -465,29 +581,82 @@
int dead = 0;
SmallVector<DestroyCounts, 2> counts;
- counts.emplace_back(live, dead);
- counts.emplace_back(live, dead);
+ {
+ // Static.
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
- counts.clear();
+ counts.clear();
- EXPECT_TRUE(counts.empty());
- EXPECT_FALSE(counts.dynamic());
-
+ EXPECT_TRUE(counts.empty());
+ EXPECT_FALSE(counts.dynamic());
+ }
EXPECT_EQ(2, live);
EXPECT_EQ(0, dead);
live = 0;
- counts.emplace_back(live, dead);
- counts.emplace_back(live, dead);
- counts.emplace_back(live, dead);
+ {
+ // Dynamic.
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
- counts.clear();
+ counts.clear();
- EXPECT_TRUE(counts.empty());
- EXPECT_TRUE(counts.dynamic());
-
+ EXPECT_TRUE(counts.empty());
+ EXPECT_TRUE(counts.dynamic());
+ }
EXPECT_EQ(3, live);
EXPECT_EQ(2, dead);
}
+TEST(SmallVector, Promote) {
+ {
+ const std::vector vector = {"snow"s, "cone"s};
+ EXPECT_EQ(vector, SmallVector("snow"s, "cone"s).promote());
+ EXPECT_EQ(vector, (SmallVector<std::string, 0>({"snow"s, "cone"s}).promote()));
+ }
+
+ int live = 0;
+ int dead = 0;
+
+ std::vector<DestroyCounts> vector;
+ {
+ // Static.
+ SmallVector<DestroyCounts, 3> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ vector = std::move(counts).promote();
+
+ ASSERT_EQ(2u, vector.size());
+ EXPECT_TRUE(vector[0].alive);
+ EXPECT_TRUE(vector[1].alive);
+ }
+ EXPECT_EQ(0, live);
+ EXPECT_EQ(2, dead);
+
+ vector.clear();
+ live = dead = 0;
+ {
+ // Dynamic.
+ SmallVector<DestroyCounts, 2> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ EXPECT_EQ(2, dead);
+ dead = 0;
+
+ vector = std::move(counts).promote();
+
+ ASSERT_EQ(3u, vector.size());
+ EXPECT_TRUE(vector[0].alive);
+ EXPECT_TRUE(vector[1].alive);
+ EXPECT_TRUE(vector[2].alive);
+ }
+ EXPECT_EQ(0, live);
+ EXPECT_EQ(0, dead);
+}
+
} // namespace android::test
diff --git a/libs/ftl/static_vector_test.cpp b/libs/ftl/static_vector_test.cpp
index 2de3ad2..0e10a5d 100644
--- a/libs/ftl/static_vector_test.cpp
+++ b/libs/ftl/static_vector_test.cpp
@@ -144,6 +144,64 @@
}
}
+TEST(StaticVector, Copy) {
+ {
+ // Same capacity.
+ const StaticVector vector = {"snow"s, "cone"s};
+
+ StaticVector<const std::string, 2> copy(vector);
+ EXPECT_EQ(copy, vector);
+
+ // The vector is assignable even if T is const.
+ const StaticVector<std::string, 2> other = {"tiramisu"s};
+ copy = other;
+ EXPECT_EQ(copy, other);
+ }
+ {
+ // From smaller capacity.
+ const StaticVector vector = {"snow"s, "cone"s};
+
+ StaticVector<const std::string, 3> copy(vector);
+ EXPECT_EQ(copy, vector);
+
+ // The vector is assignable even if T is const.
+ const StaticVector other = {"tiramisu"s};
+ copy = other;
+ EXPECT_EQ(copy, other);
+ }
+}
+
+TEST(StaticVector, Move) {
+ {
+ // Same capacity.
+ StaticVector vector = {"snow"s, "cone"s};
+
+ StaticVector<const std::string, 2> move(std::move(vector));
+ EXPECT_TRUE(vector.empty());
+ EXPECT_EQ(move, (StaticVector{"snow"s, "cone"s}));
+
+ // The vector is assignable even if T is const.
+ StaticVector<std::string, 2> other = {"tiramisu"s};
+ move = std::move(other);
+ EXPECT_TRUE(other.empty());
+ EXPECT_EQ(move, (StaticVector{"tiramisu"s}));
+ }
+ {
+ // From smaller capacity.
+ StaticVector vector = {"snow"s, "cone"s};
+
+ StaticVector<const std::string, 3> move(std::move(vector));
+ EXPECT_TRUE(vector.empty());
+ EXPECT_EQ(move, (StaticVector{"snow"s, "cone"s}));
+
+ // The vector is assignable even if T is const.
+ StaticVector other = {"tiramisu"s};
+ move = std::move(other);
+ EXPECT_TRUE(other.empty());
+ EXPECT_EQ(move, (StaticVector{"tiramisu"s}));
+ }
+}
+
TEST(StaticVector, String) {
StaticVector<char, 10> chars;
char c = 'a';
@@ -328,21 +386,20 @@
bool alive = true;
};
-void swap(DestroyCounts& lhs, DestroyCounts& rhs) {
- std::swap(lhs.alive, rhs.alive);
-}
-
} // namespace
TEST(StaticVector, Destroy) {
int live = 0;
int dead = 0;
-
- { StaticVector<DestroyCounts, 5> counts; }
+ {
+ // Empty.
+ StaticVector<DestroyCounts, 5> counts;
+ }
EXPECT_EQ(0, live);
EXPECT_EQ(0, dead);
{
+ // Non-empty.
StaticVector<DestroyCounts, 5> counts;
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
@@ -353,30 +410,33 @@
live = 0;
{
+ // Copy.
StaticVector<DestroyCounts, 5> counts;
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
- auto copy = counts;
+ const auto copy = counts;
}
EXPECT_EQ(6, live);
EXPECT_EQ(0, dead);
live = 0;
{
+ // Move.
StaticVector<DestroyCounts, 5> counts;
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
counts.emplace_back(live, dead);
- auto move = std::move(counts);
+ const auto move = std::move(counts);
}
EXPECT_EQ(3, live);
EXPECT_EQ(3, dead);
live = dead = 0;
{
+ // Swap.
StaticVector<DestroyCounts, 5> counts1;
counts1.emplace_back(live, dead);
counts1.emplace_back(live, dead);
@@ -384,29 +444,34 @@
StaticVector<DestroyCounts, 5> counts2;
counts2.emplace_back(live, dead);
+ counts2.emplace_back(live, dead);
swap(counts1, counts2);
+ EXPECT_EQ(2u, counts1.size());
+ EXPECT_EQ(3u, counts2.size());
+
EXPECT_EQ(0, live);
- EXPECT_EQ(2, dead);
+ EXPECT_EQ(7, dead); // 3 moves per swap, plus 1 move.
dead = 0;
}
- EXPECT_EQ(4, live);
+ EXPECT_EQ(5, live);
EXPECT_EQ(0, dead);
}
TEST(StaticVector, Clear) {
int live = 0;
int dead = 0;
+ {
+ StaticVector<DestroyCounts, 5> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
- StaticVector<DestroyCounts, 5> counts;
- counts.emplace_back(live, dead);
- counts.emplace_back(live, dead);
+ counts.clear();
- counts.clear();
-
- EXPECT_TRUE(counts.empty());
+ EXPECT_TRUE(counts.empty());
+ }
EXPECT_EQ(2, live);
EXPECT_EQ(0, dead);
}
diff --git a/libs/gralloc/OWNERS b/libs/gralloc/OWNERS
index 93879d8..72ff978 100644
--- a/libs/gralloc/OWNERS
+++ b/libs/gralloc/OWNERS
@@ -1 +1,4 @@
+# Graphics team
+alecmouri@google.com
chrisforbes@google.com
+jreck@google.com
\ No newline at end of file
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 61e6657..68b99b0 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -196,6 +196,35 @@
status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedMetadataType);
/**
+ * Private helper functions
+ */
+template <class T>
+status_t encodeInteger(const T& input, OutputHidlVec* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
+ return output->encode(tmp, sizeof(input));
+}
+
+template <class T>
+status_t decodeInteger(InputHidlVec* input, T* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
+ return input->decode(tmp, sizeof(*output));
+}
+
+/**
* encode/encodeMetadata are the main encoding functions. They take in T and uses the encodeHelper
* function to turn T into the hidl_vec byte stream.
*
@@ -251,10 +280,45 @@
template <class T>
status_t encodeOptionalMetadata(const MetadataType& metadataType, const std::optional<T>& input,
hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
- if (!input) {
- return NO_ERROR;
+ OutputHidlVec outputHidlVec{output};
+
+ status_t err = encodeMetadataType(metadataType, &outputHidlVec);
+ if (err) {
+ return err;
}
- return encodeMetadata(metadataType, *input, output, encodeHelper);
+
+ err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ if (input) {
+ err = encodeHelper(*input, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+ }
+
+ err = outputHidlVec.resize();
+ if (err) {
+ return err;
+ }
+
+ err = encodeMetadataType(metadataType, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ if (input) {
+ return encodeHelper(*input, &outputHidlVec);
+ }
+
+ return NO_ERROR;
}
/**
@@ -315,45 +379,36 @@
if (!output) {
return BAD_VALUE;
}
- if (input.size() <= 0) {
- output->reset();
- return NO_ERROR;
+
+ InputHidlVec inputHidlVec{&input};
+
+ status_t err = validateMetadataType(&inputHidlVec, metadataType);
+ if (err) {
+ return err;
}
- T tmp;
- status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper);
- if (!err) {
+
+ uint32_t present = 0;
+ err = decodeInteger<uint32_t>(&inputHidlVec, &present);
+ if (err) {
+ return err;
+ }
+
+ if (present) {
+ T tmp;
+ err = decodeHelper(&inputHidlVec, &tmp);
+ if (err) {
+ return err;
+ }
+
*output = tmp;
}
- return err;
-}
-/**
- * Private helper functions
- */
-template <class T>
-status_t encodeInteger(const T& input, OutputHidlVec* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
+ err = inputHidlVec.hasRemainingData();
+ if (err) {
return BAD_VALUE;
}
- const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
- return output->encode(tmp, sizeof(input));
-}
-
-template <class T>
-status_t decodeInteger(InputHidlVec* input, T* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
- return BAD_VALUE;
- }
-
- uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
- return input->decode(tmp, sizeof(*output));
+ return NO_ERROR;
}
status_t encodeString(const std::string& input, OutputHidlVec* output) {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 7ce72ff..b7a7aa0 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -132,12 +132,13 @@
}
}
-BLASTBufferQueue::BLASTBufferQueue(const std::string& name)
+BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame)
: mSurfaceControl(nullptr),
mSize(1, 1),
mRequestedSize(mSize),
mFormat(PIXEL_FORMAT_RGBA_8888),
- mSyncTransaction(nullptr) {
+ mSyncTransaction(nullptr),
+ mUpdateDestinationFrame(updateDestinationFrame) {
createBufferQueue(&mProducer, &mConsumer);
// since the adapter is in the client process, set dequeue timeout
// explicitly so that dequeueBuffer will block
@@ -184,7 +185,7 @@
}
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
- int32_t format, SurfaceComposerClient::Transaction* outTransaction) {
+ int32_t format) {
LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL");
std::unique_lock _lock{mMutex};
@@ -193,7 +194,6 @@
mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
}
- SurfaceComposerClient::Transaction t;
const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
if (surfaceControlChanged && mSurfaceControl != nullptr) {
BQA_LOGD("Updating SurfaceControl without recreating BBQ");
@@ -203,6 +203,7 @@
// Always update the native object even though they might have the same layer handle, so we can
// get the updated transform hint from WM.
mSurfaceControl = surface;
+ SurfaceComposerClient::Transaction t;
if (surfaceControlChanged) {
t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
layer_state_t::eEnableBackpressure);
@@ -221,12 +222,10 @@
// If the buffer supports scaling, update the frame immediately since the client may
// want to scale the existing buffer to the new size.
mSize = mRequestedSize;
- SurfaceComposerClient::Transaction* destFrameTransaction =
- (outTransaction) ? outTransaction : &t;
- destFrameTransaction->setDestinationFrame(mSurfaceControl,
- Rect(0, 0, newSize.getWidth(),
- newSize.getHeight()));
- applyTransaction = true;
+ if (mUpdateDestinationFrame) {
+ t.setDestinationFrame(mSurfaceControl, Rect(newSize));
+ applyTransaction = true;
+ }
}
}
if (applyTransaction) {
@@ -498,7 +497,6 @@
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
- const bool updateDestinationFrame = mRequestedSize != mSize;
mSize = mRequestedSize;
Rect crop = computeCrop(bufferItem);
mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
@@ -517,12 +515,19 @@
mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
- if (updateDestinationFrame) {
- t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight()));
+ if (mUpdateDestinationFrame) {
+ t->setDestinationFrame(mSurfaceControl, Rect(mSize));
+ } else {
+ const bool ignoreDestinationFrame =
+ bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ t->setFlags(mSurfaceControl,
+ ignoreDestinationFrame ? layer_state_t::eIgnoreDestinationFrame : 0,
+ layer_state_t::eIgnoreDestinationFrame);
}
t->setBufferCrop(mSurfaceControl, crop);
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
+ t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
if (!bufferItem.mIsAutoTimestamp) {
t->setDesiredPresentTime(bufferItem.mTimestamp);
}
@@ -532,10 +537,6 @@
mNextFrameTimelineInfoQueue.pop();
}
- if (mAutoRefresh != bufferItem.mAutoRefresh) {
- t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
- mAutoRefresh = bufferItem.mAutoRefresh;
- }
{
std::unique_lock _lock{mTimestampMutex};
auto dequeueTime = mDequeueTimestamps.find(buffer->getId());
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 26db59b..39d380d 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -126,7 +126,7 @@
ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
", displayId=%s, count=%d, vsyncId=%" PRId64,
this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
- vsyncEventData.id);
+ vsyncEventData.preferredVsyncId());
mWaitingForVsync = false;
mLastVsyncCount = vsyncCount;
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
@@ -146,18 +146,6 @@
return 1; // keep the callback
}
-void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event,
- VsyncEventData* outVsyncEventData) const {
- for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
- DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline =
- event.vsync.frameTimelines[i];
- outVsyncEventData->frameTimelines[i] =
- VsyncEventData::FrameTimeline(receiverTimeline.vsyncId,
- receiverTimeline.deadlineTimestamp,
- receiverTimeline.expectedVSyncTimestamp);
- }
-}
-
bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
PhysicalDisplayId* outDisplayId,
uint32_t* outCount,
@@ -178,12 +166,7 @@
*outTimestamp = ev.header.timestamp;
*outDisplayId = ev.header.displayId;
*outCount = ev.vsync.count;
- outVsyncEventData->id = ev.vsync.vsyncId;
- outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp;
- outVsyncEventData->frameInterval = ev.vsync.frameInterval;
- outVsyncEventData->preferredFrameTimelineIndex =
- ev.vsync.preferredFrameTimelineIndex;
- populateFrameTimelines(ev, outVsyncEventData);
+ *outVsyncEventData = ev.vsync.vsyncData;
break;
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index bb659bf..bfb7769 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -85,15 +85,14 @@
return mInitError.has_value() ? mInitError.value() : NO_INIT;
}
-status_t DisplayEventReceiver::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const {
+status_t DisplayEventReceiver::getLatestVsyncEventData(
+ ParcelableVsyncEventData* outVsyncEventData) const {
if (mEventConnection != nullptr) {
- VsyncEventData vsyncEventData;
- auto status = mEventConnection->getLatestVsyncEventData(&vsyncEventData);
+ auto status = mEventConnection->getLatestVsyncEventData(outVsyncEventData);
if (!status.isOk()) {
ALOGE("Failed to get latest vsync event data: %s", status.exceptionMessage().c_str());
return status.transactionError();
}
- *outVsyncEventData = vsyncEventData;
return NO_ERROR;
}
return NO_INIT;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 75c5e26..3c02e21 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -46,9 +46,11 @@
namespace android {
+using gui::DisplayCaptureArgs;
using gui::IDisplayEventConnection;
using gui::IRegionSamplingListener;
using gui::IWindowInfosListener;
+using gui::LayerCaptureArgs;
using ui::ColorMode;
class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
@@ -118,36 +120,6 @@
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- status_t captureDisplay(const DisplayCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(args.write, data);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
-
- return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply);
- }
-
- status_t captureDisplay(DisplayId displayId,
- const sp<IScreenCaptureListener>& captureListener) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeUint64, displayId.value);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
-
- return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply);
- }
-
- status_t captureLayers(const LayerCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(args.write, data);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
-
- return remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
- }
-
bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const override {
Parcel data, reply;
@@ -248,101 +220,6 @@
return result;
}
- sp<IBinder> createDisplay(const String8& displayName, bool secure) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- status_t status = data.writeString8(displayName);
- if (status) {
- return nullptr;
- }
- status = data.writeBool(secure);
- if (status) {
- return nullptr;
- }
-
- status = remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
- if (status) {
- return nullptr;
- }
- sp<IBinder> display;
- status = reply.readNullableStrongBinder(&display);
- if (status) {
- return nullptr;
- }
- return display;
- }
-
- void destroyDisplay(const sp<IBinder>& display) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
- }
-
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
- NO_ERROR) {
- std::vector<uint64_t> rawIds;
- if (reply.readUint64Vector(&rawIds) == NO_ERROR) {
- std::vector<PhysicalDisplayId> displayIds;
- displayIds.reserve(rawIds.size());
-
- for (const uint64_t rawId : rawIds) {
- if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
- displayIds.push_back(*id);
- }
- }
- return displayIds;
- }
- }
-
- return {};
- }
-
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId* displayId) const override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(remote()->transact, BnSurfaceComposer::GET_PRIMARY_PHYSICAL_DISPLAY_ID, data,
- &reply);
- uint64_t rawId;
- SAFE_PARCEL(reply.readUint64, &rawId);
- if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
- *displayId = *id;
- return NO_ERROR;
- }
- return NAME_NOT_FOUND;
- }
-
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeUint64(displayId.value);
- remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply);
- return reply.readStrongBinder();
- }
-
- void setPowerMode(const sp<IBinder>& display, int mode) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- data.writeInt32(mode);
- remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply);
- }
-
- status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATE, data, &reply);
- const status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- memcpy(state, reply.readInplace(sizeof(ui::DisplayState)), sizeof(ui::DisplayState));
- }
- return result;
- }
-
status_t getStaticDisplayInfo(const sp<IBinder>& display,
ui::StaticDisplayInfo* info) override {
Parcel data, reply;
@@ -365,20 +242,6 @@
return reply.read(*info);
}
- status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATS, data, &reply);
- status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- memcpy(stats,
- reply.readInplace(sizeof(DisplayStatInfo)),
- sizeof(DisplayStatInfo));
- }
- return result;
- }
-
status_t getDisplayNativePrimaries(const sp<IBinder>& display,
ui::DisplayPrimaries& primaries) override {
Parcel data, reply;
@@ -430,29 +293,6 @@
return static_cast<status_t>(reply.readInt32());
}
- // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
- status_t getBootDisplayModeSupport(bool* outSupport) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to write interface token: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::GET_BOOT_DISPLAY_MODE_SUPPORT, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to transact: %d", error);
- return error;
- }
- bool support;
- error = reply.readBool(&support);
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to read support: %d", error);
- return error;
- }
- *outSupport = support;
- return NO_ERROR;
- }
-
status_t setBootDisplayMode(const sp<IBinder>& display,
ui::DisplayModeId displayModeId) override {
Parcel data, reply;
@@ -478,73 +318,6 @@
return result;
}
- status_t clearBootDisplayMode(const sp<IBinder>& display) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::CLEAR_BOOT_DISPLAY_MODE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to transact: %d", result);
- }
- return result;
- }
-
- void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeInterfaceToken: %d", result);
- return;
- }
-
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeStrongBinder: %d", result);
- return;
- }
- result = data.writeBool(on);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeBool: %d", result);
- return;
- }
- result = remote()->transact(BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to transact: %d", result);
- return;
- }
- }
-
- void setGameContentType(const sp<IBinder>& display, bool on) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeInterfaceToken: %d", result);
- return;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeStrongBinder: %d", result);
- return;
- }
- result = data.writeBool(on);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeBool: %d", result);
- return;
- }
- result = remote()->transact(BnSurfaceComposer::SET_GAME_CONTENT_TYPE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to transact: %d", result);
- }
- }
-
status_t clearAnimationFrameStats() override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -819,26 +592,6 @@
return error;
}
- status_t isWideColorDisplay(const sp<IBinder>& token,
- bool* outIsWideColorDisplay) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- return error;
- }
- error = data.writeStrongBinder(token);
- if (error != NO_ERROR) {
- return error;
- }
-
- error = remote()->transact(BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY, data, &reply);
- if (error != NO_ERROR) {
- return error;
- }
- error = reply.readBool(outIsWideColorDisplay);
- return error;
- }
-
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override {
Parcel data, reply;
@@ -1071,109 +824,6 @@
return reply.readInt32();
}
- status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeStrongBinder(displayToken);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to write display token: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to transact: %d", error);
- return error;
- }
- bool support;
- error = reply.readBool(&support);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to read support: %d", error);
- return error;
- }
- *outSupport = support;
- return NO_ERROR;
- }
-
- status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeStrongBinder(displayToken);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write display token: %d", error);
- return error;
- }
- error = data.writeParcelable(brightness);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write brightness: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to transact: %d", error);
- return error;
- }
- return NO_ERROR;
- }
-
- status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeStrongBinder, displayToken);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
- const status_t error =
- remote()->transact(BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER, data, &reply);
- if (error != OK) {
- ALOGE("addHdrLayerInfoListener: Failed to transact; error = %d", error);
- }
- return error;
- }
-
- status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeStrongBinder, displayToken);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
- const status_t error =
- remote()->transact(BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER, data, &reply);
- if (error != OK) {
- ALOGE("removeHdrLayerInfoListener: Failed to transact; error = %d", error);
- }
- return error;
- }
-
- status_t notifyPowerBoost(int32_t boostId) override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeInt32(boostId);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to write boostId: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::NOTIFY_POWER_BOOST, data, &reply,
- IBinder::FLAG_ONEWAY);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to transact: %d", error);
- return error;
- }
- return NO_ERROR;
- }
-
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override {
Parcel data, reply;
@@ -1451,36 +1101,6 @@
bootFinished();
return NO_ERROR;
}
- case CAPTURE_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- DisplayCaptureArgs args;
- sp<IScreenCaptureListener> captureListener;
- SAFE_PARCEL(args.read, data);
- SAFE_PARCEL(data.readStrongBinder, &captureListener);
-
- return captureDisplay(args, captureListener);
- }
- case CAPTURE_DISPLAY_BY_ID: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- uint64_t value;
- SAFE_PARCEL(data.readUint64, &value);
- const auto id = DisplayId::fromValue(value);
- if (!id) return BAD_VALUE;
-
- sp<IScreenCaptureListener> captureListener;
- SAFE_PARCEL(data.readStrongBinder, &captureListener);
-
- return captureDisplay(*id, captureListener);
- }
- case CAPTURE_LAYERS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- LayerCaptureArgs args;
- sp<IScreenCaptureListener> captureListener;
- SAFE_PARCEL(args.read, data);
- SAFE_PARCEL(data.readStrongBinder, &captureListener);
-
- return captureLayers(args, captureListener);
- }
case AUTHENTICATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IGraphicBufferProducer> bufferProducer =
@@ -1519,41 +1139,6 @@
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
- case CREATE_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- String8 displayName;
- SAFE_PARCEL(data.readString8, &displayName);
- bool secure = false;
- SAFE_PARCEL(data.readBool, &secure);
- sp<IBinder> display = createDisplay(displayName, secure);
- SAFE_PARCEL(reply->writeStrongBinder, display);
- return NO_ERROR;
- }
- case DESTROY_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- destroyDisplay(display);
- return NO_ERROR;
- }
- case GET_PHYSICAL_DISPLAY_TOKEN: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- const auto id = DisplayId::fromValue<PhysicalDisplayId>(data.readUint64());
- if (!id) return BAD_VALUE;
- reply->writeStrongBinder(getPhysicalDisplayToken(*id));
- return NO_ERROR;
- }
- case GET_DISPLAY_STATE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- ui::DisplayState state;
- const sp<IBinder> display = data.readStrongBinder();
- const status_t result = getDisplayState(display, &state);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- memcpy(reply->writeInplace(sizeof(ui::DisplayState)), &state,
- sizeof(ui::DisplayState));
- }
- return NO_ERROR;
- }
case GET_STATIC_DISPLAY_INFO: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
ui::StaticDisplayInfo info;
@@ -1574,18 +1159,6 @@
SAFE_PARCEL(reply->write, info);
return NO_ERROR;
}
- case GET_DISPLAY_STATS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- DisplayStatInfo stats;
- sp<IBinder> display = data.readStrongBinder();
- status_t result = getDisplayStats(display, &stats);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- memcpy(reply->writeInplace(sizeof(DisplayStatInfo)),
- &stats, sizeof(DisplayStatInfo));
- }
- return NO_ERROR;
- }
case GET_DISPLAY_NATIVE_PRIMARIES: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
ui::DisplayPrimaries primaries;
@@ -1625,15 +1198,6 @@
result = reply->writeInt32(result);
return result;
}
- case GET_BOOT_DISPLAY_MODE_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- bool support = false;
- status_t result = getBootDisplayModeSupport(&support);
- if (result == NO_ERROR) {
- reply->writeBool(support);
- }
- return result;
- }
case SET_BOOT_DISPLAY_MODE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -1650,50 +1214,6 @@
}
return setBootDisplayMode(display, displayModeId);
}
- case CLEAR_BOOT_DISPLAY_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to readStrongBinder: %d", result);
- return result;
- }
- return clearBootDisplayMode(display);
- }
- case SET_AUTO_LOW_LATENCY_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to readStrongBinder: %d", result);
- return result;
- }
- bool setAllm = false;
- result = data.readBool(&setAllm);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to readBool: %d", result);
- return result;
- }
- setAutoLowLatencyMode(display, setAllm);
- return result;
- }
- case SET_GAME_CONTENT_TYPE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to readStrongBinder: %d", result);
- return result;
- }
- bool setGameContentTypeOn = false;
- result = data.readBool(&setGameContentTypeOn);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to readBool: %d", result);
- return result;
- }
- setGameContentType(display, setGameContentTypeOn);
- return result;
- }
case CLEAR_ANIMATION_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
status_t result = clearAnimationFrameStats();
@@ -1708,13 +1228,6 @@
reply->writeInt32(result);
return NO_ERROR;
}
- case SET_POWER_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- int32_t mode = data.readInt32();
- setPowerMode(display, mode);
- return NO_ERROR;
- }
case ENABLE_VSYNC_INJECTIONS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bool enable = false;
@@ -1864,38 +1377,6 @@
}
return error;
}
- case IS_WIDE_COLOR_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t error = data.readStrongBinder(&display);
- if (error != NO_ERROR) {
- return error;
- }
- bool result;
- error = isWideColorDisplay(display, &result);
- if (error == NO_ERROR) {
- reply->writeBool(result);
- }
- return error;
- }
- case GET_PHYSICAL_DISPLAY_IDS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- std::vector<PhysicalDisplayId> ids = getPhysicalDisplayIds();
- std::vector<uint64_t> rawIds(ids.size());
- std::transform(ids.begin(), ids.end(), rawIds.begin(),
- [](PhysicalDisplayId id) { return id.value; });
- return reply->writeUint64Vector(rawIds);
- }
- case GET_PRIMARY_PHYSICAL_DISPLAY_ID: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- PhysicalDisplayId id;
- status_t result = getPrimaryPhysicalDisplayId(&id);
- if (result != NO_ERROR) {
- ALOGE("getPrimaryPhysicalDisplayId: Failed to get id");
- return result;
- }
- return reply->writeUint64(id.value);
- }
case ADD_REGION_SAMPLING_LISTENER: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
Rect samplingArea;
@@ -2093,77 +1574,6 @@
reply->writeInt32(result);
return result;
}
- case GET_DISPLAY_BRIGHTNESS_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to read display token: %d", error);
- return error;
- }
- bool support = false;
- error = getDisplayBrightnessSupport(displayToken, &support);
- reply->writeBool(support);
- return error;
- }
- case SET_DISPLAY_BRIGHTNESS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to read display token: %d", error);
- return error;
- }
- gui::DisplayBrightness brightness;
- error = data.readParcelable(&brightness);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to read brightness: %d", error);
- return error;
- }
- return setDisplayBrightness(displayToken, brightness);
- }
- case ADD_HDR_LAYER_INFO_LISTENER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("addHdrLayerInfoListener: Failed to read display token");
- return error;
- }
- sp<gui::IHdrLayerInfoListener> listener;
- error = data.readNullableStrongBinder(&listener);
- if (error != NO_ERROR) {
- ALOGE("addHdrLayerInfoListener: Failed to read listener");
- return error;
- }
- return addHdrLayerInfoListener(displayToken, listener);
- }
- case REMOVE_HDR_LAYER_INFO_LISTENER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("removeHdrLayerInfoListener: Failed to read display token");
- return error;
- }
- sp<gui::IHdrLayerInfoListener> listener;
- error = data.readNullableStrongBinder(&listener);
- if (error != NO_ERROR) {
- ALOGE("removeHdrLayerInfoListener: Failed to read listener");
- return error;
- }
- return removeHdrLayerInfoListener(displayToken, listener);
- }
- case NOTIFY_POWER_BOOST: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int32_t boostId;
- status_t error = data.readInt32(&boostId);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to read boostId: %d", error);
- return error;
- }
- return notifyPowerBoost(boostId);
- }
case SET_GLOBAL_SHADOW_SETTINGS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index eec4a87..6944d38 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -35,7 +35,9 @@
using gui::WindowInfoHandle;
layer_state_t::layer_state_t()
- : what(0),
+ : surface(nullptr),
+ layerId(-1),
+ what(0),
x(0),
y(0),
z(0),
@@ -153,8 +155,12 @@
SAFE_PARCEL(output.writeBool, isTrustedOverlay);
SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dropInputMode));
- SAFE_PARCEL(output.writeNullableParcelable,
- bufferData ? std::make_optional<BufferData>(*bufferData) : std::nullopt);
+
+ const bool hasBufferData = (bufferData != nullptr);
+ SAFE_PARCEL(output.writeBool, hasBufferData);
+ if (hasBufferData) {
+ SAFE_PARCEL(output.writeParcelable, *bufferData);
+ }
return NO_ERROR;
}
@@ -264,9 +270,15 @@
uint32_t mode;
SAFE_PARCEL(input.readUint32, &mode);
dropInputMode = static_cast<gui::DropInputMode>(mode);
- std::optional<BufferData> tmpBufferData;
- SAFE_PARCEL(input.readParcelable, &tmpBufferData);
- bufferData = tmpBufferData ? std::make_shared<BufferData>(*tmpBufferData) : nullptr;
+
+ bool hasBufferData;
+ SAFE_PARCEL(input.readBool, &hasBufferData);
+ if (hasBufferData) {
+ bufferData = std::make_shared<BufferData>();
+ SAFE_PARCEL(input.readParcelable, bufferData.get());
+ } else {
+ bufferData = nullptr;
+ }
return NO_ERROR;
}
@@ -674,85 +686,89 @@
// ----------------------------------------------------------------------------
-status_t CaptureArgs::write(Parcel& output) const {
- SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(pixelFormat));
- SAFE_PARCEL(output.write, sourceCrop);
- SAFE_PARCEL(output.writeFloat, frameScaleX);
- SAFE_PARCEL(output.writeFloat, frameScaleY);
- SAFE_PARCEL(output.writeBool, captureSecureLayers);
- SAFE_PARCEL(output.writeInt32, uid);
- SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(dataspace));
- SAFE_PARCEL(output.writeBool, allowProtected);
- SAFE_PARCEL(output.writeBool, grayscale);
+namespace gui {
+
+status_t CaptureArgs::writeToParcel(Parcel* output) const {
+ SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(pixelFormat));
+ SAFE_PARCEL(output->write, sourceCrop);
+ SAFE_PARCEL(output->writeFloat, frameScaleX);
+ SAFE_PARCEL(output->writeFloat, frameScaleY);
+ SAFE_PARCEL(output->writeBool, captureSecureLayers);
+ SAFE_PARCEL(output->writeInt32, uid);
+ SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(dataspace));
+ SAFE_PARCEL(output->writeBool, allowProtected);
+ SAFE_PARCEL(output->writeBool, grayscale);
return NO_ERROR;
}
-status_t CaptureArgs::read(const Parcel& input) {
+status_t CaptureArgs::readFromParcel(const Parcel* input) {
int32_t value = 0;
- SAFE_PARCEL(input.readInt32, &value);
+ SAFE_PARCEL(input->readInt32, &value);
pixelFormat = static_cast<ui::PixelFormat>(value);
- SAFE_PARCEL(input.read, sourceCrop);
- SAFE_PARCEL(input.readFloat, &frameScaleX);
- SAFE_PARCEL(input.readFloat, &frameScaleY);
- SAFE_PARCEL(input.readBool, &captureSecureLayers);
- SAFE_PARCEL(input.readInt32, &uid);
- SAFE_PARCEL(input.readInt32, &value);
+ SAFE_PARCEL(input->read, sourceCrop);
+ SAFE_PARCEL(input->readFloat, &frameScaleX);
+ SAFE_PARCEL(input->readFloat, &frameScaleY);
+ SAFE_PARCEL(input->readBool, &captureSecureLayers);
+ SAFE_PARCEL(input->readInt32, &uid);
+ SAFE_PARCEL(input->readInt32, &value);
dataspace = static_cast<ui::Dataspace>(value);
- SAFE_PARCEL(input.readBool, &allowProtected);
- SAFE_PARCEL(input.readBool, &grayscale);
+ SAFE_PARCEL(input->readBool, &allowProtected);
+ SAFE_PARCEL(input->readBool, &grayscale);
return NO_ERROR;
}
-status_t DisplayCaptureArgs::write(Parcel& output) const {
- SAFE_PARCEL(CaptureArgs::write, output);
+status_t DisplayCaptureArgs::writeToParcel(Parcel* output) const {
+ SAFE_PARCEL(CaptureArgs::writeToParcel, output);
- SAFE_PARCEL(output.writeStrongBinder, displayToken);
- SAFE_PARCEL(output.writeUint32, width);
- SAFE_PARCEL(output.writeUint32, height);
- SAFE_PARCEL(output.writeBool, useIdentityTransform);
+ SAFE_PARCEL(output->writeStrongBinder, displayToken);
+ SAFE_PARCEL(output->writeUint32, width);
+ SAFE_PARCEL(output->writeUint32, height);
+ SAFE_PARCEL(output->writeBool, useIdentityTransform);
return NO_ERROR;
}
-status_t DisplayCaptureArgs::read(const Parcel& input) {
- SAFE_PARCEL(CaptureArgs::read, input);
+status_t DisplayCaptureArgs::readFromParcel(const Parcel* input) {
+ SAFE_PARCEL(CaptureArgs::readFromParcel, input);
- SAFE_PARCEL(input.readStrongBinder, &displayToken);
- SAFE_PARCEL(input.readUint32, &width);
- SAFE_PARCEL(input.readUint32, &height);
- SAFE_PARCEL(input.readBool, &useIdentityTransform);
+ SAFE_PARCEL(input->readStrongBinder, &displayToken);
+ SAFE_PARCEL(input->readUint32, &width);
+ SAFE_PARCEL(input->readUint32, &height);
+ SAFE_PARCEL(input->readBool, &useIdentityTransform);
return NO_ERROR;
}
-status_t LayerCaptureArgs::write(Parcel& output) const {
- SAFE_PARCEL(CaptureArgs::write, output);
+status_t LayerCaptureArgs::writeToParcel(Parcel* output) const {
+ SAFE_PARCEL(CaptureArgs::writeToParcel, output);
- SAFE_PARCEL(output.writeStrongBinder, layerHandle);
- SAFE_PARCEL(output.writeInt32, excludeHandles.size());
+ SAFE_PARCEL(output->writeStrongBinder, layerHandle);
+ SAFE_PARCEL(output->writeInt32, excludeHandles.size());
for (auto el : excludeHandles) {
- SAFE_PARCEL(output.writeStrongBinder, el);
+ SAFE_PARCEL(output->writeStrongBinder, el);
}
- SAFE_PARCEL(output.writeBool, childrenOnly);
+ SAFE_PARCEL(output->writeBool, childrenOnly);
return NO_ERROR;
}
-status_t LayerCaptureArgs::read(const Parcel& input) {
- SAFE_PARCEL(CaptureArgs::read, input);
+status_t LayerCaptureArgs::readFromParcel(const Parcel* input) {
+ SAFE_PARCEL(CaptureArgs::readFromParcel, input);
- SAFE_PARCEL(input.readStrongBinder, &layerHandle);
+ SAFE_PARCEL(input->readStrongBinder, &layerHandle);
int32_t numExcludeHandles = 0;
- SAFE_PARCEL_READ_SIZE(input.readInt32, &numExcludeHandles, input.dataSize());
+ SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize());
excludeHandles.reserve(numExcludeHandles);
for (int i = 0; i < numExcludeHandles; i++) {
sp<IBinder> binder;
- SAFE_PARCEL(input.readStrongBinder, &binder);
+ SAFE_PARCEL(input->readStrongBinder, &binder);
excludeHandles.emplace(binder);
}
- SAFE_PARCEL(input.readBool, &childrenOnly);
+ SAFE_PARCEL(input->readBool, &childrenOnly);
return NO_ERROR;
}
+}; // namespace gui
+
ReleaseCallbackId BufferData::generateReleaseCallbackId() const {
return {buffer->getId(), frameNumber};
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 20c4146..0f0a5c8 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -27,13 +27,13 @@
#include <inttypes.h>
+#include <android/gui/DisplayStatInfo.h>
#include <android/native_window.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <utils/NativeHandle.h>
-#include <ui/DisplayStatInfo.h>
#include <ui/DynamicDisplayInfo.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
@@ -45,6 +45,7 @@
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
namespace android {
@@ -125,6 +126,10 @@
return ComposerService::getComposerService();
}
+sp<gui::ISurfaceComposer> Surface::composerServiceAIDL() const {
+ return ComposerServiceAIDL::getComposerService();
+}
+
nsecs_t Surface::now() const {
return systemTime();
}
@@ -174,10 +179,10 @@
status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
ATRACE_CALL();
- DisplayStatInfo stats;
- status_t result = composerService()->getDisplayStats(nullptr, &stats);
- if (result != NO_ERROR) {
- return result;
+ gui::DisplayStatInfo stats;
+ binder::Status status = composerServiceAIDL()->getDisplayStats(nullptr, &stats);
+ if (!status.isOk()) {
+ return status.transactionError();
}
*outRefreshDuration = stats.vsyncPeriod;
@@ -343,20 +348,20 @@
status_t Surface::getWideColorSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
if (display == nullptr) {
return NAME_NOT_FOUND;
}
*supported = false;
- status_t error = composerService()->isWideColorDisplay(display, supported);
- return error;
+ binder::Status status = composerServiceAIDL()->isWideColorDisplay(display, supported);
+ return status.transactionError();
}
status_t Surface::getHdrSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
if (display == nullptr) {
return NAME_NOT_FOUND;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 9269c3e..447b3ef 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/gui/DisplayState.h>
#include <android/gui/IWindowInfosListener.h>
#include <utils/Errors.h>
#include <utils/Log.h>
@@ -43,9 +44,11 @@
#include <gui/WindowInfo.h>
#include <private/gui/ParcelUtils.h>
#include <ui/DisplayMode.h>
+#include <ui/DisplayState.h>
#include <ui/DynamicDisplayInfo.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
// This server size should always be smaller than the server cache size
#define BUFFER_CACHE_MAX_SIZE 64
@@ -62,6 +65,7 @@
// ---------------------------------------------------------------------------
ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
+ANDROID_SINGLETON_STATIC_INSTANCE(ComposerServiceAIDL);
namespace {
// Initialize transaction id counter used to generate transaction ids
@@ -120,6 +124,52 @@
mDeathObserver = nullptr;
}
+ComposerServiceAIDL::ComposerServiceAIDL() : Singleton<ComposerServiceAIDL>() {
+ std::scoped_lock lock(mMutex);
+ connectLocked();
+}
+
+bool ComposerServiceAIDL::connectLocked() {
+ const String16 name("SurfaceFlingerAIDL");
+ mComposerService = waitForService<gui::ISurfaceComposer>(name);
+ if (mComposerService == nullptr) {
+ return false; // fatal error or permission problem
+ }
+
+ // Create the death listener.
+ class DeathObserver : public IBinder::DeathRecipient {
+ ComposerServiceAIDL& mComposerService;
+ virtual void binderDied(const wp<IBinder>& who) {
+ ALOGW("ComposerService aidl remote (surfaceflinger) died [%p]", who.unsafe_get());
+ mComposerService.composerServiceDied();
+ }
+
+ public:
+ explicit DeathObserver(ComposerServiceAIDL& mgr) : mComposerService(mgr) {}
+ };
+
+ mDeathObserver = new DeathObserver(*const_cast<ComposerServiceAIDL*>(this));
+ IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
+ return true;
+}
+
+/*static*/ sp<gui::ISurfaceComposer> ComposerServiceAIDL::getComposerService() {
+ ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+ std::scoped_lock lock(instance.mMutex);
+ if (instance.mComposerService == nullptr) {
+ if (ComposerServiceAIDL::getInstance().connectLocked()) {
+ ALOGD("ComposerServiceAIDL reconnected");
+ }
+ }
+ return instance.mComposerService;
+}
+
+void ComposerServiceAIDL::composerServiceDied() {
+ std::scoped_lock lock(mMutex);
+ mComposerService = nullptr;
+ mDeathObserver = nullptr;
+}
+
class DefaultComposerClient: public Singleton<DefaultComposerClient> {
Mutex mLock;
sp<SurfaceComposerClient> mClient;
@@ -966,32 +1016,59 @@
// ---------------------------------------------------------------------------
sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
- return ComposerService::getComposerService()->createDisplay(displayName,
- secure);
+ sp<IBinder> display = nullptr;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->createDisplay(std::string(
+ displayName.string()),
+ secure, &display);
+ return status.isOk() ? display : nullptr;
}
void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->destroyDisplay(display);
+ ComposerServiceAIDL::getComposerService()->destroyDisplay(display);
}
std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() {
- return ComposerService::getComposerService()->getPhysicalDisplayIds();
+ std::vector<int64_t> displayIds;
+ std::vector<PhysicalDisplayId> physicalDisplayIds;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPhysicalDisplayIds(&displayIds);
+ if (status.isOk()) {
+ physicalDisplayIds.reserve(displayIds.size());
+ for (auto item : displayIds) {
+ auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(item));
+ physicalDisplayIds.push_back(*id);
+ }
+ }
+ return physicalDisplayIds;
}
status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) {
- return ComposerService::getComposerService()->getPrimaryPhysicalDisplayId(id);
+ int64_t displayId;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPrimaryPhysicalDisplayId(&displayId);
+ if (status.isOk()) {
+ *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+ }
+ return status.transactionError();
}
std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
- return ComposerService::getComposerService()->getInternalDisplayId();
+ ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+ return instance.getInternalDisplayId();
}
sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
- return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId);
+ sp<IBinder> display = nullptr;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPhysicalDisplayToken(displayId.value,
+ &display);
+ return status.isOk() ? display : nullptr;
}
sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
- return ComposerService::getComposerService()->getInternalDisplayToken();
+ ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+ return instance.getInternalDisplayToken();
}
void SurfaceComposerClient::Transaction::setAnimationTransaction() {
@@ -2019,7 +2096,16 @@
status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
ui::DisplayState* state) {
- return ComposerService::getComposerService()->getDisplayState(display, state);
+ gui::DisplayState ds;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getDisplayState(display, &ds);
+ if (status.isOk()) {
+ state->layerStack = ui::LayerStack::fromValue(ds.layerStack);
+ state->orientation = static_cast<ui::Rotation>(ds.orientation);
+ state->layerStackSpaceRect =
+ ui::Size(ds.layerStackSpaceRect.width, ds.layerStackSpaceRect.height);
+ }
+ return status.transactionError();
}
status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display,
@@ -2083,7 +2169,9 @@
}
status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) {
- return ComposerService::getComposerService()->getBootDisplayModeSupport(support);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getBootDisplayModeSupport(support);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display,
@@ -2092,7 +2180,9 @@
}
status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->clearBootDisplayMode(display);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->clearBootDisplayMode(display);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) {
@@ -2100,16 +2190,16 @@
}
void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
- ComposerService::getComposerService()->setAutoLowLatencyMode(display, on);
+ ComposerServiceAIDL::getComposerService()->setAutoLowLatencyMode(display, on);
}
void SurfaceComposerClient::setGameContentType(const sp<IBinder>& display, bool on) {
- ComposerService::getComposerService()->setGameContentType(display, on);
+ ComposerServiceAIDL::getComposerService()->setGameContentType(display, on);
}
void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token,
int mode) {
- ComposerService::getComposerService()->setPowerMode(token, mode);
+ ComposerServiceAIDL::getComposerService()->setPowerMode(token, mode);
}
status_t SurfaceComposerClient::getCompositionPreference(
@@ -2170,8 +2260,10 @@
status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display,
bool* outIsWideColorDisplay) {
- return ComposerService::getComposerService()->isWideColorDisplay(display,
- outIsWideColorDisplay);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->isWideColorDisplay(display,
+ outIsWideColorDisplay);
+ return status.transactionError();
}
status_t SurfaceComposerClient::addRegionSamplingListener(
@@ -2208,28 +2300,39 @@
bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) {
bool support = false;
- ComposerService::getComposerService()->getDisplayBrightnessSupport(displayToken, &support);
- return support;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getDisplayBrightnessSupport(displayToken,
+ &support);
+ return status.isOk() ? support : false;
}
status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness) {
- return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->setDisplayBrightness(displayToken,
+ brightness);
+ return status.transactionError();
}
status_t SurfaceComposerClient::addHdrLayerInfoListener(
const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
- return ComposerService::getComposerService()->addHdrLayerInfoListener(displayToken, listener);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->addHdrLayerInfoListener(displayToken,
+ listener);
+ return status.transactionError();
}
status_t SurfaceComposerClient::removeHdrLayerInfoListener(
const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
- return ComposerService::getComposerService()->removeHdrLayerInfoListener(displayToken,
- listener);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->removeHdrLayerInfoListener(displayToken,
+ listener);
+ return status.transactionError();
}
status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) {
- return ComposerService::getComposerService()->notifyPowerBoost(boostId);
+ binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor,
@@ -2267,26 +2370,29 @@
status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
const sp<IScreenCaptureListener>& captureListener) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
if (s == nullptr) return NO_INIT;
- return s->captureDisplay(captureArgs, captureListener);
+ binder::Status status = s->captureDisplay(captureArgs, captureListener);
+ return status.transactionError();
}
status_t ScreenshotClient::captureDisplay(DisplayId displayId,
const sp<IScreenCaptureListener>& captureListener) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
if (s == nullptr) return NO_INIT;
- return s->captureDisplay(displayId, captureListener);
+ binder::Status status = s->captureDisplayById(displayId.value, captureListener);
+ return status.transactionError();
}
status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
const sp<IScreenCaptureListener>& captureListener) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
if (s == nullptr) return NO_INIT;
- return s->captureLayers(captureArgs, captureListener);
+ binder::Status status = s->captureLayers(captureArgs, captureListener);
+ return status.transactionError();
}
// ---------------------------------------------------------------------------------
diff --git a/libs/gui/VsyncEventData.cpp b/libs/gui/VsyncEventData.cpp
index aad81d0..23f0921 100644
--- a/libs/gui/VsyncEventData.cpp
+++ b/libs/gui/VsyncEventData.cpp
@@ -23,52 +23,46 @@
namespace android::gui {
-status_t VsyncEventData::readFromParcel(const Parcel* parcel) {
+int64_t VsyncEventData::preferredVsyncId() const {
+ return frameTimelines[preferredFrameTimelineIndex].vsyncId;
+}
+
+int64_t VsyncEventData::preferredDeadlineTimestamp() const {
+ return frameTimelines[preferredFrameTimelineIndex].deadlineTimestamp;
+}
+
+int64_t VsyncEventData::preferredExpectedPresentationTime() const {
+ return frameTimelines[preferredFrameTimelineIndex].expectedPresentationTime;
+}
+
+status_t ParcelableVsyncEventData::readFromParcel(const Parcel* parcel) {
if (parcel == nullptr) {
ALOGE("%s: Null parcel", __func__);
return BAD_VALUE;
}
- SAFE_PARCEL(parcel->readInt64, &id)
- SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp);
- SAFE_PARCEL(parcel->readInt64, &frameInterval);
+ SAFE_PARCEL(parcel->readInt64, &vsync.frameInterval);
uint64_t uintPreferredFrameTimelineIndex;
SAFE_PARCEL(parcel->readUint64, &uintPreferredFrameTimelineIndex);
- preferredFrameTimelineIndex = static_cast<size_t>(uintPreferredFrameTimelineIndex);
+ vsync.preferredFrameTimelineIndex = static_cast<size_t>(uintPreferredFrameTimelineIndex);
- std::vector<FrameTimeline> timelines;
- SAFE_PARCEL(parcel->readParcelableVector, &timelines);
- std::copy_n(timelines.begin(), timelines.size(), frameTimelines.begin());
-
- return OK;
-}
-status_t VsyncEventData::writeToParcel(Parcel* parcel) const {
- SAFE_PARCEL(parcel->writeInt64, id)
- SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp);
- SAFE_PARCEL(parcel->writeInt64, frameInterval);
- SAFE_PARCEL(parcel->writeUint64, preferredFrameTimelineIndex);
- SAFE_PARCEL(parcel->writeParcelableVector,
- std::vector(frameTimelines.begin(), frameTimelines.end()));
-
- return OK;
-}
-status_t VsyncEventData::FrameTimeline::readFromParcel(const Parcel* parcel) {
- if (parcel == nullptr) {
- ALOGE("%s: Null parcel", __func__);
- return BAD_VALUE;
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].vsyncId);
+ SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].deadlineTimestamp);
+ SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].expectedPresentationTime);
}
- SAFE_PARCEL(parcel->readInt64, &id)
- SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp);
- SAFE_PARCEL(parcel->readInt64, &expectedPresentTime);
-
return OK;
}
-status_t VsyncEventData::FrameTimeline::writeToParcel(Parcel* parcel) const {
- SAFE_PARCEL(parcel->writeInt64, id);
- SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp);
- SAFE_PARCEL(parcel->writeInt64, expectedPresentTime);
+status_t ParcelableVsyncEventData::writeToParcel(Parcel* parcel) const {
+ SAFE_PARCEL(parcel->writeInt64, vsync.frameInterval);
+ SAFE_PARCEL(parcel->writeUint64, vsync.preferredFrameTimelineIndex);
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].vsyncId);
+ SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].deadlineTimestamp);
+ SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].expectedPresentationTime);
+ }
return OK;
}
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index a866786..80bd638 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -18,7 +18,6 @@
#define LOG_TAG "WindowInfo"
#define LOG_NDEBUG 0
-#include <android-base/stringprintf.h>
#include <binder/Parcel.h>
#include <gui/WindowInfo.h>
@@ -27,6 +26,14 @@
namespace android::gui {
// --- WindowInfo ---
+void WindowInfo::setInputConfig(Flags<InputConfig> config, bool value) {
+ if (value) {
+ inputConfig |= config;
+ return;
+ }
+ inputConfig &= ~config;
+}
+
void WindowInfo::addTouchableRegion(const Rect& region) {
touchableRegion.orSelf(region);
}
@@ -40,7 +47,7 @@
}
bool WindowInfo::supportsSplitTouch() const {
- return flags.test(Flag::SPLIT_TOUCH);
+ return !inputConfig.test(InputConfig::PREVENT_SPLITTING);
}
bool WindowInfo::isSpy() const {
@@ -58,20 +65,19 @@
}
bool WindowInfo::operator==(const WindowInfo& info) const {
- return info.token == token && info.id == id && info.name == name && info.flags == flags &&
- info.type == type && info.dispatchingTimeout == dispatchingTimeout &&
- info.frameLeft == frameLeft && info.frameTop == frameTop &&
- info.frameRight == frameRight && info.frameBottom == frameBottom &&
- info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor &&
- info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) &&
- info.visible == visible && info.trustedOverlay == trustedOverlay &&
- info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode &&
- info.hasWallpaper == hasWallpaper && info.paused == paused &&
- info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
- info.packageName == packageName && info.inputFeatures == inputFeatures &&
+ return info.token == token && info.id == id && info.name == name &&
+ info.dispatchingTimeout == dispatchingTimeout && info.frameLeft == frameLeft &&
+ info.frameTop == frameTop && info.frameRight == frameRight &&
+ info.frameBottom == frameBottom && info.surfaceInset == surfaceInset &&
+ info.globalScaleFactor == globalScaleFactor && info.transform == transform &&
+ info.touchableRegion.hasSameRects(touchableRegion) &&
+ info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid &&
+ info.ownerUid == ownerUid && info.packageName == packageName &&
+ info.inputFeatures == inputFeatures && info.inputConfig == inputConfig &&
info.displayId == displayId &&
info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
- info.applicationInfo == applicationInfo;
+ info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
+ info.layoutParamsFlags == layoutParamsFlags;
}
status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -85,13 +91,18 @@
}
parcel->writeInt32(1);
+ // Ensure that the size of the flags that we use is 32 bits for writing into the parcel.
+ static_assert(sizeof(inputFeatures) == 4u);
+ static_assert(sizeof(inputConfig) == 4u);
+
// clang-format off
status_t status = parcel->writeStrongBinder(token) ?:
parcel->writeInt64(dispatchingTimeout.count()) ?:
parcel->writeInt32(id) ?:
parcel->writeUtf8AsUtf16(name) ?:
- parcel->writeInt32(flags.get()) ?:
- parcel->writeInt32(static_cast<std::underlying_type_t<WindowInfo::Type>>(type)) ?:
+ parcel->writeInt32(layoutParamsFlags.get()) ?:
+ parcel->writeInt32(
+ static_cast<std::underlying_type_t<WindowInfo::Type>>(layoutParamsType)) ?:
parcel->writeInt32(frameLeft) ?:
parcel->writeInt32(frameTop) ?:
parcel->writeInt32(frameRight) ?:
@@ -105,16 +116,12 @@
parcel->writeFloat(transform.dtdy()) ?:
parcel->writeFloat(transform.dsdy()) ?:
parcel->writeFloat(transform.ty()) ?:
- parcel->writeBool(visible) ?:
- parcel->writeBool(focusable) ?:
- parcel->writeBool(hasWallpaper) ?:
- parcel->writeBool(paused) ?:
- parcel->writeBool(trustedOverlay) ?:
parcel->writeInt32(static_cast<int32_t>(touchOcclusionMode)) ?:
parcel->writeInt32(ownerPid) ?:
parcel->writeInt32(ownerUid) ?:
parcel->writeUtf8AsUtf16(packageName) ?:
parcel->writeInt32(inputFeatures.get()) ?:
+ parcel->writeInt32(inputConfig.get()) ?:
parcel->writeInt32(displayId) ?:
applicationInfo.writeToParcel(parcel) ?:
parcel->write(touchableRegion) ?:
@@ -141,8 +148,8 @@
return status;
}
- flags = Flags<Flag>(parcel->readInt32());
- type = static_cast<Type>(parcel->readInt32());
+ layoutParamsFlags = Flags<Flag>(parcel->readInt32());
+ layoutParamsType = static_cast<Type>(parcel->readInt32());
float dsdx, dtdx, tx, dtdy, dsdy, ty;
int32_t touchOcclusionModeInt;
// clang-format off
@@ -159,11 +166,6 @@
parcel->readFloat(&dtdy) ?:
parcel->readFloat(&dsdy) ?:
parcel->readFloat(&ty) ?:
- parcel->readBool(&visible) ?:
- parcel->readBool(&focusable) ?:
- parcel->readBool(&hasWallpaper) ?:
- parcel->readBool(&paused) ?:
- parcel->readBool(&trustedOverlay) ?:
parcel->readInt32(&touchOcclusionModeInt) ?:
parcel->readInt32(&ownerPid) ?:
parcel->readInt32(&ownerUid) ?:
@@ -177,6 +179,7 @@
touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt);
inputFeatures = Flags<Feature>(parcel->readInt32());
+ inputConfig = Flags<InputConfig>(parcel->readInt32());
// clang-format off
status = parcel->readInt32(&displayId) ?:
applicationInfo.readFromParcel(parcel) ?:
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl
similarity index 89%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl
index 7343515..2caa2b9 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl
@@ -16,4 +16,4 @@
package android.gui;
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+parcelable DisplayCaptureArgs cpp_header "gui/DisplayCaptureArgs.h";
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
similarity index 81%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/DisplayStatInfo.aidl
index 7343515..68f3942 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * 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.
@@ -16,4 +16,8 @@
package android.gui;
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+/** @hide */
+parcelable DisplayStatInfo {
+ long vsyncTime;
+ long vsyncPeriod;
+}
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/DisplayState.aidl
similarity index 70%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/DisplayState.aidl
index 7343515..9589ab6 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/DisplayState.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * 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.
@@ -16,4 +16,12 @@
package android.gui;
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+import android.gui.Rotation;
+import android.gui.Size;
+
+/** @hide */
+parcelable DisplayState {
+ int layerStack;
+ Rotation orientation = Rotation.Rotation0;
+ Size layerStackSpaceRect;
+}
diff --git a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
index e9a6a0c..9781ca9 100644
--- a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
+++ b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
@@ -17,7 +17,7 @@
package android.gui;
import android.gui.BitTube;
-import android.gui.VsyncEventData;
+import android.gui.ParcelableVsyncEventData;
/** @hide */
interface IDisplayEventConnection {
@@ -43,5 +43,5 @@
/*
* getLatestVsyncEventData() gets the latest vsync event data.
*/
- VsyncEventData getLatestVsyncEventData();
+ ParcelableVsyncEventData getLatestVsyncEventData();
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
new file mode 100644
index 0000000..a9977b0
--- /dev/null
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+import android.gui.DisplayCaptureArgs;
+import android.gui.DisplayBrightness;
+import android.gui.DisplayState;
+import android.gui.DisplayStatInfo;
+import android.gui.IHdrLayerInfoListener;
+import android.gui.LayerCaptureArgs;
+import android.gui.IScreenCaptureListener;
+
+/** @hide */
+interface ISurfaceComposer {
+
+ /* create a virtual display
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ @nullable IBinder createDisplay(@utf8InCpp String displayName, boolean secure);
+
+ /* destroy a virtual display
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ void destroyDisplay(IBinder display);
+
+ /* get stable IDs for connected physical displays.
+ */
+ long[] getPhysicalDisplayIds();
+
+ long getPrimaryPhysicalDisplayId();
+
+ /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
+ * DisplayEventReceiver hotplug event.
+ */
+ @nullable IBinder getPhysicalDisplayToken(long displayId);
+
+ /* set display power mode. depending on the mode, it can either trigger
+ * screen on, off or low power mode and wait for it to complete.
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ void setPowerMode(IBinder display, int mode);
+
+ /* returns display statistics for a given display
+ * intended to be used by the media framework to properly schedule
+ * video frames */
+ DisplayStatInfo getDisplayStats(IBinder display);
+
+ /**
+ * Get transactional state of given display.
+ */
+ DisplayState getDisplayState(IBinder display);
+
+ /**
+ * Clears the user-preferred display mode. The device should now boot in system preferred
+ * display mode.
+ */
+ void clearBootDisplayMode(IBinder display);
+
+ /**
+ * Gets whether boot time display mode operations are supported on the device.
+ *
+ * outSupport
+ * An output parameter for whether boot time display mode operations are supported.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
+ boolean getBootDisplayModeSupport();
+
+ /**
+ * Switches Auto Low Latency Mode on/off on the connected display, if it is
+ * available. This should only be called if the display supports Auto Low
+ * Latency Mode as reported in #getDynamicDisplayInfo.
+ * For more information, see the HDMI 2.1 specification.
+ */
+ void setAutoLowLatencyMode(IBinder display, boolean on);
+
+ /**
+ * This will start sending infoframes to the connected display with
+ * ContentType=Game (if on=true). This should only be called if the display
+ * Game Content Type as reported in #getDynamicDisplayInfo.
+ * For more information, see the HDMI 1.4 specification.
+ */
+ void setGameContentType(IBinder display, boolean on);
+
+ /**
+ * Capture the specified screen. This requires READ_FRAME_BUFFER
+ * permission. This function will fail if there is a secure window on
+ * screen and DisplayCaptureArgs.captureSecureLayers is false.
+ *
+ * This function can capture a subregion (the source crop) of the screen.
+ * The subregion can be optionally rotated. It will also be scaled to
+ * match the size of the output buffer.
+ */
+ void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener);
+ void captureDisplayById(long displayId, IScreenCaptureListener listener);
+ /**
+ * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+ * This requires READ_FRAME_BUFFER permission. This function will fail if there
+ * is a secure window on screen
+ */
+ void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
+
+ /*
+ * Queries whether the given display is a wide color display.
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ boolean isWideColorDisplay(IBinder token);
+
+ /*
+ * Gets whether brightness operations are supported on a display.
+ *
+ * displayToken
+ * The token of the display.
+ * outSupport
+ * An output parameter for whether brightness operations are supported.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ boolean getDisplayBrightnessSupport(IBinder displayToken);
+
+ /*
+ * Sets the brightness of a display.
+ *
+ * displayToken
+ * The token of the display whose brightness is set.
+ * brightness
+ * The DisplayBrightness info to set on the desired display.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the brightness is invalid, or
+ * INVALID_OPERATION if brightness operations are not supported.
+ */
+ void setDisplayBrightness(IBinder displayToken, in DisplayBrightness brightness);
+
+ /*
+ * Adds a listener that receives HDR layer information. This is used in combination
+ * with setDisplayBrightness to adjust the display brightness depending on factors such
+ * as whether or not HDR is in use.
+ *
+ * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
+ */
+ void addHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+ /*
+ * Removes a listener that was added with addHdrLayerInfoListener.
+ *
+ * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
+ * the listener wasn't registered.
+ *
+ */
+ void removeHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+ /*
+ * Sends a power boost to the composer. This function is asynchronous.
+ *
+ * boostId
+ * boost id according to android::hardware::power::Boost
+ *
+ * Returns NO_ERROR upon success.
+ */
+ void notifyPowerBoost(int boostId);
+}
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl
similarity index 90%
rename from libs/gui/aidl/android/gui/VsyncEventData.aidl
rename to libs/gui/aidl/android/gui/LayerCaptureArgs.aidl
index 7343515..f0def50 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl
@@ -16,4 +16,4 @@
package android.gui;
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+parcelable LayerCaptureArgs cpp_header "gui/LayerCaptureArgs.h";
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl
similarity index 89%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl
index 7343515..ba76671 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl
@@ -16,4 +16,4 @@
package android.gui;
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+parcelable ParcelableVsyncEventData cpp_header "gui/VsyncEventData.h";
diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/Rect.aidl
new file mode 100644
index 0000000..1b13761
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Rect.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+// copied from libs/arect/include/android/rect.h
+// TODO(b/221473398):
+// use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
+/** @hide */
+parcelable Rect {
+ /// Minimum X coordinate of the rectangle.
+ int left;
+
+ /// Minimum Y coordinate of the rectangle.
+ int top;
+
+ /// Maximum X coordinate of the rectangle.
+ int right;
+
+ /// Maximum Y coordinate of the rectangle.
+ int bottom;
+}
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/Rotation.aidl
similarity index 76%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/Rotation.aidl
index 7343515..451ff45 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/Rotation.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * 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.
@@ -16,4 +16,11 @@
package android.gui;
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+/** @hide */
+@Backing(type="int")
+enum Rotation {
+ Rotation0 = 0,
+ Rotation90 = 1,
+ Rotation180 = 2,
+ Rotation270 = 3
+}
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/Size.aidl
similarity index 82%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/Size.aidl
index 7343515..415fa36 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/Size.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * 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.
@@ -16,4 +16,8 @@
package android.gui;
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+/** @hide */
+parcelable Size {
+ int width = -1;
+ int height = -1;
+}
diff --git a/libs/gui/android/gui/FocusRequest.aidl b/libs/gui/android/gui/FocusRequest.aidl
index 9018635..b13c600 100644
--- a/libs/gui/android/gui/FocusRequest.aidl
+++ b/libs/gui/android/gui/FocusRequest.aidl
@@ -21,7 +21,7 @@
/**
* Input channel token used to identify the window that should gain focus.
*/
- IBinder token;
+ @nullable IBinder token;
@utf8InCpp String windowName;
/**
* The token that the caller expects currently to be focused. If the
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 1ed592b..74addea 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -73,7 +73,7 @@
: public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
{
public:
- BLASTBufferQueue(const std::string& name);
+ BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true);
BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
int height, int32_t format);
@@ -100,8 +100,7 @@
void applyPendingTransactions(uint64_t frameNumber);
SurfaceComposerClient::Transaction* gatherPendingTransactions(uint64_t frameNumber);
- void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format,
- SurfaceComposerClient::Transaction* outTransaction = nullptr);
+ void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format);
status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
@@ -218,11 +217,6 @@
std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>>
mPendingTransactions GUARDED_BY(mMutex);
- // Last requested auto refresh state set by the producer. The state indicates that the consumer
- // should acquire the next frame as soon as it can and not wait for a frame to become available.
- // This is only relevant for shared buffer mode.
- bool mAutoRefresh GUARDED_BY(mMutex) = false;
-
std::queue<FrameTimelineInfo> mNextFrameTimelineInfoQueue GUARDED_BY(mMutex);
// Tracks the last acquired frame number
@@ -250,6 +244,12 @@
// Flag to determine if syncTransaction should only acquire a single buffer and then clear or
// continue to acquire buffers until explicitly cleared
bool mAcquireSingleBuffer GUARDED_BY(mMutex) = true;
+
+ // True if BBQ will update the destination frame used to scale the buffer to the requested size.
+ // If false, the caller is responsible for updating the destination frame on the BBQ
+ // surfacecontol. This is useful if the caller wants to synchronize the buffer scale with
+ // additional scales in the hierarchy.
+ bool mUpdateDestinationFrame GUARDED_BY(mMutex) = true;
};
} // namespace android
diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h
new file mode 100644
index 0000000..ec884cf
--- /dev/null
+++ b/libs/gui/include/gui/DisplayCaptureArgs.h
@@ -0,0 +1,71 @@
+/*
+ * 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 <stdint.h>
+#include <sys/types.h>
+
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <ui/GraphicTypes.h>
+#include <ui/PixelFormat.h>
+
+namespace android::gui {
+
+struct CaptureArgs : public Parcelable {
+ const static int32_t UNSET_UID = -1;
+ virtual ~CaptureArgs() = default;
+
+ ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888};
+ Rect sourceCrop;
+ float frameScaleX{1};
+ float frameScaleY{1};
+ bool captureSecureLayers{false};
+ int32_t uid{UNSET_UID};
+ // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured
+ // result will be in the display's colorspace.
+ // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be
+ // different from SRGB (byte per color), and failed when checking colors in tests.
+ // NOTE: In normal cases, we want the screen to be captured in display's colorspace.
+ ui::Dataspace dataspace = ui::Dataspace::UNKNOWN;
+
+ // The receiver of the capture can handle protected buffer. A protected buffer has
+ // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour.
+ // Any read/write access from unprotected context will result in undefined behaviour.
+ // Protected contents are typically DRM contents. This has no direct implication to the
+ // secure property of the surface, which is specified by the application explicitly to avoid
+ // the contents being accessed/captured by screenshot or unsecure display.
+ bool allowProtected = false;
+
+ bool grayscale = false;
+
+ virtual status_t writeToParcel(Parcel* output) const;
+ virtual status_t readFromParcel(const Parcel* input);
+};
+
+struct DisplayCaptureArgs : CaptureArgs {
+ sp<IBinder> displayToken;
+ uint32_t width{0};
+ uint32_t height{0};
+ bool useIdentityTransform{false};
+
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+};
+
+}; // namespace android::gui
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 740d825..cf7a4e5 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -35,6 +35,7 @@
// ----------------------------------------------------------------------------
using gui::IDisplayEventConnection;
+using gui::ParcelableVsyncEventData;
using gui::VsyncEventData;
namespace gui {
@@ -76,16 +77,7 @@
struct VSync {
uint32_t count;
- nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
- nsecs_t deadlineTimestamp __attribute__((aligned(8)));
- nsecs_t frameInterval __attribute__((aligned(8)));
- int64_t vsyncId;
- size_t preferredFrameTimelineIndex __attribute__((aligned(8)));
- struct FrameTimeline {
- nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
- nsecs_t deadlineTimestamp __attribute__((aligned(8)));
- int64_t vsyncId;
- } frameTimelines[VsyncEventData::kFrameTimelinesLength];
+ VsyncEventData vsyncData;
};
struct Hotplug {
@@ -175,7 +167,7 @@
/**
* getLatestVsyncEventData() gets the latest vsync event data.
*/
- status_t getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const;
+ status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const;
private:
sp<IDisplayEventConnection> mEventConnection;
@@ -183,6 +175,11 @@
std::optional<status_t> mInitError;
};
+inline bool operator==(DisplayEventReceiver::Event::FrameRateOverride lhs,
+ DisplayEventReceiver::Event::FrameRateOverride rhs) {
+ return (lhs.uid == rhs.uid) && std::abs(lhs.frameRateHz - rhs.frameRateHz) < 0.001f;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 0a59f52..2e4d6b4 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -58,11 +58,9 @@
struct client_cache_t;
struct ComposerState;
-struct DisplayCaptureArgs;
struct DisplayStatInfo;
struct DisplayState;
struct InputWindowCommands;
-struct LayerCaptureArgs;
class LayerDebugInfo;
class HdrCapabilities;
class IGraphicBufferProducer;
@@ -75,6 +73,13 @@
using gui::IScreenCaptureListener;
using gui::SpHash;
+namespace gui {
+
+struct DisplayCaptureArgs;
+struct LayerCaptureArgs;
+
+} // namespace gui
+
namespace ui {
struct DisplayMode;
@@ -132,40 +137,6 @@
VsyncSource vsyncSource = eVsyncSourceApp,
EventRegistrationFlags eventRegistration = {}) = 0;
- /* create a virtual display
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual sp<IBinder> createDisplay(const String8& displayName,
- bool secure) = 0;
-
- /* destroy a virtual display
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual void destroyDisplay(const sp<IBinder>& display) = 0;
-
- /* get stable IDs for connected physical displays.
- */
- virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
-
- virtual status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const = 0;
-
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- std::optional<PhysicalDisplayId> getInternalDisplayId() const {
- const auto displayIds = getPhysicalDisplayIds();
- return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
- }
-
- /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
- * DisplayEventReceiver hotplug event.
- */
- virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const = 0;
-
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- sp<IBinder> getInternalDisplayToken() const {
- const auto displayId = getInternalDisplayId();
- return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
- }
-
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual status_t setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state,
@@ -189,24 +160,6 @@
virtual status_t getSupportedFrameTimestamps(
std::vector<FrameEvent>* outSupported) const = 0;
- /* set display power mode. depending on the mode, it can either trigger
- * screen on, off or low power mode and wait for it to complete.
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual void setPowerMode(const sp<IBinder>& display, int mode) = 0;
-
-
- /* returns display statistics for a given display
- * intended to be used by the media framework to properly schedule
- * video frames */
- virtual status_t getDisplayStats(const sp<IBinder>& display,
- DisplayStatInfo* stats) = 0;
-
- /**
- * Get transactional state of given display.
- */
- virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0;
-
/**
* Gets immutable information about given physical display.
*/
@@ -227,61 +180,6 @@
*/
virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0;
- /**
- * Clears the user-preferred display mode. The device should now boot in system preferred
- * display mode.
- */
- virtual status_t clearBootDisplayMode(const sp<IBinder>& display) = 0;
-
- /**
- * Gets whether boot time display mode operations are supported on the device.
- *
- * outSupport
- * An output parameter for whether boot time display mode operations are supported.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the output parameter is invalid.
- */
- virtual status_t getBootDisplayModeSupport(bool* outSupport) const = 0;
-
- /**
- * Switches Auto Low Latency Mode on/off on the connected display, if it is
- * available. This should only be called if the display supports Auto Low
- * Latency Mode as reported in #getDynamicDisplayInfo.
- * For more information, see the HDMI 2.1 specification.
- */
- virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) = 0;
-
- /**
- * This will start sending infoframes to the connected display with
- * ContentType=Game (if on=true). This should only be called if the display
- * Game Content Type as reported in #getDynamicDisplayInfo.
- * For more information, see the HDMI 1.4 specification.
- */
- virtual void setGameContentType(const sp<IBinder>& display, bool on) = 0;
-
- /**
- * Capture the specified screen. This requires READ_FRAME_BUFFER
- * permission. This function will fail if there is a secure window on
- * screen and DisplayCaptureArgs.captureSecureLayers is false.
- *
- * This function can capture a subregion (the source crop) of the screen.
- * The subregion can be optionally rotated. It will also be scaled to
- * match the size of the output buffer.
- */
- virtual status_t captureDisplay(const DisplayCaptureArgs&,
- const sp<IScreenCaptureListener>&) = 0;
-
- virtual status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) = 0;
-
- /**
- * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
- * This requires READ_FRAME_BUFFER permission. This function will fail if there
- * is a secure window on screen
- */
- virtual status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) = 0;
-
/* Clears the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.
@@ -360,13 +258,6 @@
*/
virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
- /*
- * Queries whether the given display is a wide color display.
- * Requires the ACCESS_SURFACE_FLINGER permission.
- */
- virtual status_t isWideColorDisplay(const sp<IBinder>& token,
- bool* outIsWideColorDisplay) const = 0;
-
/* Registers a listener to stream median luma updates from SurfaceFlinger.
*
* The sampling area is bounded by both samplingArea and the given stopLayerHandle
@@ -447,65 +338,6 @@
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) = 0;
- /*
- * Gets whether brightness operations are supported on a display.
- *
- * displayToken
- * The token of the display.
- * outSupport
- * An output parameter for whether brightness operations are supported.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the output parameter is invalid.
- */
- virtual status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const = 0;
-
- /*
- * Sets the brightness of a display.
- *
- * displayToken
- * The token of the display whose brightness is set.
- * brightness
- * The DisplayBrightness info to set on the desired display.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the brightness is invalid, or
- * INVALID_OPERATION if brightness operations are not supported.
- */
- virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) = 0;
-
- /*
- * Adds a listener that receives HDR layer information. This is used in combination
- * with setDisplayBrightness to adjust the display brightness depending on factors such
- * as whether or not HDR is in use.
- *
- * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
- */
- virtual status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) = 0;
- /*
- * Removes a listener that was added with addHdrLayerInfoListener.
- *
- * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
- * the listener wasn't registered.
- *
- */
- virtual status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) = 0;
-
- /*
- * Sends a power boost to the composer. This function is asynchronous.
- *
- * boostId
- * boost id according to android::hardware::power::Boost
- *
- * Returns NO_ERROR upon success.
- */
- virtual status_t notifyPowerBoost(int32_t boostId) = 0;
/*
* Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
@@ -612,20 +444,20 @@
CREATE_CONNECTION,
GET_STATIC_DISPLAY_INFO,
CREATE_DISPLAY_EVENT_CONNECTION,
- CREATE_DISPLAY,
- DESTROY_DISPLAY,
- GET_PHYSICAL_DISPLAY_TOKEN,
+ CREATE_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+ DESTROY_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+ GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now.
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
GET_SUPPORTED_FRAME_TIMESTAMPS,
GET_DISPLAY_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
GET_DISPLAY_STATE,
- CAPTURE_DISPLAY,
- CAPTURE_LAYERS,
+ CAPTURE_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+ CAPTURE_LAYERS, // Deprecated. Autogenerated by .aidl now.
CLEAR_ANIMATION_FRAME_STATS,
GET_ANIMATION_FRAME_STATS,
- SET_POWER_MODE,
+ SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_STATS,
GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
@@ -640,22 +472,22 @@
SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
GET_DISPLAYED_CONTENT_SAMPLE,
GET_PROTECTED_CONTENT_SUPPORT,
- IS_WIDE_COLOR_DISPLAY,
+ IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_NATIVE_PRIMARIES,
- GET_PHYSICAL_DISPLAY_IDS,
+ GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now.
ADD_REGION_SAMPLING_LISTENER,
REMOVE_REGION_SAMPLING_LISTENER,
SET_DESIRED_DISPLAY_MODE_SPECS,
GET_DESIRED_DISPLAY_MODE_SPECS,
- GET_DISPLAY_BRIGHTNESS_SUPPORT,
- SET_DISPLAY_BRIGHTNESS,
- CAPTURE_DISPLAY_BY_ID,
- NOTIFY_POWER_BOOST,
+ GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now.
+ SET_DISPLAY_BRIGHTNESS, // Deprecated. Autogenerated by .aidl now.
+ CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now.
+ NOTIFY_POWER_BOOST, // Deprecated. Autogenerated by .aidl now.
SET_GLOBAL_SHADOW_SETTINGS,
GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
- SET_AUTO_LOW_LATENCY_MODE,
- GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
- SET_GAME_CONTENT_TYPE,
+ SET_AUTO_LOW_LATENCY_MODE, // Deprecated. Autogenerated by .aidl now.
+ GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+ SET_GAME_CONTENT_TYPE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
SET_FRAME_RATE,
// Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
@@ -667,18 +499,18 @@
ADD_FPS_LISTENER,
REMOVE_FPS_LISTENER,
OVERRIDE_HDR_TYPES,
- ADD_HDR_LAYER_INFO_LISTENER,
- REMOVE_HDR_LAYER_INFO_LISTENER,
+ ADD_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
+ REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
ON_PULL_ATOM,
ADD_TUNNEL_MODE_ENABLED_LISTENER,
REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
ADD_WINDOW_INFOS_LISTENER,
REMOVE_WINDOW_INFOS_LISTENER,
- GET_PRIMARY_PHYSICAL_DISPLAY_ID,
+ GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_DECORATION_SUPPORT,
- GET_BOOT_DISPLAY_MODE_SUPPORT,
+ GET_BOOT_DISPLAY_MODE_SUPPORT, // Deprecated. Autogenerated by .aidl now.
SET_BOOT_DISPLAY_MODE,
- CLEAR_BOOT_DISPLAY_MODE,
+ CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now.
SET_OVERRIDE_FRAME_RATE,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/LayerCaptureArgs.h b/libs/gui/include/gui/LayerCaptureArgs.h
new file mode 100644
index 0000000..05ff9d5
--- /dev/null
+++ b/libs/gui/include/gui/LayerCaptureArgs.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <stdint.h>
+#include <sys/types.h>
+
+#include <gui/DisplayCaptureArgs.h>
+#include <gui/SpHash.h>
+#include <unordered_set>
+
+namespace android::gui {
+
+struct LayerCaptureArgs : CaptureArgs {
+ sp<IBinder> layerHandle;
+ std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
+ bool childrenOnly{false};
+
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+};
+
+}; // namespace android::gui
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index f720619..885b4ae 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -29,7 +29,9 @@
#include <android/gui/DropInputMode.h>
#include <android/gui/FocusRequest.h>
+#include <gui/DisplayCaptureArgs.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/LayerCaptureArgs.h>
#include <gui/LayerMetadata.h>
#include <gui/SpHash.h>
#include <gui/SurfaceControl.h>
@@ -128,8 +130,13 @@
// Queue up BufferStateLayer buffers instead of dropping the oldest buffer when this flag is
// set. This blocks the client until all the buffers have been presented. If the buffers
// have presentation timestamps, then we may drop buffers.
- eEnableBackpressure = 0x100, // ENABLE_BACKPRESSURE
- eLayerIsDisplayDecoration = 0x200, // DISPLAY_DECORATION
+ eEnableBackpressure = 0x100, // ENABLE_BACKPRESSURE
+ eLayerIsDisplayDecoration = 0x200, // DISPLAY_DECORATION
+ // Ignore any destination frame set on the layer. This is used when the buffer scaling mode
+ // is freeze and the destination frame is applied asynchronously with the buffer submission.
+ // This is needed to maintain compatibility for SurfaceView scaling behavior.
+ // See SurfaceView scaling behavior for more details.
+ eIgnoreDestinationFrame = 0x400,
};
enum {
@@ -370,56 +377,6 @@
bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy,
const char* functionName, bool privileged = false);
-struct CaptureArgs {
- const static int32_t UNSET_UID = -1;
- virtual ~CaptureArgs() = default;
-
- ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888};
- Rect sourceCrop;
- float frameScaleX{1};
- float frameScaleY{1};
- bool captureSecureLayers{false};
- int32_t uid{UNSET_UID};
- // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured
- // result will be in the display's colorspace.
- // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be
- // different from SRGB (byte per color), and failed when checking colors in tests.
- // NOTE: In normal cases, we want the screen to be captured in display's colorspace.
- ui::Dataspace dataspace = ui::Dataspace::UNKNOWN;
-
- // The receiver of the capture can handle protected buffer. A protected buffer has
- // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour.
- // Any read/write access from unprotected context will result in undefined behaviour.
- // Protected contents are typically DRM contents. This has no direct implication to the
- // secure property of the surface, which is specified by the application explicitly to avoid
- // the contents being accessed/captured by screenshot or unsecure display.
- bool allowProtected = false;
-
- bool grayscale = false;
-
- virtual status_t write(Parcel& output) const;
- virtual status_t read(const Parcel& input);
-};
-
-struct DisplayCaptureArgs : CaptureArgs {
- sp<IBinder> displayToken;
- uint32_t width{0};
- uint32_t height{0};
- bool useIdentityTransform{false};
-
- status_t write(Parcel& output) const override;
- status_t read(const Parcel& input) override;
-};
-
-struct LayerCaptureArgs : CaptureArgs {
- sp<IBinder> layerHandle;
- std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
- bool childrenOnly{false};
-
- status_t write(Parcel& output) const override;
- status_t read(const Parcel& input) override;
-};
-
}; // namespace android
#endif // ANDROID_SF_LAYER_STATE_H
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 40d096e..ba9ee6c 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -35,6 +35,10 @@
namespace android {
+namespace gui {
+class ISurfaceComposer;
+} // namespace gui
+
class ISurfaceComposer;
/* This is the same as ProducerListener except that onBuffersDiscarded is
@@ -196,6 +200,7 @@
// Virtual for testing.
virtual sp<ISurfaceComposer> composerService() const;
+ virtual sp<gui::ISurfaceComposer> composerServiceAIDL() const;
virtual nsecs_t now() const;
private:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 25637ef..6c79b5b 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -57,7 +57,9 @@
class ITunnelModeEnabledListener;
class Region;
+using gui::DisplayCaptureArgs;
using gui::IRegionSamplingListener;
+using gui::LayerCaptureArgs;
struct SurfaceControlStats {
SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h
index abac61c..8e99539 100644
--- a/libs/gui/include/gui/VsyncEventData.h
+++ b/libs/gui/include/gui/VsyncEventData.h
@@ -21,52 +21,44 @@
#include <array>
namespace android::gui {
-struct VsyncEventData : public Parcelable {
+// Plain Old Data (POD) vsync data structure. For example, it can be easily used in the
+// DisplayEventReceiver::Event union.
+struct VsyncEventData {
// Max amount of frame timelines is arbitrarily set to be reasonable.
static constexpr int64_t kFrameTimelinesLength = 7;
- // The Vsync Id corresponsing to this vsync event. This will be used to
- // populate ISurfaceComposer::setFrameTimelineVsync and
- // SurfaceComposerClient::setFrameTimelineVsync
- // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array.
- int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
-
- // The deadline in CLOCK_MONOTONIC that the app needs to complete its
- // frame by (both on the CPU and the GPU)
- // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array.
- int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
-
// The current frame interval in ns when this frame was scheduled.
- int64_t frameInterval = 0;
+ int64_t frameInterval;
- struct FrameTimeline : public Parcelable {
- FrameTimeline() = default;
- FrameTimeline(int64_t id, int64_t deadlineTimestamp, int64_t expectedPresentTime)
- : id(id),
- deadlineTimestamp(deadlineTimestamp),
- expectedPresentTime(expectedPresentTime) {}
+ // Index into the frameTimelines that represents the platform's preferred frame timeline.
+ uint32_t preferredFrameTimelineIndex;
+ struct alignas(8) FrameTimeline {
// The Vsync Id corresponsing to this vsync event. This will be used to
// populate ISurfaceComposer::setFrameTimelineVsync and
// SurfaceComposerClient::setFrameTimelineVsync
- int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
+ int64_t vsyncId;
- // The deadline in CLOCK_MONOTONIC that the app needs to complete its
- // frame by (both on the CPU and the GPU)
- int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
+ // The deadline in CLOCK_MONOTONIC in nanos that the app needs to complete its
+ // frame by (both on the CPU and the GPU).
+ int64_t deadlineTimestamp;
- // The anticipated Vsync present time.
- int64_t expectedPresentTime = 0;
+ // The anticipated Vsync presentation time in nanos.
+ int64_t expectedPresentationTime;
+ } frameTimelines[kFrameTimelinesLength]; // Sorted possible frame timelines.
- status_t readFromParcel(const Parcel*) override;
- status_t writeToParcel(Parcel*) const override;
- };
+ // Gets the preferred frame timeline's vsync ID.
+ int64_t preferredVsyncId() const;
- // Sorted possible frame timelines.
- std::array<FrameTimeline, kFrameTimelinesLength> frameTimelines;
+ // Gets the preferred frame timeline's deadline timestamp.
+ int64_t preferredDeadlineTimestamp() const;
- // Index into the frameTimelines that represents the platform's preferred frame timeline.
- size_t preferredFrameTimelineIndex = std::numeric_limits<size_t>::max();
+ // Gets the preferred frame timeline's expected vsync timestamp.
+ int64_t preferredExpectedPresentationTime() const;
+};
+
+struct ParcelableVsyncEventData : public Parcelable {
+ VsyncEventData vsync;
status_t readFromParcel(const Parcel*) override;
status_t writeToParcel(Parcel*) const override;
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index eb64ac9..b9bffaa 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -151,6 +151,33 @@
// clang-format on
};
+ // Flags used to determine configuration of this input window.
+ // Input windows can be configured with two sets of flags: InputFeature (WindowInfo::Feature
+ // defined above), and InputConfig. When adding a new configuration for an input window:
+ // - If you are adding a new flag that's visible and accessible to apps, it should be added
+ // as an InputFeature.
+ // - If you are adding an internal behaviour that is used within the system or shell and is
+ // not exposed to apps, it should be added as an InputConfig.
+ enum class InputConfig : uint32_t {
+ // clang-format off
+ NONE = 0,
+ NOT_VISIBLE = 1 << 0,
+ NOT_FOCUSABLE = 1 << 1,
+ NOT_TOUCHABLE = 1 << 2,
+ PREVENT_SPLITTING = 1 << 3,
+ DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 4,
+ IS_WALLPAPER = 1 << 5,
+ PAUSE_DISPATCHING = 1 << 6,
+ // This flag is set when the window is of a trusted type that is allowed to silently
+ // overlay other windows for the purpose of implementing the secure views feature.
+ // Trusted overlays, such as IME windows, can partly obscure other windows without causing
+ // motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
+ TRUSTED_OVERLAY = 1 << 7,
+ WATCH_OUTSIDE_TOUCH = 1 << 8,
+ SLIPPERY = 1 << 9,
+ // clang-format on
+ };
+
/* These values are filled in by the WM and passed through SurfaceFlinger
* unless specified otherwise.
*/
@@ -164,8 +191,6 @@
// This uniquely identifies the input window.
int32_t id = -1;
std::string name;
- Flags<Flag> flags;
- Type type = Type::UNKNOWN;
std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5);
/* These values are filled in by SurfaceFlinger. */
@@ -198,26 +223,24 @@
* to absolute coordinates by SurfaceFlinger once the frame is computed.
*/
Region touchableRegion;
- bool visible = false;
- bool focusable = false;
- bool hasWallpaper = false;
- bool paused = false;
- /* This flag is set when the window is of a trusted type that is allowed to silently
- * overlay other windows for the purpose of implementing the secure views feature.
- * Trusted overlays, such as IME windows, can partly obscure other windows without causing
- * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
- */
- bool trustedOverlay = false;
+
TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED;
int32_t ownerPid = -1;
int32_t ownerUid = -1;
std::string packageName;
Flags<Feature> inputFeatures;
+ Flags<InputConfig> inputConfig;
int32_t displayId = ADISPLAY_ID_NONE;
InputApplicationInfo applicationInfo;
bool replaceTouchableRegionWithCrop = false;
wp<IBinder> touchableRegionCropHandle;
+ // The window's layout params flags and type set by WM.
+ Type layoutParamsType = Type::UNKNOWN;
+ Flags<Flag> layoutParamsFlags;
+
+ void setInputConfig(Flags<InputConfig> config, bool value);
+
void addTouchableRegion(const Rect& region);
bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
diff --git a/libs/gui/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h
index fa1071a..05ed0a0 100644
--- a/libs/gui/include/private/gui/ComposerService.h
+++ b/libs/gui/include/private/gui/ComposerService.h
@@ -37,7 +37,7 @@
// Users of this class should not retain the value from
// getComposerService() for an extended period.
//
-// (It's not clear that using Singleton is useful here anymore.)
+// (TODO: b/219785927, It's not clear that using Singleton is useful here anymore.)
class ComposerService : public Singleton<ComposerService>
{
sp<ISurfaceComposer> mComposerService;
diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h
new file mode 100644
index 0000000..9a96976
--- /dev/null
+++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <android/gui/ISurfaceComposer.h>
+
+#include <utils/Singleton.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+
+// This holds our connection to the composer service (i.e. SurfaceFlinger).
+// If the remote side goes away, we will re-establish the connection.
+// Users of this class should not retain the value from
+// getComposerService() for an extended period.
+//
+// (TODO: b/219785927, It's not clear that using Singleton is useful here anymore.)
+class ComposerServiceAIDL : public Singleton<ComposerServiceAIDL> {
+ sp<gui::ISurfaceComposer> mComposerService;
+ sp<IBinder::DeathRecipient> mDeathObserver;
+ mutable std::mutex mMutex;
+
+ ComposerServiceAIDL();
+ bool connectLocked();
+ void composerServiceDied();
+ friend class Singleton<ComposerServiceAIDL>;
+
+public:
+ // Get a connection to the Composer Service. This will block until
+ // a connection is established. Returns null if permission is denied.
+ static sp<gui::ISurfaceComposer> getComposerService();
+
+ // the following two methods are moved from ISurfaceComposer.h
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+ std::vector<int64_t> displayIds;
+ binder::Status status = mComposerService->getPhysicalDisplayIds(&displayIds);
+ return (!status.isOk() || displayIds.empty())
+ ? std::nullopt
+ : DisplayId::fromValue<PhysicalDisplayId>(
+ static_cast<uint64_t>(displayIds.front()));
+ }
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId) return nullptr;
+ sp<IBinder> display;
+ binder::Status status =
+ mComposerService->getPhysicalDisplayToken(static_cast<int64_t>(displayId->value),
+ &display);
+ return status.isOk() ? display : nullptr;
+ }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 42a32f3..179bdd7 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -29,6 +29,7 @@
#include <gui/SyncScreenCaptureListener.h>
#include <gui/test/CallbackUtils.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
#include <ui/DisplayMode.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicTypes.h>
@@ -283,13 +284,13 @@
static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
ScreenCaptureResults& captureResults) {
- const auto sf = ComposerService::getComposerService();
+ const auto sf = ComposerServiceAIDL::getComposerService();
SurfaceComposerClient::Transaction().apply(true);
const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- status_t status = sf->captureDisplay(captureArgs, captureListener);
- if (status != NO_ERROR) {
- return status;
+ binder::Status status = sf->captureDisplay(captureArgs, captureListener);
+ if (status.transactionError() != NO_ERROR) {
+ return status.transactionError();
}
captureResults = captureListener->waitForResults();
return captureResults.result;
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index bcd39db..da88463 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -20,9 +20,10 @@
namespace android::test {
#define CHECK_OFFSET(type, member, expected_offset) \
- static_assert((offsetof(type, member) == (expected_offset)), "")
+ static_assert((offsetof(type, member) == (expected_offset)))
TEST(DisplayEventStructLayoutTest, TestEventAlignment) {
+ static_assert(std::is_pod<DisplayEventReceiver::Event::VSync>::value);
CHECK_OFFSET(DisplayEventReceiver::Event, vsync, 24);
CHECK_OFFSET(DisplayEventReceiver::Event, hotplug, 24);
CHECK_OFFSET(DisplayEventReceiver::Event, modeChange, 24);
@@ -32,10 +33,29 @@
CHECK_OFFSET(DisplayEventReceiver::Event::Header, timestamp, 16);
CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0);
- CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8);
- CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16);
- CHECK_OFFSET(DisplayEventReceiver::Event::VSync, frameInterval, 24);
- CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 32);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameInterval, 8);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.preferredFrameTimelineIndex, 16);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines, 24);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].vsyncId, 24);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].deadlineTimestamp,
+ 32);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+ vsyncData.frameTimelines[0].expectedPresentationTime, 40);
+ // Also test the offsets of the last frame timeline. A loop is not used because the non-const
+ // index cannot be used in static_assert.
+ const int lastFrameTimelineOffset = /* Start of array */ 24 +
+ (VsyncEventData::kFrameTimelinesLength - 1) * /* Size of FrameTimeline */ 24;
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+ vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1].vsyncId,
+ lastFrameTimelineOffset);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+ vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1]
+ .deadlineTimestamp,
+ lastFrameTimelineOffset + 8);
+ CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+ vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1]
+ .expectedPresentationTime,
+ lastFrameTimelineOffset + 16);
CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 06a0aca..fcfe21b 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -266,14 +266,8 @@
void populateInputInfo(int width, int height) {
mInputInfo.token = mClientChannel->getConnectionToken();
mInputInfo.name = "Test info";
- mInputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
- mInputInfo.type = WindowInfo::Type::BASE_APPLICATION;
mInputInfo.dispatchingTimeout = 5s;
mInputInfo.globalScaleFactor = 1.0;
- mInputInfo.focusable = true;
- mInputInfo.hasWallpaper = false;
- mInputInfo.paused = false;
-
mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
InputApplicationInfo aInfo;
@@ -750,7 +744,7 @@
// Add non touchable window to fully cover touchable window. Window behind gets touch, but
// with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
- nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
nonTouchableSurface->mInputInfo.ownerUid = 22222;
// Overriding occlusion mode otherwise the touch would be discarded at InputDispatcher by
// the default obscured/untrusted touch filter introduced in S.
@@ -770,8 +764,8 @@
// AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED
std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
- nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
- parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
+ parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
nonTouchableSurface->mInputInfo.ownerUid = 22222;
parentSurface->mInputInfo.ownerUid = 22222;
nonTouchableSurface->showAt(0, 0);
@@ -794,8 +788,8 @@
// the touchable window. Window behind gets touch with no obscured flags.
std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
- nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
- parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
+ parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
nonTouchableSurface->mInputInfo.ownerUid = 22222;
parentSurface->mInputInfo.ownerUid = 22222;
nonTouchableSurface->showAt(0, 0);
@@ -815,7 +809,7 @@
std::unique_ptr<InputSurface> bufferSurface =
InputSurface::makeBufferInputSurface(mComposerClient, 0, 0);
- bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
bufferSurface->mInputInfo.ownerUid = 22222;
surface->showAt(10, 10);
@@ -830,7 +824,7 @@
std::unique_ptr<BlastInputSurface> bufferSurface =
BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
- bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
bufferSurface->mInputInfo.ownerUid = 22222;
surface->showAt(10, 10);
@@ -883,7 +877,7 @@
[&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
surface->showAt(100, 100);
std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
- obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
obscuringSurface->mInputInfo.ownerUid = 22222;
obscuringSurface->showAt(100, 100);
injectTap(101, 101);
@@ -902,7 +896,7 @@
[&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
surface->showAt(100, 100);
std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
- obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+ obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
obscuringSurface->mInputInfo.ownerUid = 22222;
obscuringSurface->showAt(190, 190);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 6056280..e0b86e0 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -20,6 +20,7 @@
#include <SurfaceFlingerProperties.h>
#include <android/gui/IDisplayEventConnection.h>
+#include <android/gui/ISurfaceComposer.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <binder/ProcessState.h>
#include <configstore/Utils.h>
@@ -31,6 +32,7 @@
#include <gui/SyncScreenCaptureListener.h>
#include <inttypes.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
#include <sys/types.h>
#include <ui/BufferQueueDefs.h>
#include <ui/DisplayMode.h>
@@ -205,13 +207,13 @@
static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
ScreenCaptureResults& captureResults) {
- const auto sf = ComposerService::getComposerService();
+ const auto sf = ComposerServiceAIDL::getComposerService();
SurfaceComposerClient::Transaction().apply(true);
const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- status_t status = sf->captureDisplay(captureArgs, captureListener);
- if (status != NO_ERROR) {
- return status;
+ binder::Status status = sf->captureDisplay(captureArgs, captureListener);
+ if (status.transactionError() != NO_ERROR) {
+ return status.transactionError();
}
captureResults = captureListener->waitForResults();
return captureResults.result;
@@ -259,9 +261,7 @@
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
- const sp<IBinder> display = sf->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
DisplayCaptureArgs captureArgs;
@@ -695,12 +695,6 @@
ISurfaceComposer::VsyncSource, ISurfaceComposer::EventRegistrationFlags) override {
return nullptr;
}
- sp<IBinder> createDisplay(const String8& /*displayName*/,
- bool /*secure*/) override { return nullptr; }
- void destroyDisplay(const sp<IBinder>& /*display */) override {}
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override { return NO_ERROR; }
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
const Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
@@ -739,7 +733,6 @@
return NO_ERROR;
}
- void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override {
return NO_ERROR;
}
@@ -747,34 +740,15 @@
ui::DynamicDisplayInfo*) override {
return NO_ERROR;
}
- status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
- return NO_ERROR;
- }
- status_t getDisplayStats(const sp<IBinder>& /*display*/,
- DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
ui::DisplayPrimaries& /*primaries*/) override {
return NO_ERROR;
}
status_t setActiveColorMode(const sp<IBinder>& /*display*/,
ColorMode /*colorMode*/) override { return NO_ERROR; }
- status_t getBootDisplayModeSupport(bool* /*outSupport*/) const override { return NO_ERROR; }
status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override {
return NO_ERROR;
}
- status_t clearBootDisplayMode(const sp<IBinder>& /*display*/) override { return NO_ERROR; }
- void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
- void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
-
- status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override {
- return NO_ERROR;
- }
- status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override {
- return NO_ERROR;
- }
- status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override {
- return NO_ERROR;
- }
status_t clearAnimationFrameStats() override { return NO_ERROR; }
status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
@@ -821,26 +795,6 @@
status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
- status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
- status_t getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
- bool* /*outSupport*/) const override {
- return NO_ERROR;
- }
- status_t setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
- const gui::DisplayBrightness& /*brightness*/) override {
- return NO_ERROR;
- }
-
- status_t addHdrLayerInfoListener(const sp<IBinder>&,
- const sp<gui::IHdrLayerInfoListener>&) override {
- return NO_ERROR;
- }
-
- status_t removeHdrLayerInfoListener(const sp<IBinder>&,
- const sp<gui::IHdrLayerInfoListener>&) override {
- return NO_ERROR;
- }
-
status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
const sp<IBinder>& /*stopLayerHandle*/,
const sp<IRegionSamplingListener>& /*listener*/) override {
@@ -882,7 +836,6 @@
float* /*outAppRequestRefreshRateMax*/) override {
return NO_ERROR;
};
- status_t notifyPowerBoost(int32_t /*boostId*/) override { return NO_ERROR; }
status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/,
float /*lightPosY*/, float /*lightPosZ*/,
@@ -934,6 +887,114 @@
bool mSupportsPresent{true};
};
+class FakeSurfaceComposerAIDL : public gui::ISurfaceComposer {
+public:
+ ~FakeSurfaceComposerAIDL() override {}
+
+ void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; }
+
+ binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/,
+ sp<IBinder>* /*outDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status destroyDisplay(const sp<IBinder>& /*display*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPhysicalDisplayIds(std::vector<int64_t>* /*outDisplayIds*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPhysicalDisplayToken(int64_t /*displayId*/,
+ sp<IBinder>* /*outDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayStats(const sp<IBinder>& /*display*/,
+ gui::DisplayStatInfo* /*outStatInfo*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayState(const sp<IBinder>& /*display*/,
+ gui::DisplayState* /*outState*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getBootDisplayModeSupport(bool* /*outMode*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureDisplay(const DisplayCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureLayers(const LayerCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/,
+ bool* /*outIsWideColorDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
+ bool* /*outSupport*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
+ const gui::DisplayBrightness& /*brightness*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status addHdrLayerInfoListener(
+ const sp<IBinder>& /*displayToken*/,
+ const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status removeHdrLayerInfoListener(
+ const sp<IBinder>& /*displayToken*/,
+ const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status notifyPowerBoost(int /*boostId*/) override { return binder::Status::ok(); }
+
+protected:
+ IBinder* onAsBinder() override { return nullptr; }
+
+private:
+ bool mSupportsPresent{true};
+};
+
class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
public:
explicit FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap) : mFenceMap(fenceMap) {}
diff --git a/libs/gui/tests/VsyncEventData_test.cpp b/libs/gui/tests/VsyncEventData_test.cpp
index a670d42..f114522 100644
--- a/libs/gui/tests/VsyncEventData_test.cpp
+++ b/libs/gui/tests/VsyncEventData_test.cpp
@@ -22,54 +22,37 @@
namespace android {
+using gui::ParcelableVsyncEventData;
using gui::VsyncEventData;
using FrameTimeline = gui::VsyncEventData::FrameTimeline;
namespace test {
-TEST(VsyncEventData, Parcelling) {
- VsyncEventData data;
- data.id = 123;
- data.deadlineTimestamp = 456;
- data.frameInterval = 789;
- data.preferredFrameTimelineIndex = 1;
- FrameTimeline timeline0 = FrameTimeline(1, 2, 3);
- FrameTimeline timeline1 = FrameTimeline(4, 5, 6);
- data.frameTimelines[0] = timeline0;
- data.frameTimelines[1] = timeline1;
+TEST(ParcelableVsyncEventData, Parcelling) {
+ ParcelableVsyncEventData data;
+ data.vsync.frameInterval = 789;
+ data.vsync.preferredFrameTimelineIndex = 1;
+ FrameTimeline timeline0 = FrameTimeline{1, 2, 3};
+ FrameTimeline timeline1 = FrameTimeline{4, 5, 6};
+ data.vsync.frameTimelines[0] = timeline0;
+ data.vsync.frameTimelines[1] = timeline1;
Parcel p;
data.writeToParcel(&p);
p.setDataPosition(0);
- VsyncEventData data2;
+ ParcelableVsyncEventData data2;
data2.readFromParcel(&p);
- ASSERT_EQ(data.id, data2.id);
- ASSERT_EQ(data.deadlineTimestamp, data2.deadlineTimestamp);
- ASSERT_EQ(data.frameInterval, data2.frameInterval);
- ASSERT_EQ(data.preferredFrameTimelineIndex, data2.preferredFrameTimelineIndex);
- for (int i = 0; i < data.frameTimelines.size(); i++) {
- ASSERT_EQ(data.frameTimelines[i].id, data2.frameTimelines[i].id);
- ASSERT_EQ(data.frameTimelines[i].deadlineTimestamp,
- data2.frameTimelines[i].deadlineTimestamp);
- ASSERT_EQ(data.frameTimelines[i].expectedPresentTime,
- data2.frameTimelines[i].expectedPresentTime);
+ ASSERT_EQ(data.vsync.frameInterval, data2.vsync.frameInterval);
+ ASSERT_EQ(data.vsync.preferredFrameTimelineIndex, data2.vsync.preferredFrameTimelineIndex);
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ ASSERT_EQ(data.vsync.frameTimelines[i].vsyncId, data2.vsync.frameTimelines[i].vsyncId);
+ ASSERT_EQ(data.vsync.frameTimelines[i].deadlineTimestamp,
+ data2.vsync.frameTimelines[i].deadlineTimestamp);
+ ASSERT_EQ(data.vsync.frameTimelines[i].expectedPresentationTime,
+ data2.vsync.frameTimelines[i].expectedPresentationTime);
}
}
-TEST(FrameTimeline, Parcelling) {
- FrameTimeline timeline = FrameTimeline(1, 2, 3);
-
- Parcel p;
- timeline.writeToParcel(&p);
- p.setDataPosition(0);
-
- FrameTimeline timeline2;
- timeline2.readFromParcel(&p);
- ASSERT_EQ(timeline.id, timeline2.id);
- ASSERT_EQ(timeline.deadlineTimestamp, timeline2.deadlineTimestamp);
- ASSERT_EQ(timeline.expectedPresentTime, timeline2.expectedPresentTime);
-}
-
} // namespace test
} // namespace android
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index ff3ba2a..ff9bae2 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -49,8 +49,8 @@
i.windowToken = new BBinder();
i.id = 1;
i.name = "Foobar";
- i.flags = WindowInfo::Flag::SLIPPERY;
- i.type = WindowInfo::Type::INPUT_METHOD;
+ i.layoutParamsFlags = WindowInfo::Flag::SLIPPERY;
+ i.layoutParamsType = WindowInfo::Type::INPUT_METHOD;
i.dispatchingTimeout = 12s;
i.frameLeft = 93;
i.frameTop = 34;
@@ -60,15 +60,12 @@
i.globalScaleFactor = 0.3;
i.alpha = 0.7;
i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
- i.visible = false;
- i.focusable = false;
- i.hasWallpaper = false;
- i.paused = false;
i.touchOcclusionMode = TouchOcclusionMode::ALLOW;
i.ownerPid = 19;
i.ownerUid = 24;
i.packageName = "com.example.package";
i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY;
+ i.inputConfig = WindowInfo::InputConfig::NOT_FOCUSABLE;
i.displayId = 34;
i.replaceTouchableRegionWithCrop = true;
i.touchableRegionCropHandle = touchableRegionCropHandle;
@@ -85,8 +82,8 @@
ASSERT_EQ(i.windowToken, i2.windowToken);
ASSERT_EQ(i.id, i2.id);
ASSERT_EQ(i.name, i2.name);
- ASSERT_EQ(i.flags, i2.flags);
- ASSERT_EQ(i.type, i2.type);
+ ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
+ ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout);
ASSERT_EQ(i.frameLeft, i2.frameLeft);
ASSERT_EQ(i.frameTop, i2.frameTop);
@@ -96,15 +93,12 @@
ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
ASSERT_EQ(i.alpha, i2.alpha);
ASSERT_EQ(i.transform, i2.transform);
- ASSERT_EQ(i.visible, i2.visible);
- ASSERT_EQ(i.focusable, i2.focusable);
- ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper);
- ASSERT_EQ(i.paused, i2.paused);
ASSERT_EQ(i.touchOcclusionMode, i2.touchOcclusionMode);
ASSERT_EQ(i.ownerPid, i2.ownerPid);
ASSERT_EQ(i.ownerUid, i2.ownerUid);
ASSERT_EQ(i.packageName, i2.packageName);
ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
+ ASSERT_EQ(i.inputConfig, i2.inputConfig);
ASSERT_EQ(i.displayId, i2.displayId);
ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop);
ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 3073d94..fe1754c 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -846,6 +846,7 @@
return calculateTransformedXYUnchecked(source, transform, xy);
}
+// Keep in sync with calculateTransformedCoords.
float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source,
const ui::Transform& transform,
const PointerCoords& coords) {
@@ -874,6 +875,34 @@
return coords.getAxisValue(axis);
}
+// Keep in sync with calculateTransformedAxisValue. This is an optimization of
+// calculateTransformedAxisValue for all PointerCoords axes.
+PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source,
+ const ui::Transform& transform,
+ const PointerCoords& coords) {
+ if (shouldDisregardTransformation(source)) {
+ return coords;
+ }
+ PointerCoords out = coords;
+
+ const vec2 xy = calculateTransformedXYUnchecked(source, transform, coords.getXYValue());
+ out.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x);
+ out.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y);
+
+ const vec2 relativeXy =
+ transformWithoutTranslation(transform,
+ {coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+ coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)});
+ out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, relativeXy.x);
+ out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, relativeXy.y);
+
+ out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
+ transformAngle(transform,
+ coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)));
+
+ return out;
+}
+
// --- FocusEvent ---
void FocusEvent::initialize(int32_t id, bool hasFocus) {
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index b182a4a..a3eebdd 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -78,7 +78,7 @@
struct FrameCallback {
AChoreographer_frameCallback callback;
AChoreographer_frameCallback64 callback64;
- AChoreographer_extendedFrameCallback extendedCallback;
+ AChoreographer_vsyncCallback vsyncCallback;
void* data;
nsecs_t dueTime;
@@ -103,9 +103,7 @@
struct ChoreographerFrameCallbackDataImpl {
int64_t frameTimeNanos{0};
- std::array<VsyncEventData::FrameTimeline, VsyncEventData::kFrameTimelinesLength> frameTimelines;
-
- size_t preferredFrameTimelineIndex;
+ VsyncEventData vsyncEventData;
const Choreographer* choreographer;
};
@@ -123,7 +121,7 @@
explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock);
void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
AChoreographer_frameCallback64 cb64,
- AChoreographer_extendedFrameCallback extendedCallback, void* data,
+ AChoreographer_vsyncCallback vsyncCallback, void* data,
nsecs_t delay);
void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
EXCLUDES(gChoreographers.lock);
@@ -232,10 +230,10 @@
void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb,
AChoreographer_frameCallback64 cb64,
- AChoreographer_extendedFrameCallback extendedCallback,
- void* data, nsecs_t delay) {
+ AChoreographer_vsyncCallback vsyncCallback, void* data,
+ nsecs_t delay) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- FrameCallback callback{cb, cb64, extendedCallback, data, now + delay};
+ FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay};
{
std::lock_guard<std::mutex> _l{mLock};
mFrameCallbacks.push(callback);
@@ -391,13 +389,13 @@
}
mLastVsyncEventData = vsyncEventData;
for (const auto& cb : callbacks) {
- if (cb.extendedCallback != nullptr) {
+ if (cb.vsyncCallback != nullptr) {
const ChoreographerFrameCallbackDataImpl frameCallbackData =
createFrameCallbackData(timestamp);
mInCallback = true;
- cb.extendedCallback(reinterpret_cast<const AChoreographerFrameCallbackData*>(
- &frameCallbackData),
- cb.data);
+ cb.vsyncCallback(reinterpret_cast<const AChoreographerFrameCallbackData*>(
+ &frameCallbackData),
+ cb.data);
mInCallback = false;
} else if (cb.callback64 != nullptr) {
cb.callback64(timestamp, cb.data);
@@ -450,8 +448,7 @@
ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const {
return {.frameTimeNanos = timestamp,
- .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex,
- .frameTimelines = mLastVsyncEventData.frameTimelines,
+ .vsyncEventData = mLastVsyncEventData,
.choreographer = this};
}
@@ -525,10 +522,9 @@
void* data, uint32_t delayMillis) {
return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis);
}
-void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer,
- AChoreographer_extendedFrameCallback callback,
- void* data) {
- return AChoreographer_postExtendedFrameCallback(choreographer, callback, data);
+void AChoreographer_routePostVsyncCallback(AChoreographer* choreographer,
+ AChoreographer_vsyncCallback callback, void* data) {
+ return AChoreographer_postVsyncCallback(choreographer, callback, data);
}
void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
AChoreographer_refreshRateCallback callback,
@@ -556,9 +552,10 @@
const AChoreographerFrameCallbackData* data, size_t index) {
return AChoreographerFrameCallbackData_getFrameTimelineVsyncId(data, index);
}
-int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos(
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentationTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
- return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(data, index);
+ return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(data,
+ index);
}
int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
@@ -592,9 +589,8 @@
AChoreographer_to_Choreographer(choreographer)
->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis));
}
-void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer,
- AChoreographer_extendedFrameCallback callback,
- void* data) {
+void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
+ AChoreographer_vsyncCallback callback, void* data) {
AChoreographer_to_Choreographer(choreographer)
->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0);
}
@@ -634,7 +630,7 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- return frameCallbackData->frameTimelines.size();
+ return VsyncEventData::kFrameTimelinesLength;
}
size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
const AChoreographerFrameCallbackData* data) {
@@ -642,7 +638,7 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- return frameCallbackData->preferredFrameTimelineIndex;
+ return frameCallbackData->vsyncEventData.preferredFrameTimelineIndex;
}
AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
const AChoreographerFrameCallbackData* data, size_t index) {
@@ -650,17 +646,17 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
- return frameCallbackData->frameTimelines[index].id;
+ LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds");
+ return frameCallbackData->vsyncEventData.frameTimelines[index].vsyncId;
}
-int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
const ChoreographerFrameCallbackDataImpl* frameCallbackData =
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
- return frameCallbackData->frameTimelines[index].expectedPresentTime;
+ LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds");
+ return frameCallbackData->vsyncEventData.frameTimelines[index].expectedPresentationTime;
}
int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
@@ -668,8 +664,8 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
- return frameCallbackData->frameTimelines[index].deadlineTimestamp;
+ LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds");
+ return frameCallbackData->vsyncEventData.frameTimelines[index].deadlineTimestamp;
}
AChoreographer* AChoreographer_create() {
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index d650c26..19be5bd 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -50,9 +50,8 @@
void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
AChoreographer_frameCallback64 callback,
void* data, uint32_t delayMillis);
-void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer,
- AChoreographer_extendedFrameCallback callback,
- void* data);
+void AChoreographer_routePostVsyncCallback(AChoreographer* choreographer,
+ AChoreographer_vsyncCallback callback, void* data);
void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
AChoreographer_refreshRateCallback callback,
void* data);
@@ -67,7 +66,7 @@
const AChoreographerFrameCallbackData* data);
AVsyncId AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId(
const AChoreographerFrameCallbackData* data, size_t index);
-int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos(
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentationTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index);
int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index);
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 6579313..2da10cd 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -7,12 +7,12 @@
AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
AChoreographer_registerRefreshRateCallback; # apex # introduced=30
AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
- AChoreographer_postExtendedFrameCallback; # apex # introduced=33
+ AChoreographer_postVsyncCallback; # apex # introduced=33
AChoreographerFrameCallbackData_getFrameTimeNanos; # apex # introduced=33
AChoreographerFrameCallbackData_getFrameTimelinesLength; # apex # introduced=33
AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # apex # introduced=33
AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # apex # introduced=33
- AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos; # apex # introduced=33
+ AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos; # apex # introduced=33
AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos; # apex # introduced=33
AChoreographer_create; # apex # introduced=30
AChoreographer_destroy; # apex # introduced=30
@@ -35,12 +35,12 @@
android::AChoreographer_routePostFrameCallbackDelayed64*;
android::AChoreographer_routeRegisterRefreshRateCallback*;
android::AChoreographer_routeUnregisterRefreshRateCallback*;
- android::AChoreographer_routePostExtendedFrameCallback*;
+ android::AChoreographer_routePostVsyncCallback*;
android::AChoreographerFrameCallbackData_routeGetFrameTimeNanos*;
android::AChoreographerFrameCallbackData_routeGetFrameTimelinesLength*;
android::AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex*;
android::AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId*;
- android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos*;
+ android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentationTimeNanos*;
android::AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos*;
android::AChoreographer_signalRefreshRateCallbacks*;
android::AChoreographer_getFrameInterval*;
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 2578ee8..576941f 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -353,12 +353,12 @@
return INVALID_OPERATION;
}
- GraphicBuffer* gBuffer = new GraphicBuffer();
+ sp<GraphicBuffer> gBuffer(new GraphicBuffer());
status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount);
if (err != NO_ERROR) {
return err;
}
- *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer);
+ *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer.get());
// Ensure the buffer has a positive ref-count.
AHardwareBuffer_acquire(*outBuffer);
@@ -584,6 +584,8 @@
"HAL and AHardwareBuffer pixel format don't match");
static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I,
"HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010,
+ "HAL and AHardwareBuffer pixel format don't match");
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");
@@ -617,6 +619,7 @@
case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+ case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
return true;
default:
@@ -633,6 +636,7 @@
case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+ case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
return true;
default:
return false;
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 6f1f04d..c35507b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -160,6 +160,14 @@
AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 = 0x23,
/**
+ * YUV P010 format.
+ * Must have an even width and height. Can be accessed in OpenGL
+ * shaders through an external sampler. Does not support mip-maps
+ * cube-maps or multi-layered textures.
+ */
+ AHARDWAREBUFFER_FORMAT_YCbCr_P010 = 0x36,
+
+ /**
* Corresponding formats:
* Vulkan: VK_FORMAT_R8_UNORM
* OpenGL ES: GR_GL_R8
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 2c51ccd..40ba5ad 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -54,6 +54,10 @@
// dataspace, in non-linear space.
mat4 colorTransform = mat4();
+ // If true, and colorTransform is non-identity, most client draw calls can
+ // ignore it. Some draws (e.g. screen decorations) may need it, though.
+ bool deviceHandlesColorTransform = false;
+
// An additional orientation flag to be applied after clipping the output.
// By way of example, this may be used for supporting fullscreen screenshot
// capture of a device in landscape while the buffer is in portrait
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 763b82d..b467b35 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -792,7 +792,7 @@
// setup color filter if necessary
sk_sp<SkColorFilter> displayColorTransform;
- if (display.colorTransform != mat4()) {
+ if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
}
const bool ctModifiesAlpha =
@@ -1107,11 +1107,37 @@
if (imageTextureRef->colorType() == kAlpha_8_SkColorType) {
LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8");
- float matrix[] = { 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, -1, 1 };
- paint.setColorFilter(SkColorFilters::Matrix(matrix));
+
+ // SysUI creates the alpha layer as a coverage layer, which is
+ // appropriate for the DPU. Use a color matrix to convert it to
+ // a mask.
+ // TODO (b/219525258): Handle input as a mask.
+ //
+ // The color matrix will convert A8 pixels with no alpha to
+ // black, as described by this vector. If the display handles
+ // the color transform, we need to invert it to find the color
+ // that will result in black after the DPU applies the transform.
+ SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a
+ if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) {
+ SkM44 colorSpaceMatrix = getSkM44(display.colorTransform);
+ if (colorSpaceMatrix.invert(&colorSpaceMatrix)) {
+ black = colorSpaceMatrix * black;
+ } else {
+ // We'll just have to use 0,0,0 as black, which should
+ // be close to correct.
+ ALOGI("Could not invert colorTransform!");
+ }
+ }
+ SkColorMatrix colorMatrix(0, 0, 0, 0, black[0],
+ 0, 0, 0, 0, black[1],
+ 0, 0, 0, 0, black[2],
+ 0, 0, 0, -1, 1);
+ if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
+ // On the other hand, if the device doesn't handle it, we
+ // have to apply it ourselves.
+ colorMatrix.postConcat(toSkColorMatrix(display.colorTransform));
+ }
+ paint.setColorFilter(SkColorFilters::Matrix(colorMatrix));
}
} else {
ATRACE_NAME("DrawColor");
@@ -1134,8 +1160,8 @@
paint.setBlendMode(SkBlendMode::kSrc);
}
- // A color filter will have been set for an A8 buffer. Do not replace
- // it with the displayColorTransform, which shouldn't affect A8.
+ // An A8 buffer will already have the proper color filter attached to
+ // its paint, including the displayColorTransform as needed.
if (!paint.getColorFilter()) {
paint.setColorFilter(displayColorTransform);
}
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index e197150..add7a94 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -2627,6 +2627,7 @@
const auto r8Buffer = allocateR8Buffer(2, 1);
if (!r8Buffer) {
+ GTEST_SKIP() << "Test is only necessary on devices that support r8";
return;
}
{
@@ -2677,6 +2678,144 @@
expectBufferColor(Rect(0, 0, 1, 1), 0, 0, 0, 255);
expectBufferColor(Rect(1, 0, 2, 1), 0, 255, 0, 255);
}
+
+TEST_P(RenderEngineTest, r8_respects_color_transform) {
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+
+ initializeRenderEngine();
+
+ const auto r8Buffer = allocateR8Buffer(2, 1);
+ if (!r8Buffer) {
+ GTEST_SKIP() << "Test is only necessary on devices that support r8";
+ return;
+ }
+ {
+ uint8_t* pixels;
+ r8Buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+ pixels[0] = 0;
+ pixels[1] = 255;
+ r8Buffer->getBuffer()->unlock();
+ }
+
+ const auto rect = Rect(0, 0, 2, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = rect,
+ .clip = rect,
+ .outputDataspace = ui::Dataspace::SRGB,
+ // Verify that the R8 layer respects the color transform when
+ // deviceHandlesColorTransform is false. This transform converts
+ // pure red to pure green. That will occur when the R8 buffer is
+ // 255. When the R8 buffer is 0, it will still change to black, as
+ // with r8_behaves_as_mask.
+ .colorTransform = mat4(0, 1, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1),
+ .deviceHandlesColorTransform = false,
+ };
+
+ const auto redBuffer = allocateAndFillSourceBuffer(2, 1, ubyte4(255, 0, 0, 255));
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = rect.toFloatRect(),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = redBuffer,
+ },
+ },
+ .alpha = 1.0f,
+ };
+ const renderengine::LayerSettings r8Layer{
+ .geometry.boundaries = rect.toFloatRect(),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = r8Buffer,
+ },
+ },
+ .alpha = 1.0f,
+ };
+
+ std::vector<renderengine::LayerSettings> layers{redLayer, r8Layer};
+ invokeDraw(display, layers);
+
+ expectBufferColor(Rect(0, 0, 1, 1), 0, 0, 0, 255);
+ expectBufferColor(Rect(1, 0, 2, 1), 0, 255, 0, 255);
+}
+
+TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) {
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+
+ initializeRenderEngine();
+
+ const auto r8Buffer = allocateR8Buffer(2, 1);
+ if (!r8Buffer) {
+ GTEST_SKIP() << "Test is only necessary on devices that support r8";
+ return;
+ }
+ {
+ uint8_t* pixels;
+ r8Buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+ pixels[0] = 0;
+ pixels[1] = 255;
+ r8Buffer->getBuffer()->unlock();
+ }
+
+ const auto rect = Rect(0, 0, 2, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = rect,
+ .clip = rect,
+ .outputDataspace = ui::Dataspace::SRGB,
+ // If deviceHandlesColorTransform is true, pixels where the A8
+ // buffer is opaque are unaffected. If the colorTransform is
+ // invertible, pixels where the A8 buffer are transparent have the
+ // inverse applied to them so that the DPU will convert them back to
+ // black. Test with an arbitrary, invertible matrix.
+ .colorTransform = mat4(1, 0, 0, 2,
+ 3, 1, 2, 5,
+ 0, 5, 3, 0,
+ 0, 1, 0, 2),
+ .deviceHandlesColorTransform = true,
+ };
+
+ const auto redBuffer = allocateAndFillSourceBuffer(2, 1, ubyte4(255, 0, 0, 255));
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = rect.toFloatRect(),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = redBuffer,
+ },
+ },
+ .alpha = 1.0f,
+ };
+ const renderengine::LayerSettings r8Layer{
+ .geometry.boundaries = rect.toFloatRect(),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = r8Buffer,
+ },
+ },
+ .alpha = 1.0f,
+ };
+
+ std::vector<renderengine::LayerSettings> layers{redLayer, r8Layer};
+ invokeDraw(display, layers);
+
+ expectBufferColor(Rect(1, 0, 2, 1), 255, 0, 0, 255); // Still red.
+ expectBufferColor(Rect(0, 0, 1, 1), 0, 70, 0, 255);
+}
} // namespace renderengine
} // namespace android
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index ef3ceda..2be98e7 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -55,12 +55,12 @@
return service;
}
-bool SensorPrivacyManager::supportsSensorToggle(int sensor) {
+bool SensorPrivacyManager::supportsSensorToggle(int toggleType, int sensor) {
if (mSupportedCache.find(sensor) == mSupportedCache.end()) {
sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
bool result;
- service->supportsSensorToggle(sensor, &result);
+ service->supportsSensorToggle(toggleType, sensor, &result);
mSupportedCache[sensor] = result;
return result;
}
@@ -80,12 +80,12 @@
}
}
-status_t SensorPrivacyManager::addIndividualSensorPrivacyListener(int userId, int sensor,
+status_t SensorPrivacyManager::addToggleSensorPrivacyListener(
const sp<hardware::ISensorPrivacyListener>& listener)
{
sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
- return service->addIndividualSensorPrivacyListener(userId, sensor, listener)
+ return service->addToggleSensorPrivacyListener(listener)
.transactionError();
}
return UNEXPECTED_NULL;
@@ -100,12 +100,12 @@
}
}
-void SensorPrivacyManager::removeIndividualSensorPrivacyListener(int sensor,
+void SensorPrivacyManager::removeToggleSensorPrivacyListener(
const sp<hardware::ISensorPrivacyListener>& listener)
{
sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
- service->removeIndividualSensorPrivacyListener(sensor, listener);
+ service->removeToggleSensorPrivacyListener(listener);
}
}
@@ -121,24 +121,36 @@
return false;
}
-bool SensorPrivacyManager::isIndividualSensorPrivacyEnabled(int userId, int sensor)
+bool SensorPrivacyManager::isToggleSensorPrivacyEnabled(int sensor)
{
- sp<hardware::ISensorPrivacyManager> service = getService();
+ sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
bool result;
- service->isIndividualSensorPrivacyEnabled(userId, sensor, &result);
+ service->isCombinedToggleSensorPrivacyEnabled(sensor, &result);
return result;
}
// if the SensorPrivacyManager is not available then assume sensor privacy is disabled
return false;
}
-status_t SensorPrivacyManager::isIndividualSensorPrivacyEnabled(int userId, int sensor,
+bool SensorPrivacyManager::isToggleSensorPrivacyEnabled(int toggleType, int sensor)
+{
+ sp<hardware::ISensorPrivacyManager> service = getService();
+ if (service != nullptr) {
+ bool result;
+ service->isToggleSensorPrivacyEnabled(toggleType, sensor, &result);
+ return result;
+ }
+ // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
+ return false;
+}
+
+status_t SensorPrivacyManager::isToggleSensorPrivacyEnabled(int toggleType, int sensor,
bool &returnVal)
{
sp<hardware::ISensorPrivacyManager> service = getService();
if (service != nullptr) {
- binder::Status res = service->isIndividualSensorPrivacyEnabled(userId, sensor, &returnVal);
+ binder::Status res = service->isToggleSensorPrivacyEnabled(toggleType, sensor, &returnVal);
return res.transactionError();
}
// if the SensorPrivacyManager is not available then assume sensor privacy is disabled
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
index 58177d8..eccd54c 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
@@ -20,5 +20,5 @@
* @hide
*/
oneway interface ISensorPrivacyListener {
- void onSensorPrivacyChanged(boolean enabled);
+ void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled);
}
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
index 9564cba..49a1e1e 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -20,23 +20,25 @@
/** @hide */
interface ISensorPrivacyManager {
- boolean supportsSensorToggle(int sensor);
+ boolean supportsSensorToggle(int toggleType, int sensor);
void addSensorPrivacyListener(in ISensorPrivacyListener listener);
- void addIndividualSensorPrivacyListener(int userId, int sensor, in ISensorPrivacyListener listener);
+ void addToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
void removeSensorPrivacyListener(in ISensorPrivacyListener listener);
- void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+ void removeToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
boolean isSensorPrivacyEnabled();
- boolean isIndividualSensorPrivacyEnabled(int userId, int sensor);
+ boolean isCombinedToggleSensorPrivacyEnabled(int sensor);
+
+ boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor);
void setSensorPrivacy(boolean enable);
- void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable);
+ void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable);
- void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
+ void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
}
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index af699d0..fc5fdf7 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -31,22 +31,26 @@
{
public:
enum {
- INDIVIDUAL_SENSOR_MICROPHONE = 1,
- INDIVIDUAL_SENSOR_CAMERA = 2
+ TOGGLE_SENSOR_MICROPHONE = 1,
+ TOGGLE_SENSOR_CAMERA = 2
+ };
+
+ enum {
+ TOGGLE_TYPE_SOFTWARE = 1,
+ TOGGLE_TYPE_HARDWARE = 2
};
SensorPrivacyManager();
- bool supportsSensorToggle(int sensor);
+ bool supportsSensorToggle(int toggleType, int sensor);
void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
- status_t addIndividualSensorPrivacyListener(int userId, int sensor,
- const sp<hardware::ISensorPrivacyListener>& listener);
+ status_t addToggleSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
- void removeIndividualSensorPrivacyListener(int sensor,
- const sp<hardware::ISensorPrivacyListener>& listener);
+ void removeToggleSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
bool isSensorPrivacyEnabled();
- bool isIndividualSensorPrivacyEnabled(int userId, int sensor);
- status_t isIndividualSensorPrivacyEnabled(int userId, int sensor, bool &result);
+ bool isToggleSensorPrivacyEnabled(int sensor);
+ bool isToggleSensorPrivacyEnabled(int toggleType, int sensor);
+ status_t isToggleSensorPrivacyEnabled(int toggleType, int sensor, bool &result);
status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 41e9ce2..9691ad8 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -61,18 +61,13 @@
ALOGE("There is no focused window for %s", applicationHandle->getName().c_str());
}
- void notifyWindowUnresponsive(const sp<IBinder>& connectionToken,
+ void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, std::optional<int32_t> pid,
const std::string& reason) override {
ALOGE("Window is not responding: %s", reason.c_str());
}
- void notifyWindowResponsive(const sp<IBinder>& connectionToken) override {}
-
- void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) override {
- ALOGE("Monitor is not responding: %s", reason.c_str());
- }
-
- void notifyMonitorResponsive(int32_t pid) override {}
+ void notifyWindowResponsive(const sp<IBinder>& connectionToken,
+ std::optional<int32_t> pid) override {}
void notifyInputChannelBroken(const sp<IBinder>&) override {}
@@ -193,7 +188,6 @@
void updateInfo() {
mInfo.token = mClientChannel->getConnectionToken();
mInfo.name = "FakeWindowHandle";
- mInfo.type = WindowInfo::Type::APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
mInfo.frameLeft = mFrame.left;
mInfo.frameTop = mFrame.top;
@@ -202,10 +196,6 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(mFrame);
- mInfo.visible = true;
- mInfo.focusable = true;
- mInfo.hasWallpaper = false;
- mInfo.paused = false;
mInfo.ownerPid = INJECTOR_PID;
mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = ADISPLAY_ID_DEFAULT;
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index 600f02b..a02b3e8 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -148,11 +148,11 @@
continue;
}
windowFound = true;
- if (window->getInfo()->visible) {
+ if (!window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE)) {
// Check if at least a single window is visible.
visibleWindowFound = true;
}
- if (!window->getInfo()->focusable) {
+ if (window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)) {
// Check if all windows with the window token are focusable.
allWindowsAreFocusable = false;
break;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 7062aef..99d23af 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -118,10 +118,7 @@
// when an application takes too long to respond and the user has pressed an app switch key.
constexpr nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
-// Amount of time to allow for an event to be dispatched (measured since its eventTime)
-// before considering it stale and dropping it.
-const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL // 10sec
- * HwTimeoutMultiplier();
+const std::chrono::duration STALE_EVENT_TIMEOUT = std::chrono::seconds(10) * HwTimeoutMultiplier();
// Log a warning when an event takes longer than this to process, even if an ANR does not occur.
constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec
@@ -322,10 +319,6 @@
first->applicationInfo.token == second->applicationInfo.token;
}
-bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
- return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
-}
-
std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
std::shared_ptr<EventEntry> eventEntry,
int32_t inputTargetFlags) {
@@ -500,17 +493,16 @@
// Returns true if the given window can accept pointer events at the given display location.
bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y,
bool isStylus) {
- if (windowInfo.displayId != displayId || !windowInfo.visible) {
+ const auto inputConfig = windowInfo.inputConfig;
+ if (windowInfo.displayId != displayId ||
+ inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
return false;
}
- const auto flags = windowInfo.flags;
const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus();
- if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
+ if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
return false;
}
- const bool isModalWindow = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
- !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL);
- if (!isModalWindow && !windowInfo.touchableRegionContainsPoint(x, y)) {
+ if (!windowInfo.touchableRegionContainsPoint(x, y)) {
return false;
}
return true;
@@ -527,6 +519,10 @@
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
+ : InputDispatcher(policy, STALE_EVENT_TIMEOUT) {}
+
+InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,
+ std::chrono::nanoseconds staleEventTimeout)
: mPolicy(policy),
mPendingEvent(nullptr),
mLastDropReason(DropReason::NOT_DROPPED),
@@ -545,6 +541,7 @@
mMaximumObscuringOpacityForTouch(1.0f),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
+ mStaleEventTimeout(staleEventTimeout),
mLatencyAggregator(),
mLatencyTracker(&mLatencyAggregator) {
mLooper = new Looper(false);
@@ -902,6 +899,10 @@
}
}
+bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
+ return std::chrono::nanoseconds(currentTime - entry.eventTime) >= mStaleEventTimeout;
+}
+
/**
* Return true if the events preceding this incoming motion event should be dropped
* Return false otherwise (the default behaviour)
@@ -1047,7 +1048,8 @@
return windowHandle;
}
- if (addOutsideTargets && info.flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
+ if (addOutsideTargets &&
+ info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) {
touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
BitSet32(0));
}
@@ -1900,7 +1902,8 @@
return InputEventInjectionResult::PERMISSION_DENIED;
}
- if (focusedWindowHandle->getInfo()->paused) {
+ if (focusedWindowHandle->getInfo()->inputConfig.test(
+ WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());
return InputEventInjectionResult::PENDING;
}
@@ -2101,7 +2104,7 @@
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
const WindowInfo& info = *windowHandle->getInfo();
- if (info.paused) {
+ if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Not sending touch event to %s because it is paused",
windowHandle->getName().c_str());
continue;
@@ -2324,13 +2327,16 @@
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
sp<WindowInfoHandle> foregroundWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
- if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) {
+ if (foregroundWindowHandle &&
+ foregroundWindowHandle->getInfo()->inputConfig.test(
+ WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
const std::vector<sp<WindowInfoHandle>>& windowHandles =
getWindowHandlesLocked(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
const WindowInfo* info = windowHandle->getInfo();
if (info->displayId == displayId &&
- windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) {
+ windowHandle->getInfo()->inputConfig.test(
+ WindowInfo::InputConfig::IS_WALLPAPER)) {
tempTouchState
.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED |
@@ -2599,9 +2605,10 @@
}
auto info = windowHandle->getInfo();
auto otherInfo = otherHandle->getInfo();
- if (!otherInfo->visible) {
+ if (otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
return false;
- } else if (otherInfo->alpha == 0 && otherInfo->flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
+ } else if (otherInfo->alpha == 0 &&
+ otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE)) {
// Those act as if they were invisible, so we don't need to flag them.
// We do want to potentially flag touchable windows even if they have 0
// opacity, since they can consume touches and alter the effects of the
@@ -2613,7 +2620,7 @@
// If ownerUid is the same we don't generate occlusion events as there
// is no security boundary within an uid.
return false;
- } else if (otherInfo->trustedOverlay) {
+ } else if (otherInfo->inputConfig.test(gui::WindowInfo::InputConfig::TRUSTED_OVERLAY)) {
return false;
} else if (otherInfo->displayId != info->displayId) {
return false;
@@ -2694,17 +2701,17 @@
std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info,
bool isTouchedWindow) const {
return StringPrintf(INDENT2
- "* %stype=%s, package=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, "
+ "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, "
"frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32
- "], touchableRegion=%s, window={%s}, flags={%s}, inputFeatures={%s}, "
+ "], touchableRegion=%s, window={%s}, inputConfig={%s}, inputFeatures={%s}, "
"hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n",
- isTouchedWindow ? "[TOUCHED] " : "", ftl::enum_string(info->type).c_str(),
- info->packageName.c_str(), info->ownerUid, info->id,
- toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft,
- info->frameTop, info->frameRight, info->frameBottom,
- dumpRegion(info->touchableRegion).c_str(), info->name.c_str(),
- info->flags.string().c_str(), info->inputFeatures.string().c_str(),
- toString(info->token != nullptr), info->applicationInfo.name.c_str(),
+ isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(),
+ info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(),
+ info->alpha, info->frameLeft, info->frameTop, info->frameRight,
+ info->frameBottom, dumpRegion(info->touchableRegion).c_str(),
+ info->name.c_str(), info->inputConfig.string().c_str(),
+ info->inputFeatures.string().c_str(), toString(info->token != nullptr),
+ info->applicationInfo.name.c_str(),
toString(info->applicationInfo.token).c_str());
}
@@ -4421,19 +4428,9 @@
const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform;
for (uint32_t i = 0; i < entry.pointerCount; i++) {
- PointerCoords& pc = entry.pointerCoords[i];
- // Make a copy of the injected coords. We cannot change them in place because some of them
- // are interdependent (for example, X coordinate might depend on the Y coordinate).
- PointerCoords injectedCoords = entry.pointerCoords[i];
-
- BitSet64 bits(injectedCoords.bits);
- while (!bits.isEmpty()) {
- const auto axis = static_cast<int32_t>(bits.clearFirstMarkedBit());
- const float value =
- MotionEvent::calculateTransformedAxisValue(axis, entry.source,
- transformToDisplay, injectedCoords);
- pc.setAxisValue(axis, value);
- }
+ entry.pointerCoords[i] =
+ MotionEvent::calculateTransformedCoords(entry.source, transformToDisplay,
+ entry.pointerCoords[i]);
}
}
@@ -4572,8 +4569,9 @@
if (getInputChannelLocked(handle->getToken()) == nullptr) {
const bool noInputChannel =
info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL);
- const bool canReceiveInput = !info->flags.test(WindowInfo::Flag::NOT_TOUCHABLE) ||
- !info->flags.test(WindowInfo::Flag::NOT_FOCUSABLE);
+ const bool canReceiveInput =
+ !info->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) ||
+ !info->inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE);
if (canReceiveInput && !noInputChannel) {
ALOGV("Window handle %s has no registered input channel",
handle->getName().c_str());
@@ -4644,12 +4642,16 @@
}
// Ensure all spy windows are trusted overlays
- LOG_ALWAYS_FATAL_IF(info.isSpy() && !info.trustedOverlay,
+ LOG_ALWAYS_FATAL_IF(info.isSpy() &&
+ !info.inputConfig.test(
+ WindowInfo::InputConfig::TRUSTED_OVERLAY),
"%s has feature SPY, but is not a trusted overlay.",
window->getName().c_str());
// Ensure all stylus interceptors are trusted overlays
- LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && !info.trustedOverlay,
+ LOG_ALWAYS_FATAL_IF(info.interceptsStylus() &&
+ !info.inputConfig.test(
+ WindowInfo::InputConfig::TRUSTED_OVERLAY),
"%s has feature INTERCEPTS_STYLUS, but is not a trusted overlay.",
window->getName().c_str());
}
@@ -4699,7 +4701,8 @@
// Since we are about to drop the touch, cancel the events for the wallpaper as
// well.
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND &&
- touchedWindow.windowHandle->getInfo()->hasWallpaper) {
+ touchedWindow.windowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();
if (wallpaper != nullptr) {
sp<Connection> wallpaperConnection =
@@ -5194,34 +5197,27 @@
const WindowInfo* windowInfo = windowHandle->getInfo();
dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, "
- "paused=%s, focusable=%s, "
- "hasWallpaper=%s, visible=%s, alpha=%.2f, "
- "flags=%s, type=%s, "
+ "inputConfig=%s, alpha=%.2f, "
"frame=[%d,%d][%d,%d], globalScale=%f, "
"applicationInfo.name=%s, "
"applicationInfo.token=%s, "
"touchableRegion=",
i, windowInfo->name.c_str(), windowInfo->id,
- windowInfo->displayId, toString(windowInfo->paused),
- toString(windowInfo->focusable),
- toString(windowInfo->hasWallpaper),
- toString(windowInfo->visible), windowInfo->alpha,
- windowInfo->flags.string().c_str(),
- ftl::enum_string(windowInfo->type).c_str(),
- windowInfo->frameLeft, windowInfo->frameTop,
- windowInfo->frameRight, windowInfo->frameBottom,
- windowInfo->globalScaleFactor,
+ windowInfo->displayId,
+ windowInfo->inputConfig.string().c_str(),
+ windowInfo->alpha, windowInfo->frameLeft,
+ windowInfo->frameTop, windowInfo->frameRight,
+ windowInfo->frameBottom, windowInfo->globalScaleFactor,
windowInfo->applicationInfo.name.c_str(),
toString(windowInfo->applicationInfo.token).c_str());
dump += dumpRegion(windowInfo->touchableRegion);
dump += StringPrintf(", inputFeatures=%s",
windowInfo->inputFeatures.string().c_str());
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
- "ms, trustedOverlay=%s, hasToken=%s, "
+ "ms, hasToken=%s, "
"touchOcclusionMode=%s\n",
windowInfo->ownerPid, windowInfo->ownerUid,
millis(windowInfo->dispatchingTimeout),
- toString(windowInfo->trustedOverlay),
toString(windowInfo->token != nullptr),
toString(windowInfo->touchOcclusionMode).c_str());
windowInfo->transform.dump(dump, "transform", INDENT4);
@@ -5812,35 +5808,21 @@
}
}
-void InputDispatcher::sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) {
- auto command = [this, pid, reason = std::move(reason)]() REQUIRES(mLock) {
- scoped_unlock unlock(mLock);
- mPolicy->notifyMonitorUnresponsive(pid, reason);
- };
- postCommandLocked(std::move(command));
-}
-
void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token,
+ std::optional<int32_t> pid,
std::string reason) {
- auto command = [this, token, reason = std::move(reason)]() REQUIRES(mLock) {
+ auto command = [this, token, pid, reason = std::move(reason)]() REQUIRES(mLock) {
scoped_unlock unlock(mLock);
- mPolicy->notifyWindowUnresponsive(token, reason);
+ mPolicy->notifyWindowUnresponsive(token, pid, reason);
};
postCommandLocked(std::move(command));
}
-void InputDispatcher::sendMonitorResponsiveCommandLocked(int32_t pid) {
- auto command = [this, pid]() REQUIRES(mLock) {
+void InputDispatcher::sendWindowResponsiveCommandLocked(const sp<IBinder>& token,
+ std::optional<int32_t> pid) {
+ auto command = [this, token, pid]() REQUIRES(mLock) {
scoped_unlock unlock(mLock);
- mPolicy->notifyMonitorResponsive(pid);
- };
- postCommandLocked(std::move(command));
-}
-
-void InputDispatcher::sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) {
- auto command = [this, connectionToken]() REQUIRES(mLock) {
- scoped_unlock unlock(mLock);
- mPolicy->notifyWindowResponsive(connectionToken);
+ mPolicy->notifyWindowResponsive(token, pid);
};
postCommandLocked(std::move(command));
}
@@ -5853,22 +5835,21 @@
void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection,
std::string reason) {
const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
+ std::optional<int32_t> pid;
if (connection.monitor) {
ALOGW("Monitor %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
reason.c_str());
- std::optional<int32_t> pid = findMonitorPidByTokenLocked(connectionToken);
- if (!pid.has_value()) {
- ALOGE("Could not find unresponsive monitor for connection %s",
- connection.inputChannel->getName().c_str());
- return;
+ pid = findMonitorPidByTokenLocked(connectionToken);
+ } else {
+ // The connection is a window
+ ALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
+ reason.c_str());
+ const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken);
+ if (handle != nullptr) {
+ pid = handle->getInfo()->ownerPid;
}
- sendMonitorUnresponsiveCommandLocked(pid.value(), std::move(reason));
- return;
}
- // If not a monitor, must be a window
- ALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
- reason.c_str());
- sendWindowUnresponsiveCommandLocked(connectionToken, std::move(reason));
+ sendWindowUnresponsiveCommandLocked(connectionToken, pid, std::move(reason));
}
/**
@@ -5876,18 +5857,17 @@
*/
void InputDispatcher::processConnectionResponsiveLocked(const Connection& connection) {
const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
+ std::optional<int32_t> pid;
if (connection.monitor) {
- std::optional<int32_t> pid = findMonitorPidByTokenLocked(connectionToken);
- if (!pid.has_value()) {
- ALOGE("Could not find responsive monitor for connection %s",
- connection.inputChannel->getName().c_str());
- return;
+ pid = findMonitorPidByTokenLocked(connectionToken);
+ } else {
+ // The connection is a window
+ const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken);
+ if (handle != nullptr) {
+ pid = handle->getInfo()->ownerPid;
}
- sendMonitorResponsiveCommandLocked(pid.value());
- return;
}
- // If not a monitor, must be a window
- sendWindowResponsiveCommandLocked(connectionToken);
+ sendWindowResponsiveCommandLocked(connectionToken, pid);
}
bool InputDispatcher::afterKeyEventLockedInterruptable(const sp<Connection>& connection,
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index e162c78..3c79c98 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -84,6 +84,8 @@
static constexpr bool kDefaultInTouchMode = true;
explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
+ explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,
+ std::chrono::nanoseconds staleEventTimeout);
~InputDispatcher() override;
void dump(std::string& dump) override;
@@ -471,6 +473,11 @@
*/
std::optional<nsecs_t> mNoFocusedWindowTimeoutTime GUARDED_BY(mLock);
+ // Amount of time to allow for an event to be dispatched (measured since its eventTime)
+ // before considering it stale and dropping it.
+ const std::chrono::nanoseconds mStaleEventTimeout;
+ bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry);
+
bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock);
/**
@@ -503,11 +510,11 @@
*/
void processConnectionResponsiveLocked(const Connection& connection) REQUIRES(mLock);
- void sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) REQUIRES(mLock);
- void sendWindowUnresponsiveCommandLocked(const sp<IBinder>& connectionToken, std::string reason)
+ void sendWindowUnresponsiveCommandLocked(const sp<IBinder>& connectionToken,
+ std::optional<int32_t> pid, std::string reason)
REQUIRES(mLock);
- void sendMonitorResponsiveCommandLocked(int32_t pid) REQUIRES(mLock);
- void sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock);
+ void sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken,
+ std::optional<int32_t> pid) REQUIRES(mLock);
// Optimization: AnrTracker is used to quickly find which connection is due for a timeout next.
// AnrTracker must be kept in-sync with all responsive connection.waitQueues.
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index b63fe10..61e78cc 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -100,7 +100,8 @@
for (const TouchedWindow& window : windows) {
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
if (haveSlipperyForegroundWindow ||
- !window.windowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) {
+ !window.windowHandle->getInfo()->inputConfig.test(
+ WindowInfo::InputConfig::SLIPPERY)) {
return false;
}
haveSlipperyForegroundWindow = true;
@@ -112,7 +113,8 @@
sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows[i];
- if (window.windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) {
+ if (window.windowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
return window.windowHandle;
}
}
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 3c1e637..de0b6da 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -51,30 +51,19 @@
const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) = 0;
/* Notifies the system that a window just became unresponsive. This indicates that ANR
- * should be raised for this window. The window is identified via token.
- * The string reason contains information about the input event that we haven't received
- * a response for.
+ * should be raised for this window. The window can be identified via its input token and the
+ * pid of the owner. The string reason contains information about the input event that we
+ * haven't received a response for.
*/
- virtual void notifyWindowUnresponsive(const sp<IBinder>& token, const std::string& reason) = 0;
- /* Notifies the system that a monitor just became unresponsive. This indicates that ANR
- * should be raised for this monitor. The monitor is identified via its pid.
- * The string reason contains information about the input event that we haven't received
- * a response for.
- */
- virtual void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) = 0;
+ virtual void notifyWindowUnresponsive(const sp<IBinder>& token, std::optional<int32_t> pid,
+ const std::string& reason) = 0;
/* Notifies the system that a window just became responsive. This is only called after the
* window was first marked "unresponsive". This indicates that ANR dialog (if any) should
* no longer should be shown to the user. The window is eligible to cause a new ANR in the
* future.
*/
- virtual void notifyWindowResponsive(const sp<IBinder>& token) = 0;
- /* Notifies the system that a monitor just became responsive. This is only called after the
- * monitor was first marked "unresponsive". This indicates that ANR dialog (if any) should
- * no longer should be shown to the user. The monitor is eligible to cause a new ANR in the
- * future.
- */
- virtual void notifyMonitorResponsive(int32_t pid) = 0;
+ virtual void notifyWindowResponsive(const sp<IBinder>& token, std::optional<int32_t> pid) = 0;
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 51546ce..3bd3275 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -71,6 +71,7 @@
"libstatslog",
"libui",
"libutils",
+ "PlatformProperties",
],
static_libs: [
"libc++fs",
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index a8e9bae..7d30d0c 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -335,12 +335,15 @@
// button will likely wake the device.
// TODO: Use the input device configuration to control this behavior more finely.
uint32_t policyFlags = 0;
+ int32_t displayId = ADISPLAY_ID_NONE;
+ if (getDeviceContext().getAssociatedViewport()) {
+ displayId = getDeviceContext().getAssociatedViewport()->displayId;
+ }
NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(),
- AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
- AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &pointerProperties, &pointerCoords, 0, 0,
+ AINPUT_SOURCE_JOYSTICK, displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE,
+ 0, 0, metaState, buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0,
AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
getListener().notifyMotion(&args);
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index ff3a592..8f5dc9b 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -18,6 +18,8 @@
#include "MultiTouchInputMapper.h"
+#include <android/sysprop/InputProperties.sysprop.h>
+
namespace android {
// --- Constants ---
@@ -29,23 +31,15 @@
MultiTouchMotionAccumulator::MultiTouchMotionAccumulator()
: mCurrentSlot(-1),
- mSlots(nullptr),
- mSlotCount(0),
mUsingSlotsProtocol(false),
mHaveStylus(false) {}
-MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() {
- delete[] mSlots;
-}
-
void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount,
bool usingSlotsProtocol) {
- mSlotCount = slotCount;
mUsingSlotsProtocol = usingSlotsProtocol;
mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
- delete[] mSlots;
- mSlots = new Slot[slotCount];
+ mSlots = std::vector<Slot>(slotCount);
}
void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) {
@@ -74,10 +68,8 @@
}
void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
- if (mSlots) {
- for (size_t i = 0; i < mSlotCount; i++) {
- mSlots[i].clear();
- }
+ for (Slot& slot : mSlots) {
+ slot.clear();
}
mCurrentSlot = initialSlot;
}
@@ -94,68 +86,68 @@
mCurrentSlot = 0;
}
- if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
+ if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) {
if (DEBUG_POINTERS) {
if (newSlot) {
ALOGW("MultiTouch device emitted invalid slot index %d but it "
"should be between 0 and %zd; ignoring this slot.",
- mCurrentSlot, mSlotCount - 1);
+ mCurrentSlot, mSlots.size() - 1);
}
}
} else {
- Slot* slot = &mSlots[mCurrentSlot];
+ Slot& slot = mSlots[mCurrentSlot];
// If mUsingSlotsProtocol is true, it means the raw pointer has axis info of
// ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while
// updating the slot.
if (!mUsingSlotsProtocol) {
- slot->mInUse = true;
+ slot.mInUse = true;
}
switch (rawEvent->code) {
case ABS_MT_POSITION_X:
- slot->mAbsMTPositionX = rawEvent->value;
- warnIfNotInUse(*rawEvent, *slot);
+ slot.mAbsMTPositionX = rawEvent->value;
+ warnIfNotInUse(*rawEvent, slot);
break;
case ABS_MT_POSITION_Y:
- slot->mAbsMTPositionY = rawEvent->value;
- warnIfNotInUse(*rawEvent, *slot);
+ slot.mAbsMTPositionY = rawEvent->value;
+ warnIfNotInUse(*rawEvent, slot);
break;
case ABS_MT_TOUCH_MAJOR:
- slot->mAbsMTTouchMajor = rawEvent->value;
+ slot.mAbsMTTouchMajor = rawEvent->value;
break;
case ABS_MT_TOUCH_MINOR:
- slot->mAbsMTTouchMinor = rawEvent->value;
- slot->mHaveAbsMTTouchMinor = true;
+ slot.mAbsMTTouchMinor = rawEvent->value;
+ slot.mHaveAbsMTTouchMinor = true;
break;
case ABS_MT_WIDTH_MAJOR:
- slot->mAbsMTWidthMajor = rawEvent->value;
+ slot.mAbsMTWidthMajor = rawEvent->value;
break;
case ABS_MT_WIDTH_MINOR:
- slot->mAbsMTWidthMinor = rawEvent->value;
- slot->mHaveAbsMTWidthMinor = true;
+ slot.mAbsMTWidthMinor = rawEvent->value;
+ slot.mHaveAbsMTWidthMinor = true;
break;
case ABS_MT_ORIENTATION:
- slot->mAbsMTOrientation = rawEvent->value;
+ slot.mAbsMTOrientation = rawEvent->value;
break;
case ABS_MT_TRACKING_ID:
if (mUsingSlotsProtocol && rawEvent->value < 0) {
// The slot is no longer in use but it retains its previous contents,
// which may be reused for subsequent touches.
- slot->mInUse = false;
+ slot.mInUse = false;
} else {
- slot->mInUse = true;
- slot->mAbsMTTrackingId = rawEvent->value;
+ slot.mInUse = true;
+ slot.mAbsMTTrackingId = rawEvent->value;
}
break;
case ABS_MT_PRESSURE:
- slot->mAbsMTPressure = rawEvent->value;
+ slot.mAbsMTPressure = rawEvent->value;
break;
case ABS_MT_DISTANCE:
- slot->mAbsMTDistance = rawEvent->value;
+ slot.mAbsMTDistance = rawEvent->value;
break;
case ABS_MT_TOOL_TYPE:
- slot->mAbsMTToolType = rawEvent->value;
- slot->mHaveAbsMTToolType = true;
+ slot.mAbsMTToolType = rawEvent->value;
+ slot.mHaveAbsMTToolType = true;
break;
}
}
@@ -184,28 +176,6 @@
// --- MultiTouchMotionAccumulator::Slot ---
-MultiTouchMotionAccumulator::Slot::Slot() {
- clear();
-}
-
-void MultiTouchMotionAccumulator::Slot::clear() {
- mInUse = false;
- mHaveAbsMTTouchMinor = false;
- mHaveAbsMTWidthMinor = false;
- mHaveAbsMTToolType = false;
- mAbsMTPositionX = 0;
- mAbsMTPositionY = 0;
- mAbsMTTouchMajor = 0;
- mAbsMTTouchMinor = 0;
- mAbsMTWidthMajor = 0;
- mAbsMTWidthMinor = 0;
- mAbsMTOrientation = 0;
- mAbsMTTrackingId = -1;
- mAbsMTPressure = 0;
- mAbsMTDistance = 0;
- mAbsMTToolType = 0;
-}
-
int32_t MultiTouchMotionAccumulator::Slot::getToolType() const {
if (mHaveAbsMTToolType) {
switch (mAbsMTToolType) {
@@ -262,14 +232,14 @@
mHavePointerIds = true;
for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
- const MultiTouchMotionAccumulator::Slot* inSlot =
+ const MultiTouchMotionAccumulator::Slot& inSlot =
mMultiTouchMotionAccumulator.getSlot(inIndex);
- if (!inSlot->isInUse()) {
+ if (!inSlot.isInUse()) {
continue;
}
- if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
- std::optional<int32_t> id = getActiveBitId(*inSlot);
+ if (inSlot.getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
+ std::optional<int32_t> id = getActiveBitId(inSlot);
if (id) {
outState->rawPointerData.canceledIdBits.markBit(id.value());
}
@@ -290,34 +260,38 @@
}
RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
- outPointer.x = inSlot->getX();
- outPointer.y = inSlot->getY();
- outPointer.pressure = inSlot->getPressure();
- outPointer.touchMajor = inSlot->getTouchMajor();
- outPointer.touchMinor = inSlot->getTouchMinor();
- outPointer.toolMajor = inSlot->getToolMajor();
- outPointer.toolMinor = inSlot->getToolMinor();
- outPointer.orientation = inSlot->getOrientation();
- outPointer.distance = inSlot->getDistance();
+ outPointer.x = inSlot.getX();
+ outPointer.y = inSlot.getY();
+ outPointer.pressure = inSlot.getPressure();
+ outPointer.touchMajor = inSlot.getTouchMajor();
+ outPointer.touchMinor = inSlot.getTouchMinor();
+ outPointer.toolMajor = inSlot.getToolMajor();
+ outPointer.toolMinor = inSlot.getToolMinor();
+ outPointer.orientation = inSlot.getOrientation();
+ outPointer.distance = inSlot.getDistance();
outPointer.tiltX = 0;
outPointer.tiltY = 0;
- outPointer.toolType = inSlot->getToolType();
+ outPointer.toolType = inSlot.getToolType();
if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
outPointer.toolType = mTouchButtonAccumulator.getToolType();
if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
}
}
+ if (shouldSimulateStylusWithTouch() &&
+ outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) {
+ outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ }
bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE &&
(mTouchButtonAccumulator.isHovering() ||
- (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0));
+ (mRawPointerAxes.pressure.valid && inSlot.getPressure() <= 0));
outPointer.isHovering = isHovering;
// Assign pointer id using tracking id if available.
if (mHavePointerIds) {
- int32_t trackingId = inSlot->getTrackingId();
+ int32_t trackingId = inSlot.getTrackingId();
int32_t id = -1;
if (trackingId >= 0) {
for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
@@ -385,7 +359,15 @@
}
bool MultiTouchInputMapper::hasStylus() const {
- return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus();
+ return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus() ||
+ shouldSimulateStylusWithTouch();
+}
+
+bool MultiTouchInputMapper::shouldSimulateStylusWithTouch() const {
+ static const bool SIMULATE_STYLUS_WITH_TOUCH =
+ sysprop::InputProperties::simulate_stylus_with_touch().value_or(false);
+ return SIMULATE_STYLUS_WITH_TOUCH &&
+ mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 225ad49..fe8af5d 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -46,29 +46,27 @@
private:
friend class MultiTouchMotionAccumulator;
- bool mInUse;
- bool mHaveAbsMTTouchMinor;
- bool mHaveAbsMTWidthMinor;
- bool mHaveAbsMTToolType;
+ bool mInUse = false;
+ bool mHaveAbsMTTouchMinor = false;
+ bool mHaveAbsMTWidthMinor = false;
+ bool mHaveAbsMTToolType = false;
- int32_t mAbsMTPositionX;
- int32_t mAbsMTPositionY;
- int32_t mAbsMTTouchMajor;
- int32_t mAbsMTTouchMinor;
- int32_t mAbsMTWidthMajor;
- int32_t mAbsMTWidthMinor;
- int32_t mAbsMTOrientation;
- int32_t mAbsMTTrackingId;
- int32_t mAbsMTPressure;
- int32_t mAbsMTDistance;
- int32_t mAbsMTToolType;
+ int32_t mAbsMTPositionX = 0;
+ int32_t mAbsMTPositionY = 0;
+ int32_t mAbsMTTouchMajor = 0;
+ int32_t mAbsMTTouchMinor = 0;
+ int32_t mAbsMTWidthMajor = 0;
+ int32_t mAbsMTWidthMinor = 0;
+ int32_t mAbsMTOrientation = 0;
+ int32_t mAbsMTTrackingId = -1;
+ int32_t mAbsMTPressure = 0;
+ int32_t mAbsMTDistance = 0;
+ int32_t mAbsMTToolType = 0;
- Slot();
- void clear();
+ void clear() { *this = Slot(); }
};
MultiTouchMotionAccumulator();
- ~MultiTouchMotionAccumulator();
void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol);
void reset(InputDeviceContext& deviceContext);
@@ -76,13 +74,15 @@
void finishSync();
bool hasStylus() const;
- inline size_t getSlotCount() const { return mSlotCount; }
- inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }
+ inline size_t getSlotCount() const { return mSlots.size(); }
+ inline const Slot& getSlot(size_t index) const {
+ LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index);
+ return mSlots[index];
+ }
private:
int32_t mCurrentSlot;
- Slot* mSlots;
- size_t mSlotCount;
+ std::vector<Slot> mSlots;
bool mUsingSlotsProtocol;
bool mHaveStylus;
@@ -104,6 +104,14 @@
bool hasStylus() const override;
private:
+ // simulate_stylus_with_touch is a debug mode that converts all finger pointers reported by this
+ // mapper's touchscreen into stylus pointers, and adds SOURCE_STYLUS to the input device.
+ // It is used to simulate stylus events for debugging and testing on a device that does not
+ // support styluses. It can be enabled using
+ // "adb shell setprop persist.debug.input.simulate_stylus_with_touch true",
+ // and requires a reboot to take effect.
+ inline bool shouldSimulateStylusWithTouch() const;
+
// If the slot is in use, return the bit id. Return std::nullopt otherwise.
std::optional<int32_t> getActiveBitId(const MultiTouchMotionAccumulator::Slot& inSlot);
MultiTouchMotionAccumulator mMultiTouchMotionAccumulator;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index f729ba9..c1934ff 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -550,18 +550,15 @@
/**
* Determine which DisplayViewport to use.
- * 1. If display port is specified, return the matching viewport. If matching viewport not
- * found, then return.
+ * 1. If a device has associated display, get the matching viewport.
* 2. Always use the suggested viewport from WindowManagerService for pointers.
- * 3. If a device has associated display, get the matching viewport by either unique id or by
- * the display type (internal or external).
+ * 3. Get the matching viewport by either unique id in idc file or by the display type
+ * (internal or external).
* 4. Otherwise, use a non-display viewport.
*/
std::optional<DisplayViewport> TouchInputMapper::findViewport() {
if (mParameters.hasAssociatedDisplay && mDeviceMode != DeviceMode::UNSCALED) {
- const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
- if (displayPort) {
- // Find the viewport that contains the same port
+ if (getDeviceContext().getAssociatedViewport()) {
return getDeviceContext().getAssociatedViewport();
}
diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp
index 662be80..91be4a3 100644
--- a/services/inputflinger/tests/FocusResolver_test.cpp
+++ b/services/inputflinger/tests/FocusResolver_test.cpp
@@ -37,12 +37,16 @@
bool visible) {
mInfo.token = token;
mInfo.name = name;
- mInfo.visible = visible;
- mInfo.focusable = focusable;
+ setFocusable(focusable);
+ setVisible(visible);
}
- void setFocusable(bool focusable) { mInfo.focusable = focusable; }
- void setVisible(bool visible) { mInfo.visible = visible; }
+ void setFocusable(bool focusable) {
+ mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
+ }
+ void setVisible(bool visible) {
+ mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+ }
};
TEST(FocusResolverTest, SetFocusedWindow) {
@@ -80,6 +84,30 @@
ASSERT_FALSE(changes);
}
+TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) {
+ sp<IBinder> focusableWindowToken = new BBinder();
+ std::vector<sp<WindowInfoHandle>> windows;
+ windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
+ true /* visible */));
+
+ FocusRequest request;
+ request.displayId = 42;
+ request.token = focusableWindowToken;
+ FocusResolver focusResolver;
+ // Focusable window gets focus.
+ request.token = focusableWindowToken;
+ std::optional<FocusResolver::FocusChanges> changes =
+ focusResolver.setFocusedWindow(request, windows);
+ ASSERT_FOCUS_CHANGE(changes, nullptr, focusableWindowToken);
+
+ // Window token of a request is null, focus should be revoked.
+ request.token = NULL;
+ changes = focusResolver.setFocusedWindow(request, windows);
+ ASSERT_EQ(focusableWindowToken, changes->oldFocus);
+ ASSERT_EQ(nullptr, changes->newFocus);
+ ASSERT_FOCUS_CHANGE(changes, focusableWindowToken, nullptr);
+}
+
TEST(FocusResolverTest, SetFocusedMirroredWindow) {
sp<IBinder> focusableWindowToken = new BBinder();
sp<IBinder> invisibleWindowToken = new BBinder();
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 813acd8..3fb406c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -60,6 +60,8 @@
// An arbitrary pid of the gesture monitor window
static constexpr int32_t MONITOR_PID = 2001;
+static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
+
struct PointF {
float x;
float y;
@@ -88,6 +90,8 @@
class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
InputDispatcherConfiguration mConfig;
+ using AnrResult = std::pair<sp<IBinder>, int32_t /*pid*/>;
+
protected:
virtual ~FakeInputDispatcherPolicy() {}
@@ -161,122 +165,71 @@
void assertNotifyNoFocusedWindowAnrWasCalled(
std::chrono::nanoseconds timeout,
const std::shared_ptr<InputApplicationHandle>& expectedApplication) {
+ std::unique_lock lock(mLock);
+ android::base::ScopedLockAssertion assumeLocked(mLock);
std::shared_ptr<InputApplicationHandle> application;
- { // acquire lock
- std::unique_lock lock(mLock);
- android::base::ScopedLockAssertion assumeLocked(mLock);
- ASSERT_NO_FATAL_FAILURE(
- application = getAnrTokenLockedInterruptible(timeout, mAnrApplications, lock));
- } // release lock
+ ASSERT_NO_FATAL_FAILURE(
+ application = getAnrTokenLockedInterruptible(timeout, mAnrApplications, lock));
ASSERT_EQ(expectedApplication, application);
}
void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
- const sp<IBinder>& expectedConnectionToken) {
- sp<IBinder> connectionToken = getUnresponsiveWindowToken(timeout);
- ASSERT_EQ(expectedConnectionToken, connectionToken);
+ const sp<WindowInfoHandle>& window) {
+ LOG_ALWAYS_FATAL_IF(window == nullptr, "window should not be null");
+ assertNotifyWindowUnresponsiveWasCalled(timeout, window->getToken(),
+ window->getInfo()->ownerPid);
}
- void assertNotifyWindowResponsiveWasCalled(const sp<IBinder>& expectedConnectionToken) {
- sp<IBinder> connectionToken = getResponsiveWindowToken();
- ASSERT_EQ(expectedConnectionToken, connectionToken);
+ void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
+ const sp<IBinder>& expectedToken,
+ int32_t expectedPid) {
+ std::unique_lock lock(mLock);
+ android::base::ScopedLockAssertion assumeLocked(mLock);
+ AnrResult result;
+ ASSERT_NO_FATAL_FAILURE(result =
+ getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock));
+ const auto& [token, pid] = result;
+ ASSERT_EQ(expectedToken, token);
+ ASSERT_EQ(expectedPid, pid);
}
- void assertNotifyMonitorUnresponsiveWasCalled(std::chrono::nanoseconds timeout) {
- int32_t pid = getUnresponsiveMonitorPid(timeout);
- ASSERT_EQ(MONITOR_PID, pid);
- }
-
- void assertNotifyMonitorResponsiveWasCalled() {
- int32_t pid = getResponsiveMonitorPid();
- ASSERT_EQ(MONITOR_PID, pid);
- }
-
+ /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */
sp<IBinder> getUnresponsiveWindowToken(std::chrono::nanoseconds timeout) {
std::unique_lock lock(mLock);
android::base::ScopedLockAssertion assumeLocked(mLock);
- return getAnrTokenLockedInterruptible(timeout, mAnrWindowTokens, lock);
+ AnrResult result = getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock);
+ const auto& [token, _] = result;
+ return token;
}
+ void assertNotifyWindowResponsiveWasCalled(const sp<IBinder>& expectedToken,
+ int32_t expectedPid) {
+ std::unique_lock lock(mLock);
+ android::base::ScopedLockAssertion assumeLocked(mLock);
+ AnrResult result;
+ ASSERT_NO_FATAL_FAILURE(
+ result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock));
+ const auto& [token, pid] = result;
+ ASSERT_EQ(expectedToken, token);
+ ASSERT_EQ(expectedPid, pid);
+ }
+
+ /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */
sp<IBinder> getResponsiveWindowToken() {
std::unique_lock lock(mLock);
android::base::ScopedLockAssertion assumeLocked(mLock);
- return getAnrTokenLockedInterruptible(0s, mResponsiveWindowTokens, lock);
- }
-
- int32_t getUnresponsiveMonitorPid(std::chrono::nanoseconds timeout) {
- std::unique_lock lock(mLock);
- android::base::ScopedLockAssertion assumeLocked(mLock);
- return getAnrTokenLockedInterruptible(timeout, mAnrMonitorPids, lock);
- }
-
- int32_t getResponsiveMonitorPid() {
- std::unique_lock lock(mLock);
- android::base::ScopedLockAssertion assumeLocked(mLock);
- return getAnrTokenLockedInterruptible(0s, mResponsiveMonitorPids, lock);
- }
-
- // All three ANR-related callbacks behave the same way, so we use this generic function to wait
- // for a specific container to become non-empty. When the container is non-empty, return the
- // first entry from the container and erase it.
- template <class T>
- T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue<T>& storage,
- std::unique_lock<std::mutex>& lock) REQUIRES(mLock) {
- // If there is an ANR, Dispatcher won't be idle because there are still events
- // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle
- // before checking if ANR was called.
- // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need
- // to provide it some time to act. 100ms seems reasonable.
- std::chrono::duration timeToWait = timeout + 100ms; // provide some slack
- const std::chrono::time_point start = std::chrono::steady_clock::now();
- std::optional<T> token =
- getItemFromStorageLockedInterruptible(timeToWait, storage, lock, mNotifyAnr);
- if (!token.has_value()) {
- ADD_FAILURE() << "Did not receive the ANR callback";
- return {};
- }
-
- const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
- // Ensure that the ANR didn't get raised too early. We can't be too strict here because
- // the dispatcher started counting before this function was called
- if (std::chrono::abs(timeout - waited) > 100ms) {
- ADD_FAILURE() << "ANR was raised too early or too late. Expected "
- << std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()
- << "ms, but waited "
- << std::chrono::duration_cast<std::chrono::milliseconds>(waited).count()
- << "ms instead";
- }
- return *token;
- }
-
- template <class T>
- std::optional<T> getItemFromStorageLockedInterruptible(std::chrono::nanoseconds timeout,
- std::queue<T>& storage,
- std::unique_lock<std::mutex>& lock,
- std::condition_variable& condition)
- REQUIRES(mLock) {
- condition.wait_for(lock, timeout,
- [&storage]() REQUIRES(mLock) { return !storage.empty(); });
- if (storage.empty()) {
- ADD_FAILURE() << "Did not receive the expected callback";
- return std::nullopt;
- }
- T item = storage.front();
- storage.pop();
- return std::make_optional(item);
+ AnrResult result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock);
+ const auto& [token, _] = result;
+ return token;
}
void assertNotifyAnrWasNotCalled() {
std::scoped_lock lock(mLock);
ASSERT_TRUE(mAnrApplications.empty());
- ASSERT_TRUE(mAnrWindowTokens.empty());
- ASSERT_TRUE(mAnrMonitorPids.empty());
- ASSERT_TRUE(mResponsiveWindowTokens.empty())
+ ASSERT_TRUE(mAnrWindows.empty());
+ ASSERT_TRUE(mResponsiveWindows.empty())
<< "ANR was not called, but please also consume the 'connection is responsive' "
"signal";
- ASSERT_TRUE(mResponsiveMonitorPids.empty())
- << "Monitor ANR was not called, but please also consume the 'monitor is responsive'"
- " signal";
}
void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) {
@@ -344,10 +297,8 @@
// ANR handling
std::queue<std::shared_ptr<InputApplicationHandle>> mAnrApplications GUARDED_BY(mLock);
- std::queue<sp<IBinder>> mAnrWindowTokens GUARDED_BY(mLock);
- std::queue<sp<IBinder>> mResponsiveWindowTokens GUARDED_BY(mLock);
- std::queue<int32_t> mAnrMonitorPids GUARDED_BY(mLock);
- std::queue<int32_t> mResponsiveMonitorPids GUARDED_BY(mLock);
+ std::queue<AnrResult> mAnrWindows GUARDED_BY(mLock);
+ std::queue<AnrResult> mResponsiveWindows GUARDED_BY(mLock);
std::condition_variable mNotifyAnr;
std::queue<sp<IBinder>> mBrokenInputChannels GUARDED_BY(mLock);
std::condition_variable mNotifyInputChannelBroken;
@@ -355,32 +306,74 @@
sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false;
+ // All three ANR-related callbacks behave the same way, so we use this generic function to wait
+ // for a specific container to become non-empty. When the container is non-empty, return the
+ // first entry from the container and erase it.
+ template <class T>
+ T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue<T>& storage,
+ std::unique_lock<std::mutex>& lock) REQUIRES(mLock) {
+ // If there is an ANR, Dispatcher won't be idle because there are still events
+ // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle
+ // before checking if ANR was called.
+ // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need
+ // to provide it some time to act. 100ms seems reasonable.
+ std::chrono::duration timeToWait = timeout + 100ms; // provide some slack
+ const std::chrono::time_point start = std::chrono::steady_clock::now();
+ std::optional<T> token =
+ getItemFromStorageLockedInterruptible(timeToWait, storage, lock, mNotifyAnr);
+ if (!token.has_value()) {
+ ADD_FAILURE() << "Did not receive the ANR callback";
+ return {};
+ }
+
+ const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
+ // Ensure that the ANR didn't get raised too early. We can't be too strict here because
+ // the dispatcher started counting before this function was called
+ if (std::chrono::abs(timeout - waited) > 100ms) {
+ ADD_FAILURE() << "ANR was raised too early or too late. Expected "
+ << std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()
+ << "ms, but waited "
+ << std::chrono::duration_cast<std::chrono::milliseconds>(waited).count()
+ << "ms instead";
+ }
+ return *token;
+ }
+
+ template <class T>
+ std::optional<T> getItemFromStorageLockedInterruptible(std::chrono::nanoseconds timeout,
+ std::queue<T>& storage,
+ std::unique_lock<std::mutex>& lock,
+ std::condition_variable& condition)
+ REQUIRES(mLock) {
+ condition.wait_for(lock, timeout,
+ [&storage]() REQUIRES(mLock) { return !storage.empty(); });
+ if (storage.empty()) {
+ ADD_FAILURE() << "Did not receive the expected callback";
+ return std::nullopt;
+ }
+ T item = storage.front();
+ storage.pop();
+ return std::make_optional(item);
+ }
+
void notifyConfigurationChanged(nsecs_t when) override {
std::scoped_lock lock(mLock);
mConfigurationChangedTime = when;
}
- void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, const std::string&) override {
+ void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, std::optional<int32_t> pid,
+ const std::string&) override {
std::scoped_lock lock(mLock);
- mAnrWindowTokens.push(connectionToken);
+ ASSERT_TRUE(pid.has_value());
+ mAnrWindows.push({connectionToken, *pid});
mNotifyAnr.notify_all();
}
- void notifyMonitorUnresponsive(int32_t pid, const std::string&) override {
+ void notifyWindowResponsive(const sp<IBinder>& connectionToken,
+ std::optional<int32_t> pid) override {
std::scoped_lock lock(mLock);
- mAnrMonitorPids.push(pid);
- mNotifyAnr.notify_all();
- }
-
- void notifyWindowResponsive(const sp<IBinder>& connectionToken) override {
- std::scoped_lock lock(mLock);
- mResponsiveWindowTokens.push(connectionToken);
- mNotifyAnr.notify_all();
- }
-
- void notifyMonitorResponsive(int32_t pid) override {
- std::scoped_lock lock(mLock);
- mResponsiveMonitorPids.push(pid);
+ ASSERT_TRUE(pid.has_value());
+ mResponsiveWindows.push({connectionToken, *pid});
mNotifyAnr.notify_all();
}
@@ -493,7 +486,7 @@
void SetUp() override {
mFakePolicy = new FakeInputDispatcherPolicy();
- mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy);
+ mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy, STALE_EVENT_TIMEOUT);
mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
// Start InputDispatcher thread
ASSERT_EQ(OK, mDispatcher->start());
@@ -987,7 +980,6 @@
mInfo.token = *token;
mInfo.id = sId++;
mInfo.name = name;
- mInfo.type = WindowInfo::Type::APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
mInfo.alpha = 1.0;
mInfo.frameLeft = 0;
@@ -998,14 +990,10 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo.visible = true;
- mInfo.focusable = false;
- mInfo.hasWallpaper = false;
- mInfo.paused = false;
mInfo.ownerPid = INJECTOR_PID;
mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = displayId;
- mInfo.trustedOverlay = false;
+ mInfo.inputConfig = WindowInfo::InputConfig::NONE;
}
sp<FakeWindowHandle> clone(
@@ -1017,15 +1005,37 @@
return handle;
}
- void setFocusable(bool focusable) { mInfo.focusable = focusable; }
+ void setTouchable(bool touchable) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, !touchable);
+ }
- void setVisible(bool visible) { mInfo.visible = visible; }
+ void setFocusable(bool focusable) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
+ }
+
+ void setVisible(bool visible) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+ }
void setDispatchingTimeout(std::chrono::nanoseconds timeout) {
mInfo.dispatchingTimeout = timeout;
}
- void setPaused(bool paused) { mInfo.paused = paused; }
+ void setPaused(bool paused) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::PAUSE_DISPATCHING, paused);
+ }
+
+ void setPreventSplitting(bool preventSplitting) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting);
+ }
+
+ void setSlippery(bool slippery) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::SLIPPERY, slippery);
+ }
+
+ void setWatchOutsideTouch(bool watchOutside) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, watchOutside);
+ }
void setAlpha(float alpha) { mInfo.alpha = alpha; }
@@ -1049,17 +1059,19 @@
void setTouchableRegion(const Region& region) { mInfo.touchableRegion = region; }
- void setType(WindowInfo::Type type) { mInfo.type = type; }
+ void setIsWallpaper(bool isWallpaper) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::IS_WALLPAPER, isWallpaper);
+ }
- void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; }
-
- void addFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags |= flags; }
-
- void setFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags = flags; }
+ void setDupTouchToWallpaper(bool hasWallpaper) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, hasWallpaper);
+ }
void setInputFeatures(Flags<WindowInfo::Feature> features) { mInfo.inputFeatures = features; }
- void setTrustedOverlay(bool trustedOverlay) { mInfo.trustedOverlay = trustedOverlay; }
+ void setTrustedOverlay(bool trustedOverlay) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::TRUSTED_OVERLAY, trustedOverlay);
+ }
void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) {
mInfo.transform.set(dsdx, dtdx, dtdy, dsdy);
@@ -1226,6 +1238,8 @@
mInfo.ownerUid = ownerUid;
}
+ int32_t getPid() const { return mInfo.ownerPid; }
+
void destroyReceiver() { mInputReceiver = nullptr; }
int getChannelFd() { return mInputReceiver->getChannelFd(); }
@@ -1540,19 +1554,15 @@
}
/**
- * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues.
- * To ensure that window receives only events that were directly inside of it, add
- * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
- * when finding touched windows.
+ * Calling setInputWindows once should not cause any issues.
* This test serves as a sanity check for the next test, where setInputWindows is
* called twice.
*/
-TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) {
+TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1566,16 +1576,12 @@
/**
* Calling setInputWindows twice, with the same info, should not cause any issues.
- * To ensure that window receives only events that were directly inside of it, add
- * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
- * when finding touched windows.
*/
TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1610,17 +1616,17 @@
* Two windows: A top window, and a wallpaper behind the window.
* Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
* gets ACTION_CANCEL.
- * 1. foregroundWindow <-- has wallpaper (hasWallpaper=true)
- * 2. wallpaperWindow <-- is wallpaper (type=InputWindowInfo::Type::WALLPAPER)
+ * 1. foregroundWindow <-- dup touch to wallpaper
+ * 2. wallpaperWindow <-- is wallpaper
*/
TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> foregroundWindow =
new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
- foregroundWindow->setHasWallpaper(true);
+ foregroundWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
- wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1661,10 +1667,10 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> foregroundWindow =
new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
- foregroundWindow->setHasWallpaper(true);
+ foregroundWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
- wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1705,11 +1711,11 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
- window->setHasWallpaper(true);
+ window->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
- wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1763,19 +1769,17 @@
sp<FakeWindowHandle> leftWindow =
new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
leftWindow->setFrame(Rect(0, 0, 200, 200));
- leftWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL);
- leftWindow->setHasWallpaper(true);
+ leftWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> rightWindow =
new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
rightWindow->setFrame(Rect(200, 0, 400, 200));
- rightWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL);
- rightWindow->setHasWallpaper(true);
+ rightWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
- wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1849,11 +1853,9 @@
sp<FakeWindowHandle> windowLeft =
new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
windowLeft->setFrame(Rect(0, 0, 600, 800));
- windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> windowRight =
new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
windowRight->setFrame(Rect(600, 0, 1200, 800));
- windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -1960,7 +1962,6 @@
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 1200, 800));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2042,11 +2043,9 @@
sp<FakeWindowHandle> windowLeft =
new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
windowLeft->setFrame(Rect(0, 0, 600, 800));
- windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> windowRight =
new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
windowRight->setFrame(Rect(600, 0, 1200, 800));
- windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2152,14 +2151,12 @@
// Add two windows to the display. Their frames are represented in the display space.
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
- firstWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
addWindow(firstWindow);
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window",
ADISPLAY_ID_DEFAULT);
- secondWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
addWindow(secondWindow);
return {std::move(firstWindow), std::move(secondWindow)};
@@ -2302,8 +2299,10 @@
// Create a couple of windows
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ firstWindow->setPreventSplitting(true);
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ secondWindow->setPreventSplitting(true);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2376,17 +2375,13 @@
TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create a non touch modal window that supports split touch
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
- firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- // Create a non touch modal window that supports split touch
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
- secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2448,17 +2443,13 @@
TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create a non touch modal window that supports split touch
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
- firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- // Create a non touch modal window that supports split touch
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
- secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2523,26 +2514,21 @@
sp<FakeWindowHandle> firstWindowInPrimary =
new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
- firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> secondWindowInPrimary =
new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
- secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> mirrorWindowInPrimary =
firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT);
mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
- mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> firstWindowInSecondary =
firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
- firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> secondWindowInSecondary =
secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
- secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Update window info, let it find window handle of second display first.
mDispatcher->setInputWindows(
@@ -2587,26 +2573,21 @@
sp<FakeWindowHandle> firstWindowInPrimary =
new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
- firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> secondWindowInPrimary =
new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
- secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> mirrorWindowInPrimary =
firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT);
mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
- mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> firstWindowInSecondary =
firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
- firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
sp<FakeWindowHandle> secondWindowInSecondary =
secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
- secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Update window info, let it find window handle of second display first.
mDispatcher->setInputWindows(
@@ -2700,17 +2681,13 @@
TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create first non touch modal window that supports split touch
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
- firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- // Create second non touch modal window that supports split touch
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
- secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -3230,9 +3207,9 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ window->setFocusable(false);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- // Window is not focusable.
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
setFocusedWindow(window);
@@ -3240,7 +3217,7 @@
ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher))
<< "Inject key event should return InputEventInjectionResult::TIMED_OUT";
- // window is invalid, so it should not receive any input event.
+ // window is not focusable, so it should not receive any input event.
window->assertNoEvents();
}
@@ -3377,7 +3354,7 @@
sp<FakeWindowHandle> slipperyExitWindow =
new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
- slipperyExitWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SLIPPERY);
+ slipperyExitWindow->setSlippery(true);
// Make sure this one overlaps the bottom window
slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
// Change the owner uid/pid of the window so that it is considered to be occluding the bottom
@@ -3983,14 +3960,10 @@
mUnfocusedWindow =
new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
- // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
- // window.
- mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mFocusedWindow =
new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
- mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -4097,14 +4070,10 @@
std::make_shared<FakeApplicationHandle>();
mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1",
ADISPLAY_ID_DEFAULT);
- // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window.
- // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows.
- mWindow1->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mWindow1->setFrame(Rect(0, 0, 100, 100));
mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2",
ADISPLAY_ID_DEFAULT, mWindow1->getToken());
- mWindow2->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mWindow2->setFrame(Rect(100, 100, 200, 200));
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}});
@@ -4301,9 +4270,6 @@
mWindow->setFrame(Rect(0, 0, 30, 30));
mWindow->setDispatchingTimeout(30ms);
mWindow->setFocusable(true);
- // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
- // window.
- mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
@@ -4393,13 +4359,13 @@
std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN
ASSERT_TRUE(sequenceNum);
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
mWindow->finishEvent(*sequenceNum);
mWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL,
ADISPLAY_ID_DEFAULT, 0 /*flags*/);
ASSERT_TRUE(mDispatcher->waitForIdle());
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
}
// Send a key to the app and have the app not respond right away.
@@ -4409,7 +4375,7 @@
std::optional<uint32_t> sequenceNum = mWindow->receiveEvent();
ASSERT_TRUE(sequenceNum);
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
ASSERT_TRUE(mDispatcher->waitForIdle());
}
@@ -4439,6 +4405,38 @@
ASSERT_TRUE(mDispatcher->waitForIdle());
}
+/**
+ * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
+ * there will not be an ANR.
+ */
+TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
+ mWindow->setFocusable(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
+ mWindow->consumeFocusEvent(false);
+
+ KeyEvent event;
+ const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
+ std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
+
+ // Define a valid key down event that is stale (too old).
+ event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+ INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A,
+ AMETA_NONE, 1 /*repeatCount*/, eventTime, eventTime);
+
+ const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
+
+ InputEventInjectionResult result =
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::WAIT_FOR_RESULT,
+ INJECT_EVENT_TIMEOUT, policyFlags);
+ ASSERT_EQ(InputEventInjectionResult::FAILED, result)
+ << "Injection should fail because the event is stale";
+
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ mFakePolicy->assertNotifyAnrWasNotCalled();
+ mWindow->assertNoEvents();
+}
+
// We have a focused application, but no focused window
// Make sure that we don't notify policy twice about the same ANR.
TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
@@ -4514,7 +4512,7 @@
// We have now sent down and up. Let's consume first event and then ANR on the second.
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
}
// A spy window can receive an ANR
@@ -4529,13 +4527,13 @@
std::optional<uint32_t> sequenceNum = spy->receiveEvent(); // ACTION_DOWN
ASSERT_TRUE(sequenceNum);
const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
spy->finishEvent(*sequenceNum);
spy->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT,
0 /*flags*/);
ASSERT_TRUE(mDispatcher->waitForIdle());
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
}
// If an app is not responding to a key event, spy windows should continue to receive
@@ -4550,7 +4548,7 @@
// Stuck on the ACTION_UP
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
// New tap will go to the spy window, but not to the window
tapOnWindow();
@@ -4559,7 +4557,7 @@
mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
mDispatcher->waitForIdle();
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
mWindow->assertNoEvents();
spy->assertNoEvents();
}
@@ -4576,7 +4574,7 @@
mWindow->consumeMotionDown();
// Stuck on the ACTION_UP
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
// New tap will go to the spy window, but not to the window
tapOnWindow();
@@ -4585,7 +4583,7 @@
mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
mDispatcher->waitForIdle();
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
mWindow->assertNoEvents();
spy->assertNoEvents();
}
@@ -4603,13 +4601,13 @@
const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
ASSERT_TRUE(consumeSeq);
- mFakePolicy->assertNotifyMonitorUnresponsiveWasCalled(30ms);
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(30ms, monitor.getToken(), MONITOR_PID);
monitor.finishEvent(*consumeSeq);
monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
ASSERT_TRUE(mDispatcher->waitForIdle());
- mFakePolicy->assertNotifyMonitorResponsiveWasCalled();
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
}
// If a window is unresponsive, then you get anr. if the window later catches up and starts to
@@ -4624,19 +4622,19 @@
mWindow->consumeMotionDown();
// Block on ACTION_UP
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
mWindow->consumeMotionUp(); // Now the connection should be healthy again
mDispatcher->waitForIdle();
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
mWindow->assertNoEvents();
tapOnWindow();
mWindow->consumeMotionDown();
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
mWindow->consumeMotionUp();
mDispatcher->waitForIdle();
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
mFakePolicy->assertNotifyAnrWasNotCalled();
mWindow->assertNoEvents();
}
@@ -4649,7 +4647,7 @@
WINDOW_LOCATION));
const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
std::this_thread::sleep_for(windowTimeout);
// 'notifyConnectionUnresponsive' should only be called once per connection
mFakePolicy->assertNotifyAnrWasNotCalled();
@@ -4659,7 +4657,7 @@
ADISPLAY_ID_DEFAULT, 0 /*flags*/);
mWindow->assertNoEvents();
mDispatcher->waitForIdle();
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
mFakePolicy->assertNotifyAnrWasNotCalled();
}
@@ -4751,18 +4749,13 @@
mUnfocusedWindow =
new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT);
mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
- // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
- // window.
// Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
- mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL |
- WindowInfo::Flag::WATCH_OUTSIDE_TOUCH |
- WindowInfo::Flag::SPLIT_TOUCH);
+ mUnfocusedWindow->setWatchOutsideTouch(true);
mFocusedWindow =
new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT);
mFocusedWindow->setDispatchingTimeout(30ms);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
- mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
@@ -4826,7 +4819,7 @@
const std::chrono::duration timeout =
mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
// Because we injected two DOWN events in a row, CANCEL is enqueued for the first event
// sequence to make it consistent
mFocusedWindow->consumeMotionCancel();
@@ -4837,7 +4830,8 @@
mFocusedWindow->assertNoEvents();
mUnfocusedWindow->assertNoEvents();
ASSERT_TRUE(mDispatcher->waitForIdle());
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
+ mFocusedWindow->getPid());
mFakePolicy->assertNotifyAnrWasNotCalled();
}
@@ -4851,8 +4845,9 @@
tapOnFocusedWindow();
// we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
- sp<IBinder> anrConnectionToken1 = mFakePolicy->getUnresponsiveWindowToken(10ms);
- sp<IBinder> anrConnectionToken2 = mFakePolicy->getUnresponsiveWindowToken(0ms);
+ sp<IBinder> anrConnectionToken1, anrConnectionToken2;
+ ASSERT_NO_FATAL_FAILURE(anrConnectionToken1 = mFakePolicy->getUnresponsiveWindowToken(10ms));
+ ASSERT_NO_FATAL_FAILURE(anrConnectionToken2 = mFakePolicy->getUnresponsiveWindowToken(0ms));
// We don't know which window will ANR first. But both of them should happen eventually.
ASSERT_TRUE(mFocusedWindow->getToken() == anrConnectionToken1 ||
@@ -4867,8 +4862,9 @@
mFocusedWindow->consumeMotionUp();
mUnfocusedWindow->consumeMotionOutside();
- sp<IBinder> responsiveToken1 = mFakePolicy->getResponsiveWindowToken();
- sp<IBinder> responsiveToken2 = mFakePolicy->getResponsiveWindowToken();
+ sp<IBinder> responsiveToken1, responsiveToken2;
+ ASSERT_NO_FATAL_FAILURE(responsiveToken1 = mFakePolicy->getResponsiveWindowToken());
+ ASSERT_NO_FATAL_FAILURE(responsiveToken2 = mFakePolicy->getResponsiveWindowToken());
// Both applications should be marked as responsive, in any order
ASSERT_TRUE(mFocusedWindow->getToken() == responsiveToken1 ||
@@ -4892,7 +4888,7 @@
ASSERT_TRUE(upEventSequenceNum);
const std::chrono::duration timeout =
mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
// Tap once again
// We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
@@ -4913,7 +4909,8 @@
// The second tap did not go to the focused window
mFocusedWindow->assertNoEvents();
// Since all events are finished, connection should be deemed healthy again
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
+ mFocusedWindow->getPid());
mFakePolicy->assertNotifyAnrWasNotCalled();
}
@@ -5025,7 +5022,7 @@
const std::chrono::duration timeout =
mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
mUnfocusedWindow->consumeMotionDown();
mFocusedWindow->consumeMotionDown();
@@ -5044,7 +5041,8 @@
ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
}
ASSERT_TRUE(mDispatcher->waitForIdle());
- mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
+ mFocusedWindow->getPid());
mUnfocusedWindow->assertNoEvents();
mFocusedWindow->assertNoEvents();
@@ -5496,7 +5494,7 @@
sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, TouchOcclusionMode mode,
float alpha = 1.0f) {
sp<FakeWindowHandle> window = getWindow(uid, name);
- window->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ window->setTouchable(false);
window->setTouchOcclusionMode(mode);
window->setAlpha(alpha);
return window;
@@ -5610,7 +5608,7 @@
WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
const sp<FakeWindowHandle>& w =
getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
- w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ w->setWatchOutsideTouch(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
touch();
@@ -5621,7 +5619,7 @@
TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
const sp<FakeWindowHandle>& w =
getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
- w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ w->setWatchOutsideTouch(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
touch();
@@ -5871,11 +5869,9 @@
mApp = std::make_shared<FakeApplicationHandle>();
mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFrame(Rect(0, 0, 100, 100));
- mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFrame(Rect(100, 0, 200, 100));
- mSecondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
@@ -6130,7 +6126,7 @@
ADISPLAY_ID_DEFAULT);
obscuringWindow->setFrame(Rect(0, 0, 50, 50));
obscuringWindow->setOwnerInfo(111, 111);
- obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ obscuringWindow->setTouchable(false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
@@ -6176,7 +6172,7 @@
ADISPLAY_ID_DEFAULT);
obscuringWindow->setFrame(Rect(0, 0, 50, 50));
obscuringWindow->setOwnerInfo(111, 111);
- obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ obscuringWindow->setTouchable(false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
@@ -6282,7 +6278,7 @@
class InputDispatcherSpyWindowTest : public InputDispatcherTest {
public:
- sp<FakeWindowHandle> createSpy(const Flags<WindowInfo::Flag> flags) {
+ sp<FakeWindowHandle> createSpy() {
std::shared_ptr<FakeApplicationHandle> application =
std::make_shared<FakeApplicationHandle>();
std::string name = "Fake Spy ";
@@ -6291,7 +6287,6 @@
new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT);
spy->setInputFeatures(WindowInfo::Feature::SPY);
spy->setTrustedOverlay(true);
- spy->addFlags(flags);
return spy;
}
@@ -6300,7 +6295,6 @@
std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
- window->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
window->setFocusable(true);
return window;
}
@@ -6316,7 +6310,7 @@
TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
ScopedSilentDeath _silentDeath;
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
spy->setTrustedOverlay(false);
ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}),
".* not a trusted overlay");
@@ -6326,7 +6320,7 @@
* Input injection into a display with a spy window but no foreground windows should succeed.
*/
TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6349,9 +6343,9 @@
*/
TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
auto window = createForeground();
- auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
- auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
- auto spy3 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy1 = createSpy();
+ auto spy2 = createSpy();
+ auto spy3 = createSpy();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window, spy3}}});
const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
const size_t numChannels = channels.size();
@@ -6402,7 +6396,8 @@
*/
TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
auto window = createForeground();
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCHABLE);
+ auto spy = createSpy();
+ spy->setTouchable(false);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6419,7 +6414,7 @@
*/
TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
auto window = createForeground();
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
spy->setTouchableRegion(Region{{0, 0, 20, 20}});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -6445,32 +6440,14 @@
}
/**
- * A spy window that is a modal window will receive gestures outside of its frame and touchable
- * region.
- */
-TEST_F(InputDispatcherSpyWindowTest, ModalWindow) {
- auto window = createForeground();
- auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
- // This spy window does not have the NOT_TOUCH_MODAL flag set.
- spy->setFrame(Rect{0, 0, 20, 20});
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
-
- // Inject an event outside the spy window's frame and touchable region.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionDown();
- spy->consumeMotionDown();
-}
-
-/**
* A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
* flag, but it will get zero-ed out coordinates if the foreground has a different owner.
*/
TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
auto window = createForeground();
window->setOwnerInfo(12, 34);
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ auto spy = createSpy();
+ spy->setWatchOutsideTouch(true);
spy->setOwnerInfo(56, 78);
spy->setFrame(Rect{0, 0, 20, 20});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -6490,8 +6467,8 @@
*/
TEST_F(InputDispatcherSpyWindowTest, PilferPointers) {
auto window = createForeground();
- auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
- auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy1 = createSpy();
+ auto spy2 = createSpy();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6523,7 +6500,7 @@
*/
TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) {
auto window = createForeground();
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6547,9 +6524,8 @@
* the spy, but not to any other windows.
*/
TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) {
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ auto spy = createSpy();
auto window = createForeground();
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -6615,7 +6591,7 @@
windowLeft->setFrame({0, 0, 100, 200});
auto windowRight = createForeground();
windowRight->setFrame({100, 0, 200, 200});
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spy = createSpy();
spy->setFrame({0, 0, 200, 200});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}});
@@ -6650,7 +6626,7 @@
TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
auto window = createForeground();
window->setFrame({0, 0, 200, 200});
- auto spyRight = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ auto spyRight = createSpy();
spyRight->setFrame({100, 0, 200, 200});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}});
@@ -6683,15 +6659,13 @@
* windows should be allowed to control split touch.
*/
TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
- // Create a touch modal spy that spies on the entire display.
- // This spy window does not set the SPLIT_TOUCH flag. However, we still expect to split touches
+ // This spy window prevents touch splitting. However, we still expect to split touches
// because a foreground window has not disabled splitting.
- auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+ auto spy = createSpy();
+ spy->setPreventSplitting(true);
- // Create a non touch modal window that supports split touch.
auto window = createForeground();
window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -6729,7 +6703,7 @@
* do not receive key events.
*/
TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
- auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+ auto spy = createSpy();
spy->setFocusable(false);
auto window = createForeground();
@@ -6758,7 +6732,7 @@
ADISPLAY_ID_DEFAULT);
overlay->setFocusable(false);
overlay->setOwnerInfo(111, 111);
- overlay->setFlags(WindowInfo::Flag::NOT_TOUCHABLE | WindowInfo::Flag::SPLIT_TOUCH);
+ overlay->setTouchable(false);
overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS);
overlay->setTrustedOverlay(true);
@@ -6769,7 +6743,6 @@
ADISPLAY_ID_DEFAULT);
window->setFocusable(true);
window->setOwnerInfo(222, 222);
- window->setFlags(WindowInfo::Flag::SPLIT_TOUCH);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 54cf15d..9f33d23 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -20,6 +20,7 @@
#include <InputReader.h>
#include <InputReaderBase.h>
#include <InputReaderFactory.h>
+#include <JoystickInputMapper.h>
#include <KeyboardInputMapper.h>
#include <MultiTouchInputMapper.h>
#include <PeripheralController.h>
@@ -8251,6 +8252,25 @@
ASSERT_EQ(DISPLAY_ID, args.displayId);
}
+TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayUniqueId) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareAxes(POSITION);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, VIRTUAL_DISPLAY_UNIQUE_ID);
+
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareVirtualDisplay(DISPLAY_ORIENTATION_0);
+
+ // Send a touch event
+ processPosition(mapper, 100, 100);
+ processSync(mapper);
+
+ NotifyMotionArgs args;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(VIRTUAL_DISPLAY_ID, args.displayId);
+}
+
TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
// Setup for second display.
std::shared_ptr<FakePointerController> fakePointerController =
@@ -9260,6 +9280,67 @@
ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
}
+// --- JoystickInputMapperTest ---
+
+class JoystickInputMapperTest : public InputMapperTest {
+protected:
+ static const int32_t RAW_X_MIN;
+ static const int32_t RAW_X_MAX;
+ static const int32_t RAW_Y_MIN;
+ static const int32_t RAW_Y_MAX;
+
+ void SetUp() override {
+ InputMapperTest::SetUp(InputDeviceClass::JOYSTICK | InputDeviceClass::EXTERNAL);
+ }
+ void prepareAxes() {
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+ }
+
+ void processAxis(JoystickInputMapper& mapper, int32_t axis, int32_t value) {
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, axis, value);
+ }
+
+ void processSync(JoystickInputMapper& mapper) {
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ }
+
+ void prepareVirtualDisplay(int32_t orientation) {
+ setDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
+ VIRTUAL_DISPLAY_HEIGHT, orientation, VIRTUAL_DISPLAY_UNIQUE_ID,
+ NO_PORT, ViewportType::VIRTUAL);
+ }
+};
+
+const int32_t JoystickInputMapperTest::RAW_X_MIN = -32767;
+const int32_t JoystickInputMapperTest::RAW_X_MAX = 32767;
+const int32_t JoystickInputMapperTest::RAW_Y_MIN = -32767;
+const int32_t JoystickInputMapperTest::RAW_Y_MAX = 32767;
+
+TEST_F(JoystickInputMapperTest, Configure_AssignsDisplayUniqueId) {
+ prepareAxes();
+ JoystickInputMapper& mapper = addMapperAndConfigure<JoystickInputMapper>();
+
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, VIRTUAL_DISPLAY_UNIQUE_ID);
+
+ prepareVirtualDisplay(DISPLAY_ORIENTATION_0);
+
+ // Send an axis event
+ processAxis(mapper, ABS_X, 100);
+ processSync(mapper);
+
+ NotifyMotionArgs args;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(VIRTUAL_DISPLAY_ID, args.displayId);
+
+ // Send another axis event
+ processAxis(mapper, ABS_Y, 100);
+ processSync(mapper);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(VIRTUAL_DISPLAY_ID, args.displayId);
+}
+
// --- PeripheralControllerTest ---
class PeripheralControllerTest : public testing::Test {
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 971491d..3c164aa 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -134,6 +134,7 @@
mWakeLockAcquired(false), mLastReportedProxIsActive(false) {
mUidPolicy = new UidPolicy(this);
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
+ mMicSensorPrivacyPolicy = new MicrophonePrivacyPolicy(this);
}
bool SensorService::initializeHmacKey() {
@@ -369,6 +370,9 @@
// Start watching sensor privacy changes
mSensorPrivacyPolicy->registerSelf();
+
+ // Start watching mic sensor privacy changes
+ mMicSensorPrivacyPolicy->registerSelf();
}
}
}
@@ -439,9 +443,7 @@
}
mUidPolicy->unregisterSelf();
mSensorPrivacyPolicy->unregisterSelf();
- for (auto const& [userId, policy] : mMicSensorPrivacyPolicies) {
- policy->unregisterSelf();
- }
+ mMicSensorPrivacyPolicy->unregisterSelf();
}
status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -773,33 +775,25 @@
checkAndReportProxStateChangeLocked();
}
-void SensorService::capRates(userid_t userId) {
+void SensorService::capRates() {
ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
- if (conn->getUserId() == userId) {
- conn->onMicSensorAccessChanged(true);
- }
+ conn->onMicSensorAccessChanged(true);
}
for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
- if (conn->getUserId() == userId) {
- conn->onMicSensorAccessChanged(true);
- }
+ conn->onMicSensorAccessChanged(true);
}
}
-void SensorService::uncapRates(userid_t userId) {
+void SensorService::uncapRates() {
ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
- if (conn->getUserId() == userId) {
- conn->onMicSensorAccessChanged(false);
- }
+ conn->onMicSensorAccessChanged(false);
}
for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
- if (conn->getUserId() == userId) {
- conn->onMicSensorAccessChanged(false);
- }
+ conn->onMicSensorAccessChanged(false);
}
}
@@ -2243,7 +2237,6 @@
status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
const String16& opPackageName) {
- uid_t uid = IPCThreadState::self()->getCallingUid();
if (*requestedPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
return OK;
}
@@ -2255,7 +2248,7 @@
}
return OK;
}
- if (isMicSensorPrivacyEnabledForUid(uid)) {
+ if (mMicSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
*requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
return OK;
}
@@ -2264,7 +2257,6 @@
status_t SensorService::adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
const String16& opPackageName) {
- uid_t uid = IPCThreadState::self()->getCallingUid();
if (*requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
return OK;
}
@@ -2276,7 +2268,7 @@
}
return OK;
}
- if (isMicSensorPrivacyEnabledForUid(uid)) {
+ if (mMicSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
*requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
return OK;
}
@@ -2293,69 +2285,63 @@
void SensorService::SensorPrivacyPolicy::unregisterSelf() {
AutoCallerClear acc;
SensorPrivacyManager spm;
- if (mIsIndividualMic) {
- spm.removeIndividualSensorPrivacyListener(
- SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
- } else {
- spm.removeSensorPrivacyListener(this);
- }
+ spm.removeSensorPrivacyListener(this);
}
bool SensorService::SensorPrivacyPolicy::isSensorPrivacyEnabled() {
return mSensorPrivacyEnabled;
}
-binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool enabled) {
+binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(int toggleType __unused,
+ int sensor __unused, bool enabled) {
mSensorPrivacyEnabled = enabled;
sp<SensorService> service = mService.promote();
if (service != nullptr) {
- if (mIsIndividualMic) {
- if (enabled) {
- service->capRates(mUserId);
- } else {
- service->uncapRates(mUserId);
- }
+ if (enabled) {
+ service->disableAllSensors();
} else {
- if (enabled) {
- service->disableAllSensors();
- } else {
- service->enableAllSensors();
- }
+ service->enableAllSensors();
}
}
return binder::Status::ok();
}
-status_t SensorService::SensorPrivacyPolicy::registerSelfForIndividual(int userId) {
- Mutex::Autolock _l(mSensorPrivacyLock);
+void SensorService::MicrophonePrivacyPolicy::registerSelf() {
AutoCallerClear acc;
SensorPrivacyManager spm;
- status_t err = spm.addIndividualSensorPrivacyListener(userId,
- SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
-
- if (err != OK) {
- ALOGE("Cannot register a mic listener.");
- return err;
- }
- mSensorPrivacyEnabled = spm.isIndividualSensorPrivacyEnabled(userId,
- SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE);
-
- mIsIndividualMic = true;
- mUserId = userId;
- return OK;
+ mSensorPrivacyEnabled =
+ spm.isToggleSensorPrivacyEnabled(
+ SensorPrivacyManager::TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE)
+ || spm.isToggleSensorPrivacyEnabled(
+ SensorPrivacyManager::TOGGLE_TYPE_HARDWARE,
+ SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE);
+ spm.addToggleSensorPrivacyListener(this);
}
-bool SensorService::isMicSensorPrivacyEnabledForUid(uid_t uid) {
- userid_t userId = multiuser_get_user_id(uid);
- if (mMicSensorPrivacyPolicies.find(userId) == mMicSensorPrivacyPolicies.end()) {
- sp<SensorPrivacyPolicy> userPolicy = new SensorPrivacyPolicy(this);
- if (userPolicy->registerSelfForIndividual(userId) != OK) {
- return false;
- }
- mMicSensorPrivacyPolicies[userId] = userPolicy;
+void SensorService::MicrophonePrivacyPolicy::unregisterSelf() {
+ AutoCallerClear acc;
+ SensorPrivacyManager spm;
+ spm.removeToggleSensorPrivacyListener(this);
+}
+
+binder::Status SensorService::MicrophonePrivacyPolicy::onSensorPrivacyChanged(int toggleType __unused,
+ int sensor, bool enabled) {
+ if (sensor != SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE) {
+ return binder::Status::ok();
}
- return mMicSensorPrivacyPolicies[userId]->isSensorPrivacyEnabled();
+ mSensorPrivacyEnabled = enabled;
+ sp<SensorService> service = mService.promote();
+
+ if (service != nullptr) {
+ if (enabled) {
+ service->capRates();
+ } else {
+ service->uncapRates();
+ }
+ }
+ return binder::Status::ok();
}
SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock(
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b009829..7194db3 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -289,22 +289,32 @@
class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener {
public:
explicit SensorPrivacyPolicy(wp<SensorService> service)
- : mService(service), mIsIndividualMic(false), mUserId(0) {}
+ : mService(service) {}
void registerSelf();
void unregisterSelf();
- status_t registerSelfForIndividual(int userId);
-
bool isSensorPrivacyEnabled();
- binder::Status onSensorPrivacyChanged(bool enabled);
+ binder::Status onSensorPrivacyChanged(int toggleType, int sensor,
+ bool enabled);
+
+ protected:
+ std::atomic_bool mSensorPrivacyEnabled;
+ wp<SensorService> mService;
private:
- wp<SensorService> mService;
Mutex mSensorPrivacyLock;
- std::atomic_bool mSensorPrivacyEnabled;
- bool mIsIndividualMic;
- userid_t mUserId;
+ };
+
+ class MicrophonePrivacyPolicy : public SensorPrivacyPolicy {
+ public:
+ explicit MicrophonePrivacyPolicy(wp<SensorService> service)
+ : SensorPrivacyPolicy(service) {}
+ void registerSelf();
+ void unregisterSelf();
+
+ binder::Status onSensorPrivacyChanged(int toggleType, int sensor,
+ bool enabled);
};
// A class automatically clearing and restoring binder caller identity inside
@@ -444,9 +454,9 @@
void enableAllSensorsLocked(ConnectionSafeAutolock* connLock);
// Caps active direct connections (when the mic toggle is flipped to on)
- void capRates(userid_t userId);
+ void capRates();
// Removes the capped rate on active direct connections (when the mic toggle is flipped to off)
- void uncapRates(userid_t userId);
+ void uncapRates();
static inline bool isAudioServerOrSystemServerUid(uid_t uid) {
return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
@@ -497,10 +507,7 @@
static Mutex sPackageTargetVersionLock;
static String16 sSensorInterfaceDescriptorPrefix;
- // Map from user to SensorPrivacyPolicy
- std::map<userid_t, sp<SensorPrivacyPolicy>> mMicSensorPrivacyPolicies;
- // Checks if the mic sensor privacy is enabled for the uid
- bool isMicSensorPrivacyEnabledForUid(uid_t uid);
+ sp<MicrophonePrivacyPolicy> mMicSensorPrivacyPolicy;
// Keeps track of the handles of all proximity sensors in the system.
std::vector<int32_t> mProxSensorHandles;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index d9958f3..000a2cb 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -76,6 +76,7 @@
"libaidlcommonsupport",
"libcompositionengine",
"libframetimeline",
+ "libgui_aidl_static",
"libperfetto_client_experimental",
"librenderengine",
"libscheduler",
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 02e444d..e6a76e8 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -271,7 +271,8 @@
// Translate destination frame into scale and position. If a destination frame is not set, use the
// provided scale and position
bool BufferStateLayer::updateGeometry() {
- if (mDrawingState.destinationFrame.isEmpty()) {
+ if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) ||
+ mDrawingState.destinationFrame.isEmpty()) {
// If destination frame is not set, use the requested transform set via
// BufferStateLayer::setPosition and BufferStateLayer::setMatrix.
return assignTransform(&mDrawingState.transform, mRequestedTransform);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 6c7ba22..58d2530 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -78,7 +78,7 @@
virtual void applyChangedTypesToLayers(const ChangedTypes&);
virtual void applyDisplayRequests(const DisplayRequests&);
virtual void applyLayerRequestsToLayers(const LayerRequests&);
- virtual void applyClientTargetRequests(const ClientTargetProperty&, float whitePointNits);
+ virtual void applyClientTargetRequests(const ClientTargetProperty&, float brightness);
// Internal
virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
index 7521324..196af70 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <optional>
#include <string>
#include <type_traits>
@@ -63,4 +64,13 @@
void dumpVal(std::string& out, const char* name, const mat4&);
void dumpVal(std::string& out, const char* name, const StretchEffect&);
+template <typename T>
+void dumpVal(std::string& out, const char* name, std::optional<T> value) {
+ if (value.has_value()) {
+ return dumpVal(out, name, *value);
+ } else {
+ return dumpVal(out, name, "nullopt");
+ }
+}
+
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index cc7c257..66dd825 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -130,8 +130,8 @@
// SDR white point
float sdrWhitePointNits{-1.f};
- // White point of the client target
- float clientTargetWhitePointNits{-1.f};
+ // Brightness of the client target, normalized to display brightness
+ float clientTargetBrightness{1.f};
// Display brightness that will take effect this frame.
// This is slightly distinct from nits, in that nits cannot be passed to hw composer.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 08cfaa6..2b383c1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -153,9 +153,11 @@
// Timestamp for when the layer is queued for client composition
nsecs_t clientCompositionTimestamp{0};
- // White point of the layer, in nits.
static constexpr float kDefaultWhitePointNits = 200.f;
float whitePointNits = kDefaultWhitePointNits;
+ // Dimming ratio of the layer from [0, 1]
+ static constexpr float kDefaultDimmingRatio = 1.f;
+ float dimmingRatio = kDefaultDimmingRatio;
};
} // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index b9d7983..6a75283 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -266,8 +266,7 @@
applyChangedTypesToLayers(changes->changedTypes);
applyDisplayRequests(changes->displayRequests);
applyLayerRequestsToLayers(changes->layerRequests);
- applyClientTargetRequests(changes->clientTargetProperty,
- changes->clientTargetWhitePointNits);
+ applyClientTargetRequests(changes->clientTargetProperty, changes->clientTargetBrightness);
}
// Determine what type of composition we are doing from the final state
@@ -343,13 +342,13 @@
}
void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty,
- float whitePointNits) {
+ float brightness) {
if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
return;
}
editState().dataspace = clientTargetProperty.dataspace;
- editState().clientTargetWhitePointNits = whitePointNits;
+ editState().clientTargetBrightness = brightness;
getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 65f9731..ff332eb 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1076,12 +1076,13 @@
: mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
clientCompositionDisplay.maxLuminance =
mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
- clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetWhitePointNits;
+ clientCompositionDisplay.targetLuminanceNits =
+ outputState.clientTargetBrightness * outputState.displayBrightnessNits;
// Compute the global color transform matrix.
- if (!outputState.usesDeviceComposition && !getSkipColorTransform()) {
- clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
- }
+ clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
+ clientCompositionDisplay.deviceHandlesColorTransform =
+ outputState.usesDeviceComposition || getSkipColorTransform();
// Generate the client composition requests for the layers on this output.
std::vector<LayerFE*> clientCompositionLayersFE;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index acc9216..482250a 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -52,6 +52,10 @@
dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "colorTransformMatrix", colorTransformMatrix);
dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
+ dumpVal(out, "displayBrightnessNits", displayBrightnessNits);
+ dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
+ dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
+ dumpVal(out, "displayBrightness", displayBrightness);
out.append("\n");
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 4ccf11f..3e983f3 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -324,9 +324,14 @@
// For hdr content, treat the white point as the display brightness - HDR content should not be
// boosted or dimmed.
- if (isHdrDataspace(state.dataspace)) {
+ if (isHdrDataspace(state.dataspace) ||
+ getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits) {
+ state.dimmingRatio = 1.f;
state.whitePointNits = getOutput().getState().displayBrightnessNits;
} else {
+ state.dimmingRatio = std::clamp(getOutput().getState().sdrWhitePointNits /
+ getOutput().getState().displayBrightnessNits,
+ 0.f, 1.f);
state.whitePointNits = getOutput().getState().sdrWhitePointNits;
}
@@ -502,13 +507,12 @@
}
// Don't dim cached layers
- const auto whitePointNits = outputDependentState.overrideInfo.buffer
- ? getOutput().getState().displayBrightnessNits
- : outputDependentState.whitePointNits;
+ const auto dimmingRatio =
+ outputDependentState.overrideInfo.buffer ? 1.f : outputDependentState.dimmingRatio;
- if (auto error = hwcLayer->setWhitePointNits(whitePointNits); error != hal::Error::NONE) {
- ALOGE("[%s] Failed to set white point %f: %s (%d)", getLayerFE().getDebugName(),
- whitePointNits, to_string(error).c_str(), static_cast<int32_t>(error));
+ if (auto error = hwcLayer->setBrightness(dimmingRatio); error != hal::Error::NONE) {
+ ALOGE("[%s] Failed to set brightness %f: %s (%d)", getLayerFE().getDebugName(),
+ dimmingRatio, to_string(error).c_str(), static_cast<int32_t>(error));
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index cfa740e..6749427 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -67,6 +67,8 @@
dumpVal(out, "sourceCrop", sourceCrop);
dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
+ dumpVal(out, "whitePointNits", whitePointNits);
+ dumpVal(out, "dimmingRatio", dimmingRatio);
dumpVal(out, "override buffer", overrideInfo.buffer.get());
dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get());
dumpVal(out, "override display frame", overrideInfo.displayFrame);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 44d34a3..cd03235 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -839,7 +839,7 @@
auto& state = mDisplay->getState();
EXPECT_EQ(clientTargetProperty.dataspace, state.dataspace);
- EXPECT_EQ(kWhitePointNits, state.clientTargetWhitePointNits);
+ EXPECT_EQ(kWhitePointNits, state.clientTargetBrightness);
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index 5185ea9..d933b94 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -74,7 +74,7 @@
MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
MOCK_METHOD3(setLayerGenericMetadata,
Error(const std::string&, bool, const std::vector<uint8_t>&));
- MOCK_METHOD1(setWhitePointNits, Error(float));
+ MOCK_METHOD1(setBrightness, Error(float));
MOCK_METHOD1(setBlockingRegion, Error(const android::Region&));
};
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 82dcc66..dda0822 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -751,6 +751,8 @@
static constexpr bool kLayerGenericMetadata2Mandatory = true;
static constexpr float kWhitePointNits = 200.f;
static constexpr float kDisplayBrightnessNits = 400.f;
+ static constexpr float kLayerBrightness = kWhitePointNits / kDisplayBrightnessNits;
+ static constexpr float kFullLayerBrightness = 1.f;
static const half4 kColor;
static const Rect kDisplayFrame;
@@ -782,6 +784,7 @@
outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion;
outputLayerState.dataspace = kDataspace;
outputLayerState.whitePointNits = kWhitePointNits;
+ outputLayerState.dimmingRatio = kLayerBrightness;
mLayerFEState.blendMode = kBlendMode;
mLayerFEState.alpha = kAlpha;
@@ -846,11 +849,11 @@
ui::Dataspace dataspace = kDataspace,
const Region& visibleRegion = kOutputSpaceVisibleRegion,
const Region& surfaceDamage = kSurfaceDamage,
- float whitePointNits = kWhitePointNits,
+ float brightness = kLayerBrightness,
const Region& blockingRegion = Region()) {
EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(visibleRegion))).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setDataspace(dataspace)).WillOnce(Return(kError));
- EXPECT_CALL(*mHwcLayer, setWhitePointNits(whitePointNits)).WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setBrightness(brightness)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
.WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
? hal::Error::UNSUPPORTED
@@ -1114,7 +1117,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kSkipAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ kOverrideSurfaceDamage, kFullLayerBrightness);
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1130,7 +1133,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kSkipAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ kOverrideSurfaceDamage, kFullLayerBrightness);
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1146,7 +1149,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ kOverrideSurfaceDamage, kFullLayerBrightness);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1162,7 +1165,7 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ kOverrideSurfaceDamage, kFullLayerBrightness);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1288,7 +1291,7 @@
expectGeometryCommonCalls();
expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
- kSurfaceDamage, kWhitePointNits, blockingRegion);
+ kSurfaceDamage, kLayerBrightness, blockingRegion);
expectSetHdrMetadataAndBufferCalls();
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
expectSetCompositionTypeCall(Composition::DISPLAY_DECORATION);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index e72bc9f..c2521b2 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3067,7 +3067,7 @@
mOutput.mState.usesDeviceComposition = false;
mOutput.mState.reusedClientComposition = false;
mOutput.mState.flipClientTarget = false;
- mOutput.mState.clientTargetWhitePointNits = kClientTargetLuminanceNits;
+ mOutput.mState.clientTargetBrightness = kClientTargetBrightness;
EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
@@ -3103,8 +3103,9 @@
static constexpr float kDefaultAvgLuminance = 0.7f;
static constexpr float kDefaultMinLuminance = 0.1f;
static constexpr float kUnknownLuminance = -1.f;
- static constexpr float kDisplayLuminance = 80.f;
+ static constexpr float kDisplayLuminance = 400.f;
static constexpr float kClientTargetLuminanceNits = 200.f;
+ static constexpr float kClientTargetBrightness = 0.5f;
static const Rect kDefaultOutputFrame;
static const Rect kDefaultOutputViewport;
@@ -3487,7 +3488,8 @@
.maxLuminance = kDefaultMaxLuminance,
.currentLuminanceNits = kDefaultMaxLuminance,
.outputDataspace = kDefaultOutputDataspace,
- .colorTransform = mat4(),
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
.orientation = kDefaultOutputOrientationFlags,
.targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
@@ -3505,7 +3507,8 @@
.maxLuminance = kDefaultMaxLuminance,
.currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
- .colorTransform = mat4(),
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
.orientation = kDefaultOutputOrientationFlags,
.targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
@@ -3522,7 +3525,8 @@
.maxLuminance = kDefaultMaxLuminance,
.currentLuminanceNits = kDefaultMaxLuminance,
.outputDataspace = kDefaultOutputDataspace,
- .colorTransform = mat4(),
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
.orientation = kDefaultOutputOrientationFlags,
.targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
@@ -3540,6 +3544,7 @@
.currentLuminanceNits = kDefaultMaxLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = false,
.orientation = kDefaultOutputOrientationFlags,
.targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
@@ -3557,6 +3562,7 @@
.currentLuminanceNits = kDefaultMaxLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = false,
.orientation = kDefaultOutputOrientationFlags,
.targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
@@ -3574,7 +3580,8 @@
.maxLuminance = kDefaultMaxLuminance,
.currentLuminanceNits = kDefaultMaxLuminance,
.outputDataspace = kDefaultOutputDataspace,
- .colorTransform = mat4(),
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
.orientation = kDefaultOutputOrientationFlags,
.targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2b41ef4..45b98bb 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -141,7 +141,7 @@
return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
}
-std::pair<gui::DisplayInfo, ui::Transform> DisplayDevice::getInputInfo() const {
+auto DisplayDevice::getInputInfo() const -> InputInfo {
gui::DisplayInfo info;
info.displayId = getLayerStack().id;
@@ -166,10 +166,13 @@
info.logicalWidth = getLayerStackSpaceRect().width();
info.logicalHeight = getLayerStackSpaceRect().height();
- return {info, displayTransform};
+
+ return {.info = info,
+ .transform = displayTransform,
+ .receivesInput = receivesInput(),
+ .isSecure = isSecure()};
}
-// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
mPowerMode = mode;
getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e8bd62d..690f240 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -174,9 +174,14 @@
return mDeviceProductInfo;
}
- // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should
- // be applied to all the input windows on the display.
- std::pair<gui::DisplayInfo, ui::Transform> getInputInfo() const;
+ struct InputInfo {
+ gui::DisplayInfo info;
+ ui::Transform transform;
+ bool receivesInput;
+ bool isSecure;
+ };
+
+ InputInfo getInputInfo() const;
/* ------------------------------------------------------------------------
* Display power mode management.
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 04723a2..80e2d99 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -20,6 +20,7 @@
#include "AidlComposerHal.h"
+#include <android-base/file.h>
#include <android/binder_ibinder_platform.h>
#include <android/binder_manager.h>
#include <log/log.h>
@@ -115,7 +116,7 @@
AidlPerFrameMetadataBlob translate(IComposerClient::PerFrameMetadataBlob x) {
AidlPerFrameMetadataBlob blob;
blob.key = translate<AidlPerFrameMetadataKey>(x.key),
- std::copy(blob.blob.begin(), blob.blob.end(), x.blob.begin());
+ std::copy(x.blob.begin(), x.blob.end(), std::inserter(blob.blob, blob.blob.end()));
return blob;
}
@@ -262,13 +263,27 @@
}
std::string AidlComposer::dumpDebugInfo() {
- std::string info;
- const auto status = mAidlComposer->dumpDebugInfo(&info);
- if (!status.isOk()) {
- ALOGE("dumpDebugInfo failed %s", status.getDescription().c_str());
+ int pipefds[2];
+ int result = pipe(pipefds);
+ if (result < 0) {
+ ALOGE("dumpDebugInfo: pipe failed: %s", strerror(errno));
return {};
}
- return info;
+
+ std::string str;
+ const auto status = mAidlComposer->dump(pipefds[1], /*args*/ nullptr, /*numArgs*/ 0);
+ // Close the write-end of the pipe to make sure that when reading from the
+ // read-end we will get eof instead of blocking forever
+ close(pipefds[1]);
+
+ if (status == STATUS_OK) {
+ base::ReadFdToString(pipefds[0], &str);
+ } else {
+ ALOGE("dumpDebugInfo: dump failed: %d", status);
+ }
+
+ close(pipefds[0]);
+ return str;
}
void AidlComposer::registerCallback(HWC2::ComposerCallback& callback) {
@@ -1054,17 +1069,16 @@
Error AidlComposer::getClientTargetProperty(
Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* whitePointNits) {
+ float* outBrightness) {
const auto property = mReader.takeClientTargetProperty(translate<int64_t>(display));
*outClientTargetProperty =
translate<IComposerClient::ClientTargetProperty>(property.clientTargetProperty);
- *whitePointNits = property.whitePointNits;
+ *outBrightness = property.brightness;
return Error::NONE;
}
-Error AidlComposer::setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) {
- mWriter.setLayerWhitePointNits(translate<int64_t>(display), translate<int64_t>(layer),
- whitePointNits);
+Error AidlComposer::setLayerBrightness(Display display, Layer layer, float brightness) {
+ mWriter.setLayerBrightness(translate<int64_t>(display), translate<int64_t>(layer), brightness);
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index ed8049a..80ca8da 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -209,10 +209,10 @@
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
Error getClientTargetProperty(Display display,
IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outClientTargetWhitePointNits) override;
+ float* outBrightness) override;
// AIDL Composer HAL
- Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
+ Error setLayerBrightness(Display display, Layer layer, float brightness) override;
Error setLayerBlockingRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& blocking) override;
Error setBootDisplayConfig(Display displayId, Config) override;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 2c5164d..23886d4 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -261,10 +261,10 @@
virtual Error getClientTargetProperty(
Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outWhitePointNits) = 0;
+ float* outBrightness) = 0;
// AIDL Composer
- virtual Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) = 0;
+ virtual Error setLayerBrightness(Display display, Layer layer, float brightness) = 0;
virtual Error setLayerBlockingRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& blocking) = 0;
virtual Error setBootDisplayConfig(Display displayId, Config) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 50a6604..a1b663c 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -947,12 +947,12 @@
}
// AIDL HAL
-Error Layer::setWhitePointNits(float whitePointNits) {
+Error Layer::setBrightness(float brightness) {
if (CC_UNLIKELY(!mDisplay)) {
return Error::BAD_DISPLAY;
}
- auto intError = mComposer.setLayerWhitePointNits(mDisplay->getId(), mId, whitePointNits);
+ auto intError = mComposer.setLayerBrightness(mDisplay->getId(), mId, brightness);
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index f03aafc..334d6ec 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -327,7 +327,7 @@
const std::string& name, bool mandatory, const std::vector<uint8_t>& value) = 0;
// AIDL HAL
- [[clang::warn_unused_result]] virtual hal::Error setWhitePointNits(float whitePointNits) = 0;
+ [[clang::warn_unused_result]] virtual hal::Error setBrightness(float brightness) = 0;
[[clang::warn_unused_result]] virtual hal::Error setBlockingRegion(
const android::Region& region) = 0;
};
@@ -376,7 +376,7 @@
const std::vector<uint8_t>& value) override;
// AIDL HAL
- hal::Error setWhitePointNits(float whitePointNits) override;
+ hal::Error setBrightness(float brightness) override;
hal::Error setBlockingRegion(const android::Region& region) override;
private:
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 6a3162e..ed6e4b0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -479,13 +479,12 @@
RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
- float clientTargetWhitePointNits;
- error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &clientTargetWhitePointNits);
+ float brightness = 1.f;
+ error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &brightness);
outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
std::move(layerRequests),
- std::move(clientTargetProperty),
- clientTargetWhitePointNits});
+ std::move(clientTargetProperty), brightness});
error = hwcDisplay->acceptChanges();
RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 916c4b7..5b2e265 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -86,7 +86,7 @@
DisplayRequests displayRequests;
LayerRequests layerRequests;
ClientTargetProperty clientTargetProperty;
- float clientTargetWhitePointNits;
+ float clientTargetBrightness;
};
struct HWCDisplayMode {
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index e33f1e0..f735bba 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -1297,13 +1297,13 @@
Error HidlComposer::getClientTargetProperty(
Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outWhitePointNits) {
+ float* outBrightness) {
mReader.takeClientTargetProperty(display, outClientTargetProperty);
- *outWhitePointNits = -1.f;
+ *outBrightness = 1.f;
return Error::NONE;
}
-Error HidlComposer::setLayerWhitePointNits(Display, Layer, float) {
+Error HidlComposer::setLayerBrightness(Display, Layer, float) {
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 6b33945..c2b60cb 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -318,10 +318,10 @@
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
Error getClientTargetProperty(Display display,
IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outWhitePointNits) override;
+ float* outBrightness) override;
// AIDL Composer HAL
- Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
+ Error setLayerBrightness(Display display, Layer layer, float brightness) override;
Error setLayerBlockingRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& blocking) override;
Error setBootDisplayConfig(Display displayId, Config) override;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 6f02843..3dab389 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -16,6 +16,8 @@
//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#undef LOG_TAG
#define LOG_TAG "PowerAdvisor"
@@ -27,6 +29,7 @@
#include <android-base/properties.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
+#include <utils/Trace.h>
#include <android/hardware/power/1.3/IPower.h>
#include <android/hardware/power/IPower.h>
@@ -70,6 +73,14 @@
return timeout;
}
+void traceExpensiveRendering(bool enabled) {
+ if (enabled) {
+ ATRACE_ASYNC_BEGIN("ExpensiveRendering", 0);
+ } else {
+ ATRACE_ASYNC_END("ExpensiveRendering", 0);
+ }
+}
+
} // namespace
PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger)
@@ -247,6 +258,9 @@
bool setExpensiveRendering(bool enabled) override {
ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F");
auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled);
+ if (ret.isOk()) {
+ traceExpensiveRendering(enabled);
+ }
return ret.isOk();
}
@@ -323,6 +337,9 @@
}
auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
+ if (ret.isOk()) {
+ traceExpensiveRendering(enabled);
+ }
return ret.isOk();
}
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
index e09a192..bd3cf74 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -101,7 +101,6 @@
}
bool FlagManager::use_skia_tracing() const {
- ALOGD("use_skia_tracing ?");
std::optional<bool> sysPropVal =
doParse<bool>(base::GetProperty(PROPERTY_SKIA_ATRACE_ENABLED, "").c_str());
return getValue("SkiaTracingFeature__use_skia_tracing", sysPropVal, false);
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 86e96d7..81747d5 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -492,17 +492,22 @@
void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
nsecs_t& deadlineDelta) {
- if (mPredictionState == PredictionState::Expired ||
- mActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
+ if (mActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
// Cannot do any classification for invalid present time.
- // For prediction expired case, we do not know what happened here to classify this
- // correctly. This could potentially be AppDeadlineMissed but that's assuming no app will
- // request frames 120ms apart.
mJankType = JankType::Unknown;
deadlineDelta = -1;
return;
}
+ if (mPredictionState == PredictionState::Expired) {
+ // We classify prediction expired as AppDeadlineMissed as the
+ // TokenManager::kMaxTokens we store is large enough to account for a
+ // reasonable app, so prediction expire would mean a huge scheduling delay.
+ mJankType = JankType::AppDeadlineMissed;
+ deadlineDelta = -1;
+ return;
+ }
+
if (mPredictionState == PredictionState::None) {
// Cannot do jank classification on frames that don't have a token.
return;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a039250..533acfd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1993,29 +1993,31 @@
setTransactionFlags(eTransactionNeeded);
}
-LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags,
- const DisplayDevice* display) {
+LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) {
LayerProto* layerProto = layersProto.add_layers();
- writeToProtoDrawingState(layerProto, traceFlags, display);
+ writeToProtoDrawingState(layerProto);
writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
// Only populate for the primary display.
+ UnnecessaryLock assumeLocked(mFlinger->mStateLock); // called from the main thread.
+ const auto display = mFlinger->getDefaultDisplayDeviceLocked();
if (display) {
const auto compositionType = getCompositionType(*display);
layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
+ LayerProtoHelper::writeToProto(getVisibleRegion(display.get()),
+ [&]() { return layerProto->mutable_visible_region(); });
}
}
for (const sp<Layer>& layer : mDrawingChildren) {
- layer->writeToProto(layersProto, traceFlags, display);
+ layer->writeToProto(layersProto, traceFlags);
}
return layerProto;
}
-void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags,
- const DisplayDevice* display) {
+void Layer::writeToProtoDrawingState(LayerProto* layerInfo) {
const ui::Transform transform = getTransform();
auto buffer = getExternalTexture();
if (buffer != nullptr) {
@@ -2039,10 +2041,6 @@
LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
[&]() { return layerInfo->mutable_position(); });
LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
- if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
- LayerProtoHelper::writeToProto(getVisibleRegion(display),
- [&]() { return layerInfo->mutable_visible_region(); });
- }
LayerProtoHelper::writeToProto(surfaceDamageRegion,
[&]() { return layerInfo->mutable_damage_region(); });
@@ -2144,6 +2142,9 @@
(*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
}
}
+
+ LayerProtoHelper::writeToProto(state.destinationFrame,
+ [&]() { return layerInfo->mutable_destination_frame(); });
}
bool Layer::isRemovedFromCurrentState() const {
@@ -2161,8 +2162,7 @@
void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
Rect tmpBounds = getInputBounds();
if (!tmpBounds.isValid()) {
- info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE;
- info.focusable = false;
+ info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true);
info.touchableRegion.clear();
// A layer could have invalid input bounds and still expect to receive touch input if it has
// replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated
@@ -2309,7 +2309,6 @@
mDrawingState.inputInfo.ownerUid = mOwnerUid;
mDrawingState.inputInfo.ownerPid = mOwnerPid;
mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL;
- mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
mDrawingState.inputInfo.displayId = getLayerStack().id;
}
@@ -2327,7 +2326,9 @@
// We are just using these layers for occlusion detection in
// InputDispatcher, and obviously if they aren't visible they can't occlude
// anything.
- info.visible = hasInputInfo() ? canReceiveInput() : isVisible();
+ const bool visible = hasInputInfo() ? canReceiveInput() : isVisible();
+ info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+
info.alpha = getAlpha();
fillTouchOcclusionMode(info);
handleDropInputMode(info);
@@ -2349,8 +2350,9 @@
// Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
// if it was set by WM for a known system overlay
- info.trustedOverlay = info.trustedOverlay || isTrustedOverlay();
-
+ if (isTrustedOverlay()) {
+ info.inputConfig |= WindowInfo::InputConfig::TRUSTED_OVERLAY;
+ }
// If the layer is a clone, we need to crop the input region to cloned root to prevent
// touches from going outside the cloned area.
@@ -2482,7 +2484,7 @@
}
// Cloned layers shouldn't handle watch outside since their z order is not determined by
// WM or the client.
- mDrawingState.inputInfo.flags &= ~WindowInfo::Flag::WATCH_OUTSIDE_TOUCH;
+ mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, false);
}
void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e51af1e..21dd5f4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -686,12 +686,12 @@
bool isRemovedFromCurrentState() const;
- LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*);
+ LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags);
// Write states that are modified by the main thread. This includes drawing
// state as well as buffer data. This should be called in the main or tracing
// thread.
- void writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice*);
+ void writeToProtoDrawingState(LayerProto* layerInfo);
// Write drawing or current state. If writing current state, the caller should hold the
// external mStateLock. If writing drawing state, this function should be called on the
// main or tracing thread.
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 015caa6..0506c47 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -156,14 +156,14 @@
void LayerProtoHelper::writeToProto(const renderengine::ExternalTexture& buffer,
std::function<ActiveBufferProto*()> getActiveBufferProto) {
- if (buffer.getBuffer()->getWidth() != 0 || buffer.getBuffer()->getHeight() != 0 ||
- buffer.getBuffer()->getUsage() != 0 || buffer.getBuffer()->getPixelFormat() != 0) {
+ if (buffer.getWidth() != 0 || buffer.getHeight() != 0 || buffer.getUsage() != 0 ||
+ buffer.getPixelFormat() != 0) {
// Use a lambda do avoid writing the object header when the object is empty
ActiveBufferProto* activeBufferProto = getActiveBufferProto();
- activeBufferProto->set_width(buffer.getBuffer()->getWidth());
- activeBufferProto->set_height(buffer.getBuffer()->getHeight());
- activeBufferProto->set_format(buffer.getBuffer()->getPixelFormat());
- activeBufferProto->set_usage(buffer.getBuffer()->getUsage());
+ activeBufferProto->set_width(buffer.getWidth());
+ activeBufferProto->set_height(buffer.getHeight());
+ activeBufferProto->set_stride(buffer.getUsage());
+ activeBufferProto->set_format(buffer.getPixelFormat());
}
}
@@ -175,12 +175,12 @@
}
InputWindowInfoProto* proto = getInputWindowInfoProto();
- proto->set_layout_params_flags(inputInfo.flags.get());
+ proto->set_layout_params_flags(inputInfo.layoutParamsFlags.get());
using U = std::underlying_type_t<WindowInfo::Type>;
// TODO(b/129481165): This static assert can be safely removed once conversion warnings
// are re-enabled.
static_assert(std::is_same_v<U, int32_t>);
- proto->set_layout_params_type(static_cast<U>(inputInfo.type));
+ proto->set_layout_params_type(static_cast<U>(inputInfo.layoutParamsType));
LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight,
inputInfo.frameBottom},
@@ -189,9 +189,10 @@
[&]() { return proto->mutable_touchable_region(); });
proto->set_surface_inset(inputInfo.surfaceInset);
- proto->set_visible(inputInfo.visible);
- proto->set_focusable(inputInfo.focusable);
- proto->set_has_wallpaper(inputInfo.hasWallpaper);
+ using InputConfig = gui::WindowInfo::InputConfig;
+ proto->set_visible(!inputInfo.inputConfig.test(InputConfig::NOT_VISIBLE));
+ proto->set_focusable(!inputInfo.inputConfig.test(InputConfig::NOT_FOCUSABLE));
+ proto->set_has_wallpaper(inputInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
proto->set_global_scale_factor(inputInfo.globalScaleFactor);
LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform());
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 2d0da46..5ba8a1b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -87,9 +87,10 @@
to_string(event.header.displayId).c_str(),
event.hotplug.connected ? "connected" : "disconnected");
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- return StringPrintf("VSync{displayId=%s, count=%u, expectedVSyncTimestamp=%" PRId64 "}",
+ return StringPrintf("VSync{displayId=%s, count=%u, expectedPresentationTime=%" PRId64
+ "}",
to_string(event.header.displayId).c_str(), event.vsync.count,
- event.vsync.expectedVSyncTimestamp);
+ event.vsync.vsyncData.preferredExpectedPresentationTime());
case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
return StringPrintf("ModeChanged{displayId=%s, modeId=%u}",
to_string(event.header.displayId).c_str(), event.modeChange.modeId);
@@ -107,13 +108,19 @@
}
DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
- uint32_t count, nsecs_t expectedVSyncTimestamp,
+ uint32_t count, nsecs_t expectedPresentationTime,
nsecs_t deadlineTimestamp) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
event.vsync.count = count;
- event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp;
- event.vsync.deadlineTimestamp = deadlineTimestamp;
+ event.vsync.vsyncData.preferredFrameTimelineIndex = 0;
+ // Temporarily store the current vsync information in frameTimelines[0], marked as
+ // platform-preferred. When the event is dispatched later, the frame interval at that time is
+ // used with this information to generate multiple frame timeline choices.
+ event.vsync.vsyncData.frameTimelines[0] = {.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID,
+ .deadlineTimestamp = deadlineTimestamp,
+ .expectedPresentationTime =
+ expectedPresentationTime};
return event;
}
@@ -186,9 +193,10 @@
return binder::Status::ok();
}
-binder::Status EventThreadConnection::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) {
+binder::Status EventThreadConnection::getLatestVsyncEventData(
+ ParcelableVsyncEventData* outVsyncEventData) {
ATRACE_CALL();
- *outVsyncEventData = mEventThread->getLatestVsyncEventData(this);
+ outVsyncEventData->vsync = mEventThread->getLatestVsyncEventData(this);
return binder::Status::ok();
}
@@ -338,10 +346,16 @@
VsyncEventData EventThread::getLatestVsyncEventData(
const sp<EventThreadConnection>& connection) const {
- nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
VsyncEventData vsyncEventData;
+ nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
vsyncEventData.frameInterval = frameInterval;
- generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC));
+ VSyncSource::VSyncData vsyncData;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ vsyncData = mVSyncSource->getLatestVSyncData();
+ }
+ generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC),
+ vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
return vsyncEventData;
}
@@ -370,7 +384,7 @@
LOG_FATAL_IF(!mVSyncState);
mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
- vsyncData.expectedVSyncTimestamp,
+ vsyncData.expectedPresentationTime,
vsyncData.deadlineTimestamp));
mCondition.notify_all();
}
@@ -518,7 +532,8 @@
const sp<EventThreadConnection>& connection) const {
const auto throttleVsync = [&] {
return mThrottleVsyncCallback &&
- mThrottleVsyncCallback(event.vsync.expectedVSyncTimestamp, connection->mOwnerUid);
+ mThrottleVsyncCallback(event.vsync.vsyncData.preferredExpectedPresentationTime(),
+ connection->mOwnerUid);
};
switch (event.header.type) {
@@ -568,79 +583,49 @@
}
int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp,
- nsecs_t expectedVSyncTimestamp) const {
+ nsecs_t expectedPresentationTime) const {
if (mTokenManager != nullptr) {
return mTokenManager->generateTokenForPredictions(
- {timestamp, deadlineTimestamp, expectedVSyncTimestamp});
+ {timestamp, deadlineTimestamp, expectedPresentationTime});
}
return FrameTimelineInfo::INVALID_VSYNC_ID;
}
-void EventThread::generateFrameTimeline(
- nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp,
- nsecs_t preferredDeadlineTimestamp,
- std::function<void(int64_t index)> setPreferredFrameTimelineIndex,
- std::function<void(int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp)>
- setFrameTimeline) const {
+void EventThread::generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval,
+ nsecs_t timestamp,
+ nsecs_t preferredExpectedPresentationTime,
+ nsecs_t preferredDeadlineTimestamp) const {
// Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included.
for (int64_t multiplier = -VsyncEventData::kFrameTimelinesLength + 1, currentIndex = 0;
currentIndex < VsyncEventData::kFrameTimelinesLength; multiplier++) {
- nsecs_t deadline = preferredDeadlineTimestamp + multiplier * frameInterval;
+ nsecs_t deadlineTimestamp = preferredDeadlineTimestamp + multiplier * frameInterval;
// Valid possible frame timelines must have future values.
- if (deadline > timestamp) {
+ if (deadlineTimestamp > timestamp) {
if (multiplier == 0) {
- setPreferredFrameTimelineIndex(currentIndex);
+ outVsyncEventData.preferredFrameTimelineIndex = currentIndex;
}
- nsecs_t expectedVSyncTimestamp =
- preferredExpectedVSyncTimestamp + multiplier * frameInterval;
- setFrameTimeline(currentIndex,
- generateToken(timestamp, deadline, expectedVSyncTimestamp),
- expectedVSyncTimestamp, deadline);
+ nsecs_t expectedPresentationTime =
+ preferredExpectedPresentationTime + multiplier * frameInterval;
+ outVsyncEventData.frameTimelines[currentIndex] =
+ {.vsyncId =
+ generateToken(timestamp, deadlineTimestamp, expectedPresentationTime),
+ .deadlineTimestamp = deadlineTimestamp,
+ .expectedPresentationTime = expectedPresentationTime};
currentIndex++;
}
}
}
-void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const {
- generateFrameTimeline(
- event.vsync.frameInterval, event.header.timestamp, event.vsync.expectedVSyncTimestamp,
- event.vsync.deadlineTimestamp,
- [&](int index) { event.vsync.preferredFrameTimelineIndex = index; },
- [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp) {
- event.vsync.frameTimelines[index] = {.vsyncId = vsyncId,
- .deadlineTimestamp = deadlineTimestamp,
- .expectedVSyncTimestamp =
- expectedVSyncTimestamp};
- });
-}
-
-void EventThread::generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval,
- const nsecs_t timestamp) const {
- VSyncSource::VSyncData vsyncData;
- {
- std::lock_guard<std::mutex> lock(mMutex);
- vsyncData = mVSyncSource->getLatestVSyncData();
- }
- generateFrameTimeline(
- frameInterval, timestamp, vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp,
- [&](int index) { out.preferredFrameTimelineIndex = index; },
- [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp) {
- out.frameTimelines[index] =
- VsyncEventData::FrameTimeline(vsyncId, deadlineTimestamp,
- expectedVSyncTimestamp);
- });
-}
-
void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
const DisplayEventConsumers& consumers) {
for (const auto& consumer : consumers) {
DisplayEventReceiver::Event copy = event;
if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
- generateFrameTimeline(copy);
+ const int64_t frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
+ copy.vsync.vsyncData.frameInterval = frameInterval;
+ generateFrameTimeline(copy.vsync.vsyncData, frameInterval, copy.header.timestamp,
+ event.vsync.vsyncData.preferredExpectedPresentationTime(),
+ event.vsync.vsyncData.preferredDeadlineTimestamp());
}
switch (consumer->postEvent(copy)) {
case NO_ERROR:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index a858169..c406478 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -45,6 +45,7 @@
class TokenManager;
} // namespace frametimeline
+using gui::ParcelableVsyncEventData;
using gui::VsyncEventData;
// ---------------------------------------------------------------------------
@@ -66,7 +67,7 @@
public:
class VSyncData {
public:
- nsecs_t expectedVSyncTimestamp;
+ nsecs_t expectedPresentationTime;
nsecs_t deadlineTimestamp;
};
@@ -99,7 +100,7 @@
binder::Status stealReceiveChannel(gui::BitTube* outChannel) override;
binder::Status setVsyncRate(int rate) override;
binder::Status requestNextVsync() override; // asynchronous
- binder::Status getLatestVsyncEventData(VsyncEventData* outVsyncEventData) override;
+ binder::Status getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) override;
// Called in response to requestNextVsync.
const ResyncCallback resyncCallback;
@@ -217,17 +218,10 @@
void onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) override;
int64_t generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp,
- nsecs_t expectedVSyncTimestamp) const;
- void generateFrameTimeline(DisplayEventReceiver::Event& event) const;
- void generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval,
- const nsecs_t timestamp) const;
- void generateFrameTimeline(
- nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp,
- nsecs_t preferredDeadlineTimestamp,
- std::function<void(int64_t index)> setPreferredFrameTimelineIndex,
- std::function<void(int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp)>
- setFrameTimeline) const;
+ nsecs_t expectedPresentationTime) const;
+ void generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval,
+ nsecs_t timestamp, nsecs_t preferredExpectedPresentationTime,
+ nsecs_t preferredDeadlineTimestamp) const;
const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
frametimeline::TokenManager* const mTokenManager;
diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
index d9d64ae..c233455 100644
--- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
+++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
@@ -51,7 +51,8 @@
return std::nullopt;
}
-std::vector<FrameRateOverride> FrameRateOverrideMappings::getAllFrameRateOverrides() {
+std::vector<FrameRateOverride> FrameRateOverrideMappings::getAllFrameRateOverrides(
+ bool supportsFrameRateOverrideByContent) {
std::lock_guard lock(mFrameRateOverridesLock);
std::vector<FrameRateOverride> overrides;
overrides.reserve(std::max({mFrameRateOverridesFromGameManager.size(),
@@ -67,6 +68,11 @@
overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
}
}
+
+ if (!supportsFrameRateOverrideByContent) {
+ return overrides;
+ }
+
for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) {
if (std::find_if(overrides.begin(), overrides.end(),
[uid = uid](auto i) { return i.uid == uid; }) == overrides.end()) {
diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h
index 278f87c..4185a4c 100644
--- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h
+++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h
@@ -32,7 +32,8 @@
std::optional<Fps> getFrameRateOverrideForUid(uid_t uid,
bool supportsFrameRateOverrideByContent) const
EXCLUDES(mFrameRateOverridesLock);
- std::vector<FrameRateOverride> getAllFrameRateOverrides() EXCLUDES(mFrameRateOverridesLock);
+ std::vector<FrameRateOverride> getAllFrameRateOverrides(bool supportsFrameRateOverrideByContent)
+ EXCLUDES(mFrameRateOverridesLock);
void dump(std::string& result) const;
bool updateFrameRateOverridesByContent(const UidToFrameRateOverride& frameRateOverrides)
EXCLUDES(mFrameRateOverridesLock);
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 0efc28b..5f64efa 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -83,8 +83,7 @@
void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) {
std::lock_guard lock(mLock);
- LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first !=
- LayerHistory::layerStatus::NotFound,
+ LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound,
"%s already registered", layer->getName().c_str());
auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
@@ -108,9 +107,9 @@
auto id = layer->getSequence();
auto [found, layerPair] = findLayer(id);
- if (found == LayerHistory::layerStatus::NotFound) {
+ if (found == LayerStatus::NotFound) {
// Offscreen layer
- ALOGV("LayerHistory::record: %s not registered", layer->getName().c_str());
+ ALOGV("%s: %s not registered", __func__, layer->getName().c_str());
return;
}
@@ -126,16 +125,15 @@
info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps);
// Activate layer if inactive.
- if (found == LayerHistory::layerStatus::LayerInInactiveMap) {
+ if (found == LayerStatus::LayerInInactiveMap) {
mActiveLayerInfos.insert(
{id, std::make_pair(layerPair->first, std::move(layerPair->second))});
mInactiveLayerInfos.erase(id);
}
}
-LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshRateConfigs,
- nsecs_t now) {
- LayerHistory::Summary summary;
+auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> Summary {
+ Summary summary;
std::lock_guard lock(mLock);
@@ -148,9 +146,9 @@
ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
layerFocused ? "" : "not");
- const auto vote = info->getRefreshRateVote(refreshRateConfigs, now);
+ const auto vote = info->getRefreshRateVote(configs, now);
// Skip NoVote layer as those don't have any requirements
- if (vote.type == LayerHistory::LayerVoteType::NoVote) {
+ if (vote.type == LayerVoteType::NoVote) {
continue;
}
@@ -187,7 +185,7 @@
it = mInactiveLayerInfos.erase(it);
} else {
if (CC_UNLIKELY(mTraceEnabled)) {
- trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+ trace(*info, LayerVoteType::NoVote, 0);
}
info->onLayerInactive(now);
it++;
@@ -224,7 +222,7 @@
it++;
} else {
if (CC_UNLIKELY(mTraceEnabled)) {
- trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+ trace(*info, LayerVoteType::NoVote, 0);
}
info->onLayerInactive(now);
// move this to the inactive map
@@ -251,37 +249,23 @@
float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const {
std::lock_guard lock(mLock);
auto [found, layerPair] = findLayer(id);
- if (found != LayerHistory::layerStatus::NotFound) {
+ if (found != LayerStatus::NotFound) {
return layerPair->second->getFps(now).getValue();
}
return 0.f;
}
-std::pair<LayerHistory::layerStatus, LayerHistory::LayerPair*> LayerHistory::findLayer(int32_t id) {
+auto LayerHistory::findLayer(int32_t id) -> std::pair<LayerStatus, LayerPair*> {
// the layer could be in either the active or inactive map, try both
auto it = mActiveLayerInfos.find(id);
if (it != mActiveLayerInfos.end()) {
- return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
+ return {LayerStatus::LayerInActiveMap, &(it->second)};
}
it = mInactiveLayerInfos.find(id);
if (it != mInactiveLayerInfos.end()) {
- return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
+ return {LayerStatus::LayerInInactiveMap, &(it->second)};
}
- return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
-}
-
-std::pair<LayerHistory::layerStatus, const LayerHistory::LayerPair*> LayerHistory::findLayer(
- int32_t id) const {
- // the layer could be in either the active or inactive map, try both
- auto it = mActiveLayerInfos.find(id);
- if (it != mActiveLayerInfos.end()) {
- return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
- }
- it = mInactiveLayerInfos.find(id);
- if (it != mInactiveLayerInfos.end()) {
- return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
- }
- return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
+ return {LayerStatus::NotFound, nullptr};
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index cc55700..7b6096f 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -89,7 +89,7 @@
// worst case time complexity is O(2 * inactive + active)
void partitionLayers(nsecs_t now) REQUIRES(mLock);
- enum class layerStatus {
+ enum class LayerStatus {
NotFound,
LayerInActiveMap,
LayerInInactiveMap,
@@ -97,9 +97,11 @@
// looks up a layer by sequence id in both layerInfo maps.
// The first element indicates if and where the item was found
- std::pair<layerStatus, LayerHistory::LayerPair*> findLayer(int32_t id) REQUIRES(mLock);
- std::pair<layerStatus, const LayerHistory::LayerPair*> findLayer(int32_t id) const
- REQUIRES(mLock);
+ std::pair<LayerStatus, LayerPair*> findLayer(int32_t id) REQUIRES(mLock);
+
+ std::pair<LayerStatus, const LayerPair*> findLayer(int32_t id) const REQUIRES(mLock) {
+ return const_cast<LayerHistory*>(this)->findLayer(id);
+ }
mutable std::mutex mLock;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index a020e2c..712cd5b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -191,7 +191,8 @@
for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
auto& vsync = buffer[i].vsync;
- mHandler->dispatchFrame(vsync.vsyncId, vsync.expectedVSyncTimestamp);
+ mHandler->dispatchFrame(vsync.vsyncData.preferredVsyncId(),
+ vsync.vsyncData.preferredExpectedPresentationTime());
break;
}
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 3b9cfa6..15e30b3 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -69,11 +69,6 @@
using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
using RefreshRate = RefreshRateConfigs::RefreshRate;
-bool RefreshRate::inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const {
- using fps_approx_ops::operator<=;
- return minRefreshRate <= getFps() && getFps() <= maxRefreshRate;
-}
-
std::string RefreshRate::toString() const {
return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
getModeId().value(), mode->getHwcId(), getFps().getValue(),
@@ -84,7 +79,7 @@
return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d"
", primary range: %s, app request range: %s",
defaultMode.value(), allowGroupSwitching,
- primaryRange.toString().c_str(), appRequestRange.toString().c_str());
+ to_string(primaryRange).c_str(), to_string(appRequestRange).c_str());
}
std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod,
@@ -207,24 +202,24 @@
}
if (layer.vote == LayerVoteType::ExplicitExact) {
- const int divider = getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate);
+ const int divisor = getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate);
if (mSupportsFrameRateOverrideByContent) {
// Since we support frame rate override, allow refresh rates which are
// multiples of the layer's request, as those apps would be throttled
// down to run at the desired refresh rate.
- return divider > 0;
+ return divisor > 0;
}
- return divider == 1;
+ return divisor == 1;
}
- // If the layer frame rate is a divider of the refresh rate it should score
+ // If the layer frame rate is a divisor of the refresh rate it should score
// the highest score.
- if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
+ if (getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
return 1.0f * seamlessness;
}
- // The layer frame rate is not a divider of the refresh rate,
+ // The layer frame rate is not a divisor of the refresh rate,
// there is a small penalty attached to the score to favor the frame rates
// the exactly matches the display refresh rate or a multiple.
constexpr float kNonExactMatchingPenalty = 0.95f;
@@ -396,8 +391,9 @@
continue;
}
- bool inPrimaryRange = scores[i].refreshRate->inPolicy(policy->primaryRange.min,
- policy->primaryRange.max);
+ const bool inPrimaryRange =
+ policy->primaryRange.includes(scores[i].refreshRate->getFps());
+
if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
!(layer.focused &&
(layer.vote == LayerVoteType::ExplicitDefault ||
@@ -547,11 +543,11 @@
}
}
- // We just care about the refresh rates which are a divider of the
+ // We just care about the refresh rates which are a divisor of the
// display refresh rate
auto iter =
std::remove_if(scores.begin(), scores.end(), [&](const RefreshRateScore& score) {
- return getFrameRateDivider(displayFrameRate, score.refreshRate->getFps()) == 0;
+ return getFrameRateDivisor(displayFrameRate, score.refreshRate->getFps()) == 0;
});
scores.erase(iter, scores.end());
@@ -727,7 +723,7 @@
if (mConfig.enableFrameRateOverride) {
for (const auto& mode1 : sortedModes) {
for (const auto& mode2 : sortedModes) {
- if (getFrameRateDivider(mode1->getFps(), mode2->getFps()) >= 2) {
+ if (getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) {
mSupportsFrameRateOverrideByContent = true;
break;
}
@@ -746,7 +742,7 @@
return false;
}
const RefreshRate& refreshRate = *iter->second;
- if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
+ if (!policy.primaryRange.includes(refreshRate.getFps())) {
ALOGE("Default mode is not in the primary range.");
return false;
}
@@ -843,7 +839,7 @@
ALOGV("constructAvailableRefreshRates: %s ", policy->toString().c_str());
auto filterRefreshRates =
- [&](Fps min, Fps max, const char* listName,
+ [&](FpsRange range, const char* rangeName,
std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock) {
getSortedRefreshRateListLocked(
[&](const RefreshRate& refreshRate) REQUIRES(mLock) {
@@ -855,13 +851,13 @@
mode->getDpiY() == defaultMode->getDpiY() &&
(policy->allowGroupSwitching ||
mode->getGroup() == defaultMode->getGroup()) &&
- refreshRate.inPolicy(min, max);
+ range.includes(mode->getFps());
},
outRefreshRates);
- LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
- "No matching modes for %s range: min=%s max=%s", listName,
- to_string(min).c_str(), to_string(max).c_str());
+ LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(), "No matching modes for %s range %s",
+ rangeName, to_string(range).c_str());
+
auto stringifyRefreshRates = [&]() -> std::string {
std::string str;
for (auto refreshRate : *outRefreshRates) {
@@ -869,13 +865,11 @@
}
return str;
};
- ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
+ ALOGV("%s refresh rates: %s", rangeName, stringifyRefreshRates().c_str());
};
- filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary",
- &mPrimaryRefreshRates);
- filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request",
- &mAppRequestRefreshRates);
+ filterRefreshRates(policy->primaryRange, "primary", &mPrimaryRefreshRates);
+ filterRefreshRates(policy->appRequestRange, "app request", &mAppRequestRefreshRates);
}
Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const {
@@ -921,7 +915,7 @@
return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
}
-int RefreshRateConfigs::getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate) {
+int RefreshRateConfigs::getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate) {
// This calculation needs to be in sync with the java code
// in DisplayManagerService.getDisplayInfoForFrameRateOverride
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index ade1787..14583e3 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -22,7 +22,6 @@
#include <type_traits>
#include <utility>
-#include <android-base/stringprintf.h>
#include <gui/DisplayEventReceiver.h>
#include <scheduler/Fps.h>
@@ -101,21 +100,6 @@
using AllRefreshRatesMapType =
std::unordered_map<DisplayModeId, std::unique_ptr<const RefreshRate>>;
- struct FpsRange {
- Fps min = Fps::fromValue(0.f);
- Fps max = Fps::fromValue(std::numeric_limits<float>::max());
-
- bool operator==(const FpsRange& other) const {
- return isApproxEqual(min, other.min) && isApproxEqual(max, other.max);
- }
-
- bool operator!=(const FpsRange& other) const { return !(*this == other); }
-
- std::string toString() const {
- return base::StringPrintf("[%s %s]", to_string(min).c_str(), to_string(max).c_str());
- }
- };
-
struct Policy {
private:
static constexpr int kAllowGroupSwitchingDefault = false;
@@ -140,24 +124,24 @@
Policy() = default;
- Policy(DisplayModeId defaultMode, const FpsRange& range)
+ Policy(DisplayModeId defaultMode, FpsRange range)
: Policy(defaultMode, kAllowGroupSwitchingDefault, range, range) {}
- Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& range)
+ Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange range)
: Policy(defaultMode, allowGroupSwitching, range, range) {}
- Policy(DisplayModeId defaultMode, const FpsRange& primaryRange,
- const FpsRange& appRequestRange)
+ Policy(DisplayModeId defaultMode, FpsRange primaryRange, FpsRange appRequestRange)
: Policy(defaultMode, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {}
- Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& primaryRange,
- const FpsRange& appRequestRange)
+ Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange primaryRange,
+ FpsRange appRequestRange)
: defaultMode(defaultMode),
allowGroupSwitching(allowGroupSwitching),
primaryRange(primaryRange),
appRequestRange(appRequestRange) {}
bool operator==(const Policy& other) const {
+ using namespace fps_approx_ops;
return defaultMode == other.defaultMode && primaryRange == other.primaryRange &&
appRequestRange == other.appRequestRange &&
allowGroupSwitching == other.allowGroupSwitching;
@@ -332,10 +316,10 @@
bool supportsFrameRateOverrideByContent() const { return mSupportsFrameRateOverrideByContent; }
- // Return the display refresh rate divider to match the layer
+ // Return the display refresh rate divisor to match the layer
// frame rate, or 0 if the display refresh rate is not a multiple of the
// layer refresh rate.
- static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
+ static int getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate);
// Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000
// for an integer t.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index de27bd1..1fa455a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -173,15 +173,15 @@
return basePeriod;
}
- const auto divider =
- scheduler::RefreshRateConfigs::getFrameRateDivider(refreshRateConfigs
+ const auto divisor =
+ scheduler::RefreshRateConfigs::getFrameRateDivisor(refreshRateConfigs
->getCurrentRefreshRate()
.getFps(),
*frameRate);
- if (divider <= 1) {
+ if (divisor <= 1) {
return basePeriod;
}
- return basePeriod * divider;
+ return basePeriod * divisor;
};
}
@@ -263,8 +263,12 @@
}
void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
+ const bool supportsFrameRateOverrideByContent =
+ refreshRateConfigs->supportsFrameRateOverrideByContent();
+
std::vector<FrameRateOverride> overrides =
- mFrameRateOverrideMappings.getAllFrameRateOverrides();
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent);
android::EventThread* thread;
{
@@ -531,50 +535,13 @@
}
void Scheduler::chooseRefreshRateForContent() {
- {
- std::scoped_lock lock(mRefreshRateConfigsLock);
- if (!mRefreshRateConfigs->canSwitch()) return;
- }
+ const auto configs = holdRefreshRateConfigs();
+ if (!configs->canSwitch()) return;
ATRACE_CALL();
- DisplayModePtr newMode;
- GlobalSignals consideredSignals;
-
- bool frameRateChanged;
- bool frameRateOverridesChanged;
-
- const auto refreshRateConfigs = holdRefreshRateConfigs();
- LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime());
- {
- std::lock_guard<std::mutex> lock(mPolicyLock);
- mPolicy.contentRequirements = std::move(summary);
-
- std::tie(newMode, consideredSignals) = chooseDisplayMode();
- frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
-
- if (mPolicy.mode == newMode) {
- // We don't need to change the display mode, but we might need to send an event
- // about a mode change, since it was suppressed due to a previous idleConsidered
- if (!consideredSignals.idle) {
- dispatchCachedReportedMode();
- }
- frameRateChanged = false;
- } else {
- mPolicy.mode = newMode;
- frameRateChanged = true;
- }
- }
- if (frameRateChanged) {
- const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
-
- mSchedulerCallback.changeRefreshRate(newRefreshRate,
- consideredSignals.idle ? DisplayModeEvent::None
- : DisplayModeEvent::Changed);
- }
- if (frameRateOverridesChanged) {
- mSchedulerCallback.triggerOnFrameRateOverridesChanged();
- }
+ LayerHistory::Summary summary = mLayerHistory.summarize(*configs, systemTime());
+ applyPolicy(&Policy::contentRequirements, std::move(summary));
}
void Scheduler::resetIdleTimer() {
@@ -636,7 +603,7 @@
}
void Scheduler::idleTimerCallback(TimerState state) {
- handleTimerStateChanged(&mPolicy.idleTimer, state);
+ applyPolicy(&Policy::idleTimer, state);
ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
}
@@ -646,14 +613,14 @@
// Clear layer history to get fresh FPS detection.
// NOTE: Instead of checking all the layers, we should be checking the layer
// that is currently on top. b/142507166 will give us this capability.
- if (handleTimerStateChanged(&mPolicy.touch, touch)) {
+ if (applyPolicy(&Policy::touch, touch).touch) {
mLayerHistory.clear();
}
ATRACE_INT("TouchState", static_cast<int>(touch));
}
void Scheduler::displayPowerTimerCallback(TimerState state) {
- handleTimerStateChanged(&mPolicy.displayPowerTimer, state);
+ applyPolicy(&Policy::displayPowerTimer, state);
ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
}
@@ -682,10 +649,10 @@
bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) {
const auto refreshRateConfigs = holdRefreshRateConfigs();
- if (!refreshRateConfigs->supportsFrameRateOverrideByContent()) {
- return false;
- }
+ // we always update mFrameRateOverridesByContent here
+ // supportsFrameRateOverridesByContent will be checked
+ // when getting FrameRateOverrides from mFrameRateOverrideMappings
if (!consideredSignals.idle) {
const auto frameRateOverrides =
refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements,
@@ -695,8 +662,8 @@
return false;
}
-template <class T>
-bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
+template <typename S, typename T>
+auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals {
DisplayModePtr newMode;
GlobalSignals consideredSignals;
@@ -706,15 +673,17 @@
const auto refreshRateConfigs = holdRefreshRateConfigs();
{
std::lock_guard<std::mutex> lock(mPolicyLock);
- if (*currentState == newState) {
- return false;
- }
- *currentState = newState;
+
+ auto& currentState = mPolicy.*statePtr;
+ if (currentState == newState) return {};
+ currentState = std::forward<T>(newState);
+
std::tie(newMode, consideredSignals) = chooseDisplayMode();
frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
+
if (mPolicy.mode == newMode) {
// We don't need to change the display mode, but we might need to send an event
- // about a mode change, since it was suppressed due to a previous idleConsidered
+ // about a mode change, since it was suppressed if previously considered idle.
if (!consideredSignals.idle) {
dispatchCachedReportedMode();
}
@@ -733,7 +702,7 @@
if (frameRateOverridesChanged) {
mSchedulerCallback.triggerOnFrameRateOverridesChanged();
}
- return consideredSignals.touch;
+ return consideredSignals;
}
auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 468c4cc..f6c81c0 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -169,6 +169,7 @@
// The period is the vsync period from the current display configuration.
void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
void resync() EXCLUDES(mRefreshRateConfigsLock);
+ void forceNextResync() { mLastResyncTime = 0; }
// Passes a vsync sample to VsyncController. periodFlushed will be true if
// VsyncController detected that the vsync period changed, and false otherwise.
@@ -263,14 +264,17 @@
void touchTimerCallback(TimerState);
void displayPowerTimerCallback(TimerState);
- // handles various timer features to change the refresh rate.
- template <class T>
- bool handleTimerStateChanged(T* currentState, T newState);
-
void setVsyncPeriod(nsecs_t period);
using GlobalSignals = RefreshRateConfigs::GlobalSignals;
+ struct Policy;
+
+ // Sets the S state of the policy to the T value under mPolicyLock, and chooses a display mode
+ // that fulfills the new policy if the state changed. Returns the signals that were considered.
+ template <typename S, typename T>
+ GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock);
+
// Returns the display mode that fulfills the policy, and the signals that were considered.
std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock);
@@ -323,7 +327,7 @@
mutable std::mutex mPolicyLock;
- struct {
+ struct Policy {
// Policy for choosing the display mode.
LayerHistory::Summary contentRequirements;
TimerState idleTimer = TimerState::Reset;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 61d2fb7..77782e9 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -256,7 +256,7 @@
/*
* Returns whether a given vsync timestamp is in phase with a frame rate.
- * If the frame rate is not a divider of the refresh rate, it is always considered in phase.
+ * If the frame rate is not a divisor of the refresh rate, it is always considered in phase.
* For example, if the vsync timestamps are (16.6,33.3,50.0,66.6):
* isVSyncInPhase(16.6, 30) = true
* isVSyncInPhase(33.3, 30) = false
@@ -271,42 +271,42 @@
};
std::lock_guard lock(mMutex);
- const auto divider =
- RefreshRateConfigs::getFrameRateDivider(Fps::fromPeriodNsecs(mIdealPeriod), frameRate);
- if (divider <= 1 || timePoint == 0) {
+ const auto divisor =
+ RefreshRateConfigs::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), frameRate);
+ if (divisor <= 1 || timePoint == 0) {
return true;
}
const nsecs_t period = mRateMap[mIdealPeriod].slope;
const nsecs_t justBeforeTimePoint = timePoint - period / 2;
- const nsecs_t dividedPeriod = mIdealPeriod / divider;
+ const nsecs_t dividedPeriod = mIdealPeriod / divisor;
- // If this is the first time we have asked about this divider with the
+ // If this is the first time we have asked about this divisor with the
// current vsync period, it is considered in phase and we store the closest
// vsync timestamp
- const auto knownTimestampIter = mRateDividerKnownTimestampMap.find(dividedPeriod);
- if (knownTimestampIter == mRateDividerKnownTimestampMap.end()) {
+ const auto knownTimestampIter = mRateDivisorKnownTimestampMap.find(dividedPeriod);
+ if (knownTimestampIter == mRateDivisorKnownTimestampMap.end()) {
const auto vsync = nextAnticipatedVSyncTimeFromLocked(justBeforeTimePoint);
- mRateDividerKnownTimestampMap[dividedPeriod] = vsync;
+ mRateDivisorKnownTimestampMap[dividedPeriod] = vsync;
return true;
}
- // Find the next N vsync timestamp where N is the divider.
+ // Find the next N vsync timestamp where N is the divisor.
// One of these vsyncs will be in phase. We return the one which is
// the most aligned with the last known in phase vsync
- std::vector<VsyncError> vsyncs(static_cast<size_t>(divider));
+ std::vector<VsyncError> vsyncs(static_cast<size_t>(divisor));
const nsecs_t knownVsync = knownTimestampIter->second;
nsecs_t point = justBeforeTimePoint;
- for (size_t i = 0; i < divider; i++) {
+ for (size_t i = 0; i < divisor; i++) {
const nsecs_t vsync = nextAnticipatedVSyncTimeFromLocked(point);
- const auto numPeriods = static_cast<float>(vsync - knownVsync) / (period * divider);
+ const auto numPeriods = static_cast<float>(vsync - knownVsync) / (period * divisor);
const auto error = std::abs(std::round(numPeriods) - numPeriods);
vsyncs[i] = {vsync, error};
point = vsync + 1;
}
const auto minVsyncError = std::min_element(vsyncs.begin(), vsyncs.end());
- mRateDividerKnownTimestampMap[dividedPeriod] = minVsyncError->vsyncTimestamp;
+ mRateDivisorKnownTimestampMap[dividedPeriod] = minVsyncError->vsyncTimestamp;
return std::abs(minVsyncError->vsyncTimestamp - timePoint) < period / 2;
}
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index cfaf7d6..3181102 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -96,7 +96,7 @@
std::unordered_map<nsecs_t, Model> mutable mRateMap GUARDED_BY(mMutex);
// Map between the divided vsync period and the last known vsync timestamp
- std::unordered_map<nsecs_t, nsecs_t> mutable mRateDividerKnownTimestampMap GUARDED_BY(mMutex);
+ std::unordered_map<nsecs_t, nsecs_t> mutable mRateDivisorKnownTimestampMap GUARDED_BY(mMutex);
size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0;
std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index 245db0f..be57b2a 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -134,16 +134,27 @@
return mVsyncConfig;
}
-const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
+auto VsyncModulator::getNextVsyncConfigType() const -> VsyncConfigType {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd ||
mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
- return mVsyncConfigSet.early;
+ return VsyncConfigType::Early;
} else if (mEarlyGpuFrames > 0) {
- return mVsyncConfigSet.earlyGpu;
+ return VsyncConfigType::EarlyGpu;
} else {
- return mVsyncConfigSet.late;
+ return VsyncConfigType::Late;
+ }
+}
+
+const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
+ switch (getNextVsyncConfigType()) {
+ case VsyncConfigType::Early:
+ return mVsyncConfigSet.early;
+ case VsyncConfigType::EarlyGpu:
+ return mVsyncConfigSet.earlyGpu;
+ case VsyncConfigType::Late:
+ return mVsyncConfigSet.late;
}
}
@@ -176,4 +187,9 @@
static_cast<void>(updateVsyncConfigLocked());
}
+bool VsyncModulator::isVsyncConfigDefault() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return getNextVsyncConfigType() == VsyncConfigType::Late;
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index 2000c54..537cae1 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -109,11 +109,16 @@
[[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);
+ [[nodiscard]] bool isVsyncConfigDefault() const;
+
protected:
// Called from unit tests as well
void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);
private:
+ enum class VsyncConfigType { Early, EarlyGpu, Late };
+
+ VsyncConfigType getNextVsyncConfigType() const REQUIRES(mMutex);
const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex);
[[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex);
[[nodiscard]] VsyncConfig updateVsyncConfigLocked() REQUIRES(mMutex);
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
index 639b3e5..bd4f409 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
@@ -17,6 +17,7 @@
#pragma once
#include <cmath>
+#include <limits>
#include <ostream>
#include <string>
#include <type_traits>
@@ -60,6 +61,13 @@
nsecs_t mPeriod = 0;
};
+struct FpsRange {
+ Fps min = Fps::fromValue(0.f);
+ Fps max = Fps::fromValue(std::numeric_limits<float>::max());
+
+ bool includes(Fps) const;
+};
+
static_assert(std::is_trivially_copyable_v<Fps>);
constexpr Fps operator""_Hz(unsigned long long frequency) {
@@ -111,8 +119,21 @@
return !isApproxLess(lhs, rhs);
}
+inline bool operator==(FpsRange lhs, FpsRange rhs) {
+ return isApproxEqual(lhs.min, rhs.min) && isApproxEqual(lhs.max, rhs.max);
+}
+
+inline bool operator!=(FpsRange lhs, FpsRange rhs) {
+ return !(lhs == rhs);
+}
+
} // namespace fps_approx_ops
+inline bool FpsRange::includes(Fps fps) const {
+ using fps_approx_ops::operator<=;
+ return min <= fps && fps <= max;
+}
+
struct FpsApproxEqual {
bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); }
};
@@ -125,4 +146,9 @@
return stream << to_string(fps);
}
+inline std::string to_string(FpsRange range) {
+ const auto [min, max] = range;
+ return base::StringPrintf("[%s, %s]", to_string(min).c_str(), to_string(max).c_str());
+}
+
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 54a777a..d139d64 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -50,6 +50,7 @@
#include <cutils/compiler.h>
#include <cutils/properties.h>
#include <ftl/future.h>
+#include <ftl/small_map.h>
#include <gui/BufferQueue.h>
#include <gui/DebugEGLImageTracker.h>
#include <gui/IProducerListener.h>
@@ -146,15 +147,16 @@
#define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
+// Note: The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
#define ON_MAIN_THREAD(expr) \
- [&] { \
+ [&]() -> decltype(auto) { \
LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
UnnecessaryLock lock(mStateLock); \
return (expr); \
}()
#define MAIN_THREAD_GUARD(expr) \
- [&] { \
+ [&]() -> decltype(auto) { \
LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
MainThreadScopedGuard lock(SF_MAIN_THREAD); \
return (expr); \
@@ -250,11 +252,6 @@
const status_t status;
};
-struct SCOPED_CAPABILITY UnnecessaryLock {
- explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {}
- ~UnnecessaryLock() RELEASE() {}
-};
-
// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
@@ -510,7 +507,7 @@
return LatchUnsignaledConfig::Always;
}
- if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) {
+ if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) {
return LatchUnsignaledConfig::AutoSingleLayer;
}
@@ -1349,9 +1346,8 @@
auto future = mScheduler->schedule([=]() MAIN_THREAD {
ATRACE_CALL();
if (mPowerAdvisor.isUsingExpensiveRendering()) {
- const auto& displays = ON_MAIN_THREAD(mDisplays);
- for (const auto& [_, display] : displays) {
- const static constexpr auto kDisable = false;
+ for (const auto& [_, display] : mDisplays) {
+ constexpr bool kDisable = false;
mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable);
}
}
@@ -1744,11 +1740,15 @@
// If we support applying display brightness as a command, then we also support
// dimming SDR layers.
if (supportsDisplayBrightnessCommand) {
- display->getCompositionDisplay()
- ->setDisplayBrightness(brightness.sdrWhitePointNits,
- brightness.displayBrightnessNits);
+ auto compositionDisplay = display->getCompositionDisplay();
+ float currentDimmingRatio =
+ compositionDisplay->editState().sdrWhitePointNits /
+ compositionDisplay->editState().displayBrightnessNits;
+ compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits,
+ brightness.displayBrightnessNits);
MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness));
- if (hasVisibleHdrLayer(display)) {
+ if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits !=
+ currentDimmingRatio) {
scheduleComposite(FrameHint::kNone);
} else {
scheduleCommit(FrameHint::kNone);
@@ -1964,8 +1964,8 @@
}
void SurfaceFlinger::onComposerHalVsyncIdle(hal::HWDisplayId) {
- // TODO(b/198106220): force enable HWVsync to avoid drift problem during
- // idle.
+ ATRACE_CALL();
+ mScheduler->forceNextResync();
}
void SurfaceFlinger::setVsyncEnabled(bool enabled) {
@@ -2351,16 +2351,19 @@
void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
nsecs_t compositeToPresentLatency) {
+ // Avoid division by 0 by defaulting to 60Hz
+ const auto vsyncPeriod = stats.vsyncPeriod ?: (60_Hz).getPeriodNsecs();
+
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
nsecs_t idealLatency = (mVsyncConfiguration->getCurrentConfigs().late.sfOffset > 0)
- ? (stats.vsyncPeriod -
- (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % stats.vsyncPeriod))
- : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % stats.vsyncPeriod);
+ ? (vsyncPeriod -
+ (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % vsyncPeriod))
+ : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % vsyncPeriod);
// Just in case mVsyncConfiguration->getCurrentConfigs().late.sf == -vsyncInterval.
if (idealLatency <= 0) {
- idealLatency = stats.vsyncPeriod;
+ idealLatency = vsyncPeriod;
}
// Snap the latency to a value that removes scheduling jitter from the
@@ -2369,16 +2372,14 @@
// something (such as user input) to an accurate diasplay time.
// Snapping also allows an app to precisely calculate
// mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval).
- const nsecs_t bias = stats.vsyncPeriod / 2;
- const int64_t extraVsyncs = (stats.vsyncPeriod) > 0 ?
- ((compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod) :
- 0;
+ const nsecs_t bias = vsyncPeriod / 2;
+ const int64_t extraVsyncs = ((compositeToPresentLatency - idealLatency + bias) / vsyncPeriod);
const nsecs_t snappedCompositeToPresentLatency =
- (extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
+ (extraVsyncs > 0) ? idealLatency + (extraVsyncs * vsyncPeriod) : idealLatency;
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
- getBE().mCompositorTiming.interval = stats.vsyncPeriod;
+ getBE().mCompositorTiming.interval = vsyncPeriod;
getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
@@ -3243,9 +3244,7 @@
return;
}
- const auto& displays = ON_MAIN_THREAD(mDisplays);
-
- for (const auto& [_, display] : displays) {
+ for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
if (const auto brightness = display->getStagedBrightness(); brightness) {
if (!needsComposite) {
const status_t error =
@@ -3266,60 +3265,48 @@
void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
std::vector<DisplayInfo>& outDisplayInfos) {
- struct Details {
- Details(bool receivesInput, bool isSecure, const ui::Transform& transform,
- const DisplayInfo& info)
- : receivesInput(receivesInput),
- isSecure(isSecure),
- transform(std::move(transform)),
- info(std::move(info)) {}
- bool receivesInput;
- bool isSecure;
- ui::Transform transform;
- DisplayInfo info;
- };
- std::unordered_map<uint32_t /*layerStackId*/, Details> inputDisplayDetails;
+ ftl::SmallMap<ui::LayerStack, DisplayDevice::InputInfo, 4> displayInputInfos;
+
for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
- const uint32_t layerStackId = display->getLayerStack().id;
- const auto& [info, transform] = display->getInputInfo();
- const auto& [it, emplaced] =
- inputDisplayDetails.try_emplace(layerStackId, display->receivesInput(),
- display->isSecure(), transform, info);
+ const auto layerStack = display->getLayerStack();
+ const auto info = display->getInputInfo();
+
+ const auto [it, emplaced] = displayInputInfos.try_emplace(layerStack, info);
if (emplaced) {
continue;
}
- // There is more than one display for the layerStack. In this case, the display that is
- // configured to receive input takes precedence.
- auto& details = it->second;
- if (!display->receivesInput()) {
- continue;
+ // If the layer stack is mirrored on multiple displays, the first display that is configured
+ // to receive input takes precedence.
+ auto& otherInfo = it->second;
+ if (otherInfo.receivesInput) {
+ ALOGW_IF(display->receivesInput(),
+ "Multiple displays claim to accept input for the same layer stack: %u",
+ layerStack.id);
+ } else {
+ otherInfo = info;
}
- ALOGE_IF(details.receivesInput,
- "Multiple displays claim to accept input for the same layer stack: %u",
- layerStackId);
- details.receivesInput = display->receivesInput();
- details.isSecure = display->isSecure();
- details.transform = std::move(transform);
- details.info = std::move(info);
}
+ static size_t sNumWindowInfos = 0;
+ outWindowInfos.reserve(sNumWindowInfos);
+ sNumWindowInfos = 0;
+
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
- const uint32_t layerStackId = layer->getLayerStack().id;
- const auto it = inputDisplayDetails.find(layerStackId);
- if (it == inputDisplayDetails.end()) {
- // Do not create WindowInfos for windows on displays that cannot receive input.
- 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& details = it->second;
- outWindowInfos.push_back(layer->fillInputInfo(details.transform, details.isSecure));
});
- for (const auto& [_, details] : inputDisplayDetails) {
- outDisplayInfos.push_back(std::move(details.info));
+ sNumWindowInfos = outWindowInfos.size();
+
+ outDisplayInfos.reserve(displayInputInfos.size());
+ for (const auto& [_, info] : displayInputInfos) {
+ outDisplayInfos.push_back(info.info);
}
}
@@ -3667,6 +3654,54 @@
return false;
}
+void SurfaceFlinger::flushPendingTransactionQueues(
+ std::vector<TransactionState>& transactions,
+ std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
+ std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions,
+ bool tryApplyUnsignaled) {
+ auto it = mPendingTransactionQueues.begin();
+ while (it != mPendingTransactionQueues.end()) {
+ auto& [applyToken, transactionQueue] = *it;
+ while (!transactionQueue.empty()) {
+ if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+ ATRACE_NAME("stopTransactionProcessing");
+ break;
+ }
+
+ auto& transaction = transactionQueue.front();
+ const auto ready =
+ transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+ transaction.isAutoTimestamp,
+ transaction.desiredPresentTime,
+ transaction.originUid, transaction.states,
+ bufferLayersReadyToPresent, transactions.size(),
+ tryApplyUnsignaled);
+ ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
+ if (ready == TransactionReadiness::NotReady) {
+ setTransactionFlags(eTransactionFlushNeeded);
+ break;
+ }
+ transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
+ bufferLayersReadyToPresent.insert(state.surface);
+ });
+ const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled);
+ if (appliedUnsignaled) {
+ applyTokensWithUnsignaledTransactions.insert(transaction.applyToken);
+ }
+
+ transactions.emplace_back(std::move(transaction));
+ transactionQueue.pop();
+ }
+
+ if (transactionQueue.empty()) {
+ it = mPendingTransactionQueues.erase(it);
+ mTransactionQueueCV.broadcast();
+ } else {
+ it = std::next(it, 1);
+ }
+ }
+}
+
bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
@@ -3679,60 +3714,25 @@
Mutex::Autolock _l(mStateLock);
{
Mutex::Autolock _l(mQueueLock);
- // Collect transactions from pending transaction queue.
- auto it = mPendingTransactionQueues.begin();
- while (it != mPendingTransactionQueues.end()) {
- auto& [applyToken, transactionQueue] = *it;
- while (!transactionQueue.empty()) {
- if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
- break;
- }
- auto& transaction = transactionQueue.front();
- const auto ready =
- transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
- transaction.isAutoTimestamp,
- transaction.desiredPresentTime,
- transaction.originUid, transaction.states,
- bufferLayersReadyToPresent,
- transactions.size());
- if (ready == TransactionReadiness::NotReady) {
- setTransactionFlags(eTransactionFlushNeeded);
- break;
- }
- transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
- bufferLayersReadyToPresent.insert(state.surface);
- });
- const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled);
- if (appliedUnsignaled) {
- applyTokensWithUnsignaledTransactions.insert(transaction.applyToken);
- }
+ // First collect transactions from the pending transaction queues.
+ // We are not allowing unsignaled buffers here as we want to
+ // collect all the transactions from applyTokens that are ready first.
+ flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+ applyTokensWithUnsignaledTransactions,
+ /*tryApplyUnsignaled*/ false);
- transactions.emplace_back(std::move(transaction));
- transactionQueue.pop();
- }
-
- if (transactionQueue.empty()) {
- it = mPendingTransactionQueues.erase(it);
- mTransactionQueueCV.broadcast();
- } else {
- it = std::next(it, 1);
- }
- }
-
- // Collect transactions from current transaction queue or queue to pending transactions.
- // Case 1: push to pending when transactionIsReadyToBeApplied is false
- // or the first transaction was unsignaled.
- // Case 2: push to pending when there exist a pending queue.
- // Case 3: others are the transactions that are ready to apply.
+ // Second, collect transactions from the transaction queue.
+ // Here as well we are not allowing unsignaled buffers for the same
+ // reason as above.
while (!mTransactionQueue.empty()) {
auto& transaction = mTransactionQueue.front();
const bool pendingTransactions =
mPendingTransactionQueues.find(transaction.applyToken) !=
mPendingTransactionQueues.end();
const auto ready = [&]() REQUIRES(mStateLock) {
- if (pendingTransactions ||
- stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+ if (pendingTransactions) {
+ ATRACE_NAME("pendingTransactions");
return TransactionReadiness::NotReady;
}
@@ -3741,25 +3741,31 @@
transaction.desiredPresentTime,
transaction.originUid, transaction.states,
bufferLayersReadyToPresent,
- transactions.size());
+ transactions.size(),
+ /*tryApplyUnsignaled*/ false);
}();
-
+ ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
if (ready == TransactionReadiness::NotReady) {
mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
} else {
transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
bufferLayersReadyToPresent.insert(state.surface);
});
- const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled);
- if (appliedUnsignaled) {
- applyTokensWithUnsignaledTransactions.insert(transaction.applyToken);
- }
transactions.emplace_back(std::move(transaction));
}
mTransactionQueue.pop_front();
ATRACE_INT("TransactionQueue", mTransactionQueue.size());
}
+ // We collected all transactions that could apply without latching unsignaled buffers.
+ // If we are allowing latch unsignaled of some form, now it's the time to go over the
+ // transactions that were not applied and try to apply them unsignaled.
+ if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
+ flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+ applyTokensWithUnsignaledTransactions,
+ /*tryApplyUnsignaled*/ true);
+ }
+
return applyTransactions(transactions, vsyncId);
}
}
@@ -3818,7 +3824,7 @@
prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
}
bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state,
- size_t numStates, size_t totalTXapplied) {
+ size_t numStates, size_t totalTXapplied) const {
if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__);
return false;
@@ -3836,11 +3842,22 @@
return false;
}
- if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer &&
- totalTXapplied > 0) {
- ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", __func__,
- totalTXapplied);
- return false;
+ if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
+ if (totalTXapplied > 0) {
+ ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)",
+ __func__, totalTXapplied);
+ return false;
+ }
+
+ // We don't want to latch unsignaled if are in early / client composition
+ // as it leads to jank due to RenderEngine waiting for unsignaled buffer
+ // or window animations being slow.
+ const auto isDefaultVsyncConfig = mVsyncModulator->isVsyncConfigDefault();
+ if (!isDefaultVsyncConfig) {
+ ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; !isDefaultVsyncConfig)",
+ __func__);
+ return false;
+ }
}
if (!layer->simpleBufferUpdate(state)) {
@@ -3856,7 +3873,7 @@
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
- size_t totalTXapplied) const -> TransactionReadiness {
+ size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness {
ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId);
const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
// Do not present if the desiredPresentTime has not passed unless it is more than one second
@@ -3893,11 +3910,10 @@
continue;
}
- ATRACE_NAME(layer->getName().c_str());
-
- const bool allowLatchUnsignaled =
+ const bool allowLatchUnsignaled = tryApplyUnsignaled &&
shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied);
- ATRACE_INT("allowLatchUnsignaled", allowLatchUnsignaled);
+ ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(),
+ allowLatchUnsignaled ? "true" : "false");
const bool acquireFenceChanged = s.bufferData &&
s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
@@ -5109,11 +5125,9 @@
}
LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
-
LayersProto layersProto;
for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
- layer->writeToProto(layersProto, traceFlags, display.get());
+ layer->writeToProto(layersProto, traceFlags);
}
return layersProto;
@@ -5154,8 +5168,7 @@
rootProto->add_children(offscreenLayer->sequence);
// Add layer
- LayerProto* layerProto =
- offscreenLayer->writeToProto(layersProto, traceFlags, nullptr /*device*/);
+ LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags);
layerProto->set_parent(offscreenRootLayerId);
}
}
@@ -5352,7 +5365,7 @@
colorizer.reset(result);
const bool hwcDisabled = mDebugDisableHWC || mDebugFlashDelay;
StringAppendF(&result, " h/w composer %s\n", hwcDisabled ? "disabled" : "enabled");
- getHwComposer().dump(result);
+ dumpHwc(result);
/*
* Dump gralloc state
@@ -5406,30 +5419,21 @@
// access to SF.
case BOOT_FINISHED:
case CLEAR_ANIMATION_FRAME_STATS:
- case CREATE_DISPLAY:
- case DESTROY_DISPLAY:
case GET_ANIMATION_FRAME_STATS:
case OVERRIDE_HDR_TYPES:
case GET_HDR_CAPABILITIES:
case SET_DESIRED_DISPLAY_MODE_SPECS:
case GET_DESIRED_DISPLAY_MODE_SPECS:
case SET_ACTIVE_COLOR_MODE:
- case GET_BOOT_DISPLAY_MODE_SUPPORT:
case SET_BOOT_DISPLAY_MODE:
- case CLEAR_BOOT_DISPLAY_MODE:
case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
- case SET_AUTO_LOW_LATENCY_MODE:
case GET_GAME_CONTENT_TYPE_SUPPORT:
- case SET_GAME_CONTENT_TYPE:
- case SET_POWER_MODE:
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
case GET_DISPLAYED_CONTENT_SAMPLE:
case ADD_TUNNEL_MODE_ENABLED_LISTENER:
case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
- case NOTIFY_POWER_BOOST:
case SET_GLOBAL_SHADOW_SETTINGS:
- case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
// OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary
// permission dynamically. Don't use the permission cache for this check.
@@ -5460,15 +5464,11 @@
case AUTHENTICATE_SURFACE:
case GET_ACTIVE_COLOR_MODE:
case GET_ACTIVE_DISPLAY_MODE:
- case GET_PHYSICAL_DISPLAY_IDS:
- case GET_PHYSICAL_DISPLAY_TOKEN:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_NATIVE_PRIMARIES:
case GET_STATIC_DISPLAY_INFO:
case GET_DYNAMIC_DISPLAY_INFO:
case GET_DISPLAY_MODES:
- case GET_DISPLAY_STATE:
- case GET_DISPLAY_STATS:
case GET_SUPPORTED_FRAME_TIMESTAMPS:
// Calling setTransactionState is safe, because you need to have been
// granted a reference to Client* and Handle* to do anything with it.
@@ -5477,34 +5477,16 @@
case GET_COLOR_MANAGEMENT:
case GET_COMPOSITION_PREFERENCE:
case GET_PROTECTED_CONTENT_SUPPORT:
- case IS_WIDE_COLOR_DISPLAY:
// setFrameRate() is deliberately available for apps to call without any
// special permissions.
case SET_FRAME_RATE:
- case GET_DISPLAY_BRIGHTNESS_SUPPORT:
case GET_DISPLAY_DECORATION_SUPPORT:
- // captureLayers and captureDisplay will handle the permission check in the function
- case CAPTURE_LAYERS:
- case CAPTURE_DISPLAY:
case SET_FRAME_TIMELINE_INFO:
case GET_GPU_CONTEXT_PRIORITY:
case GET_MAX_ACQUIRED_BUFFER_COUNT: {
// This is not sensitive information, so should not require permission control.
return OK;
}
- case SET_DISPLAY_BRIGHTNESS:
- case ADD_HDR_LAYER_INFO_LISTENER:
- case REMOVE_HDR_LAYER_INFO_LISTENER: {
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
- !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
- ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- return OK;
- }
case ADD_FPS_LISTENER:
case REMOVE_FPS_LISTENER:
case ADD_REGION_SAMPLING_LISTENER:
@@ -5520,8 +5502,7 @@
}
return OK;
}
- case ADD_TRANSACTION_TRACE_LISTENER:
- case CAPTURE_DISPLAY_BY_ID: {
+ case ADD_TRANSACTION_TRACE_LISTENER: {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
@@ -5551,6 +5532,29 @@
}
return PERMISSION_DENIED;
}
+ case CREATE_DISPLAY:
+ case DESTROY_DISPLAY:
+ case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
+ case GET_PHYSICAL_DISPLAY_IDS:
+ case GET_PHYSICAL_DISPLAY_TOKEN:
+ case SET_POWER_MODE:
+ case GET_DISPLAY_STATE:
+ case GET_DISPLAY_STATS:
+ case CLEAR_BOOT_DISPLAY_MODE:
+ case GET_BOOT_DISPLAY_MODE_SUPPORT:
+ case SET_AUTO_LOW_LATENCY_MODE:
+ case SET_GAME_CONTENT_TYPE:
+ case CAPTURE_LAYERS:
+ case CAPTURE_DISPLAY:
+ case CAPTURE_DISPLAY_BY_ID:
+ case IS_WIDE_COLOR_DISPLAY:
+ case GET_DISPLAY_BRIGHTNESS_SUPPORT:
+ case SET_DISPLAY_BRIGHTNESS:
+ case ADD_HDR_LAYER_INFO_LISTENER:
+ case REMOVE_HDR_LAYER_INFO_LISTENER:
+ case NOTIFY_POWER_BOOST:
+ LOG_FATAL("Deprecated opcode: %d, migrated to AIDL", code);
+ return PERMISSION_DENIED;
}
// These codes are used for the IBinder protocol to either interrogate the recipient
@@ -5750,9 +5754,9 @@
}
case 1025: { // Set layer tracing
n = data.readInt32();
- int64_t fixedStartingTime = data.readInt64();
bool tracingEnabledChanged;
- if (n) {
+ if (n == 1) {
+ int64_t fixedStartingTime = data.readInt64();
ALOGD("LayerTracing enabled");
tracingEnabledChanged = mLayerTracing.enable();
if (tracingEnabledChanged) {
@@ -5764,6 +5768,10 @@
})
.wait();
}
+ } else if (n == 2) {
+ std::string filename = std::string(data.readCString());
+ ALOGD("LayerTracing disabled. Trace wrote to %s", filename.c_str());
+ tracingEnabledChanged = mLayerTracing.disable(filename.c_str());
} else {
ALOGD("LayerTracing disabled");
tracingEnabledChanged = mLayerTracing.disable();
@@ -6016,9 +6024,9 @@
mTransactionTracing->setBufferSize(
TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
} else {
+ mTransactionTracing->writeToFile();
mTransactionTracing->setBufferSize(
TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE);
- mTransactionTracing->writeToFile();
}
}
reply->writeInt32(NO_ERROR);
@@ -7195,6 +7203,223 @@
mLayersAdded = true;
return true;
}
+
+// gui::ISurfaceComposer
+
+binder::Status SurfaceComposerAIDL::createDisplay(const std::string& displayName, bool secure,
+ sp<IBinder>* outDisplay) {
+ status_t status = checkAccessPermission();
+ if (status != OK) {
+ return binder::Status::fromStatusT(status);
+ }
+ String8 displayName8 = String8::format("%s", displayName.c_str());
+ *outDisplay = mFlinger->createDisplay(displayName8, secure);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::destroyDisplay(const sp<IBinder>& display) {
+ status_t status = checkAccessPermission();
+ if (status != OK) {
+ return binder::Status::fromStatusT(status);
+ }
+ mFlinger->destroyDisplay(display);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) {
+ std::vector<PhysicalDisplayId> physicalDisplayIds = mFlinger->getPhysicalDisplayIds();
+ std::vector<int64_t> displayIds;
+ displayIds.reserve(physicalDisplayIds.size());
+ for (auto item : physicalDisplayIds) {
+ displayIds.push_back(static_cast<int64_t>(item.value));
+ }
+ *outDisplayIds = displayIds;
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) {
+ status_t status = checkAccessPermission();
+ if (status != OK) {
+ return binder::Status::fromStatusT(status);
+ }
+
+ PhysicalDisplayId id;
+ status = mFlinger->getPrimaryPhysicalDisplayId(&id);
+ if (status == NO_ERROR) {
+ *outDisplayId = id.value;
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId,
+ sp<IBinder>* outDisplay) {
+ const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+ *outDisplay = mFlinger->getPhysicalDisplayToken(*id);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setPowerMode(const sp<IBinder>& display, int mode) {
+ status_t status = checkAccessPermission();
+ if (status != OK) {
+ return binder::Status::fromStatusT(status);
+ }
+ mFlinger->setPowerMode(display, mode);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display,
+ gui::DisplayStatInfo* outStatInfo) {
+ DisplayStatInfo statInfo;
+ status_t status = mFlinger->getDisplayStats(display, &statInfo);
+ if (status == NO_ERROR) {
+ outStatInfo->vsyncTime = static_cast<long>(statInfo.vsyncTime);
+ outStatInfo->vsyncPeriod = static_cast<long>(statInfo.vsyncPeriod);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display,
+ gui::DisplayState* outState) {
+ ui::DisplayState state;
+ status_t status = mFlinger->getDisplayState(display, &state);
+ if (status == NO_ERROR) {
+ outState->layerStack = state.layerStack.id;
+ outState->orientation = static_cast<gui::Rotation>(state.orientation);
+ outState->layerStackSpaceRect.width = state.layerStackSpaceRect.width;
+ outState->layerStackSpaceRect.height = state.layerStackSpaceRect.height;
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ status = mFlinger->clearBootDisplayMode(display);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ status = mFlinger->getBootDisplayModeSupport(outMode);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
+ status_t status = checkAccessPermission();
+ if (status != OK) {
+ return binder::Status::fromStatusT(status);
+ }
+ mFlinger->setAutoLowLatencyMode(display, on);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& display, bool on) {
+ status_t status = checkAccessPermission();
+ if (status != OK) {
+ return binder::Status::fromStatusT(status);
+ }
+ mFlinger->setGameContentType(display, on);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::captureDisplay(
+ const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
+ status_t status = mFlinger->captureDisplay(args, captureListener);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::captureDisplayById(
+ int64_t displayId, const sp<IScreenCaptureListener>& captureListener) {
+ status_t status;
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int uid = ipc->getCallingUid();
+ if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
+ std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
+ status = mFlinger->captureDisplay(*id, captureListener);
+ } else {
+ status = PERMISSION_DENIED;
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::captureLayers(
+ const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
+ status_t status = mFlinger->captureLayers(args, captureListener);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) {
+ status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) {
+ status_t status = mFlinger->getDisplayBrightnessSupport(displayToken, outSupport);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status == OK) {
+ status = mFlinger->setDisplayBrightness(displayToken, brightness);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status == OK) {
+ status = mFlinger->addHdrLayerInfoListener(displayToken, listener);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status == OK) {
+ status = mFlinger->removeHdrLayerInfoListener(displayToken, listener);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ status = mFlinger->notifyPowerBoost(boostId);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) {
+ if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(),
+ ipc->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+ return OK;
+}
+
+status_t SurfaceComposerAIDL::checkControlDisplayBrightnessPermission() {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS) &&
+ !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
+ ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ return OK;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9525573..d44acff 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -7,7 +7,6 @@
*
* 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
@@ -23,6 +22,9 @@
*/
#include <android-base/thread_annotations.h>
+#include <android/gui/BnSurfaceComposer.h>
+#include <android/gui/DisplayStatInfo.h>
+#include <android/gui/DisplayState.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <gui/BufferQueue.h>
@@ -106,9 +108,13 @@
class RenderArea;
class TimeStats;
class FrameTracer;
+class ScreenCapturer;
class WindowInfosListenerInvoker;
+using gui::CaptureArgs;
+using gui::DisplayCaptureArgs;
using gui::IRegionSamplingListener;
+using gui::LayerCaptureArgs;
using gui::ScreenCaptureResults;
namespace frametimeline {
@@ -177,6 +183,11 @@
std::atomic<nsecs_t> mLastSwapTime = 0;
};
+struct SCOPED_CAPABILITY UnnecessaryLock {
+ explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {}
+ ~UnnecessaryLock() RELEASE() {}
+};
+
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
private IBinder::DeathRecipient,
@@ -507,17 +518,30 @@
bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true)
EXCLUDES(mStateLock);
+ // the following two methods are moved from ISurfaceComposer.h
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+ const auto displayIds = getPhysicalDisplayIds();
+ return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
+ }
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+ }
+
// Implements ISurfaceComposer
sp<ISurfaceComposerClient> createConnection() override;
- sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
- void destroyDisplay(const sp<IBinder>& displayToken) override;
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override EXCLUDES(mStateLock) {
+ sp<IBinder> createDisplay(const String8& displayName, bool secure);
+ void destroyDisplay(const sp<IBinder>& displayToken);
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const EXCLUDES(mStateLock) {
Mutex::Autolock lock(mStateLock);
return getPhysicalDisplayIdsLocked();
}
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override EXCLUDES(mStateLock);
+ status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const EXCLUDES(mStateLock);
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
+ sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
@@ -535,13 +559,13 @@
ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override;
- status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override;
- status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override;
- status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override;
+ status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
+ status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
+ status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
- status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
+ status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
- EXCLUDES(mStateLock) override;
+ EXCLUDES(mStateLock);
status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*)
EXCLUDES(mStateLock) override;
status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*)
@@ -549,12 +573,12 @@
status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
ui::DisplayPrimaries&) override;
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
- status_t getBootDisplayModeSupport(bool* outSupport) const override;
+ status_t getBootDisplayModeSupport(bool* outSupport) const;
status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override;
- status_t clearBootDisplayMode(const sp<IBinder>& displayToken) override;
- void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) override;
- void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
- void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
+ status_t clearBootDisplayMode(const sp<IBinder>& displayToken);
+ void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
+ void setGameContentType(const sp<IBinder>& displayToken, bool on);
+ void setPowerMode(const sp<IBinder>& displayToken, int mode);
status_t clearAnimationFrameStats() override;
status_t getAnimationFrameStats(FrameStats* outStats) const override;
status_t overrideHdrTypes(const sp<IBinder>& displayToken,
@@ -577,8 +601,7 @@
uint64_t timestamp,
DisplayedFrameStats* outStats) const override;
status_t getProtectedContentSupport(bool* outSupported) const override;
- status_t isWideColorDisplay(const sp<IBinder>& displayToken,
- bool* outIsWideColorDisplay) const override;
+ status_t isWideColorDisplay(const sp<IBinder>& displayToken, bool* outIsWideColorDisplay) const;
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
@@ -600,15 +623,14 @@
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) override;
- status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override;
+ status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const;
status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) override;
+ const gui::DisplayBrightness& brightness);
status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override;
+ const sp<gui::IHdrLayerInfoListener>& listener);
status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override;
- status_t notifyPowerBoost(int32_t boostId) override;
+ const sp<gui::IHdrLayerInfoListener>& listener);
+ status_t notifyPowerBoost(int32_t boostId);
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
status_t getDisplayDecorationSupport(
@@ -745,6 +767,12 @@
// Returns true if there is at least one transaction that needs to be flushed
bool transactionFlushNeeded();
+ void flushPendingTransactionQueues(
+ std::vector<TransactionState>& transactions,
+ std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
+ std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions,
+ bool tryApplyUnsignaled) REQUIRES(mStateLock, mQueueLock);
+
uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&,
int64_t desiredPresentTime, bool isAutoTimestamp,
int64_t postTime, uint32_t permissions) REQUIRES(mStateLock);
@@ -775,10 +803,10 @@
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
- size_t totalTXapplied) const REQUIRES(mStateLock);
+ size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock);
static LatchUnsignaledConfig getLatchUnsignaledConfig();
- static bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&,
- size_t numStates, size_t totalTXapplied);
+ bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, size_t numStates,
+ size_t totalTXapplied) const;
bool stopTransactionProcessing(const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
applyTokensWithUnsignaledTransactions) const;
bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId)
@@ -1283,6 +1311,7 @@
ui::Dataspace mDefaultCompositionDataspace;
ui::Dataspace mWideColorGamutCompositionDataspace;
ui::Dataspace mColorSpaceAgnosticDataspace;
+ float mDimmingRatio = -1.f;
SurfaceFlingerBE mBE;
std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
@@ -1395,6 +1424,54 @@
} mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD);
nsecs_t mAnimationTransactionTimeout = s2ns(5);
+
+ friend class SurfaceComposerAIDL;
+};
+
+class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
+public:
+ SurfaceComposerAIDL(sp<SurfaceFlinger> sf) { mFlinger = sf; }
+
+ binder::Status createDisplay(const std::string& displayName, bool secure,
+ sp<IBinder>* outDisplay) override;
+ binder::Status destroyDisplay(const sp<IBinder>& display) override;
+ binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override;
+ binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override;
+ binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
+ binder::Status setPowerMode(const sp<IBinder>& display, int mode) override;
+ binder::Status getDisplayStats(const sp<IBinder>& display,
+ gui::DisplayStatInfo* outStatInfo) override;
+ binder::Status getDisplayState(const sp<IBinder>& display,
+ gui::DisplayState* outState) override;
+ binder::Status clearBootDisplayMode(const sp<IBinder>& display) override;
+ binder::Status getBootDisplayModeSupport(bool* outMode) override;
+ binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override;
+ binder::Status setGameContentType(const sp<IBinder>& display, bool on) override;
+ binder::Status captureDisplay(const DisplayCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override;
+ binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override;
+ binder::Status captureLayers(const LayerCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override;
+ binder::Status isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) override;
+ binder::Status getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) override;
+ binder::Status setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) override;
+ binder::Status addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
+ binder::Status removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
+ binder::Status notifyPowerBoost(int boostId) override;
+
+private:
+ static const constexpr bool kUsePermissionCache = true;
+ status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache);
+ status_t checkControlDisplayBrightnessPermission();
+
+private:
+ sp<SurfaceFlinger> mFlinger;
};
} // namespace android
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 006efdf..49554c7 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -45,14 +45,14 @@
return true;
}
-bool LayerTracing::disable() {
+bool LayerTracing::disable(std::string filename) {
std::scoped_lock lock(mTraceLock);
if (!mEnabled) {
return false;
}
mEnabled = false;
LayersTraceFileProto fileProto = createTraceFileProto();
- mBuffer->writeToFile(fileProto, FILE_NAME);
+ mBuffer->writeToFile(fileProto, filename);
mBuffer->reset();
return true;
}
diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h
index bd448c9..88a19ec 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -43,7 +43,7 @@
LayerTracing(SurfaceFlinger& flinger);
~LayerTracing();
bool enable();
- bool disable();
+ bool disable(std::string filename = FILE_NAME);
bool isEnabled() const;
status_t writeToFile();
LayersTraceFileProto createTraceFileProto() const;
diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h
index 3b2626d..7e38c55 100644
--- a/services/surfaceflinger/Tracing/RingBuffer.h
+++ b/services/surfaceflinger/Tracing/RingBuffer.h
@@ -67,7 +67,7 @@
// -rw-r--r--
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) {
- ALOGE("Could not save the proto file.");
+ ALOGE("Could not save the proto file %s", filename.c_str());
return PERMISSION_DENIED;
}
return NO_ERROR;
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index a91698f..4cd5ace 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -15,6 +15,7 @@
*/
#include <gui/SurfaceComposerClient.h>
+#include <ui/Fence.h>
#include <ui/Rect.h>
#include "LayerProtoHelper.h"
@@ -22,9 +23,7 @@
namespace android::surfaceflinger {
-proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t,
- LayerHandleToIdFn getLayerId,
- DisplayHandleToIdFn getDisplayId) {
+proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t) {
proto::TransactionState proto;
proto.set_pid(t.originPid);
proto.set_uid(t.originUid);
@@ -33,12 +32,14 @@
proto.set_post_time(t.postTime);
proto.set_transaction_id(t.id);
+ proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(t.states.size()));
for (auto& layerState : t.states) {
- proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state, getLayerId)));
+ proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state)));
}
+ proto.mutable_display_changes()->Reserve(static_cast<int32_t>(t.displays.size()));
for (auto& displayState : t.displays) {
- proto.mutable_display_changes()->Add(std::move(toProto(displayState, getDisplayId)));
+ proto.mutable_display_changes()->Add(std::move(toProto(displayState)));
}
return proto;
}
@@ -46,8 +47,9 @@
proto::TransactionState TransactionProtoParser::toProto(
const std::map<int32_t /* layerId */, TracingLayerState>& states) {
proto::TransactionState proto;
+ proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(states.size()));
for (auto& [layerId, state] : states) {
- proto::LayerState layerProto = toProto(state, nullptr);
+ proto::LayerState layerProto = toProto(state);
if (layerProto.has_buffer_data()) {
proto::LayerState_BufferData* bufferProto = layerProto.mutable_buffer_data();
bufferProto->set_buffer_id(state.bufferId);
@@ -69,11 +71,10 @@
return proto;
}
-proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer,
- LayerHandleToIdFn getLayerId) {
+proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) {
proto::LayerState proto;
- if (getLayerId != nullptr) {
- proto.set_layer_id(getLayerId(layer.surface));
+ if (layer.surface) {
+ proto.set_layer_id(mMapper->getLayerId(layer.surface));
} else {
proto.set_layer_id(layer.layerId);
}
@@ -136,13 +137,27 @@
}
if (layer.what & layer_state_t::eBufferChanged) {
proto::LayerState_BufferData* bufferProto = proto.mutable_buffer_data();
- if (layer.bufferData->buffer) {
+ if (layer.bufferData->hasBuffer()) {
bufferProto->set_buffer_id(layer.bufferData->getId());
bufferProto->set_width(layer.bufferData->getWidth());
bufferProto->set_height(layer.bufferData->getHeight());
bufferProto->set_pixel_format(static_cast<proto::LayerState_BufferData_PixelFormat>(
layer.bufferData->getPixelFormat()));
bufferProto->set_usage(layer.bufferData->getUsage());
+ } else {
+ uint64_t bufferId;
+ uint32_t width;
+ uint32_t height;
+ int32_t pixelFormat;
+ uint64_t usage;
+ mMapper->getGraphicBufferPropertiesFromCache(layer.bufferData->cachedBuffer, &bufferId,
+ &width, &height, &pixelFormat, &usage);
+ bufferProto->set_buffer_id(bufferId);
+ bufferProto->set_width(width);
+ bufferProto->set_height(height);
+ bufferProto->set_pixel_format(
+ static_cast<proto::LayerState_BufferData_PixelFormat>(pixelFormat));
+ bufferProto->set_usage(usage);
}
bufferProto->set_frame_number(layer.bufferData->frameNumber);
bufferProto->set_flags(layer.bufferData->flags.get());
@@ -165,15 +180,15 @@
}
}
- if ((layer.what & layer_state_t::eReparent) && getLayerId != nullptr) {
+ if (layer.what & layer_state_t::eReparent) {
int32_t layerId = layer.parentSurfaceControlForChild
- ? getLayerId(layer.parentSurfaceControlForChild->getHandle())
+ ? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle())
: -1;
proto.set_parent_id(layerId);
}
- if ((layer.what & layer_state_t::eRelativeLayerChanged) && getLayerId != nullptr) {
+ if (layer.what & layer_state_t::eRelativeLayerChanged) {
int32_t layerId = layer.relativeLayerSurfaceControl
- ? getLayerId(layer.relativeLayerSurfaceControl->getHandle())
+ ? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle())
: -1;
proto.set_relative_parent_id(layerId);
proto.set_z(layer.z);
@@ -183,13 +198,16 @@
if (layer.windowInfoHandle) {
const gui::WindowInfo* inputInfo = layer.windowInfoHandle->getInfo();
proto::LayerState_WindowInfo* windowInfoProto = proto.mutable_window_info_handle();
- windowInfoProto->set_layout_params_flags(inputInfo->flags.get());
- windowInfoProto->set_layout_params_type(static_cast<int32_t>(inputInfo->type));
+ windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get());
+ windowInfoProto->set_layout_params_type(
+ static_cast<int32_t>(inputInfo->layoutParamsType));
LayerProtoHelper::writeToProto(inputInfo->touchableRegion,
windowInfoProto->mutable_touchable_region());
windowInfoProto->set_surface_inset(inputInfo->surfaceInset);
- windowInfoProto->set_focusable(inputInfo->focusable);
- windowInfoProto->set_has_wallpaper(inputInfo->hasWallpaper);
+ windowInfoProto->set_focusable(
+ !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
+ windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor);
proto::LayerState_Transform* transformProto = windowInfoProto->mutable_transform();
transformProto->set_dsdx(inputInfo->transform.dsdx());
@@ -200,12 +218,8 @@
transformProto->set_ty(inputInfo->transform.ty());
windowInfoProto->set_replace_touchable_region_with_crop(
inputInfo->replaceTouchableRegionWithCrop);
- if (getLayerId != nullptr) {
- windowInfoProto->set_crop_layer_id(
- getLayerId(inputInfo->touchableRegionCropHandle.promote()));
- } else {
- windowInfoProto->set_crop_layer_id(-1);
- }
+ windowInfoProto->set_crop_layer_id(
+ mMapper->getLayerId(inputInfo->touchableRegionCropHandle.promote()));
}
}
if (layer.what & layer_state_t::eBackgroundColorChanged) {
@@ -252,13 +266,10 @@
return proto;
}
-proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display,
- DisplayHandleToIdFn getDisplayId) {
+proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display) {
proto::DisplayState proto;
proto.set_what(display.what);
- if (getDisplayId != nullptr) {
- proto.set_id(getDisplayId(display.token));
- }
+ proto.set_id(mMapper->getDisplayId(display.token));
if (display.what & DisplayState::eLayerStackChanged) {
proto.set_layer_stack(display.layerStack.id);
@@ -290,9 +301,7 @@
return proto;
}
-TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto,
- LayerIdToHandleFn getLayerHandle,
- DisplayIdToHandleFn getDisplayHandle) {
+TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto) {
TransactionState t;
t.originPid = proto.pid();
t.originUid = proto.uid();
@@ -306,14 +315,14 @@
for (int i = 0; i < layerCount; i++) {
ComposerState s;
s.state.what = 0;
- fromProto(proto.layer_changes(i), getLayerHandle, s.state);
+ fromProto(proto.layer_changes(i), s.state);
t.states.add(s);
}
int32_t displayCount = proto.display_changes_size();
t.displays.reserve(static_cast<size_t>(displayCount));
for (int i = 0; i < displayCount; i++) {
- t.displays.add(fromProto(proto.display_changes(i), getDisplayHandle));
+ t.displays.add(fromProto(proto.display_changes(i)));
}
return t;
}
@@ -328,10 +337,9 @@
}
void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto,
- LayerIdToHandleFn getLayerHandle,
TracingLayerState& outState) {
layer_state_t state;
- fromProto(proto, getLayerHandle, state);
+ fromProto(proto, state);
outState.merge(state);
if (state.what & layer_state_t::eReparent) {
@@ -356,14 +364,10 @@
}
}
-void TransactionProtoParser::fromProto(const proto::LayerState& proto,
- LayerIdToHandleFn getLayerHandle, layer_state_t& layer) {
+void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) {
layer.layerId = proto.layer_id();
layer.what |= proto.what();
-
- if (getLayerHandle != nullptr) {
- layer.surface = getLayerHandle(layer.layerId);
- }
+ layer.surface = mMapper->getLayerHandle(layer.layerId);
if (proto.what() & layer_state_t::ePositionChanged) {
layer.x = proto.x();
@@ -420,13 +424,15 @@
LayerProtoHelper::readFromProto(proto.crop(), layer.crop);
}
if (proto.what() & layer_state_t::eBufferChanged) {
- if (!layer.bufferData) {
- layer.bufferData = std::make_shared<BufferData>();
- }
const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
+ layer.bufferData =
+ std::move(mMapper->getGraphicData(bufferProto.buffer_id(), bufferProto.width(),
+ bufferProto.height(), bufferProto.pixel_format(),
+ bufferProto.usage()));
layer.bufferData->frameNumber = bufferProto.frame_number();
layer.bufferData->flags = Flags<BufferData::BufferDataChange>(bufferProto.flags());
layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id();
+ layer.bufferData->acquireFence = Fence::NO_FENCE;
}
if (proto.what() & layer_state_t::eApiChanged) {
@@ -445,24 +451,24 @@
}
}
- if ((proto.what() & layer_state_t::eReparent) && (getLayerHandle != nullptr)) {
+ if (proto.what() & layer_state_t::eReparent) {
int32_t layerId = proto.parent_id();
if (layerId == -1) {
layer.parentSurfaceControlForChild = nullptr;
} else {
layer.parentSurfaceControlForChild =
- new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
- nullptr, layerId);
+ new SurfaceControl(SurfaceComposerClient::getDefault(),
+ mMapper->getLayerHandle(layerId), nullptr, layerId);
}
}
if (proto.what() & layer_state_t::eRelativeLayerChanged) {
int32_t layerId = proto.relative_parent_id();
if (layerId == -1) {
layer.relativeLayerSurfaceControl = nullptr;
- } else if (getLayerHandle != nullptr) {
+ } else {
layer.relativeLayerSurfaceControl =
- new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
- nullptr, layerId);
+ new SurfaceControl(SurfaceComposerClient::getDefault(),
+ mMapper->getLayerHandle(layerId), nullptr, layerId);
}
layer.z = proto.z();
}
@@ -471,13 +477,17 @@
gui::WindowInfo inputInfo;
const proto::LayerState_WindowInfo& windowInfoProto = proto.window_info_handle();
- inputInfo.flags = static_cast<gui::WindowInfo::Flag>(windowInfoProto.layout_params_flags());
- inputInfo.type = static_cast<gui::WindowInfo::Type>(windowInfoProto.layout_params_type());
+ inputInfo.layoutParamsFlags =
+ static_cast<gui::WindowInfo::Flag>(windowInfoProto.layout_params_flags());
+ inputInfo.layoutParamsType =
+ static_cast<gui::WindowInfo::Type>(windowInfoProto.layout_params_type());
LayerProtoHelper::readFromProto(windowInfoProto.touchable_region(),
inputInfo.touchableRegion);
inputInfo.surfaceInset = windowInfoProto.surface_inset();
- inputInfo.focusable = windowInfoProto.focusable();
- inputInfo.hasWallpaper = windowInfoProto.has_wallpaper();
+ inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE,
+ !windowInfoProto.focusable());
+ inputInfo.setInputConfig(gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER,
+ windowInfoProto.has_wallpaper());
inputInfo.globalScaleFactor = windowInfoProto.global_scale_factor();
const proto::LayerState_Transform& transformProto = windowInfoProto.transform();
inputInfo.transform.set(transformProto.dsdx(), transformProto.dtdx(), transformProto.dtdy(),
@@ -486,9 +496,7 @@
inputInfo.replaceTouchableRegionWithCrop =
windowInfoProto.replace_touchable_region_with_crop();
int32_t layerId = windowInfoProto.crop_layer_id();
- if (getLayerHandle != nullptr) {
- inputInfo.touchableRegionCropHandle = getLayerHandle(layerId);
- }
+ inputInfo.touchableRegionCropHandle = mMapper->getLayerHandle(layerId);
layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
}
if (proto.what() & layer_state_t::eBackgroundColorChanged) {
@@ -534,13 +542,10 @@
}
}
-DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto,
- DisplayIdToHandleFn getDisplayHandle) {
+DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto) {
DisplayState display;
display.what = proto.what();
- if (getDisplayHandle != nullptr) {
- display.token = getDisplayHandle(proto.id());
- }
+ display.token = mMapper->getDisplayHandle(proto.id());
if (display.what & DisplayState::eLayerStackChanged) {
display.layerStack.id = proto.layer_stack();
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index d589936..2f70b27 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -43,33 +43,77 @@
TracingLayerCreationArgs args;
};
-class TransactionProtoParser {
+// Class which exposes buffer properties from BufferData without holding on to the actual buffer
+// handle.
+class BufferDataStub : public BufferData {
public:
- typedef std::function<sp<IBinder>(int32_t)> LayerIdToHandleFn;
- typedef std::function<sp<IBinder>(int32_t)> DisplayIdToHandleFn;
- typedef std::function<int32_t(const sp<IBinder>&)> LayerHandleToIdFn;
- typedef std::function<int32_t(const sp<IBinder>&)> DisplayHandleToIdFn;
-
- static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn,
- DisplayHandleToIdFn getDisplayIdFn);
- static proto::TransactionState toProto(
- const std::map<int32_t /* layerId */, TracingLayerState>&);
-
- static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
-
- static TransactionState fromProto(const proto::TransactionState&,
- LayerIdToHandleFn getLayerHandleFn,
- DisplayIdToHandleFn getDisplayHandleFn);
- static void mergeFromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn,
- TracingLayerState& outState);
- static void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
+ BufferDataStub(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat,
+ uint64_t outUsage)
+ : mBufferId(bufferId),
+ mWidth(width),
+ mHeight(height),
+ mPixelFormat(pixelFormat),
+ mOutUsage(outUsage) {}
+ bool hasBuffer() const override { return mBufferId != 0; }
+ bool hasSameBuffer(const BufferData& other) const override {
+ return getId() == other.getId() && frameNumber == other.frameNumber;
+ }
+ uint32_t getWidth() const override { return mWidth; }
+ uint32_t getHeight() const override { return mHeight; }
+ uint64_t getId() const override { return mBufferId; }
+ PixelFormat getPixelFormat() const override { return mPixelFormat; }
+ uint64_t getUsage() const override { return mOutUsage; }
private:
- static proto::LayerState toProto(const layer_state_t&, LayerHandleToIdFn getLayerId);
- static proto::DisplayState toProto(const DisplayState&, DisplayHandleToIdFn getDisplayId);
- static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandle,
- layer_state_t& out);
- static DisplayState fromProto(const proto::DisplayState&, DisplayIdToHandleFn getDisplayHandle);
+ uint64_t mBufferId;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ int32_t mPixelFormat;
+ uint64_t mOutUsage;
+};
+
+class TransactionProtoParser {
+public:
+ // Utility class to map handles to ids and buffers to buffer properties without pulling
+ // in SurfaceFlinger dependencies.
+ class FlingerDataMapper {
+ public:
+ virtual ~FlingerDataMapper() = default;
+ virtual sp<IBinder> getLayerHandle(int32_t /* layerId */) const { return nullptr; }
+ virtual int32_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
+ virtual sp<IBinder> getDisplayHandle(int32_t /* displayId */) const { return nullptr; }
+ virtual int32_t getDisplayId(const sp<IBinder>& /* displayHandle */) const { return -1; }
+ virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width,
+ uint32_t height, int32_t pixelFormat,
+ uint64_t usage) const {
+ return std::make_shared<BufferDataStub>(bufferId, width, height, pixelFormat, usage);
+ }
+ virtual void getGraphicBufferPropertiesFromCache(client_cache_t /* cachedBuffer */,
+ uint64_t* /* outBufferId */,
+ uint32_t* /* outWidth */,
+ uint32_t* /* outHeight */,
+ int32_t* /* outPixelFormat */,
+ uint64_t* /* outUsage */) const {}
+ };
+
+ TransactionProtoParser(std::unique_ptr<FlingerDataMapper> provider)
+ : mMapper(std::move(provider)) {}
+
+ proto::TransactionState toProto(const TransactionState&);
+ proto::TransactionState toProto(const std::map<int32_t /* layerId */, TracingLayerState>&);
+ proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
+
+ TransactionState fromProto(const proto::TransactionState&);
+ void mergeFromProto(const proto::LayerState&, TracingLayerState& outState);
+ void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
+
+private:
+ proto::LayerState toProto(const layer_state_t&);
+ proto::DisplayState toProto(const DisplayState&);
+ void fromProto(const proto::LayerState&, layer_state_t& out);
+ DisplayState fromProto(const proto::DisplayState&);
+
+ std::unique_ptr<FlingerDataMapper> mMapper;
};
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index a46b795..d5e837f 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -23,11 +23,57 @@
#include <utils/SystemClock.h>
#include <utils/Trace.h>
+#include "ClientCache.h"
#include "TransactionTracing.h"
+#include "renderengine/ExternalTexture.h"
namespace android {
-TransactionTracing::TransactionTracing() {
+class FlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
+ std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
+
+public:
+ FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
+ : mLayerHandles(layerHandles) {}
+
+ int32_t getLayerId(const sp<IBinder>& layerHandle) const override {
+ if (layerHandle == nullptr) {
+ return -1;
+ }
+ auto it = mLayerHandles.find(layerHandle->localBinder());
+ if (it == mLayerHandles.end()) {
+ ALOGW("Could not find layer handle %p", layerHandle->localBinder());
+ return -1;
+ }
+ return it->second;
+ }
+
+ void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId,
+ uint32_t* outWidth, uint32_t* outHeight,
+ int32_t* outPixelFormat,
+ uint64_t* outUsage) const override {
+ std::shared_ptr<renderengine::ExternalTexture> buffer =
+ ClientCache::getInstance().get(cachedBuffer);
+ if (!buffer || !buffer->getBuffer()) {
+ *outBufferId = 0;
+ *outWidth = 0;
+ *outHeight = 0;
+ *outPixelFormat = 0;
+ *outUsage = 0;
+ return;
+ }
+
+ *outBufferId = buffer->getId();
+ *outWidth = buffer->getWidth();
+ *outHeight = buffer->getHeight();
+ *outPixelFormat = buffer->getPixelFormat();
+ *outUsage = buffer->getUsage();
+ return;
+ }
+};
+
+TransactionTracing::TransactionTracing()
+ : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)) {
std::scoped_lock lock(mTraceLock);
mBuffer.setSize(mBufferSizeInBytes);
@@ -53,11 +99,11 @@
writeToFile();
}
-status_t TransactionTracing::writeToFile() {
+status_t TransactionTracing::writeToFile(std::string filename) {
std::scoped_lock lock(mTraceLock);
proto::TransactionTraceFile fileProto = createTraceFileProto();
addStartingStateToProtoLocked(fileProto);
- return mBuffer.writeToFile(fileProto, FILE_NAME);
+ return mBuffer.writeToFile(fileProto, filename);
}
void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) {
@@ -85,11 +131,7 @@
void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
std::scoped_lock lock(mTraceLock);
ATRACE_CALL();
- mQueuedTransactions[transaction.id] =
- TransactionProtoParser::toProto(transaction,
- std::bind(&TransactionTracing::getLayerIdLocked, this,
- std::placeholders::_1),
- nullptr);
+ mQueuedTransactions[transaction.id] = mProtoParser.toProto(transaction);
}
void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
@@ -212,9 +254,7 @@
ALOGW("Duplicate handles found. %p", layerHandle);
}
mLayerHandles[layerHandle] = layerId;
- proto::LayerCreationArgs protoArgs = TransactionProtoParser::toProto(args);
- proto::LayerCreationArgs protoArgsCopy = protoArgs;
- mCreatedLayers.push_back(protoArgs);
+ mCreatedLayers.push_back(mProtoParser.toProto(args));
}
void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
@@ -225,7 +265,7 @@
ALOGW("Duplicate handles found. %p", layerHandle);
}
mLayerHandles[layerHandle] = layerId;
- mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
+ mCreatedLayers.emplace_back(mProtoParser.toProto(args));
}
void TransactionTracing::onLayerRemoved(int32_t layerId) {
@@ -263,18 +303,6 @@
}
}
-int32_t TransactionTracing::getLayerIdLocked(const sp<IBinder>& layerHandle) {
- if (layerHandle == nullptr) {
- return -1;
- }
- auto it = mLayerHandles.find(layerHandle->localBinder());
- if (it == mLayerHandles.end()) {
- ALOGW("Could not find layer handle %p", layerHandle->localBinder());
- return -1;
- }
- return it->second;
-}
-
void TransactionTracing::updateStartingStateLocked(
const proto::TransactionTraceEntry& removedEntry) {
mStartingTimestamp = removedEntry.elapsed_realtime_nanos();
@@ -283,7 +311,7 @@
for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
startingState.layerId = addedLayer.layer_id();
- TransactionProtoParser::fromProto(addedLayer, startingState.args);
+ mProtoParser.fromProto(addedLayer, startingState.args);
}
// Merge layer states to starting transaction state.
@@ -294,7 +322,7 @@
ALOGW("Could not find layer id %d", layerState.layer_id());
continue;
}
- TransactionProtoParser::mergeFromProto(layerState, nullptr, it->second);
+ mProtoParser.mergeFromProto(layerState, it->second);
}
}
@@ -316,10 +344,10 @@
entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
for (auto& [layerId, state] : mStartingStates) {
- entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(state.args));
+ entryProto->mutable_added_layers()->Add(mProtoParser.toProto(state.args));
}
- proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
+ proto::TransactionState transactionProto = mProtoParser.toProto(mStartingStates);
transactionProto.set_vsync_id(0);
transactionProto.set_post_time(mStartingTimestamp);
entryProto->mutable_transactions()->Add(std::move(transactionProto));
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index d5d98ce..95256c4 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -55,7 +55,7 @@
void addQueuedTransaction(const TransactionState&);
void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId);
- status_t writeToFile();
+ status_t writeToFile(std::string filename = FILE_NAME);
void setBufferSize(size_t bufferSizeInBytes);
void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags,
int parentId);
@@ -84,6 +84,7 @@
GUARDED_BY(mTraceLock);
std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock);
std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
+ TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock);
// We do not want main thread to block so main thread will try to acquire mMainThreadLock,
// otherwise will push data to temporary container.
diff --git a/services/surfaceflinger/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp
new file mode 100644
index 0000000..e8fe734
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/Android.bp
@@ -0,0 +1,55 @@
+// 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.
+
+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_binary {
+ name: "layertracegenerator",
+ defaults: [
+ "libsurfaceflinger_mocks_defaults",
+ "surfaceflinger_defaults",
+ "skia_renderengine_deps",
+ ],
+ srcs: [
+ ":libsurfaceflinger_sources",
+ ":libsurfaceflinger_mock_sources",
+ ":layertracegenerator_sources",
+ "main.cpp",
+ ],
+ static_libs: [
+ "libgtest",
+ ],
+ header_libs: [
+ "libsurfaceflinger_mocks_headers",
+ ],
+}
+
+filegroup {
+ name: "layertracegenerator_sources",
+ srcs: [
+ "LayerTraceGenerator.cpp",
+ ],
+}
+
+cc_library_headers {
+ name: "layertracegenerator_headers",
+ export_include_dirs: ["."],
+}
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
new file mode 100644
index 0000000..9cbd257
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerTraceGenerator"
+
+#include <TestableSurfaceFlinger.h>
+#include <Tracing/TransactionProtoParser.h>
+#include <binder/IPCThreadState.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerState.h>
+#include <log/log.h>
+#include <mock/MockEventThread.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/mock/FakeExternalTexture.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <utils/String16.h>
+#include <string>
+
+#include "LayerTraceGenerator.h"
+
+namespace android {
+
+class Factory final : public surfaceflinger::Factory {
+public:
+ ~Factory() = default;
+
+ std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; }
+
+ std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
+ Fps /*currentRefreshRate*/) override {
+ return std::make_unique<scheduler::FakePhaseOffsets>();
+ }
+
+ sp<SurfaceInterceptor> createSurfaceInterceptor() override {
+ return new android::impl::SurfaceInterceptor();
+ }
+
+ sp<StartPropertySetThread> createStartPropertySetThread(
+ bool /* timestampPropertyValue */) override {
+ return nullptr;
+ }
+
+ sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& /* creationArgs */) override {
+ return nullptr;
+ }
+
+ sp<GraphicBuffer> createGraphicBuffer(uint32_t /* width */, uint32_t /* height */,
+ PixelFormat /* format */, uint32_t /* layerCount */,
+ uint64_t /* usage */,
+ std::string /* requestorName */) override {
+ return nullptr;
+ }
+
+ void createBufferQueue(sp<IGraphicBufferProducer>* /* outProducer */,
+ sp<IGraphicBufferConsumer>* /* outConsumer */,
+ bool /* consumerIsSurfaceFlinger */) override {}
+
+ sp<IGraphicBufferProducer> createMonitoredProducer(
+ const sp<IGraphicBufferProducer>& /* producer */,
+ const sp<SurfaceFlinger>& /* flinger */, const wp<Layer>& /* layer */) override {
+ return nullptr;
+ }
+
+ sp<BufferLayerConsumer> createBufferLayerConsumer(
+ const sp<IGraphicBufferConsumer>& /* consumer */,
+ renderengine::RenderEngine& /* renderEngine */, uint32_t /* textureName */,
+ Layer* /* layer */) override {
+ return nullptr;
+ }
+
+ std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+ const sp<IGraphicBufferProducer>& /* producer */) override {
+ return nullptr;
+ }
+
+ std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override {
+ return compositionengine::impl::createCompositionEngine();
+ }
+
+ sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) {
+ return sp<ContainerLayer>::make(args);
+ }
+
+ sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) {
+ return new BufferStateLayer(args);
+ }
+
+ sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) {
+ return new EffectLayer(args);
+ }
+
+ sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
+ return nullptr;
+ }
+
+ std::unique_ptr<FrameTracer> createFrameTracer() override {
+ return std::make_unique<testing::NiceMock<mock::FrameTracer>>();
+ }
+
+ std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
+ std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid = 0) override {
+ return std::make_unique<testing::NiceMock<mock::FrameTimeline>>(timeStats,
+ surfaceFlingerPid);
+ }
+};
+
+class MockSurfaceFlinger : public SurfaceFlinger {
+public:
+ MockSurfaceFlinger(Factory& factory)
+ : SurfaceFlinger(factory, SurfaceFlinger::SkipInitialization) {}
+ std::shared_ptr<renderengine::ExternalTexture> getExternalTextureFromBufferData(
+ const BufferData& bufferData, const char* /* layerName */) const override {
+ return std::make_shared<renderengine::mock::FakeExternalTexture>(bufferData.getWidth(),
+ bufferData.getHeight(),
+ bufferData.getId(),
+ bufferData
+ .getPixelFormat(),
+ bufferData.getUsage());
+ };
+
+ // b/220017192 migrate from transact codes to ISurfaceComposer apis
+ void setLayerTracingFlags(int32_t flags) {
+ Parcel data;
+ Parcel reply;
+ data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+ data.writeInt32(flags);
+ transact(1033, data, &reply, 0 /* flags */);
+ }
+
+ void startLayerTracing(int64_t traceStartTime) {
+ Parcel data;
+ Parcel reply;
+ data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+ data.writeInt32(1);
+ data.writeInt64(traceStartTime);
+ transact(1025, data, &reply, 0 /* flags */);
+ }
+
+ void stopLayerTracing(const char* tracePath) {
+ Parcel data;
+ Parcel reply;
+ data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+ data.writeInt32(2);
+ data.writeCString(tracePath);
+ transact(1025, data, &reply, 0 /* flags */);
+ }
+};
+
+class TraceGenFlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
+public:
+ std::unordered_map<int32_t /*layerId*/, sp<IBinder> /* handle */> mLayerHandles;
+ sp<IBinder> getLayerHandle(int32_t layerId) const override {
+ if (layerId == -1) {
+ ALOGE("Error: Called with layer=%d", layerId);
+ return nullptr;
+ }
+ auto it = mLayerHandles.find(layerId);
+ if (it == mLayerHandles.end()) {
+ ALOGE("Error: Could not find handle for layer=%d", layerId);
+ return nullptr;
+ }
+ return it->second;
+ }
+};
+
+bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile,
+ const char* outputLayersTracePath) {
+ if (traceFile.entry_size() == 0) {
+ ALOGD("Trace file is empty");
+ return false;
+ }
+
+ Factory mFactory;
+ sp<MockSurfaceFlinger> flinger = new MockSurfaceFlinger(mFactory);
+ TestableSurfaceFlinger mFlinger(flinger);
+ mFlinger.setupRenderEngine(
+ std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>());
+ mock::VsyncController* mVsyncController = new testing::NiceMock<mock::VsyncController>();
+ mock::VSyncTracker* mVSyncTracker = new testing::NiceMock<mock::VSyncTracker>();
+ mock::EventThread* mEventThread = new testing::NiceMock<mock::EventThread>();
+ mock::EventThread* mSFEventThread = new testing::NiceMock<mock::EventThread>();
+ mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController),
+ std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker),
+ std::unique_ptr<EventThread>(mEventThread),
+ std::unique_ptr<EventThread>(mSFEventThread),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+ TestableSurfaceFlinger::kOneDisplayMode, true /* useNiceMock */);
+
+ Hwc2::mock::Composer* mComposer = new testing::NiceMock<Hwc2::mock::Composer>();
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+ mFlinger.mutableMaxRenderTargetSize() = 16384;
+
+ flinger->setLayerTracingFlags(LayerTracing::TRACE_BUFFERS | LayerTracing::TRACE_INPUT |
+ LayerTracing::TRACE_BUFFERS);
+ flinger->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos());
+ std::unique_ptr<TraceGenFlingerDataMapper> mapper =
+ std::make_unique<TraceGenFlingerDataMapper>();
+ TraceGenFlingerDataMapper* dataMapper = mapper.get();
+ TransactionProtoParser parser(std::move(mapper));
+
+ nsecs_t frameTime;
+ int64_t vsyncId;
+ ALOGD("Generating %d transactions...", traceFile.entry_size());
+ for (int i = 0; i < traceFile.entry_size(); i++) {
+ proto::TransactionTraceEntry entry = traceFile.entry(i);
+ ALOGV(" Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64
+ " layers +%d -%d transactions=%d",
+ i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(),
+ entry.added_layers_size(), entry.removed_layers_size(), entry.transactions_size());
+
+ for (int j = 0; j < entry.added_layers_size(); j++) {
+ // create layers
+ TracingLayerCreationArgs tracingArgs;
+ parser.fromProto(entry.added_layers(j), tracingArgs);
+
+ sp<IBinder> outHandle;
+ int32_t outLayerId;
+ LayerCreationArgs args(mFlinger.flinger(), nullptr /* client */, tracingArgs.name,
+ tracingArgs.flags, LayerMetadata());
+ args.sequence = std::make_optional<int32_t>(tracingArgs.layerId);
+
+ if (tracingArgs.mirrorFromId == -1) {
+ sp<IBinder> parentHandle = nullptr;
+ if ((tracingArgs.parentId != -1) &&
+ (dataMapper->mLayerHandles.find(tracingArgs.parentId) ==
+ dataMapper->mLayerHandles.end())) {
+ args.addToRoot = false;
+ } else {
+ parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId);
+ }
+ mFlinger.createLayer(args, &outHandle, parentHandle, &outLayerId,
+ nullptr /* parentLayer */, nullptr /* outTransformHint */);
+ } else {
+ sp<IBinder> mirrorFromHandle = dataMapper->getLayerHandle(tracingArgs.mirrorFromId);
+ mFlinger.mirrorLayer(args, mirrorFromHandle, &outHandle, &outLayerId);
+ }
+ LOG_ALWAYS_FATAL_IF(outLayerId != tracingArgs.layerId,
+ "Could not create layer expected:%d actual:%d", tracingArgs.layerId,
+ outLayerId);
+ dataMapper->mLayerHandles[tracingArgs.layerId] = outHandle;
+ }
+
+ for (int j = 0; j < entry.transactions_size(); j++) {
+ // apply transactions
+ TransactionState transaction = parser.fromProto(entry.transactions(j));
+ mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
+ transaction.displays, transaction.flags,
+ transaction.applyToken, transaction.inputWindowCommands,
+ transaction.desiredPresentTime,
+ transaction.isAutoTimestamp, {},
+ transaction.hasListenerCallbacks,
+ transaction.listenerCallbacks, transaction.id);
+ }
+
+ for (int j = 0; j < entry.removed_layer_handles_size(); j++) {
+ dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j));
+ }
+
+ frameTime = entry.elapsed_realtime_nanos();
+ vsyncId = entry.vsync_id();
+ mFlinger.commit(frameTime, vsyncId);
+ }
+
+ flinger->stopLayerTracing(outputLayersTracePath);
+ ALOGD("End of generating trace file. File written to %s", outputLayersTracePath);
+ dataMapper->mLayerHandles.clear();
+ return true;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
similarity index 66%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
index 7343515..ee1ea6c 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * 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.
@@ -14,6 +14,13 @@
* limitations under the License.
*/
-package android.gui;
+#pragma once
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+#include <Tracing/TransactionTracing.h>
+
+namespace android {
+class LayerTraceGenerator {
+public:
+ bool generate(const proto::TransactionTraceFile&, const char* outputLayersTracePath);
+};
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Tracing/tools/main.cpp b/services/surfaceflinger/Tracing/tools/main.cpp
new file mode 100644
index 0000000..f3cf42d
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/main.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerTraceGenerator"
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include "LayerTraceGenerator.h"
+
+using namespace android;
+
+int main(int argc, char** argv) {
+ if (argc > 3) {
+ std::cout << "Usage: " << argv[0]
+ << " [transaction-trace-path] [output-layers-trace-path]\n";
+ return -1;
+ }
+
+ const char* transactionTracePath =
+ (argc > 1) ? argv[1] : "/data/misc/wmtrace/transactions_trace.winscope";
+ std::cout << "Parsing " << transactionTracePath << "\n";
+ std::fstream input(transactionTracePath, std::ios::in | std::ios::binary);
+ if (!input) {
+ std::cout << "Error: Could not open " << transactionTracePath;
+ return -1;
+ }
+
+ proto::TransactionTraceFile transactionTraceFile;
+ if (!transactionTraceFile.ParseFromIstream(&input)) {
+ std::cout << "Error: Failed to parse " << transactionTracePath;
+ return -1;
+ }
+
+ const char* outputLayersTracePath =
+ (argc == 3) ? argv[2] : "/data/misc/wmtrace/layers_trace.winscope";
+ ;
+ ALOGD("Generating %s...", outputLayersTracePath);
+ std::cout << "Generating " << outputLayersTracePath << "\n";
+ if (!LayerTraceGenerator().generate(transactionTraceFile, outputLayersTracePath)) {
+ std::cout << "Error: Failed to generate layers trace " << outputLayersTracePath;
+ return -1;
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/Tracing/tools/readme.md b/services/surfaceflinger/Tracing/tools/readme.md
new file mode 100644
index 0000000..143c14f
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/readme.md
@@ -0,0 +1,13 @@
+### LayerTraceGenerator ###
+
+Generates layer traces from transaction traces. The tool is a custom
+surface flinger build that mocks out everything else apart from the
+front end logic. Transaction traces are written when the transaction
+is applied, along wth a timestamp and vsync id. The transactions
+are parsed from proto and applied to recreate the layer state. The
+result is then written as a layer trace.
+
+Usage:
+1. build and push to device
+2. run ./layertracegenerator [transaction-trace-path] [output-layers-trace-path]
+
diff --git a/services/surfaceflinger/Tracing/tools/run.sh b/services/surfaceflinger/Tracing/tools/run.sh
new file mode 100644
index 0000000..baa93f1
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/run.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -ex
+
+# Build, push and run layertracegenerator
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode layertracegenerator
+adb wait-for-device && adb push $OUT/system/bin/layertracegenerator /data/layertracegenerator
+echo "Writing transaction trace to file"
+adb shell service call SurfaceFlinger 1041 i32 0
+adb shell /data/layertracegenerator
+adb pull /data/misc/wmtrace/layers_trace.winscope
\ No newline at end of file
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 23cd993..30b9d8f 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#include "WindowInfosListenerInvoker.h"
+#include <ftl/small_vector.h>
#include <gui/ISurfaceComposer.h>
-#include <unordered_set>
+
#include "SurfaceFlinger.h"
+#include "WindowInfosListenerInvoker.h"
namespace android {
@@ -41,18 +42,17 @@
: mFlinger(flinger),
mWindowInfosReportedListener(sp<WindowInfosReportedListener>::make(*this)) {}
-void WindowInfosListenerInvoker::addWindowInfosListener(
- const sp<IWindowInfosListener>& windowInfosListener) {
- sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener);
-
+void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
asBinder->linkToDeath(this);
+
std::scoped_lock lock(mListenersMutex);
- mWindowInfosListeners.emplace(asBinder, windowInfosListener);
+ mWindowInfosListeners.try_emplace(asBinder, std::move(listener));
}
void WindowInfosListenerInvoker::removeWindowInfosListener(
- const sp<IWindowInfosListener>& windowInfosListener) {
- sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener);
+ const sp<IWindowInfosListener>& listener) {
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
std::scoped_lock lock(mListenersMutex);
asBinder->unlinkToDeath(this);
@@ -67,12 +67,11 @@
void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
const std::vector<DisplayInfo>& displayInfos,
bool shouldSync) {
- std::unordered_set<sp<IWindowInfosListener>, SpHash<IWindowInfosListener>> windowInfosListeners;
-
+ ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
{
std::scoped_lock lock(mListenersMutex);
for (const auto& [_, listener] : mWindowInfosListeners) {
- windowInfosListeners.insert(listener);
+ windowInfosListeners.push_back(listener);
}
}
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index 2eabf48..d8d8d0f 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -20,10 +20,8 @@
#include <android/gui/IWindowInfosListener.h>
#include <android/gui/IWindowInfosReportedListener.h>
#include <binder/IBinder.h>
+#include <ftl/small_map.h>
#include <utils/Mutex.h>
-#include <unordered_map>
-
-#include "WpHash.h"
namespace android {
@@ -33,7 +31,7 @@
public:
explicit WindowInfosListenerInvoker(SurfaceFlinger&);
- void addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
+ void addWindowInfosListener(sp<gui::IWindowInfosListener>);
void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
void windowInfosChanged(const std::vector<gui::WindowInfo>&,
@@ -48,8 +46,11 @@
SurfaceFlinger& mFlinger;
std::mutex mListenersMutex;
- std::unordered_map<wp<IBinder>, const sp<gui::IWindowInfosListener>, WpHash>
+
+ static constexpr size_t kStaticCapacity = 3;
+ ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity>
mWindowInfosListeners GUARDED_BY(mListenersMutex);
+
sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener;
std::atomic<size_t> mCallbacksPending{0};
};
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index b0d216e..7350e09 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -15,6 +15,15 @@
*
*/
+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_defaults {
name: "surfaceflinger_fuzz_defaults",
include_dirs: [
@@ -102,3 +111,29 @@
"surfaceflinger_scheduler_fuzzer.cpp",
],
}
+
+cc_fuzz {
+ name: "surfaceflinger_layer_fuzzer",
+ defaults: [
+ "surfaceflinger_fuzz_defaults",
+ ],
+ header_libs: [
+ "libgui_headers",
+ ],
+ static_libs: [
+ "librenderengine",
+ ],
+ srcs: [
+ "surfaceflinger_layer_fuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "surfaceflinger_frametracer_fuzzer",
+ defaults: [
+ "surfaceflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "surfaceflinger_frametracer_fuzzer.cpp",
+ ],
+}
diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md
index 6231ca5..7a5f229 100644
--- a/services/surfaceflinger/fuzzer/README.md
+++ b/services/surfaceflinger/fuzzer/README.md
@@ -3,6 +3,8 @@
+ [SurfaceFlinger](#SurfaceFlinger)
+ [DisplayHardware](#DisplayHardware)
+ [Scheduler](#Scheduler)
++ [Layer](#Layer)
++ [FrameTracer](#FrameTracer)
# <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger
@@ -70,3 +72,38 @@
$ adb sync data
$ adb shell /data/fuzz/arm64/surfaceflinger_scheduler_fuzzer/surfaceflinger_scheduler_fuzzer
```
+
+# <a name="Layer"></a> Fuzzer for Layer
+
+Layer supports the following parameters:
+1. Display Connection Types (parameter name: `fakeDisplay`)
+2. State Sets (parameter name: `traverseInZOrder`)
+3. State Subsets (parameter name: `prepareCompositionState`)
+4. Disconnect modes (parameter name: `disconnect`)
+5. Data Spaces (parameter name: `setDataspace`)
+
+You can find the possible values in the fuzzer's source code.
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) surfaceflinger_layer_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/surfaceflinger_layer_fuzzer/surfaceflinger_layer_fuzzer
+```
+
+# <a name="FrameTracer"></a> Fuzzer for FrameTracer
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) surfaceflinger_frametracer_fuzzer
+```
+2. To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/surfaceflinger_frametracer_fuzzer/surfaceflinger_frametracer_fuzzer
+```
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp
new file mode 100644
index 0000000..a22a778
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2021 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 <FrameTracer/FrameTracer.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <perfetto/trace/trace.pb.h>
+
+namespace android::fuzz {
+
+using namespace google::protobuf;
+
+constexpr size_t kMaxStringSize = 100;
+constexpr size_t kMinLayerIds = 1;
+constexpr size_t kMaxLayerIds = 10;
+constexpr int32_t kConfigDuration = 500;
+constexpr int32_t kBufferSize = 1024;
+constexpr int32_t kTimeOffset = 100000;
+
+class FrameTracerFuzzer {
+public:
+ FrameTracerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {
+ // Fuzzer is single-threaded, so no need to be thread-safe.
+ static bool wasInitialized = false;
+ if (!wasInitialized) {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kInProcessBackend;
+ perfetto::Tracing::Initialize(args);
+ wasInitialized = true;
+ }
+ mFrameTracer = std::make_unique<android::FrameTracer>();
+ }
+ ~FrameTracerFuzzer() { mFrameTracer.reset(); }
+ void process();
+
+private:
+ std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest();
+ void traceTimestamp();
+ std::vector<int32_t> generateLayerIds(size_t numLayerIds);
+ void traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds);
+ void traceFence(std::vector<int32_t> layerIds, size_t numLayerIds);
+ std::unique_ptr<android::FrameTracer> mFrameTracer = nullptr;
+ FuzzedDataProvider mFdp;
+ android::FenceToFenceTimeMap mFenceFactory;
+};
+
+std::unique_ptr<perfetto::TracingSession> FrameTracerFuzzer::getTracingSessionForTest() {
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(kConfigDuration);
+ cfg.add_buffers()->set_size_kb(kBufferSize);
+ auto* dsCfg = cfg.add_data_sources()->mutable_config();
+ dsCfg->set_name(android::FrameTracer::kFrameTracerDataSource);
+
+ auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+ tracingSession->Setup(cfg);
+ return tracingSession;
+}
+
+std::vector<int32_t> FrameTracerFuzzer::generateLayerIds(size_t numLayerIds) {
+ std::vector<int32_t> layerIds;
+ for (size_t i = 0; i < numLayerIds; ++i) {
+ layerIds.push_back(mFdp.ConsumeIntegral<int32_t>());
+ }
+ return layerIds;
+}
+
+void FrameTracerFuzzer::traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds) {
+ int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1));
+ mFrameTracer->traceTimestamp(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/,
+ mFdp.ConsumeIntegral<nsecs_t>() /*timestamp*/,
+ android::FrameTracer::FrameEvent::UNSPECIFIED,
+ mFdp.ConsumeIntegral<nsecs_t>() /*duration*/);
+}
+
+void FrameTracerFuzzer::traceFence(std::vector<int32_t> layerIds, size_t numLayerIds) {
+ const nsecs_t signalTime = systemTime();
+ const nsecs_t startTime = signalTime + kTimeOffset;
+ auto fence = mFenceFactory.createFenceTimeForTest(android::Fence::NO_FENCE);
+ mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, signalTime);
+ int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1));
+ mFrameTracer->traceFence(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/, fence,
+ android::FrameTracer::FrameEvent::ACQUIRE_FENCE, startTime);
+}
+
+void FrameTracerFuzzer::process() {
+ mFrameTracer->registerDataSource();
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+
+ size_t numLayerIds = mFdp.ConsumeIntegralInRange<size_t>(kMinLayerIds, kMaxLayerIds);
+ std::vector<int32_t> layerIds = generateLayerIds(numLayerIds);
+
+ for (auto it = layerIds.begin(); it != layerIds.end(); ++it) {
+ mFrameTracer->traceNewLayer(*it /*layerId*/,
+ mFdp.ConsumeRandomLengthString(kMaxStringSize) /*layerName*/);
+ }
+
+ traceTimestamp(layerIds, numLayerIds);
+ traceFence(layerIds, numLayerIds);
+
+ mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, systemTime());
+
+ tracingSession->StopBlocking();
+
+ for (auto it = layerIds.begin(); it != layerIds.end(); ++it) {
+ mFrameTracer->onDestroy(*it);
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FrameTracerFuzzer frameTracerFuzzer(data, size);
+ frameTracerFuzzer.process();
+ return 0;
+}
+
+} // namespace android::fuzz
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index 30a6fbd..afc1abd 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -29,35 +29,6 @@
LatchUnsignaledConfig::Disabled,
};
-static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888,
- ui::PixelFormat::RGBX_8888,
- ui::PixelFormat::RGB_888,
- ui::PixelFormat::RGB_565,
- ui::PixelFormat::BGRA_8888,
- ui::PixelFormat::YCBCR_422_SP,
- ui::PixelFormat::YCRCB_420_SP,
- ui::PixelFormat::YCBCR_422_I,
- ui::PixelFormat::RGBA_FP16,
- ui::PixelFormat::RAW16,
- ui::PixelFormat::BLOB,
- ui::PixelFormat::IMPLEMENTATION_DEFINED,
- ui::PixelFormat::YCBCR_420_888,
- ui::PixelFormat::RAW_OPAQUE,
- ui::PixelFormat::RAW10,
- ui::PixelFormat::RAW12,
- ui::PixelFormat::RGBA_1010102,
- ui::PixelFormat::Y8,
- ui::PixelFormat::Y16,
- ui::PixelFormat::YV12,
- ui::PixelFormat::DEPTH_16,
- ui::PixelFormat::DEPTH_24,
- ui::PixelFormat::DEPTH_24_STENCIL_8,
- ui::PixelFormat::DEPTH_32F,
- ui::PixelFormat::DEPTH_32F_STENCIL_8,
- ui::PixelFormat::STENCIL_8,
- ui::PixelFormat::YCBCR_P010,
- ui::PixelFormat::HSV_888};
-
static constexpr ui::Rotation kRotations[] = {ui::Rotation::Rotation0, ui::Rotation::Rotation90,
ui::Rotation::Rotation180, ui::Rotation::Rotation270};
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 0a458c2..2fcf856 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -123,6 +123,35 @@
ui::ColorMode::BT2100_HLG,
ui::ColorMode::DISPLAY_BT2020};
+static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888,
+ ui::PixelFormat::RGBX_8888,
+ ui::PixelFormat::RGB_888,
+ ui::PixelFormat::RGB_565,
+ ui::PixelFormat::BGRA_8888,
+ ui::PixelFormat::YCBCR_422_SP,
+ ui::PixelFormat::YCRCB_420_SP,
+ ui::PixelFormat::YCBCR_422_I,
+ ui::PixelFormat::RGBA_FP16,
+ ui::PixelFormat::RAW16,
+ ui::PixelFormat::BLOB,
+ ui::PixelFormat::IMPLEMENTATION_DEFINED,
+ ui::PixelFormat::YCBCR_420_888,
+ ui::PixelFormat::RAW_OPAQUE,
+ ui::PixelFormat::RAW10,
+ ui::PixelFormat::RAW12,
+ ui::PixelFormat::RGBA_1010102,
+ ui::PixelFormat::Y8,
+ ui::PixelFormat::Y16,
+ ui::PixelFormat::YV12,
+ ui::PixelFormat::DEPTH_16,
+ ui::PixelFormat::DEPTH_24,
+ ui::PixelFormat::DEPTH_24_STENCIL_8,
+ ui::PixelFormat::DEPTH_32F,
+ ui::PixelFormat::DEPTH_32F_STENCIL_8,
+ ui::PixelFormat::STENCIL_8,
+ ui::PixelFormat::YCBCR_P010,
+ ui::PixelFormat::HSV_888};
+
FloatRect getFuzzedFloatRect(FuzzedDataProvider *fdp) {
return FloatRect(fdp->ConsumeFloatingPoint<float>() /*left*/,
fdp->ConsumeFloatingPoint<float>() /*right*/,
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
new file mode 100644
index 0000000..46d52dd
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2021 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 <BufferStateLayer.h>
+#include <Client.h>
+#include <DisplayDevice.h>
+#include <EffectLayer.h>
+#include <LayerRejecter.h>
+#include <LayerRenderArea.h>
+#include <MonitoredProducer.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gui/IProducerListener.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/WindowInfo.h>
+#include <renderengine/mock/FakeExternalTexture.h>
+#include <ui/DisplayStatInfo.h>
+
+#include <FuzzableDataspaces.h>
+#include <surfaceflinger_fuzzers_utils.h>
+
+namespace android::fuzzer {
+using namespace renderengine;
+
+constexpr uint16_t kRandomStringLength = 256;
+
+class LayerFuzzer {
+public:
+ LayerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void init();
+ void invokeBufferStateLayer();
+ void invokeEffectLayer();
+ LayerCreationArgs createLayerCreationArgs(TestableSurfaceFlinger* flinger, sp<Client> client);
+ Rect getFuzzedRect();
+ FrameTimelineInfo getFuzzedFrameTimelineInfo();
+
+private:
+ FuzzedDataProvider mFdp;
+};
+
+Rect LayerFuzzer::getFuzzedRect() {
+ return Rect(mFdp.ConsumeIntegral<int32_t>() /*left*/, mFdp.ConsumeIntegral<int32_t>() /*top*/,
+ mFdp.ConsumeIntegral<int32_t>() /*right*/,
+ mFdp.ConsumeIntegral<int32_t>() /*bottom*/);
+}
+
+FrameTimelineInfo LayerFuzzer::getFuzzedFrameTimelineInfo() {
+ return FrameTimelineInfo{.vsyncId = mFdp.ConsumeIntegral<int64_t>(),
+ .inputEventId = mFdp.ConsumeIntegral<int32_t>()};
+}
+
+LayerCreationArgs LayerFuzzer::createLayerCreationArgs(TestableSurfaceFlinger* flinger,
+ sp<Client> client) {
+ flinger->setupScheduler(std::make_unique<android::mock::VsyncController>(),
+ std::make_unique<android::mock::VSyncTracker>(),
+ std::make_unique<android::mock::EventThread>(),
+ std::make_unique<android::mock::EventThread>());
+
+ return LayerCreationArgs(flinger->flinger(), client,
+ mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/,
+ mFdp.ConsumeIntegral<uint32_t>() /*flags*/, {} /*metadata*/);
+}
+
+void LayerFuzzer::invokeEffectLayer() {
+ TestableSurfaceFlinger flinger;
+ sp<Client> client = sp<Client>::make(flinger.flinger());
+ const LayerCreationArgs layerCreationArgs = createLayerCreationArgs(&flinger, client);
+ sp<EffectLayer> effectLayer = sp<EffectLayer>::make(layerCreationArgs);
+
+ effectLayer->setColor({(mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*x*/,
+ mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*y*/,
+ mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*z*/)});
+ effectLayer->setDataspace(mFdp.PickValueInArray(kDataspaces));
+ sp<EffectLayer> parent = sp<EffectLayer>::make(layerCreationArgs);
+ effectLayer->setChildrenDrawingParent(parent);
+
+ const FrameTimelineInfo frameInfo = getFuzzedFrameTimelineInfo();
+ const int64_t postTime = mFdp.ConsumeIntegral<int64_t>();
+ effectLayer->setFrameTimelineVsyncForBufferTransaction(frameInfo, postTime);
+ effectLayer->setFrameTimelineVsyncForBufferlessTransaction(frameInfo, postTime);
+ auto surfaceFrame = effectLayer->createSurfaceFrameForTransaction(frameInfo, postTime);
+ auto surfaceFrame1 =
+ effectLayer->createSurfaceFrameForBuffer(frameInfo, postTime,
+ mFdp.ConsumeRandomLengthString(
+ kRandomStringLength) /*bufferName*/);
+ effectLayer->addSurfaceFramePresentedForBuffer(surfaceFrame,
+ mFdp.ConsumeIntegral<int64_t>() /*acquireTime*/,
+ mFdp.ConsumeIntegral<int64_t>() /*currentTime*/);
+ effectLayer->addSurfaceFrameDroppedForBuffer(surfaceFrame1);
+
+ parent.clear();
+ client.clear();
+ effectLayer.clear();
+}
+
+void LayerFuzzer::invokeBufferStateLayer() {
+ TestableSurfaceFlinger flinger;
+ sp<Client> client = sp<Client>::make(flinger.flinger());
+ sp<BufferStateLayer> layer =
+ sp<BufferStateLayer>::make(createLayerCreationArgs(&flinger, client));
+ sp<Fence> fence = sp<Fence>::make();
+ const std::shared_ptr<FenceTime> fenceTime = std::make_shared<FenceTime>(fence);
+
+ const CompositorTiming compositor = {mFdp.ConsumeIntegral<int64_t>(),
+ mFdp.ConsumeIntegral<int64_t>(),
+ mFdp.ConsumeIntegral<int64_t>()};
+ std::packaged_task<renderengine::RenderEngineResult()> renderResult([&] {
+ return renderengine::RenderEngineResult{mFdp.ConsumeIntegral<int32_t>(),
+ base::unique_fd(fence->get())};
+ });
+ layer->onLayerDisplayed(renderResult.get_future());
+ layer->releasePendingBuffer(mFdp.ConsumeIntegral<int64_t>());
+ layer->finalizeFrameEventHistory(fenceTime, compositor);
+ layer->onPostComposition(nullptr, fenceTime, fenceTime, compositor);
+ layer->isBufferDue(mFdp.ConsumeIntegral<int64_t>());
+
+ layer->setTransform(mFdp.ConsumeIntegral<uint32_t>());
+ layer->setTransformToDisplayInverse(mFdp.ConsumeBool());
+ layer->setCrop(getFuzzedRect());
+
+ layer->setHdrMetadata(getFuzzedHdrMetadata(&mFdp));
+ layer->setDataspace(mFdp.PickValueInArray(kDataspaces));
+ if (mFdp.ConsumeBool()) {
+ layer->setSurfaceDamageRegion(Region());
+ layer->setTransparentRegionHint(Region());
+ } else {
+ layer->setSurfaceDamageRegion(Region(getFuzzedRect()));
+ layer->setTransparentRegionHint(Region(getFuzzedRect()));
+ }
+ layer->setApi(mFdp.ConsumeIntegral<int32_t>());
+
+ native_handle_t* testHandle = native_handle_create(0, 1);
+ const bool ownsHandle = mFdp.ConsumeBool();
+ sp<NativeHandle> nativeHandle = sp<NativeHandle>::make(testHandle, ownsHandle);
+ layer->setSidebandStream(nativeHandle);
+ layer->addFrameEvent(fence, mFdp.ConsumeIntegral<int64_t>() /*postedTime*/,
+ mFdp.ConsumeIntegral<int64_t>() /*requestedTime*/);
+ layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
+
+ layer->fenceHasSignaled();
+ layer->framePresentTimeIsCurrent(mFdp.ConsumeIntegral<int64_t>());
+ layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>());
+ const std::vector<sp<CallbackHandle>> callbacks;
+ layer->setTransactionCompletedListeners(callbacks);
+
+ std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint64_t>(),
+ static_cast<android::PixelFormat>(
+ mFdp.PickValueInArray(kPixelFormats)),
+ mFdp.ConsumeIntegral<uint64_t>());
+ layer->setBuffer(texture, {} /*bufferData*/, mFdp.ConsumeIntegral<nsecs_t>() /*postTime*/,
+ mFdp.ConsumeIntegral<nsecs_t>() /*desiredTime*/,
+ mFdp.ConsumeBool() /*isAutoTimestamp*/,
+ {mFdp.ConsumeIntegral<nsecs_t>()} /*dequeue*/, {} /*info*/);
+
+ LayerRenderArea layerArea(*(flinger.flinger()), layer, getFuzzedRect(),
+ {mFdp.ConsumeIntegral<int32_t>(),
+ mFdp.ConsumeIntegral<int32_t>()} /*reqSize*/,
+ mFdp.PickValueInArray(kDataspaces), mFdp.ConsumeBool(),
+ getFuzzedRect(), mFdp.ConsumeBool());
+ layerArea.render([]() {} /*drawLayers*/);
+
+ if (!ownsHandle) {
+ native_handle_close(testHandle);
+ native_handle_delete(testHandle);
+ }
+ nativeHandle.clear();
+ fence.clear();
+ client.clear();
+ layer.clear();
+}
+
+void LayerFuzzer::init() {
+ invokeBufferStateLayer();
+ invokeEffectLayer();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ LayerFuzzer layerFuzzer(data, size);
+ layerFuzzer.init();
+ return 0;
+}
+
+} // namespace android::fuzzer
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 09ffb02..d504155 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -357,7 +357,7 @@
mFdp.ConsumeFloatingPoint<float>()),
Fps::fromValue(
mFdp.ConsumeFloatingPoint<float>()));
- RefreshRateConfigs::getFrameRateDivider(Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+ RefreshRateConfigs::getFrameRateDivisor(Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()));
android::mock::TimeStats timeStats;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 2e9e659..3598308 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -136,6 +136,8 @@
// Corner radius explicitly set on layer rather than inherited
float requested_corner_radius = 56;
+
+ RectProto destination_frame = 57;
}
message PositionProto {
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index caeff4a..ec18054 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -152,6 +152,11 @@
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
+ // publish gui::ISurfaceComposer, the new AIDL interface
+ sp<SurfaceComposerAIDL> composerAIDL = new SurfaceComposerAIDL(flinger);
+ sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false,
+ IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
+
startDisplayService(); // dependency on SF getting registered above
if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index efcc386..ceddf27 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -26,6 +26,7 @@
defaults: ["surfaceflinger_defaults"],
test_suites: ["device-tests"],
srcs: [
+ "BootDisplayMode_test.cpp",
"BufferGenerator.cpp",
"CommonTypes_test.cpp",
"Credentials_test.cpp",
diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
new file mode 100644
index 0000000..d70908e
--- /dev/null
+++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 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 <thread>
+
+#include <gtest/gtest.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
+#include <chrono>
+
+namespace android {
+
+TEST(BootDisplayModeTest, setBootDisplayMode) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> sf_aidl(ComposerServiceAIDL::getComposerService());
+ auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+ bool bootModeSupport = false;
+ binder::Status status = sf_aidl->getBootDisplayModeSupport(&bootModeSupport);
+ ASSERT_NO_FATAL_FAILURE(status.transactionError());
+ if (bootModeSupport) {
+ ASSERT_EQ(NO_ERROR, sf->setBootDisplayMode(displayToken, 0));
+ }
+}
+
+TEST(BootDisplayModeTest, clearBootDisplayMode) {
+ sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+ auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+ bool bootModeSupport = false;
+ binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
+ ASSERT_NO_FATAL_FAILURE(status.transactionError());
+ if (bootModeSupport) {
+ status = sf->clearBootDisplayMode(displayToken);
+ ASSERT_EQ(NO_ERROR, status.transactionError());
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
index 01adbc8..0e54664 100644
--- a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
+++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
@@ -28,23 +28,24 @@
TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) {
const nsecs_t now = systemTime();
- VsyncEventData vsyncEventData;
- EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&vsyncEventData));
+ ParcelableVsyncEventData parcelableVsyncEventData;
+ EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&parcelableVsyncEventData));
+ const VsyncEventData& vsyncEventData = parcelableVsyncEventData.vsync;
EXPECT_NE(std::numeric_limits<size_t>::max(), vsyncEventData.preferredFrameTimelineIndex);
EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
<< "Deadline timestamp should be greater than frame time";
- for (size_t i = 0; i < vsyncEventData.frameTimelines.size(); i++) {
- EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].id);
- EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+ for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].vsyncId);
+ EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
vsyncEventData.frameTimelines[i].deadlineTimestamp)
<< "Expected vsync timestamp should be greater than deadline";
if (i > 0) {
EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp,
vsyncEventData.frameTimelines[i - 1].deadlineTimestamp)
<< "Deadline timestamp out of order for frame timeline " << i;
- EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
- vsyncEventData.frameTimelines[i - 1].expectedPresentTime)
+ EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+ vsyncEventData.frameTimelines[i - 1].expectedPresentationTime)
<< "Expected vsync timestamp out of order for frame timeline " << i;
}
}
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 5c16fee..8a2305b 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -141,11 +141,12 @@
continue;
}
- vsync = {event.vsync.vsyncId, event.vsync.expectedVSyncTimestamp};
+ vsync = {event.vsync.vsyncData.preferredVsyncId(),
+ event.vsync.vsyncData.preferredExpectedPresentationTime()};
}
EXPECT_GE(vsync.vsyncId, 1);
- EXPECT_GT(event.vsync.expectedVSyncTimestamp, systemTime());
+ EXPECT_GT(vsync.expectedPresentTime, systemTime());
return vsync;
}
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index fa1a5ed..094b0ff 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -22,6 +22,8 @@
#include <gui/LayerState.h>
namespace android {
+using gui::DisplayCaptureArgs;
+using gui::LayerCaptureArgs;
using gui::ScreenCaptureResults;
namespace test {
@@ -40,11 +42,11 @@
args.grayscale = true;
Parcel p;
- args.write(p);
+ args.writeToParcel(&p);
p.setDataPosition(0);
DisplayCaptureArgs args2;
- args2.read(p);
+ args2.readFromParcel(&p);
ASSERT_EQ(args.pixelFormat, args2.pixelFormat);
ASSERT_EQ(args.sourceCrop, args2.sourceCrop);
@@ -71,11 +73,11 @@
args.grayscale = true;
Parcel p;
- args.write(p);
+ args.writeToParcel(&p);
p.setDataPosition(0);
LayerCaptureArgs args2;
- args2.read(p);
+ args2.readFromParcel(&p);
ASSERT_EQ(args.pixelFormat, args2.pixelFormat);
ASSERT_EQ(args.sourceCrop, args2.sourceCrop);
diff --git a/services/surfaceflinger/tests/tracing/Android.bp b/services/surfaceflinger/tests/tracing/Android.bp
new file mode 100644
index 0000000..ff3e1c5
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/Android.bp
@@ -0,0 +1,40 @@
+// 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.
+
+cc_test {
+ name: "transactiontrace_testsuite",
+ defaults: [
+ "libsurfaceflinger_mocks_defaults",
+ "surfaceflinger_defaults",
+ "skia_renderengine_deps",
+ ],
+ test_suites: ["device-tests"],
+ sanitize: {
+ address: false,
+ },
+ srcs: [
+ ":libsurfaceflinger_sources",
+ ":libsurfaceflinger_mock_sources",
+ ":layertracegenerator_sources",
+ "TransactionTraceTestSuite.cpp",
+ ],
+ static_libs: [
+ "libc++fs",
+ ],
+ header_libs: [
+ "libsurfaceflinger_mocks_headers",
+ "layertracegenerator_headers",
+ ],
+ data: ["testdata/*"],
+}
diff --git a/services/surfaceflinger/tests/tracing/AndroidTest.xml b/services/surfaceflinger/tests/tracing/AndroidTest.xml
new file mode 100644
index 0000000..c0aeb35
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for transactiontrace_testsuite">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push"
+ value="transactiontrace_testsuite->/data/local/tmp/transactiontrace_testsuite" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="transactiontrace_testsuite" />
+ </test>
+</configuration>
diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
new file mode 100644
index 0000000..ac4354c
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include <LayerTraceGenerator.h>
+#include <Tracing/TransactionProtoParser.h>
+#include <layerproto/LayerProtoHeader.h>
+#include <log/log.h>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+class TransactionTraceTestSuite : public testing::Test,
+ public testing::WithParamInterface<std::filesystem::path> {
+public:
+ static std::vector<std::filesystem::path> sTransactionTraces;
+ static constexpr std::string_view sTransactionTracePrefix = "transactions_trace_";
+ static constexpr std::string_view sLayersTracePrefix = "layers_trace_";
+ static constexpr std::string_view sTracePostfix = ".winscope";
+
+ proto::TransactionTraceFile mTransactionTrace;
+ LayersTraceFileProto mExpectedLayersTraceProto;
+ LayersTraceFileProto mActualLayersTraceProto;
+
+protected:
+ void SetUp() override {
+ std::filesystem::path transactionTracePath = GetParam();
+ parseTransactionTraceFromFile(transactionTracePath.c_str(), mTransactionTrace);
+
+ std::string expectedLayersFilename = std::string(sLayersTracePrefix) +
+ transactionTracePath.filename().string().substr(sTransactionTracePrefix.length());
+ std::string expectedLayersTracePath =
+ transactionTracePath.parent_path().string() + "/" + expectedLayersFilename;
+ EXPECT_TRUE(std::filesystem::exists(std::filesystem::path(expectedLayersTracePath)));
+ parseLayersTraceFromFile(expectedLayersTracePath.c_str(), mExpectedLayersTraceProto);
+ TemporaryDir temp_dir;
+ std::string actualLayersTracePath =
+ std::string(temp_dir.path) + "/" + expectedLayersFilename + "_actual";
+
+ EXPECT_TRUE(
+ LayerTraceGenerator().generate(mTransactionTrace, actualLayersTracePath.c_str()))
+ << "Failed to generate layers trace from " << transactionTracePath;
+ EXPECT_TRUE(std::filesystem::exists(std::filesystem::path(actualLayersTracePath)));
+ parseLayersTraceFromFile(actualLayersTracePath.c_str(), mActualLayersTraceProto);
+ }
+
+ void parseTransactionTraceFromFile(const char* transactionTracePath,
+ proto::TransactionTraceFile& outProto) {
+ ALOGD("Parsing file %s...", transactionTracePath);
+ std::fstream input(transactionTracePath, std::ios::in | std::ios::binary);
+ EXPECT_TRUE(input) << "Error could not open " << transactionTracePath;
+ EXPECT_TRUE(outProto.ParseFromIstream(&input))
+ << "Failed to parse " << transactionTracePath;
+ }
+
+ void parseLayersTraceFromFile(const char* layersTracePath, LayersTraceFileProto& outProto) {
+ ALOGD("Parsing file %s...", layersTracePath);
+ std::fstream input(layersTracePath, std::ios::in | std::ios::binary);
+ EXPECT_TRUE(input) << "Error could not open " << layersTracePath;
+ EXPECT_TRUE(outProto.ParseFromIstream(&input)) << "Failed to parse " << layersTracePath;
+ }
+};
+
+std::vector<std::filesystem::path> TransactionTraceTestSuite::sTransactionTraces{};
+
+TEST_P(TransactionTraceTestSuite, validateEndState) {
+ ASSERT_GT(mActualLayersTraceProto.entry_size(), 0);
+ ASSERT_GT(mExpectedLayersTraceProto.entry_size(), 0);
+
+ auto expectedLastEntry =
+ mExpectedLayersTraceProto.entry(mExpectedLayersTraceProto.entry_size() - 1);
+ auto actualLastEntry = mActualLayersTraceProto.entry(mActualLayersTraceProto.entry_size() - 1);
+
+ EXPECT_EQ(expectedLastEntry.layers().layers_size(), actualLastEntry.layers().layers_size());
+ for (int i = 0;
+ i < expectedLastEntry.layers().layers_size() && i < actualLastEntry.layers().layers_size();
+ i++) {
+ auto expectedLayer = expectedLastEntry.layers().layers(i);
+ auto actualLayer = actualLastEntry.layers().layers(i);
+ EXPECT_EQ(expectedLayer.id(), actualLayer.id());
+ EXPECT_EQ(expectedLayer.name(), actualLayer.name());
+ EXPECT_EQ(expectedLayer.parent(), actualLayer.parent());
+ EXPECT_EQ(expectedLayer.z(), actualLayer.z());
+ EXPECT_EQ(expectedLayer.curr_frame(), actualLayer.curr_frame());
+ ALOGV("Validating %s[%d] parent=%d z=%d frame=%" PRIu64, expectedLayer.name().c_str(),
+ expectedLayer.id(), expectedLayer.parent(), expectedLayer.z(),
+ expectedLayer.curr_frame());
+ }
+}
+
+std::string PrintToStringParamName(const ::testing::TestParamInfo<std::filesystem::path>& info) {
+ const auto& prefix = android::TransactionTraceTestSuite::sTransactionTracePrefix;
+ const auto& postfix = android::TransactionTraceTestSuite::sTracePostfix;
+
+ const auto& filename = info.param.filename().string();
+ return filename.substr(prefix.length(), filename.length() - prefix.length() - postfix.length());
+}
+
+INSTANTIATE_TEST_CASE_P(TransactionTraceTestSuites, TransactionTraceTestSuite,
+ testing::ValuesIn(TransactionTraceTestSuite::sTransactionTraces),
+ PrintToStringParamName);
+
+} // namespace android
+
+int main(int argc, char** argv) {
+ for (const auto& entry : std::filesystem::directory_iterator(
+ android::base::GetExecutableDirectory() + "/testdata/")) {
+ if (!entry.is_regular_file()) {
+ continue;
+ }
+ const auto& filename = entry.path().filename().string();
+ const auto& prefix = android::TransactionTraceTestSuite::sTransactionTracePrefix;
+ if (filename.compare(0, prefix.length(), prefix)) {
+ continue;
+ }
+ const std::string& path = entry.path().string();
+ const auto& postfix = android::TransactionTraceTestSuite::sTracePostfix;
+ if (path.compare(path.length() - postfix.length(), postfix.length(), postfix)) {
+ continue;
+ }
+ android::TransactionTraceTestSuite::sTransactionTraces.push_back(path);
+ }
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/tracing/readme.md b/services/surfaceflinger/tests/tracing/readme.md
new file mode 100644
index 0000000..3e80a74
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/readme.md
@@ -0,0 +1,20 @@
+### TransactionTrace Testsuite ###
+
+Hassle free way to test and validate whether a sequence of
+transactions will produce the expected front end state(s). Test
+runs through all testdata/transactions_trace_*.winscope files,
+generates layer states and checks if the states match the
+corresponding layer trace in testdata.
+
+
+#### Run Test ####
+`atest transactiontrace_testsuite`
+
+
+#### Workflow ####
+Add transaction traces that resulted in front end bugs along
+with the layer trace after fixing the issue. The layer trace
+can be generated by using the layertracegenerator tool. The
+main goal of this test suite is to add regression tests with
+minimal effort.
+
diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope
new file mode 100644
index 0000000..9e4005c
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope
new file mode 100644
index 0000000..8356ae7
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 48f18b9..58cd7ba 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -42,6 +42,7 @@
cc_test {
name: "libsurfaceflinger_unittest",
defaults: [
+ "libsurfaceflinger_mocks_defaults",
"skia_renderengine_deps",
"surfaceflinger_defaults",
],
@@ -80,6 +81,7 @@
"FpsReporterTest.cpp",
"FpsTest.cpp",
"FramebufferSurfaceTest.cpp",
+ "FrameRateOverrideMappingsTest.cpp",
"FrameTimelineTest.cpp",
"GameModeTest.cpp",
"HWComposerTest.cpp",
@@ -121,6 +123,10 @@
"VSyncReactorTest.cpp",
"VsyncConfigurationTest.cpp",
],
+}
+
+cc_defaults {
+ name: "libsurfaceflinger_mocks_defaults",
static_libs: [
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
@@ -192,3 +198,8 @@
"libsurfaceflinger_headers",
],
}
+
+cc_library_headers {
+ name: "libsurfaceflinger_mocks_headers",
+ export_include_dirs: ["."],
+}
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 0b6b475..ec27eda 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -229,7 +229,7 @@
ASSERT_TRUE(callbackData.has_value());
const auto [when, vsyncData] = callbackData.value();
EXPECT_EQ(when,
- vsyncData.expectedVSyncTimestamp - mWorkDuration.count() -
+ vsyncData.expectedPresentationTime - mWorkDuration.count() -
mReadyDuration.count());
}
}
@@ -261,7 +261,7 @@
ASSERT_TRUE(callbackData.has_value());
const auto [when, vsyncData] = callbackData.value();
EXPECT_EQ(when,
- vsyncData.expectedVSyncTimestamp - mWorkDuration.count() -
+ vsyncData.expectedPresentationTime - mWorkDuration.count() -
mReadyDuration.count());
}
@@ -283,7 +283,7 @@
const auto callbackData = mVSyncEventCallRecorder.waitForCall();
ASSERT_TRUE(callbackData.has_value());
const auto [when, vsyncData] = callbackData.value();
- EXPECT_EQ(when, vsyncData.expectedVSyncTimestamp - newDuration.count());
+ EXPECT_EQ(when, vsyncData.expectedPresentationTime - newDuration.count());
}
EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
@@ -307,9 +307,9 @@
const auto vsyncData = mDispSyncSource->getLatestVSyncData();
ASSERT_GT(vsyncData.deadlineTimestamp, now);
- ASSERT_GT(vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp);
+ ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
EXPECT_EQ(vsyncData.deadlineTimestamp,
- vsyncData.expectedVSyncTimestamp - vsyncInternalDuration);
+ vsyncData.expectedPresentationTime - vsyncInternalDuration);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index cc0a40f..14d8f98 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -99,7 +99,7 @@
nsecs_t expectedTimestamp, unsigned expectedCount);
void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp,
- nsecs_t preferredDeadline);
+ VSyncSource::VSyncData preferredVsyncData);
void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
@@ -252,40 +252,42 @@
expectedCount);
}
-void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp,
- nsecs_t preferredDeadline) {
+void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(
+ nsecs_t expectedTimestamp, VSyncSource::VSyncData preferredVsyncData) {
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp "
<< expectedTimestamp;
const auto& event = std::get<0>(args.value());
for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
- auto prediction =
- mTokenManager->getPredictionsForToken(event.vsync.frameTimelines[i].vsyncId);
+ auto prediction = mTokenManager->getPredictionsForToken(
+ event.vsync.vsyncData.frameTimelines[i].vsyncId);
EXPECT_TRUE(prediction.has_value());
- EXPECT_EQ(prediction.value().endTime, event.vsync.frameTimelines[i].deadlineTimestamp)
+ EXPECT_EQ(prediction.value().endTime,
+ event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp)
<< "Deadline timestamp does not match cached value";
EXPECT_EQ(prediction.value().presentTime,
- event.vsync.frameTimelines[i].expectedVSyncTimestamp)
- << "Expected vsync timestamp does not match cached value";
+ event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime)
+ << "Expected vsync.vsyncData timestamp does not match cached value";
if (i > 0) {
- EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp,
- event.vsync.frameTimelines[i - 1].deadlineTimestamp)
+ EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp,
+ event.vsync.vsyncData.frameTimelines[i - 1].deadlineTimestamp)
<< "Deadline timestamp out of order for frame timeline " << i;
- EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp,
- event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp)
- << "Expected vsync timestamp out of order for frame timeline " << i;
+ EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime,
+ event.vsync.vsyncData.frameTimelines[i - 1].expectedPresentationTime)
+ << "Expected vsync.vsyncData timestamp out of order for frame timeline " << i;
}
// Vsync ID order lines up with registration into test token manager.
- EXPECT_EQ(i, event.vsync.frameTimelines[i].vsyncId)
+ EXPECT_EQ(i, event.vsync.vsyncData.frameTimelines[i].vsyncId)
<< "Vsync ID incorrect for frame timeline " << i;
- if (i == event.vsync.preferredFrameTimelineIndex) {
- EXPECT_EQ(event.vsync.frameTimelines[i].deadlineTimestamp, preferredDeadline)
+ if (i == event.vsync.vsyncData.preferredFrameTimelineIndex) {
+ EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp,
+ preferredVsyncData.deadlineTimestamp)
<< "Preferred deadline timestamp incorrect" << i;
- EXPECT_EQ(event.vsync.frameTimelines[i].expectedVSyncTimestamp,
- event.vsync.expectedVSyncTimestamp)
- << "Preferred expected vsync timestamp incorrect" << i;
+ EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime,
+ preferredVsyncData.expectedPresentationTime)
+ << "Preferred expected vsync.vsyncData timestamp incorrect" << i;
}
}
}
@@ -397,16 +399,17 @@
// Use the received callback to signal a vsync event.
// The interceptor should receive the event, as well as the connection.
- mCallback->onVSyncEvent(123, {456, 789});
+ VSyncSource::VSyncData vsyncData = {456, 789};
+ mCallback->onVSyncEvent(123, vsyncData);
expectInterceptCallReceived(123);
- expectVsyncEventFrameTimelinesCorrect(123, 789);
+ expectVsyncEventFrameTimelinesCorrect(123, vsyncData);
}
TEST_F(EventThreadTest, getLatestVsyncEventData) {
const nsecs_t now = systemTime();
const nsecs_t preferredDeadline = now + 10000000;
- const nsecs_t preferredExpectedVSyncTimestamp = now + 20000000;
- const VSyncSource::VSyncData preferredData = {preferredExpectedVSyncTimestamp,
+ const nsecs_t preferredExpectedPresentationTime = now + 20000000;
+ const VSyncSource::VSyncData preferredData = {preferredExpectedPresentationTime,
preferredDeadline};
EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData));
@@ -415,14 +418,14 @@
<< "Deadline timestamp should be greater than frame time";
for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
auto prediction =
- mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].id);
+ mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].vsyncId);
EXPECT_TRUE(prediction.has_value());
EXPECT_EQ(prediction.value().endTime, vsyncEventData.frameTimelines[i].deadlineTimestamp)
<< "Deadline timestamp does not match cached value";
EXPECT_EQ(prediction.value().presentTime,
- vsyncEventData.frameTimelines[i].expectedPresentTime)
+ vsyncEventData.frameTimelines[i].expectedPresentationTime)
<< "Expected vsync timestamp does not match cached value";
- EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+ EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
vsyncEventData.frameTimelines[i].deadlineTimestamp)
<< "Expected vsync timestamp should be greater than deadline";
@@ -430,19 +433,19 @@
EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp,
vsyncEventData.frameTimelines[i - 1].deadlineTimestamp)
<< "Deadline timestamp out of order for frame timeline " << i;
- EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
- vsyncEventData.frameTimelines[i - 1].expectedPresentTime)
+ EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+ vsyncEventData.frameTimelines[i - 1].expectedPresentationTime)
<< "Expected vsync timestamp out of order for frame timeline " << i;
}
// Vsync ID order lines up with registration into test token manager.
- EXPECT_EQ(i, vsyncEventData.frameTimelines[i].id)
+ EXPECT_EQ(i, vsyncEventData.frameTimelines[i].vsyncId)
<< "Vsync ID incorrect for frame timeline " << i;
if (i == vsyncEventData.preferredFrameTimelineIndex) {
EXPECT_EQ(vsyncEventData.frameTimelines[i].deadlineTimestamp, preferredDeadline)
<< "Preferred deadline timestamp incorrect" << i;
- EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentTime,
- preferredExpectedVSyncTimestamp)
+ EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+ preferredExpectedPresentationTime)
<< "Preferred expected vsync timestamp incorrect" << i;
}
}
diff --git a/services/surfaceflinger/tests/unittests/FpsTest.cpp b/services/surfaceflinger/tests/unittests/FpsTest.cpp
index 88b74d2..2193c9d 100644
--- a/services/surfaceflinger/tests/unittests/FpsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsTest.cpp
@@ -68,4 +68,14 @@
EXPECT_EQ(31, (30.5_Hz).getIntValue());
}
+TEST(FpsTest, range) {
+ const auto fps = Fps::fromPeriodNsecs(16'666'665);
+
+ EXPECT_TRUE((FpsRange{60.000004_Hz, 60.000004_Hz}.includes(fps)));
+ EXPECT_TRUE((FpsRange{59_Hz, 60.1_Hz}.includes(fps)));
+ EXPECT_FALSE((FpsRange{75_Hz, 90_Hz}.includes(fps)));
+ EXPECT_FALSE((FpsRange{60.0011_Hz, 90_Hz}.includes(fps)));
+ EXPECT_FALSE((FpsRange{50_Hz, 59.998_Hz}.includes(fps)));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
new file mode 100644
index 0000000..a581c7a
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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 "FrameRateOverrideMappingsTest"
+
+#include <gtest/gtest.h>
+#include <unordered_map>
+
+#include "Scheduler/FrameRateOverrideMappings.h"
+
+namespace android::scheduler {
+
+using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
+using UidToFrameRateOverride = std::map<uid_t, Fps>;
+
+class FrameRateOverrideMappingsTest : public testing::Test {
+protected:
+ FrameRateOverrideMappings mFrameRateOverrideMappings;
+ UidToFrameRateOverride mFrameRateOverrideByContent;
+};
+
+namespace {
+TEST_F(FrameRateOverrideMappingsTest, testUpdateFrameRateOverridesByContent) {
+ mFrameRateOverrideByContent.clear();
+ mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
+ mFrameRateOverrideByContent.emplace(1, 60.0_Hz);
+ ASSERT_TRUE(mFrameRateOverrideMappings.updateFrameRateOverridesByContent(
+ mFrameRateOverrideByContent));
+
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 0, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(60.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 1, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ false));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(3, /*supportsFrameRateOverrideByContent*/ true));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(3, /*supportsFrameRateOverrideByContent*/ false));
+}
+
+TEST_F(FrameRateOverrideMappingsTest, testSetGameModeRefreshRateForUid) {
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
+
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 1, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(90.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 2, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(0, /*supportsFrameRateOverrideByContent*/ true));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(0, /*supportsFrameRateOverrideByContent*/ false));
+}
+
+TEST_F(FrameRateOverrideMappingsTest, testSetPreferredRefreshRateForUid) {
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({0, 60.0f});
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({2, 120.0f});
+
+ ASSERT_TRUE(isApproxEqual(60.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 0, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 2, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ true));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ false));
+}
+
+TEST_F(FrameRateOverrideMappingsTest, testGetFrameRateOverrideForUidMixed) {
+ mFrameRateOverrideByContent.clear();
+ mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
+ mFrameRateOverrideByContent.emplace(1, 60.0_Hz);
+ mFrameRateOverrideByContent.emplace(2, 45.0_Hz);
+ mFrameRateOverrideByContent.emplace(5, 120.0_Hz);
+ ASSERT_TRUE(mFrameRateOverrideMappings.updateFrameRateOverridesByContent(
+ mFrameRateOverrideByContent));
+
+ std::vector<FrameRateOverride> allFrameRateOverrides;
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ false));
+ allFrameRateOverrides = {{0, 30.0f}, {1, 60.0f}, {2, 45.0f}, {5, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ true));
+
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid({4, 120.0f});
+
+ allFrameRateOverrides.clear();
+ allFrameRateOverrides = {{1, 30.0f}, {2, 90.0f}, {4, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ false));
+ allFrameRateOverrides.clear();
+ allFrameRateOverrides = {{1, 30.0f}, {2, 90.0f}, {4, 120.0f}, {0, 30.0f}, {5, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ true));
+
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({0, 60.0f});
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({2, 120.0f});
+ mFrameRateOverrideMappings.setPreferredRefreshRateForUid({3, 30.0f});
+
+ allFrameRateOverrides.clear();
+ allFrameRateOverrides = {{0, 60.0f}, {2, 120.0f}, {3, 30.0f}, {1, 30.0f}, {4, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ false));
+ allFrameRateOverrides.clear();
+ allFrameRateOverrides = {{0, 60.0f}, {2, 120.0f}, {3, 30.0f},
+ {1, 30.0f}, {4, 120.0f}, {5, 120.0f}};
+ ASSERT_EQ(allFrameRateOverrides,
+ mFrameRateOverrideMappings.getAllFrameRateOverrides(
+ /*supportsFrameRateOverrideByContent*/ true));
+
+ ASSERT_TRUE(isApproxEqual(60.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 0, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 1, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 2, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 3, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 4, /*supportsFrameRateOverrideByContent*/ true)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 5, /*supportsFrameRateOverrideByContent*/ true)));
+
+ ASSERT_TRUE(isApproxEqual(60.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 0, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 1, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 2, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_TRUE(isApproxEqual(30.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 3, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_TRUE(isApproxEqual(120.0_Hz,
+ *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+ 4, /*supportsFrameRateOverrideByContent*/ false)));
+ ASSERT_EQ(std::nullopt,
+ mFrameRateOverrideMappings
+ .getFrameRateOverrideForUid(5, /*supportsFrameRateOverrideByContent*/ false));
+}
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 397c619..834a560 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -1279,7 +1279,7 @@
validateTraceEvent(actualSurfaceFrameEnd2, protoPresentedSurfaceFrameActualEnd);
}
-TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpectedTimeline) {
+TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredIsAppMissedDeadline) {
auto tracingSession = getTracingSessionForTest();
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
@@ -1312,7 +1312,7 @@
createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
displayFrameToken, sPidOne, sLayerNameOne,
FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
- false, FrameTimelineEvent::JANK_UNKNOWN,
+ false, FrameTimelineEvent::JANK_APP_DEADLINE_MISSED,
FrameTimelineEvent::PREDICTION_EXPIRED, true);
auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1);
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index cdb2240..e108bea 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -97,7 +97,7 @@
void setDefaultLayerVote(Layer* layer,
LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
auto [found, layerPair] = history().findLayer(layer->getSequence());
- if (found != LayerHistory::layerStatus::NotFound) {
+ if (found != LayerHistory::LayerStatus::NotFound) {
layerPair->second->setDefaultLayerVote(vote);
}
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 4efcc05..97f3747 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -834,17 +834,6 @@
EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
}
-TEST_F(RefreshRateConfigsTest, testInPolicy) {
- const auto refreshRate =
- asRefreshRate(createDisplayMode(kModeId60, Fps::fromPeriodNsecs(16'666'665)));
-
- EXPECT_TRUE(refreshRate.inPolicy(60.000004_Hz, 60.000004_Hz));
- EXPECT_TRUE(refreshRate.inPolicy(59_Hz, 60.1_Hz));
- EXPECT_FALSE(refreshRate.inPolicy(75_Hz, 90_Hz));
- EXPECT_FALSE(refreshRate.inPolicy(60.0011_Hz, 90_Hz));
- EXPECT_FALSE(refreshRate.inPolicy(50_Hz, 59.998_Hz));
-}
-
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
@@ -1884,37 +1873,37 @@
EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
}
-TEST_F(RefreshRateConfigsTest, getFrameRateDivider) {
+TEST_F(RefreshRateConfigsTest, getFrameRateDivisor) {
RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30);
const auto frameRate = 30_Hz;
Fps displayRefreshRate = configs.getCurrentRefreshRate().getFps();
- EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+ EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setCurrentModeId(kModeId60);
displayRefreshRate = configs.getCurrentRefreshRate().getFps();
- EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+ EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setCurrentModeId(kModeId72);
displayRefreshRate = configs.getCurrentRefreshRate().getFps();
- EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setCurrentModeId(kModeId90);
displayRefreshRate = configs.getCurrentRefreshRate().getFps();
- EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+ EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setCurrentModeId(kModeId120);
displayRefreshRate = configs.getCurrentRefreshRate().getFps();
- EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+ EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setCurrentModeId(kModeId90);
displayRefreshRate = configs.getCurrentRefreshRate().getFps();
- EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, 22.5_Hz));
+ EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, 22.5_Hz));
- EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 25_Hz));
- EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 23.976_Hz));
- EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(30_Hz, 29.97_Hz));
- EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(60_Hz, 59.94_Hz));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 25_Hz));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 23.976_Hz));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(30_Hz, 29.97_Hz));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(60_Hz, 59.94_Hz));
}
TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) {
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index f48abb7..a992a91 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -228,7 +228,8 @@
mScheduler->setRefreshRateConfigs(
std::make_shared<RefreshRateConfigs>(DisplayModes{mode60, mode120}, mode60->getId()));
- sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+ const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+ EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true));
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
@@ -240,6 +241,10 @@
EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1);
mScheduler->chooseRefreshRateForContent();
+
+ // No-op if layer requirements have not changed.
+ EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0);
+ mScheduler->chooseRefreshRateForContent();
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 8cadb31..d83b9bb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -177,8 +177,10 @@
public:
using HotplugEvent = SurfaceFlinger::HotplugEvent;
- TestableSurfaceFlinger()
- : mFlinger(sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization)) {
+ TestableSurfaceFlinger(sp<SurfaceFlinger> flinger = nullptr) : mFlinger(flinger) {
+ if (!mFlinger) {
+ mFlinger = sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization);
+ }
mFlinger->mAnimationTransactionTimeout = ms2ns(10);
}
@@ -219,7 +221,8 @@
std::unique_ptr<EventThread> appEventThread,
std::unique_ptr<EventThread> sfEventThread,
SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp,
- DisplayModesVariant modesVariant = kOneDisplayMode) {
+ DisplayModesVariant modesVariant = kOneDisplayMode,
+ bool useNiceMock = false) {
RefreshRateConfigsPtr configs;
if (std::holds_alternative<RefreshRateConfigsPtr>(modesVariant)) {
configs = std::move(std::get<RefreshRateConfigsPtr>(modesVariant));
@@ -256,9 +259,17 @@
? static_cast<Callback&>(mNoOpSchedulerCallback)
: static_cast<Callback&>(mSchedulerCallback);
- mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
- std::move(vsyncTracker), std::move(configs),
- callback);
+ if (useNiceMock) {
+ mScheduler =
+ new testing::NiceMock<scheduler::TestableScheduler>(std::move(vsyncController),
+ std::move(vsyncTracker),
+ std::move(configs),
+ callback);
+ } else {
+ mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
+ std::move(vsyncTracker),
+ std::move(configs), callback);
+ }
mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
@@ -270,6 +281,8 @@
scheduler::TestableScheduler& mutableScheduler() { return *mScheduler; }
scheduler::mock::SchedulerCallback& mockSchedulerCallback() { return mSchedulerCallback; }
+ auto& mutableVsyncModulator() { return mFlinger->mVsyncModulator; }
+
using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
mFactory.mCreateBufferQueue = f;
@@ -453,6 +466,23 @@
mFlinger->onActiveDisplayChangedLocked(activeDisplay);
}
+ auto commit(nsecs_t frameTime, int64_t vsyncId) {
+ const nsecs_t expectedVsyncTime = frameTime + 10'000'000;
+ mFlinger->commit(frameTime, vsyncId, expectedVsyncTime);
+ }
+
+ auto createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
+ const sp<IBinder>& parentHandle, int32_t* outLayerId,
+ const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
+ return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, parentLayer,
+ outTransformHint);
+ }
+
+ auto mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle,
+ sp<IBinder>* outHandle, int32_t* outLayerId) {
+ return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId);
+ }
+
/* ------------------------------------------------------------------------
* Read-only access to private data to assert post-conditions.
*/
@@ -848,8 +878,7 @@
private:
surfaceflinger::test::Factory mFactory;
- sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
-
+ sp<SurfaceFlinger> mFlinger;
scheduler::mock::SchedulerCallback mSchedulerCallback;
scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;
scheduler::TestableScheduler* mScheduler = nullptr;
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 4683c51..46c8404 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -551,13 +551,52 @@
kExpectedTransactionsPending);
}
-TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemoveSignaledWithUnsignaledIntact) {
+TEST_F(LatchUnsignaledAutoSingleLayerTest,
+ UnsignaledNotAppliedWhenThereAreSignaled_UnsignaledFirst) {
const sp<IBinder> kApplyToken1 =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+ const sp<IBinder> kApplyToken3 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsApplied = 2u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken1,
+ {
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+
+ const auto signaledTransaction =
+ createTransactionInfo(kApplyToken2,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto signaledTransaction2 =
+ createTransactionInfo(kApplyToken3,
+ {
+ createComposerState(kLayerId2,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+
+ setTransactionStates({unsignaledTransaction, signaledTransaction, signaledTransaction2},
+ kExpectedTransactionsApplied, kExpectedTransactionsPending);
+}
+
+TEST_F(LatchUnsignaledAutoSingleLayerTest, UnsignaledNotAppliedWhenThereAreSignaled_SignaledFirst) {
+ const sp<IBinder> kApplyToken1 =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+ const sp<IBinder> kApplyToken3 = sp<BBinder>::make();
+ const auto kLayerId1 = 1;
+ const auto kLayerId2 = 2;
+ const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 1u;
const auto signaledTransaction =
@@ -567,15 +606,23 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- const auto unsignaledTransaction =
+ const auto signaledTransaction2 =
createTransactionInfo(kApplyToken2,
{
+ createComposerState(kLayerId1,
+ fence(Fence::Status::Signaled),
+ layer_state_t::eBufferChanged),
+ });
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken3,
+ {
createComposerState(kLayerId2,
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+
+ setTransactionStates({signaledTransaction, signaledTransaction2, unsignaledTransaction},
+ kExpectedTransactionsApplied, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) {
@@ -631,6 +678,28 @@
kExpectedTransactionsApplied, kExpectedTransactionsPending);
}
+TEST_F(LatchUnsignaledAutoSingleLayerTest, DontLatchUnsignaledWhenEarlyOffset) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 0u;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+
+ // Get VsyncModulator out of the default config
+ static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
+
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
+}
+
class LatchUnsignaledDisabledTest : public LatchUnsignaledTest {
public:
void SetUp() override {
@@ -999,4 +1068,26 @@
kExpectedTransactionsApplied, kExpectedTransactionsPending);
}
+TEST_F(LatchUnsignaledAlwaysTest, LatchUnsignaledWhenEarlyOffset) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsApplied = 1u;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eBufferChanged),
+ });
+
+ // Get VsyncModulator out of the default config
+ static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
+
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+ kExpectedTransactionsPending);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index 271b1c0..ab893a3 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -70,23 +70,32 @@
t1.displays.add(display);
}
- TransactionProtoParser::LayerHandleToIdFn getLayerIdFn = [&](const sp<IBinder>& handle) {
- return (handle == layerHandle) ? 42 : -1;
- };
- TransactionProtoParser::DisplayHandleToIdFn getDisplayIdFn = [&](const sp<IBinder>& handle) {
- return (handle == displayHandle) ? 43 : -1;
- };
- TransactionProtoParser::LayerIdToHandleFn getLayerHandleFn = [&](int32_t id) {
- return (id == 42) ? layerHandle : nullptr;
- };
- TransactionProtoParser::DisplayIdToHandleFn getDisplayHandleFn = [&](int32_t id) {
- return (id == 43) ? displayHandle : nullptr;
+ class TestMapper : public TransactionProtoParser::FlingerDataMapper {
+ public:
+ sp<IBinder> layerHandle;
+ sp<IBinder> displayHandle;
+
+ TestMapper(sp<IBinder> layerHandle, sp<IBinder> displayHandle)
+ : layerHandle(layerHandle), displayHandle(displayHandle) {}
+
+ sp<IBinder> getLayerHandle(int32_t id) const override {
+ return (id == 42) ? layerHandle : nullptr;
+ }
+ int32_t getLayerId(const sp<IBinder>& handle) const override {
+ return (handle == layerHandle) ? 42 : -1;
+ }
+ sp<IBinder> getDisplayHandle(int32_t id) const {
+ return (id == 43) ? displayHandle : nullptr;
+ }
+ int32_t getDisplayId(const sp<IBinder>& handle) const {
+ return (handle == displayHandle) ? 43 : -1;
+ }
};
- proto::TransactionState proto =
- TransactionProtoParser::toProto(t1, getLayerIdFn, getDisplayIdFn);
- TransactionState t2 =
- TransactionProtoParser::fromProto(proto, getLayerHandleFn, getDisplayHandleFn);
+ TransactionProtoParser parser(std::make_unique<TestMapper>(layerHandle, displayHandle));
+
+ proto::TransactionState proto = parser.toProto(t1);
+ TransactionState t2 = parser.fromProto(proto);
ASSERT_EQ(t1.originPid, t2.originPid);
ASSERT_EQ(t1.originUid, t2.originUid);
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 39dbb07..61b72a0 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -178,8 +178,8 @@
// verify we can still retrieve the layer change from the first entry containing starting
// states.
EXPECT_GT(proto.entry().size(), 0);
- EXPECT_GT(proto.entry(0).transactions().size(), 0);
- EXPECT_GT(proto.entry(0).added_layers().size(), 0);
+ EXPECT_EQ(proto.entry(0).transactions().size(), 1);
+ EXPECT_EQ(proto.entry(0).added_layers().size(), 2);
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42);
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 37ecd7c..74d2b7d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -464,16 +464,16 @@
EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
- const auto maxDivider = 5;
+ const auto maxDivisor = 5;
const auto maxPeriods = 15;
- for (int divider = 1; divider < maxDivider; divider++) {
+ for (int divisor = 1; divisor < maxDivisor; divisor++) {
for (int i = 0; i < maxPeriods; i++) {
- const bool expectedInPhase = (i % divider) == 0;
+ const bool expectedInPhase = (i % divisor) == 0;
EXPECT_THAT(expectedInPhase,
tracker.isVSyncInPhase(mNow + i * mPeriod - bias,
- Fps::fromPeriodNsecs(divider * mPeriod)))
+ Fps::fromPeriodNsecs(divisor * mPeriod)))
<< "vsync at " << mNow + (i + 1) * mPeriod - bias << " is "
- << (expectedInPhase ? "not " : "") << "in phase for divider " << divider;
+ << (expectedInPhase ? "not " : "") << "in phase for divisor " << divisor;
}
}
}
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 4a7d8eb..a1aa7e8 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -152,7 +152,7 @@
V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
MOCK_METHOD3(getClientTargetProperty,
Error(Display, IComposerClient::ClientTargetProperty*, float*));
- MOCK_METHOD3(setLayerWhitePointNits, Error(Display, Layer, float));
+ MOCK_METHOD3(setLayerBrightness, Error(Display, Layer, float));
MOCK_METHOD3(setLayerBlockingRegion,
Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
MOCK_METHOD2(getDisplayDecorationSupport,
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 9be8cc7..570ffeb 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -131,7 +131,7 @@
MOCK_METHOD(hal::Error, setColorTransform, (const android::mat4 &), (override));
MOCK_METHOD(hal::Error, setLayerGenericMetadata,
(const std::string &, bool, const std::vector<uint8_t> &), (override));
- MOCK_METHOD(hal::Error, setWhitePointNits, (float whitePointNits), (override));
+ MOCK_METHOD(hal::Error, setBrightness, (float), (override));
MOCK_METHOD(hal::Error, setBlockingRegion, (const android::Region &), (override));
};
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index cae7684..ee7e92c 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -16,6 +16,7 @@
#pragma once
#include <gui/SyncScreenCaptureListener.h>
+#include <private/gui/ComposerServiceAIDL.h>
#include <ui/Rect.h>
#include <utils/String8.h>
#include <functional>
@@ -31,15 +32,15 @@
public:
static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
ScreenCaptureResults& captureResults) {
- const auto sf = ComposerService::getComposerService();
+ const auto sf = ComposerServiceAIDL::getComposerService();
SurfaceComposerClient::Transaction().apply(true);
captureArgs.dataspace = ui::Dataspace::V0_SRGB;
const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- status_t status = sf->captureDisplay(captureArgs, captureListener);
+ binder::Status status = sf->captureDisplay(captureArgs, captureListener);
- if (status != NO_ERROR) {
- return status;
+ if (status.transactionError() != NO_ERROR) {
+ return status.transactionError();
}
captureResults = captureListener->waitForResults();
return captureResults.result;
@@ -64,14 +65,14 @@
static status_t captureLayers(LayerCaptureArgs& captureArgs,
ScreenCaptureResults& captureResults) {
- const auto sf = ComposerService::getComposerService();
+ const auto sf = ComposerServiceAIDL::getComposerService();
SurfaceComposerClient::Transaction().apply(true);
captureArgs.dataspace = ui::Dataspace::V0_SRGB;
const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- status_t status = sf->captureLayers(captureArgs, captureListener);
- if (status != NO_ERROR) {
- return status;
+ binder::Status status = sf->captureLayers(captureArgs, captureListener);
+ if (status.transactionError() != NO_ERROR) {
+ return status.transactionError();
}
captureResults = captureListener->waitForResults();
return captureResults.result;