diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:24:47 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:24:47 +0000 |
commit | db25e5ca8d5b55c1e2940cceab38f4c019e59d54 (patch) | |
tree | 8637c0c3300f6a1324bac0b35e2f0b2e69803e08 | |
parent | 8fc7d872bc04a50bfce52d5a93f33867832e4268 (diff) | |
parent | af8f6cf3aba3398b36117dd3acce6f5a3c0610c6 (diff) | |
download | native-db25e5ca8d5b55c1e2940cceab38f4c019e59d54.tar.gz |
Snap for 6439596 from af8f6cf3aba3398b36117dd3acce6f5a3c0610c6 to qt-aml-tzdata-releaseandroid-mainline-10.0.0_r11
Change-Id: I853bc427c872c044202800e8bb558018278291ed
430 files changed, 19793 insertions, 23593 deletions
diff --git a/Android.bp b/Android.bp index 9829c7fbad..de9ea86f1d 100644 --- a/Android.bp +++ b/Android.bp @@ -7,7 +7,6 @@ ndk_headers { } subdirs = [ - "adbd_auth", "cmds/*", "headers", "libs/*", @@ -21,25 +20,3 @@ cc_library_headers { vendor: true, export_include_dirs: ["include_sensor"], } - -filegroup { - name: "framework_native_aidl_binder", - srcs: ["aidl/binder/**/*.aidl"], - path: "aidl/binder", - visibility: ["//frameworks/native"], -} - -filegroup { - name: "framework_native_aidl_gui", - srcs: ["aidl/gui/**/*.aidl"], - path: "aidl/gui", - visibility: ["//frameworks/native"], -} - -filegroup { - name: "framework_native_aidl", - srcs: [ - ":framework_native_aidl_binder", - ":framework_native_aidl_gui", - ], -} diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 4f7cdf3e5e..1a932c3d04 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -4,16 +4,13 @@ clang_format = true [Builtin Hooks Options] # Only turn on clang-format check for the following subfolders. clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp - include/input/ libs/binder/ndk/ libs/graphicsenv/ libs/gui/ - libs/input/ libs/renderengine/ libs/ui/ libs/vr/ services/bufferhub/ - services/inputflinger/ services/surfaceflinger/ services/vr/ diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp index e7d0ad0549..cc2a6f7e31 100644 --- a/cmds/atrace/Android.bp +++ b/cmds/atrace/Android.bp @@ -10,7 +10,9 @@ cc_binary { shared_libs: [ "libbinder", + "libhwbinder", "libhidlbase", + "libhidltransport", "liblog", "libutils", "libcutils", diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 5186ad3a1f..1429bc8b07 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -1468,11 +1468,10 @@ int main(int argc, char **argv) // Reset the trace buffer size to 1. if (traceStop) { + cleanUpVendorTracing(); cleanUpUserspaceTracing(); - if (!onlyUserspace) { - cleanUpVendorTracing(); + if (!onlyUserspace) cleanUpKernelTracing(); - } } return g_traceAborted ? 1 : 0; diff --git a/cmds/bugreport/bugreport.cpp b/cmds/bugreport/bugreport.cpp index 840ae473bc..917c8132b7 100644 --- a/cmds/bugreport/bugreport.cpp +++ b/cmds/bugreport/bugreport.cpp @@ -37,7 +37,7 @@ int main() { property_set("ctl.start", "dumpstate"); // Socket will not be available until service starts. - int s = -1; + int s; for (int i = 0; i < 20; i++) { s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); diff --git a/cmds/bugreportz/main.cpp b/cmds/bugreportz/main.cpp index 40346bee1f..74a95b0b57 100644 --- a/cmds/bugreportz/main.cpp +++ b/cmds/bugreportz/main.cpp @@ -72,7 +72,7 @@ int main(int argc, char* argv[]) { property_set("ctl.start", "dumpstatez"); // Socket will not be available until service starts. - int s = -1; + int s; for (int i = 0; i < 20; i++) { s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); if (s >= 0) break; diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index 09aee89e1b..ee32cb4495 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -86,13 +86,15 @@ cc_defaults { "libdumpstateaidl", "libdumpstateutil", "libdumputils", - "libhardware_legacy", "libhidlbase", + "libhidltransport", "liblog", "libutils", ], srcs: [ + "DumpstateSectionReporter.cpp", "DumpstateService.cpp", + "utils.cpp", ], static_libs: [ "libincidentcompanion", @@ -118,11 +120,10 @@ cc_binary { "kill", "librank", "logcat", - "lpdump", - "lpdumpd", "lsmod", "lsof", "netstat", + "parse_radio_log", "printenv", "procrank", "screencap", @@ -145,12 +146,6 @@ cc_test { "tests/dumpstate_test.cpp", ], static_libs: ["libgmock"], - test_config: "dumpstate_test.xml", - data: [ - ":dumpstate_test_fixture", - "tests/testdata/**/*", - ], - test_suites: ["device-tests"], } cc_test { diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp index bbc724c4c0..33e35f7274 100644 --- a/cmds/dumpstate/DumpstateInternal.cpp +++ b/cmds/dumpstate/DumpstateInternal.cpp @@ -68,8 +68,7 @@ bool DropRootUser() { } static const std::vector<std::string> group_names{ - "log", "sdcard_r", "sdcard_rw", "mount", "inet", "net_bw_stats", - "readproc", "bluetooth", "wakelock"}; + "log", "sdcard_r", "sdcard_rw", "mount", "inet", "net_bw_stats", "readproc", "bluetooth"}; std::vector<gid_t> groups(group_names.size(), 0); for (size_t i = 0; i < group_names.size(); ++i) { grp = getgrnam(group_names[i].c_str()); @@ -117,11 +116,6 @@ bool DropRootUser() { capdata[cap_syslog_index].effective |= cap_syslog_mask; } - const uint32_t cap_block_suspend_mask = CAP_TO_MASK(CAP_BLOCK_SUSPEND); - const uint32_t cap_block_suspend_index = CAP_TO_INDEX(CAP_BLOCK_SUSPEND); - capdata[cap_block_suspend_index].permitted |= cap_block_suspend_mask; - capdata[cap_block_suspend_index].effective |= cap_block_suspend_mask; - if (capset(&capheader, &capdata[0]) != 0) { MYLOGE("capset({%#x, %#x}) failed: %s\n", capdata[0].effective, capdata[1].effective, strerror(errno)); diff --git a/cmds/dumpstate/DumpstateSectionReporter.cpp b/cmds/dumpstate/DumpstateSectionReporter.cpp new file mode 100644 index 0000000000..f814bde26d --- /dev/null +++ b/cmds/dumpstate/DumpstateSectionReporter.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "dumpstate" + +#include "DumpstateSectionReporter.h" + +namespace android { +namespace os { +namespace dumpstate { + +DumpstateSectionReporter::DumpstateSectionReporter(const std::string& title, + sp<android::os::IDumpstateListener> listener, + bool sendReport) + : title_(title), listener_(listener), sendReport_(sendReport), status_(OK), size_(-1) { + started_ = std::chrono::steady_clock::now(); +} + +DumpstateSectionReporter::~DumpstateSectionReporter() { + if ((listener_ != nullptr) && (sendReport_)) { + auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::steady_clock::now() - started_); + listener_->onSectionComplete(title_, status_, size_, (int32_t)elapsed.count()); + } +} + +} // namespace dumpstate +} // namespace os +} // namespace android diff --git a/cmds/dumpstate/DumpstateSectionReporter.h b/cmds/dumpstate/DumpstateSectionReporter.h new file mode 100644 index 0000000000..e971de84c5 --- /dev/null +++ b/cmds/dumpstate/DumpstateSectionReporter.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_OS_DUMPSTATESECTIONREPORTER_H_ +#define ANDROID_OS_DUMPSTATESECTIONREPORTER_H_ + +#include <android/os/IDumpstateListener.h> +#include <utils/StrongPointer.h> + +namespace android { +namespace os { +namespace dumpstate { + + +/* + * Helper class used to report per section details to a listener. + * + * Typical usage: + * + * DumpstateSectionReporter sectionReporter(title, listener, sendReport); + * sectionReporter.setSize(5000); + * + */ +class DumpstateSectionReporter { + public: + DumpstateSectionReporter(const std::string& title, sp<android::os::IDumpstateListener> listener, + bool sendReport); + + ~DumpstateSectionReporter(); + + void setStatus(status_t status) { + status_ = status; + } + + void setSize(int size) { + size_ = size; + } + + private: + std::string title_; + android::sp<android::os::IDumpstateListener> listener_; + bool sendReport_; + status_t status_; + int size_; + std::chrono::time_point<std::chrono::steady_clock> started_; +}; + +} // namespace dumpstate +} // namespace os +} // namespace android + +#endif // ANDROID_OS_DUMPSTATESECTIONREPORTER_H_ diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index f98df99534..ddae9ea8f6 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -151,15 +151,15 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); } - std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>(); - options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd, - screenshot_fd); - - if (bugreport_fd.get() == -1 || (options->do_fb && screenshot_fd.get() == -1)) { + if (bugreport_fd.get() == -1 || screenshot_fd.get() == -1) { + // TODO(b/111441001): screenshot fd should be optional MYLOGE("Invalid filedescriptor"); signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); } + std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>(); + options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd, + screenshot_fd); ds_ = &(Dumpstate::GetInstance()); ds_->SetOptions(std::move(options)); @@ -200,7 +200,8 @@ status_t DumpstateService::dump(int fd, const Vector<String16>&) { dprintf(fd, "id: %d\n", ds_->id_); dprintf(fd, "pid: %d\n", ds_->pid_); dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false"); - dprintf(fd, "last_percent_progress: %d\n", ds_->last_reported_percent_progress_); + dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_); + dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_); dprintf(fd, "progress:\n"); ds_->progress_->Dump(fd, " "); dprintf(fd, "args: %s\n", ds_->options_->args.c_str()); diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index 4b69607156..97c8ae2045 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -378,6 +378,34 @@ int RunCommandToFd(int fd, const std::string& title, const std::vector<std::stri return status; } +int GetPidByName(const std::string& ps_name) { + DIR* proc_dir; + struct dirent* ps; + unsigned int pid; + std::string cmdline; + + if (!(proc_dir = opendir("/proc"))) { + MYLOGE("Can't open /proc\n"); + return -1; + } + + while ((ps = readdir(proc_dir))) { + if (!(pid = atoi(ps->d_name))) { + continue; + } + android::base::ReadFileToString("/proc/" + std::string(ps->d_name) + "/cmdline", &cmdline); + if (cmdline.find(ps_name) == std::string::npos) { + continue; + } else { + closedir(proc_dir); + return pid; + } + } + MYLOGE("can't find the pid\n"); + closedir(proc_dir); + return -1; +} + } // namespace dumpstate } // namespace os } // namespace android diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h index b7ac25c81e..d75b08c046 100644 --- a/cmds/dumpstate/DumpstateUtil.h +++ b/cmds/dumpstate/DumpstateUtil.h @@ -205,6 +205,12 @@ int RunCommandToFd(int fd, const std::string& title, const std::vector<std::stri */ int DumpFileToFd(int fd, const std::string& title, const std::string& path); +/* + * Finds the process id by process name. + * |ps_name| the process name we want to search for + */ +int GetPidByName(const std::string& ps_name); + } // namespace dumpstate } // namespace os } // namespace android diff --git a/cmds/dumpstate/TEST_MAPPING b/cmds/dumpstate/TEST_MAPPING deleted file mode 100644 index 083944f729..0000000000 --- a/cmds/dumpstate/TEST_MAPPING +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presubmit": [ - { - "name": "dumpstate_test" - } - ] -}
\ No newline at end of file diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl index cb2d8b8d2c..347856ddcb 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl @@ -73,7 +73,7 @@ interface IDumpstate { * @param callingUid UID of the original application that requested the report. * @param callingPackage package of the original application that requested the report. * @param bugreportFd the file to which the zipped bugreport should be written - * @param screenshotFd the file to which screenshot should be written + * @param screenshotFd the file to which screenshot should be written; optional * @param bugreportMode the mode that specifies other run time options; must be one of above * @param listener callback for updates; optional */ diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl index e486460753..ea1e467dca 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl @@ -61,4 +61,21 @@ interface IDumpstateListener { * Called when taking bugreport finishes successfully. */ void onFinished(); + + // TODO(b/111441001): Remove old methods when not used anymore. + void onProgressUpdated(int progress); + void onMaxProgressUpdated(int maxProgress); + + /** + * Called after every section is complete. + * + * @param name section name + * @param status values from status_t + * {@code OK} section completed successfully + * {@code TIMEOUT} dump timed out + * {@code != OK} error + * @param size size in bytes, may be invalid if status != OK + * @param durationMs duration in ms + */ + void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs); } diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index c5bfb42bde..5de40776b9 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -22,8 +22,6 @@ #include <inttypes.h> #include <libgen.h> #include <limits.h> -#include <math.h> -#include <poll.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -34,22 +32,13 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/wait.h> -#include <signal.h> -#include <stdarg.h> -#include <string.h> -#include <sys/capability.h> -#include <sys/inotify.h> -#include <sys/klog.h> -#include <time.h> #include <unistd.h> #include <chrono> -#include <cmath> #include <fstream> #include <functional> #include <future> #include <memory> -#include <numeric> #include <regex> #include <set> #include <string> @@ -69,19 +58,17 @@ #include <binder/IServiceManager.h> #include <cutils/native_handle.h> #include <cutils/properties.h> -#include <cutils/sockets.h> #include <debuggerd/client.h> #include <dumpsys.h> #include <dumputils/dump_utils.h> -#include <hardware_legacy/power.h> #include <hidl/ServiceManagement.h> -#include <log/log.h> #include <openssl/sha.h> #include <private/android_filesystem_config.h> #include <private/android_logger.h> #include <serviceutils/PriorityDumper.h> #include <utils/StrongPointer.h> #include "DumpstateInternal.h" +#include "DumpstateSectionReporter.h" #include "DumpstateService.h" #include "dumpstate.h" @@ -106,29 +93,10 @@ using android::base::StringPrintf; using android::os::IDumpstateListener; using android::os::dumpstate::CommandOptions; using android::os::dumpstate::DumpFileToFd; +using android::os::dumpstate::DumpstateSectionReporter; +using android::os::dumpstate::GetPidByName; using android::os::dumpstate::PropertiesHelper; -// Keep in sync with -// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java -static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds - -/* Most simple commands have 10 as timeout, so 5 is a good estimate */ -static const int32_t WEIGHT_FILE = 5; - -// TODO: temporary variables and functions used during C++ refactoring -static Dumpstate& ds = Dumpstate::GetInstance(); -static int RunCommand(const std::string& title, const std::vector<std::string>& full_command, - const CommandOptions& options = CommandOptions::DEFAULT, - bool verbose_duration = false) { - return ds.RunCommand(title, full_command, options, verbose_duration); -} - -// Reasonable value for max stats. -static const int STATS_MAX_N_RUNS = 1000; -static const long STATS_MAX_AVERAGE = 100000; - -CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build(); - typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult; /* read before root is shed */ @@ -154,7 +122,6 @@ void add_mountinfo(); #define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat" #define WLUTIL "/vendor/xbin/wlutil" #define WMTRACE_DATA_DIR "/data/misc/wmtrace" -#define OTA_METADATA_DIR "/metadata/ota" // TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. @@ -166,6 +133,7 @@ static const std::string ANR_DIR = "/data/anr/"; static const std::string ANR_FILE_PREFIX = "anr_"; // TODO: temporary variables and functions used during C++ refactoring +static Dumpstate& ds = Dumpstate::GetInstance(); #define RETURN_IF_USER_DENIED_CONSENT() \ if (ds.IsUserConsentDenied()) { \ @@ -180,8 +148,6 @@ static const std::string ANR_FILE_PREFIX = "anr_"; func_ptr(__VA_ARGS__); \ RETURN_IF_USER_DENIED_CONSENT(); -static const char* WAKE_LOCK_NAME = "dumpstate_wakelock"; - namespace android { namespace os { namespace { @@ -254,7 +220,7 @@ int64_t GetModuleMetadataVersion() { MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str()); return 0L; } - MYLOGD("Module metadata package name: %s\n", package_name.c_str()); + MYLOGD("Module metadata package name: %s", package_name.c_str()); int64_t version_code; status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()), &version_code); @@ -269,6 +235,10 @@ int64_t GetModuleMetadataVersion() { } // namespace os } // namespace android +static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand, + const CommandOptions& options = CommandOptions::DEFAULT) { + return ds.RunCommand(title, fullCommand, options); +} static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs, const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS, long dumpsysTimeoutMs = 0) { @@ -301,10 +271,12 @@ static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot( * Returns a vector of dump fds under |dir_path| with a given |file_prefix|. * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime| * is set, the vector only contains files that were written in the last 30 minutes. + * If |limit_by_count| is set, the vector only contains the ten latest files. */ static std::vector<DumpData> GetDumpFds(const std::string& dir_path, const std::string& file_prefix, - bool limit_by_mtime) { + bool limit_by_mtime, + bool limit_by_count = true) { const time_t thirty_minutes_ago = ds.now_ - 60 * 30; std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir); @@ -348,6 +320,15 @@ static std::vector<DumpData> GetDumpFds(const std::string& dir_path, dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime}); } + // Sort in descending modification time so that we only keep the newest + // reports if |limit_by_count| is true. + std::sort(dump_data.begin(), dump_data.end(), + [](const DumpData& d1, const DumpData& d2) { return d1.mtime > d2.mtime; }); + + if (limit_by_count && dump_data.size() > 10) { + dump_data.erase(dump_data.begin() + 10, dump_data.end()); + } + return dump_data; } @@ -440,6 +421,108 @@ static void dump_dev_files(const char *title, const char *driverpath, const char closedir(d); } + + +// dump anrd's trace and add to the zip file. +// 1. check if anrd is running on this device. +// 2. send a SIGUSR1 to its pid which will dump anrd's trace. +// 3. wait until the trace generation completes and add to the zip file. +static bool dump_anrd_trace() { + unsigned int pid; + char buf[50], path[PATH_MAX]; + struct dirent *trace; + struct stat st; + DIR *trace_dir; + int retry = 5; + long max_ctime = 0, old_mtime; + long long cur_size = 0; + const char *trace_path = "/data/misc/anrd/"; + + if (!ds.IsZipping()) { + MYLOGE("Not dumping anrd trace because it's not a zipped bugreport\n"); + return false; + } + + // find anrd's pid if it is running. + pid = GetPidByName("/system/bin/anrd"); + + if (pid > 0) { + if (stat(trace_path, &st) == 0) { + old_mtime = st.st_mtime; + } else { + MYLOGE("Failed to find: %s\n", trace_path); + return false; + } + + // send SIGUSR1 to the anrd to generate a trace. + sprintf(buf, "%u", pid); + if (RunCommand("ANRD_DUMP", {"kill", "-SIGUSR1", buf}, + CommandOptions::WithTimeout(1).Build())) { + MYLOGE("anrd signal timed out. Please manually collect trace\n"); + return false; + } + + while (retry-- > 0 && old_mtime == st.st_mtime) { + sleep(1); + stat(trace_path, &st); + } + + if (retry < 0 && old_mtime == st.st_mtime) { + MYLOGE("Failed to stat %s or trace creation timeout\n", trace_path); + return false; + } + + // identify the trace file by its creation time. + if (!(trace_dir = opendir(trace_path))) { + MYLOGE("Can't open trace file under %s\n", trace_path); + } + while ((trace = readdir(trace_dir))) { + if (strcmp(trace->d_name, ".") == 0 + || strcmp(trace->d_name, "..") == 0) { + continue; + } + sprintf(path, "%s%s", trace_path, trace->d_name); + if (stat(path, &st) == 0) { + if (st.st_ctime > max_ctime) { + max_ctime = st.st_ctime; + sprintf(buf, "%s", trace->d_name); + } + } + } + closedir(trace_dir); + + // Wait until the dump completes by checking the size of the trace. + if (max_ctime > 0) { + sprintf(path, "%s%s", trace_path, buf); + while(true) { + sleep(1); + if (stat(path, &st) == 0) { + if (st.st_size == cur_size) { + break; + } else if (st.st_size > cur_size) { + cur_size = st.st_size; + } else { + return false; + } + } else { + MYLOGE("Cant stat() %s anymore\n", path); + return false; + } + } + // Add to the zip file. + if (!ds.AddZipEntry("anrd_trace.txt", path)) { + MYLOGE("Unable to add anrd_trace file %s to zip file\n", path); + } else { + android::os::UnlinkAndLogOnError(path); + return true; + } + } else { + MYLOGE("Can't stats any trace file under %s\n", trace_path); + } + } + return false; +} + static bool skip_not_stat(const char *path) { static const char stat[] = "/stat"; size_t len = strlen(path); @@ -877,17 +960,6 @@ static void DoKernelLogcat() { CommandOptions::WithTimeoutInMs(timeout_ms).Build()); } -static void DoSystemLogcat(time_t since) { - char since_str[80]; - strftime(since_str, sizeof(since_str), "%Y-%m-%d %H:%M:%S.000", localtime(&since)); - - unsigned long timeout_ms = logcat_timeout({"main", "system", "crash"}); - RunCommand("SYSTEM LOG", - {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v", "-T", - since_str}, - CommandOptions::WithTimeoutInMs(timeout_ms).Build()); -} - static void DoLogcat() { unsigned long timeout_ms; // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags"); @@ -900,17 +972,17 @@ static void DoLogcat() { RunCommand( "EVENT LOG", {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, - CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */); + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); timeout_ms = logcat_timeout({"stats"}); RunCommand( "STATS LOG", {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, - CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */); + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); timeout_ms = logcat_timeout({"radio"}); RunCommand( "RADIO LOG", {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, - CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */); + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"}); @@ -919,31 +991,6 @@ static void DoLogcat() { "-v", "uid", "-d", "*:v"}); } -static void DumpIncidentReport() { - if (!ds.IsZipping()) { - MYLOGD("Not dumping incident report because it's not a zipped bugreport\n"); - return; - } - DurationReporter duration_reporter("INCIDENT REPORT"); - const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report"; - auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), - O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))); - if (fd < 0) { - MYLOGE("Could not open %s to dump incident report.\n", path.c_str()); - return; - } - RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build()); - bool empty = 0 == lseek(fd, 0, SEEK_END); - if (!empty) { - // Use a different name from "incident.proto" - // /proto/incident.proto is reserved for incident service dump - // i.e. metadata for debugging. - ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path); - } - unlink(path.c_str()); -} - static void DumpIpTablesAsRoot() { RunCommand("IPTABLES", {"iptables", "-L", "-nvx"}); RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"}); @@ -955,15 +1002,6 @@ static void DumpIpTablesAsRoot() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } -static void DumpDynamicPartitionInfo() { - if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) { - return; - } - - RunCommand("LPDUMP", {"lpdump", "--all"}); - RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"}); -} - static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) { MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path, anr_traces_dir.c_str()); @@ -1083,17 +1121,20 @@ static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, i RETURN_IF_USER_DENIED_CONSENT(); std::string path(title); path.append(" - ").append(String8(service).c_str()); + DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_); size_t bytes_written = 0; - status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args); + status_t status = dumpsys.startDumpThread(service, args); if (status == OK) { dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority); std::chrono::duration<double> elapsed_seconds; status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout, /* as_proto = */ false, elapsed_seconds, bytes_written); + section_reporter.setSize(bytes_written); dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds); bool dump_complete = (status == OK); dumpsys.stopDumpThread(dump_complete); } + section_reporter.setStatus(status); auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::steady_clock::now() - start); @@ -1156,7 +1197,8 @@ static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priori path.append("_HIGH"); } path.append(kProtoExt); - status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args); + DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_); + status_t status = dumpsys.startDumpThread(service, args); if (status == OK) { status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout); bool dumpTerminated = (status == OK); @@ -1164,6 +1206,8 @@ static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priori } ZipWriter::FileEntry file_entry; ds.zip_writer_->GetLastEntry(&file_entry); + section_reporter.setSize(file_entry.compressed_size); + section_reporter.setStatus(status); auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::steady_clock::now() - start); @@ -1270,45 +1314,6 @@ static void DumpHals() { } } -static void DumpExternalFragmentationInfo() { - struct stat st; - if (stat("/proc/buddyinfo", &st) != 0) { - MYLOGE("Unable to dump external fragmentation info\n"); - return; - } - - printf("------ EXTERNAL FRAGMENTATION INFO ------\n"); - std::ifstream ifs("/proc/buddyinfo"); - auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"}; - for (std::string line; std::getline(ifs, line);) { - std::smatch match_results; - if (std::regex_match(line, match_results, unusable_index_regex)) { - std::stringstream free_pages(std::string{match_results[3]}); - std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages}, - std::istream_iterator<int>()); - - int total_free_pages = 0; - for (size_t i = 0; i < free_pages_per_order.size(); i++) { - total_free_pages += (free_pages_per_order[i] * std::pow(2, i)); - } - - printf("Node %s, zone %8s", match_results[1].str().c_str(), - match_results[2].str().c_str()); - - int usable_free_pages = total_free_pages; - for (size_t i = 0; i < free_pages_per_order.size(); i++) { - auto unusable_index = (total_free_pages - usable_free_pages) / - static_cast<double>(total_free_pages); - printf(" %5.3f", unusable_index); - usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i)); - } - - printf("\n"); - } - } - printf("\n"); -} - // Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent // via the consent they are shown. Ignores other errors that occur while running various // commands. The consent checking is currently done around long running tasks, which happen to @@ -1322,6 +1327,7 @@ static Dumpstate::RunStatus dumpstate() { dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); RunCommand("UPTIME", {"uptime"}); DumpBlockStatFiles(); + dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd"); DumpFile("MEMORY INFO", "/proc/meminfo"); RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"}); @@ -1334,10 +1340,11 @@ static Dumpstate::RunStatus dumpstate() { DumpFile("ZONEINFO", "/proc/zoneinfo"); DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo"); DumpFile("BUDDYINFO", "/proc/buddyinfo"); - DumpExternalFragmentationInfo(); + DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index"); DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources"); DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"); + DumpFile("KERNEL SYNC", "/d/sync"); RunCommand("PROCESSES AND THREADS", {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"}); @@ -1373,11 +1380,13 @@ static Dumpstate::RunStatus dumpstate() { /* Dump Bluetooth HCI logs */ ds.AddDir("/data/misc/bluetooth/logs", true); - if (ds.options_->do_fb && !ds.do_early_screenshot_) { + if (!ds.do_early_screenshot_) { MYLOGI("taking late screenshot\n"); ds.TakeScreenshot(); } + DoLogcat(); + AddAnrTraceFiles(); // NOTE: tombstones are always added as separate entries in the zip archive @@ -1410,6 +1419,8 @@ static Dumpstate::RunStatus dumpstate() { RunCommand("FILESYSTEMS & FREE SPACE", {"df"}); + RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"}); + /* Binder state is expensive to look at as it uses a lot of memory. */ DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log"); DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log"); @@ -1417,6 +1428,7 @@ static Dumpstate::RunStatus dumpstate() { DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats"); DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state"); + RunDumpsys("WINSCOPE TRACE", {"window", "trace"}); /* Add window and surface trace files. */ if (!PropertiesHelper::IsUserBuild()) { ds.AddDir(WMTRACE_DATA_DIR, false); @@ -1515,9 +1527,6 @@ static Dumpstate::RunStatus dumpstate() { printf("========================================================\n"); // This differs from the usual dumpsys stats, which is the stats report data. RunDumpsys("STATSDSTATS", {"stats", "--metadata"}); - - RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport); - return Dumpstate::RunStatus::OK; } @@ -1530,16 +1539,13 @@ static Dumpstate::RunStatus dumpstate() { * with the caller. */ static Dumpstate::RunStatus DumpstateDefault() { + // Try to dump anrd trace if the daemon is running. + dump_anrd_trace(); + // Invoking the following dumpsys calls before DumpTraces() to try and // keep the system stats as close to its initial state as possible. RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical); - // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the - // buffer. - DoLogcat(); - // Capture timestamp after first logcat to use in next logcat - time_t logcat_ts = time(nullptr); - /* collect stack traces from Dalvik and native processes (needs root) */ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path); @@ -1557,8 +1563,6 @@ static Dumpstate::RunStatus DumpstateDefault() { } add_mountinfo(); DumpIpTablesAsRoot(); - DumpDynamicPartitionInfo(); - ds.AddDir(OTA_METADATA_DIR, true); // Capture any IPSec policies in play. No keys are exposed here. RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build()); @@ -1578,19 +1582,12 @@ static Dumpstate::RunStatus DumpstateDefault() { RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"}); } - DumpFile("PSI cpu", "/proc/pressure/cpu"); - DumpFile("PSI memory", "/proc/pressure/memory"); - DumpFile("PSI io", "/proc/pressure/io"); - if (!DropRootUser()) { return Dumpstate::RunStatus::ERROR; } RETURN_IF_USER_DENIED_CONSENT(); - Dumpstate::RunStatus status = dumpstate(); - // Capture logcat since the last time we did it. - DoSystemLogcat(logcat_ts); - return status; + return dumpstate(); } // This method collects common dumpsys for telephony and wifi @@ -1907,21 +1904,22 @@ void Dumpstate::DumpstateBoard() { static void ShowUsage() { fprintf(stderr, - "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] " + "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] " "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" " -h: display this help message\n" " -b: play sound file instead of vibrate, at beginning of job\n" " -e: play sound file instead of vibrate, at end of job\n" - " -d: append date to filename\n" - " -p: capture screenshot to filename.png\n" - " -z: generate zipped file\n" + " -o: write to file (instead of stdout)\n" + " -d: append date to filename (requires -o)\n" + " -p: capture screenshot to filename.png (requires -o)\n" + " -z: generate zipped file (requires -o)\n" " -s: write output to control socket (for init)\n" - " -S: write file location to control socket (for init; requires -z)\n" + " -S: write file location to control socket (for init; requires -o and -z)\n" " -q: disable vibrate\n" - " -B: send broadcast when finished\n" + " -B: send broadcast when finished (requires -o)\n" " -P: send broadcast when started and update system properties on " - "progress (requires -B)\n" - " -R: take bugreport in remote mode (requires -z, -d and -B, " + "progress (requires -o and -B)\n" + " -R: take bugreport in remote mode (requires -o, -z, -d and -B, " "shouldn't be used with -P)\n" " -w: start binder service and make it wait for a call to startBugreport\n" " -v: prints the dumpstate header and exit\n"); @@ -2033,7 +2031,7 @@ static void SendBroadcast(const std::string& action, const std::vector<std::stri static void Vibrate(int duration_ms) { // clang-format off - RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"}, + RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"}, CommandOptions::WithTimeout(10) .Log("Vibrate: '%s'\n") .Always() @@ -2405,6 +2403,7 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) } } + // TODO: use helper function to convert argv into a string for (int i = 0; i < argc; i++) { args += argv[i]; if (i < argc - 1) { @@ -2555,13 +2554,6 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, MYLOGI("begin\n"); - if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) { - MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno)); - } else { - // Wake lock will be released automatically on process death - MYLOGD("Wake lock acquired.\n"); - } - register_sig_handler(); // TODO(b/111441001): maybe skip if already started? @@ -2635,8 +2627,13 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, } if (options_->do_fb && do_early_screenshot_) { - MYLOGI("taking early screenshot\n"); - TakeScreenshot(); + if (screenshot_path_.empty()) { + // should not have happened + MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n"); + } else { + MYLOGI("taking early screenshot\n"); + TakeScreenshot(); + } } if (options_->do_zip_file && zip_file != nullptr) { @@ -2692,7 +2689,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, // Dump state for the default case. This also drops root. RunStatus s = DumpstateDefault(); if (s != RunStatus::OK) { - if (s == RunStatus::USER_CONSENT_DENIED) { + if (s == RunStatus::USER_CONSENT_TIMED_OUT) { HandleUserConsentDenied(); } return s; @@ -2888,833 +2885,3 @@ int run_main(int argc, char* argv[]) { exit(2); } } - -// TODO(111441001): Default DumpOptions to sensible values. -Dumpstate::Dumpstate(const std::string& version) - : pid_(getpid()), - options_(new Dumpstate::DumpOptions()), - last_reported_percent_progress_(0), - version_(version), - now_(time(nullptr)) { -} - -Dumpstate& Dumpstate::GetInstance() { - static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT)); - return singleton_; -} - -DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose) - : title_(title), logcat_only_(logcat_only), verbose_(verbose) { - if (!title_.empty()) { - started_ = Nanotime(); - } -} - -DurationReporter::~DurationReporter() { - if (!title_.empty()) { - float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC; - if (elapsed < .5f && !verbose_) { - return; - } - MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed); - if (logcat_only_) { - return; - } - // Use "Yoda grammar" to make it easier to grep|sort sections. - printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str()); - } -} - -const int32_t Progress::kDefaultMax = 5000; - -Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) { -} - -Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor) - : Progress(initial_max, growth_factor, "") { - progress_ = progress; -} - -Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path) - : initial_max_(initial_max), - progress_(0), - max_(initial_max), - growth_factor_(growth_factor), - n_runs_(0), - average_max_(0), - path_(path) { - if (!path_.empty()) { - Load(); - } -} - -void Progress::Load() { - MYLOGD("Loading stats from %s\n", path_.c_str()); - std::string content; - if (!android::base::ReadFileToString(path_, &content)) { - MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_); - return; - } - if (content.empty()) { - MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_); - return; - } - std::vector<std::string> lines = android::base::Split(content, "\n"); - - if (lines.size() < 1) { - MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(), - (int)lines.size(), max_); - return; - } - char* ptr; - n_runs_ = strtol(lines[0].c_str(), &ptr, 10); - average_max_ = strtol(ptr, nullptr, 10); - if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS || - average_max_ > STATS_MAX_AVERAGE) { - MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str()); - initial_max_ = Progress::kDefaultMax; - } else { - initial_max_ = average_max_; - } - max_ = initial_max_; - - MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_); -} - -void Progress::Save() { - int32_t total = n_runs_ * average_max_ + progress_; - int32_t runs = n_runs_ + 1; - int32_t average = floor(((float)total) / runs); - MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average, - path_.c_str()); - if (path_.empty()) { - return; - } - - std::string content = android::base::StringPrintf("%d %d\n", runs, average); - if (!android::base::WriteStringToFile(content, path_)) { - MYLOGE("Could not save stats on %s\n", path_.c_str()); - } -} - -int32_t Progress::Get() const { - return progress_; -} - -bool Progress::Inc(int32_t delta_sec) { - bool changed = false; - if (delta_sec >= 0) { - progress_ += delta_sec; - if (progress_ > max_) { - int32_t old_max = max_; - max_ = floor((float)progress_ * growth_factor_); - MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_); - changed = true; - } - } - return changed; -} - -int32_t Progress::GetMax() const { - return max_; -} - -int32_t Progress::GetInitialMax() const { - return initial_max_; -} - -void Progress::Dump(int fd, const std::string& prefix) const { - const char* pr = prefix.c_str(); - dprintf(fd, "%sprogress: %d\n", pr, progress_); - dprintf(fd, "%smax: %d\n", pr, max_); - dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_); - dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_); - dprintf(fd, "%spath: %s\n", pr, path_.c_str()); - dprintf(fd, "%sn_runs: %d\n", pr, n_runs_); - dprintf(fd, "%saverage_max: %d\n", pr, average_max_); -} - -bool Dumpstate::IsZipping() const { - return zip_writer_ != nullptr; -} - -std::string Dumpstate::GetPath(const std::string& suffix) const { - return GetPath(bugreport_internal_dir_, suffix); -} - -std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const { - return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(), - name_.c_str(), suffix.c_str()); -} - -void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) { - progress_ = std::move(progress); -} - -void for_each_userid(void (*func)(int), const char *header) { - std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf( - "for_each_userid(%s)", header); - DurationReporter duration_reporter(title); - if (PropertiesHelper::IsDryRun()) return; - - DIR *d; - struct dirent *de; - - if (header) printf("\n------ %s ------\n", header); - func(0); - - if (!(d = opendir("/data/system/users"))) { - printf("Failed to open /data/system/users (%s)\n", strerror(errno)); - return; - } - - while ((de = readdir(d))) { - int userid; - if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) { - continue; - } - func(userid); - } - - closedir(d); -} - -static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) { - DIR *d; - struct dirent *de; - - if (!(d = opendir("/proc"))) { - printf("Failed to open /proc (%s)\n", strerror(errno)); - return; - } - - if (header) printf("\n------ %s ------\n", header); - while ((de = readdir(d))) { - if (ds.IsUserConsentDenied()) { - MYLOGE( - "Returning early because user denied consent to share bugreport with calling app."); - closedir(d); - return; - } - int pid; - int fd; - char cmdpath[255]; - char cmdline[255]; - - if (!(pid = atoi(de->d_name))) { - continue; - } - - memset(cmdline, 0, sizeof(cmdline)); - - snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid); - if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) { - TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2)); - close(fd); - if (cmdline[0]) { - helper(pid, cmdline, arg); - continue; - } - } - - // if no cmdline, a kernel thread has comm - snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid); - if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) { - TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4)); - close(fd); - if (cmdline[1]) { - cmdline[0] = '['; - size_t len = strcspn(cmdline, "\f\b\r\n"); - cmdline[len] = ']'; - cmdline[len+1] = '\0'; - } - } - if (!cmdline[0]) { - strcpy(cmdline, "N/A"); - } - helper(pid, cmdline, arg); - } - - closedir(d); -} - -static void for_each_pid_helper(int pid, const char *cmdline, void *arg) { - for_each_pid_func *func = (for_each_pid_func*) arg; - func(pid, cmdline); -} - -void for_each_pid(for_each_pid_func func, const char *header) { - std::string title = header == nullptr ? "for_each_pid" - : android::base::StringPrintf("for_each_pid(%s)", header); - DurationReporter duration_reporter(title); - if (PropertiesHelper::IsDryRun()) return; - - __for_each_pid(for_each_pid_helper, header, (void *) func); -} - -static void for_each_tid_helper(int pid, const char *cmdline, void *arg) { - DIR *d; - struct dirent *de; - char taskpath[255]; - for_each_tid_func *func = (for_each_tid_func *) arg; - - snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid); - - if (!(d = opendir(taskpath))) { - printf("Failed to open %s (%s)\n", taskpath, strerror(errno)); - return; - } - - func(pid, pid, cmdline); - - while ((de = readdir(d))) { - if (ds.IsUserConsentDenied()) { - MYLOGE( - "Returning early because user denied consent to share bugreport with calling app."); - closedir(d); - return; - } - int tid; - int fd; - char commpath[255]; - char comm[255]; - - if (!(tid = atoi(de->d_name))) { - continue; - } - - if (tid == pid) - continue; - - snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid); - memset(comm, 0, sizeof(comm)); - if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) { - strcpy(comm, "N/A"); - } else { - char *c; - TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2)); - close(fd); - - c = strrchr(comm, '\n'); - if (c) { - *c = '\0'; - } - } - func(pid, tid, comm); - } - - closedir(d); -} - -void for_each_tid(for_each_tid_func func, const char *header) { - std::string title = header == nullptr ? "for_each_tid" - : android::base::StringPrintf("for_each_tid(%s)", header); - DurationReporter duration_reporter(title); - - if (PropertiesHelper::IsDryRun()) return; - - __for_each_pid(for_each_tid_helper, header, (void *) func); -} - -void show_wchan(int pid, int tid, const char *name) { - if (PropertiesHelper::IsDryRun()) return; - - char path[255]; - char buffer[255]; - int fd, ret, save_errno; - char name_buffer[255]; - - memset(buffer, 0, sizeof(buffer)); - - snprintf(path, sizeof(path), "/proc/%d/wchan", tid); - if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) { - printf("Failed to open '%s' (%s)\n", path, strerror(errno)); - return; - } - - ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); - save_errno = errno; - close(fd); - - if (ret < 0) { - printf("Failed to read '%s' (%s)\n", path, strerror(save_errno)); - return; - } - - snprintf(name_buffer, sizeof(name_buffer), "%*s%s", - pid == tid ? 0 : 3, "", name); - - printf("%-7d %-32s %s\n", tid, name_buffer, buffer); - - return; -} - -// print time in centiseconds -static void snprcent(char *buffer, size_t len, size_t spc, - unsigned long long time) { - static long hz; // cache discovered hz - - if (hz <= 0) { - hz = sysconf(_SC_CLK_TCK); - if (hz <= 0) { - hz = 1000; - } - } - - // convert to centiseconds - time = (time * 100 + (hz / 2)) / hz; - - char str[16]; - - snprintf(str, sizeof(str), " %llu.%02u", - time / 100, (unsigned)(time % 100)); - size_t offset = strlen(buffer); - snprintf(buffer + offset, (len > offset) ? len - offset : 0, - "%*s", (spc > offset) ? (int)(spc - offset) : 0, str); -} - -// print permille as a percent -static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) { - char str[16]; - - snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10); - size_t offset = strlen(buffer); - snprintf(buffer + offset, (len > offset) ? len - offset : 0, - "%*s", (spc > offset) ? (int)(spc - offset) : 0, str); -} - -void show_showtime(int pid, const char *name) { - if (PropertiesHelper::IsDryRun()) return; - - char path[255]; - char buffer[1023]; - int fd, ret, save_errno; - - memset(buffer, 0, sizeof(buffer)); - - snprintf(path, sizeof(path), "/proc/%d/stat", pid); - if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) { - printf("Failed to open '%s' (%s)\n", path, strerror(errno)); - return; - } - - ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); - save_errno = errno; - close(fd); - - if (ret < 0) { - printf("Failed to read '%s' (%s)\n", path, strerror(save_errno)); - return; - } - - // field 14 is utime - // field 15 is stime - // field 42 is iotime - unsigned long long utime = 0, stime = 0, iotime = 0; - if (sscanf(buffer, - "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ", - &utime, &stime, &iotime) != 3) { - return; - } - - unsigned long long total = utime + stime; - if (!total) { - return; - } - - unsigned permille = (iotime * 1000 + (total / 2)) / total; - if (permille > 1000) { - permille = 1000; - } - - // try to beautify and stabilize columns at <80 characters - snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name); - if ((name[0] != '[') || utime) { - snprcent(buffer, sizeof(buffer), 57, utime); - } - snprcent(buffer, sizeof(buffer), 65, stime); - if ((name[0] != '[') || iotime) { - snprcent(buffer, sizeof(buffer), 73, iotime); - } - if (iotime) { - snprdec(buffer, sizeof(buffer), 79, permille); - } - puts(buffer); // adds a trailing newline - - return; -} - -void do_dmesg() { - const char *title = "KERNEL LOG (dmesg)"; - DurationReporter duration_reporter(title); - printf("------ %s ------\n", title); - - if (PropertiesHelper::IsDryRun()) return; - - /* Get size of kernel buffer */ - int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0); - if (size <= 0) { - printf("Unexpected klogctl return value: %d\n\n", size); - return; - } - char *buf = (char *) malloc(size + 1); - if (buf == nullptr) { - printf("memory allocation failed\n\n"); - return; - } - int retval = klogctl(KLOG_READ_ALL, buf, size); - if (retval < 0) { - printf("klogctl failure\n\n"); - free(buf); - return; - } - buf[retval] = '\0'; - printf("%s\n\n", buf); - free(buf); - return; -} - -void do_showmap(int pid, const char *name) { - char title[255]; - char arg[255]; - - snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name); - snprintf(arg, sizeof(arg), "%d", pid); - RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT); -} - -int Dumpstate::DumpFile(const std::string& title, const std::string& path) { - DurationReporter duration_reporter(title); - - int status = DumpFileToFd(STDOUT_FILENO, title, path); - - UpdateProgress(WEIGHT_FILE); - - return status; -} - -int read_file_as_long(const char *path, long int *output) { - int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)); - if (fd < 0) { - int err = errno; - MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err)); - return -1; - } - char buffer[50]; - ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); - if (bytes_read == -1) { - MYLOGE("Error reading file %s: %s\n", path, strerror(errno)); - return -2; - } - if (bytes_read == 0) { - MYLOGE("File %s is empty\n", path); - return -3; - } - *output = atoi(buffer); - return 0; -} - -/* calls skip to gate calling dump_from_fd recursively - * in the specified directory. dump_from_fd defaults to - * dump_file_from_fd above when set to NULL. skip defaults - * to false when set to NULL. dump_from_fd will always be - * called with title NULL. - */ -int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path), - int (*dump_from_fd)(const char* title, const char* path, int fd)) { - DurationReporter duration_reporter(title); - DIR *dirp; - struct dirent *d; - char *newpath = nullptr; - const char *slash = "/"; - int retval = 0; - - if (!title.empty()) { - printf("------ %s (%s) ------\n", title.c_str(), dir); - } - if (PropertiesHelper::IsDryRun()) return 0; - - if (dir[strlen(dir) - 1] == '/') { - ++slash; - } - dirp = opendir(dir); - if (dirp == nullptr) { - retval = -errno; - MYLOGE("%s: %s\n", dir, strerror(errno)); - return retval; - } - - if (!dump_from_fd) { - dump_from_fd = dump_file_from_fd; - } - for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) { - if ((d->d_name[0] == '.') - && (((d->d_name[1] == '.') && (d->d_name[2] == '\0')) - || (d->d_name[1] == '\0'))) { - continue; - } - asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name, - (d->d_type == DT_DIR) ? "/" : ""); - if (!newpath) { - retval = -errno; - continue; - } - if (skip && (*skip)(newpath)) { - continue; - } - if (d->d_type == DT_DIR) { - int ret = dump_files("", newpath, skip, dump_from_fd); - if (ret < 0) { - retval = ret; - } - continue; - } - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC))); - if (fd.get() < 0) { - retval = -1; - printf("*** %s: %s\n", newpath, strerror(errno)); - continue; - } - (*dump_from_fd)(nullptr, newpath, fd.get()); - } - closedir(dirp); - if (!title.empty()) { - printf("\n"); - } - return retval; -} - -/* fd must have been opened with the flag O_NONBLOCK. With this flag set, - * it's possible to avoid issues where opening the file itself can get - * stuck. - */ -int dump_file_from_fd(const char *title, const char *path, int fd) { - if (PropertiesHelper::IsDryRun()) return 0; - - int flags = fcntl(fd, F_GETFL); - if (flags == -1) { - printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno)); - return -1; - } else if (!(flags & O_NONBLOCK)) { - printf("*** %s: fd must have O_NONBLOCK set.\n", path); - return -1; - } - return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun()); -} - -int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command, - const CommandOptions& options, bool verbose_duration) { - DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration); - - int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options); - - /* TODO: for now we're simplifying the progress calculation by using the - * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys, - * where its weight should be much higher proportionally to its timeout. - * Ideally, it should use a options.EstimatedDuration() instead...*/ - UpdateProgress(options.Timeout()); - - return status; -} - -void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args, - const CommandOptions& options, long dumpsysTimeoutMs) { - long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs(); - std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)}; - dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end()); - RunCommand(title, dumpsys, options); -} - -int open_socket(const char *service) { - int s = android_get_control_socket(service); - if (s < 0) { - MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno)); - return -1; - } - fcntl(s, F_SETFD, FD_CLOEXEC); - - // Set backlog to 0 to make sure that queue size will be minimum. - // In Linux, because the minimum queue will be 1, connect() will be blocked - // if the other clients already called connect() and the connection request was not accepted. - if (listen(s, 0) < 0) { - MYLOGE("listen(control socket): %s\n", strerror(errno)); - return -1; - } - - struct sockaddr addr; - socklen_t alen = sizeof(addr); - int fd = accept4(s, &addr, &alen, SOCK_CLOEXEC); - - // Close socket just after accept(), to make sure that connect() by client will get error - // when the socket is used by the other services. - // There is still a race condition possibility between accept and close, but there is no way - // to close-on-accept atomically. - // See detail; b/123306389#comment25 - close(s); - - if (fd < 0) { - MYLOGE("accept(control socket): %s\n", strerror(errno)); - return -1; - } - - return fd; -} - -/* redirect output to a service control socket */ -bool redirect_to_socket(FILE* redirect, const char* service) { - int fd = open_socket(service); - if (fd == -1) { - return false; - } - fflush(redirect); - // TODO: handle dup2 failure - TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect))); - close(fd); - return true; -} - -// TODO: should call is_valid_output_file and/or be merged into it. -void create_parent_dirs(const char *path) { - char *chp = const_cast<char *> (path); - - /* skip initial slash */ - if (chp[0] == '/') - chp++; - - /* create leading directories, if necessary */ - struct stat dir_stat; - while (chp && chp[0]) { - chp = strchr(chp, '/'); - if (chp) { - *chp = 0; - if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) { - MYLOGI("Creating directory %s\n", path); - if (mkdir(path, 0770)) { /* drwxrwx--- */ - MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno)); - } else if (chown(path, AID_SHELL, AID_SHELL)) { - MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno)); - } - } - *chp++ = '/'; - } - } -} - -bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) { - create_parent_dirs(path); - - int fd = TEMP_FAILURE_RETRY(open(path, - O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); - if (fd < 0) { - MYLOGE("%s: %s\n", path, strerror(errno)); - return false; - } - - TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect))); - close(fd); - return true; -} - -bool redirect_to_file(FILE* redirect, char* path) { - return _redirect_to_file(redirect, path, O_TRUNC); -} - -bool redirect_to_existing_file(FILE* redirect, char* path) { - return _redirect_to_file(redirect, path, O_APPEND); -} - -void dump_route_tables() { - DurationReporter duration_reporter("DUMP ROUTE TABLES"); - if (PropertiesHelper::IsDryRun()) return; - const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables"; - ds.DumpFile("RT_TABLES", RT_TABLES_PATH); - FILE* fp = fopen(RT_TABLES_PATH, "re"); - if (!fp) { - printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno)); - return; - } - char table[16]; - // Each line has an integer (the table number), a space, and a string (the table name). We only - // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name. - // Add a fixed max limit so this doesn't go awry. - for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) { - RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table}); - RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table}); - } - fclose(fp); -} - -// TODO: make this function thread safe if sections are generated in parallel. -void Dumpstate::UpdateProgress(int32_t delta_sec) { - if (progress_ == nullptr) { - MYLOGE("UpdateProgress: progress_ not set\n"); - return; - } - - // Always update progess so stats can be tuned... - progress_->Inc(delta_sec); - - // ...but only notifiy listeners when necessary. - if (!options_->do_progress_updates) return; - - int progress = progress_->Get(); - int max = progress_->GetMax(); - int percent = 100 * progress / max; - - if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) { - return; - } - last_reported_percent_progress_ = percent; - - if (control_socket_fd_ >= 0) { - dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max); - fsync(control_socket_fd_); - } - - if (listener_ != nullptr) { - if (percent % 5 == 0) { - // We don't want to spam logcat, so only log multiples of 5. - MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max, - percent); - } else { - // stderr is ignored on normal invocations, but useful when calling - // /system/bin/dumpstate directly for debuggging. - fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), - progress, max, percent); - } - - listener_->onProgress(percent); - } -} - -void Dumpstate::TakeScreenshot(const std::string& path) { - const std::string& real_path = path.empty() ? screenshot_path_ : path; - int status = - RunCommand("", {"/system/bin/screencap", "-p", real_path}, - CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); - if (status == 0) { - MYLOGD("Screenshot saved on %s\n", real_path.c_str()); - } else { - MYLOGE("Failed to take screenshot on %s\n", real_path.c_str()); - } -} - -bool is_dir(const char* pathname) { - struct stat info; - if (stat(pathname, &info) == -1) { - return false; - } - return S_ISDIR(info.st_mode); -} - -time_t get_mtime(int fd, time_t default_mtime) { - struct stat info; - if (fstat(fd, &info) == -1) { - return default_mtime; - } - return info.st_mtime; -} diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 82bf8219a2..d02ec759a7 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -73,15 +73,13 @@ extern "C" { */ class DurationReporter { public: - explicit DurationReporter(const std::string& title, bool logcat_only = false, - bool verbose = false); + explicit DurationReporter(const std::string& title, bool logcat_only = false); ~DurationReporter(); private: std::string title_; bool logcat_only_; - bool verbose_; uint64_t started_; DISALLOW_COPY_AND_ASSIGN(DurationReporter); @@ -226,8 +224,7 @@ class Dumpstate { */ int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand, const android::os::dumpstate::CommandOptions& options = - android::os::dumpstate::CommandOptions::DEFAULT, - bool verbose_duration = false); + android::os::dumpstate::CommandOptions::DEFAULT); /* * Runs `dumpsys` with the given arguments, automatically setting its timeout @@ -403,8 +400,12 @@ class Dumpstate { // Runtime options. std::unique_ptr<DumpOptions> options_; - // Last progress that was sent to the listener [0-100]. - int last_reported_percent_progress_ = 0; + // How frequently the progess should be updated;the listener will only be notificated when the + // delta from the previous update is more than the threshold. + int32_t update_progress_threshold_ = 100; + + // Last progress that triggered a listener updated + int32_t last_updated_progress_; // Whether it should take an screenshot earlier in the process. bool do_early_screenshot_ = false; @@ -440,7 +441,8 @@ class Dumpstate { // Full path of the bugreport file, be it zip or text, inside bugreport_internal_dir_. std::string path_; - // Full path of the file containing the screenshot (when requested). + // TODO: If temporary this should be removed at the end. + // Full path of the temporary file containing the screenshot (when requested). std::string screenshot_path_; // Pointer to the zipped file. @@ -584,6 +586,9 @@ bool is_dir(const char* pathname); /** Gets the last modification time of a file, or default time if file is not found. */ time_t get_mtime(int fd, time_t default_mtime); +/* Dumps eMMC Extended CSD data. */ +void dump_emmc_ecsd(const char *ext_csd_path); + /** Gets command-line arguments. */ void format_args(int argc, const char *argv[], std::string *args); diff --git a/cmds/dumpstate/dumpstate_test.xml b/cmds/dumpstate/dumpstate_test.xml deleted file mode 100644 index e4e4a30a1e..0000000000 --- a/cmds/dumpstate/dumpstate_test.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<configuration description="Config for dumpstate_test"> - <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> - <option name="cleanup" value="true" /> - <option name="push" value="dumpstate_test->/data/local/tmp/dumpstate_test" /> - </target_preparer> - <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> - <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="file-exclusion-filter-regex" value=".*/dumpstate_test_fixture" /> - <option name="file-exclusion-filter-regex" value=".*/tests/.*" /> - <option name="module-name" value="dumpstate_test" /> - </test> -</configuration> diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index 7e6f6f53e5..fc3642c912 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -14,21 +14,20 @@ * limitations under the License. */ +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <fcntl.h> +#include <libgen.h> + #include <android-base/file.h> #include <android/os/BnDumpstate.h> #include <android/os/BnDumpstateListener.h> #include <binder/IServiceManager.h> #include <binder/ProcessState.h> #include <cutils/properties.h> -#include <fcntl.h> -#include <gmock/gmock.h> -#include <gtest/gtest.h> -#include <libgen.h> #include <ziparchive/zip_archive.h> -#include <fstream> -#include <regex> - #include "dumpstate.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) @@ -45,11 +44,6 @@ class DumpstateListener; namespace { -struct SectionInfo { - std::string name; - int32_t size_bytes; -}; - sp<IDumpstate> GetDumpstateService() { return android::interface_cast<IDumpstate>( android::defaultServiceManager()->getService(String16("dumpstate"))); @@ -61,80 +55,15 @@ int OpenForWrite(const std::string& filename) { S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); } -void GetEntry(const ZipArchiveHandle archive, const std::string_view entry_name, ZipEntry* data) { - int32_t e = FindEntry(archive, entry_name, data); - EXPECT_EQ(e, 0) << ErrorCodeString(e) << " entry name: " << entry_name; -} - -// Extracts the main bugreport txt from the given archive and writes into output_fd. -void ExtractBugreport(const ZipArchiveHandle* handle, int output_fd) { - // Read contents of main_entry.txt which is a single line indicating the name of the zip entry - // that contains the main bugreport txt. - ZipEntry main_entry; - GetEntry(*handle, "main_entry.txt", &main_entry); - std::string bugreport_txt_name; - bugreport_txt_name.resize(main_entry.uncompressed_length); - ExtractToMemory(*handle, &main_entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()), - main_entry.uncompressed_length); - - // Read the main bugreport txt and extract to output_fd. - ZipEntry entry; - GetEntry(*handle, bugreport_txt_name, &entry); - ExtractEntryToFile(*handle, &entry, output_fd); -} - -bool IsSectionStart(const std::string& line, std::string* section_name) { - static const std::regex kSectionStart = std::regex{"DUMP OF SERVICE (.*):"}; - std::smatch match; - if (std::regex_match(line, match, kSectionStart)) { - *section_name = match.str(1); - return true; - } - return false; -} - -bool IsSectionEnd(const std::string& line) { - // Not all lines that contain "was the duration of" is a section end, but all section ends do - // contain "was the duration of". The disambiguation can be done by the caller. - return (line.find("was the duration of") != std::string::npos); -} - -// Extracts the zipped bugreport and identifies the sections. -void ParseSections(const std::string& zip_path, std::vector<SectionInfo>* sections) { - // Open the archive - ZipArchiveHandle handle; - ASSERT_EQ(OpenArchive(zip_path.c_str(), &handle), 0); - - // Extract the main entry to a temp file - TemporaryFile tmp_binary; - ASSERT_NE(-1, tmp_binary.fd); - ExtractBugreport(&handle, tmp_binary.fd); - - // Read line by line and identify sections - std::ifstream ifs(tmp_binary.path, std::ifstream::in); - std::string line; - int section_bytes = 0; - std::string current_section_name; - while (std::getline(ifs, line)) { - std::string section_name; - if (IsSectionStart(line, §ion_name)) { - section_bytes = 0; - current_section_name = section_name; - } else if (IsSectionEnd(line)) { - if (!current_section_name.empty()) { - sections->push_back({current_section_name, section_bytes}); - } - current_section_name = ""; - } else if (!current_section_name.empty()) { - section_bytes += line.length(); - } - } - - CloseArchive(handle); -} - } // namespace +struct SectionInfo { + std::string name; + status_t status; + int32_t size_bytes; + int32_t duration_ms; +}; + /** * Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the * section details generated by dumpstate are added to a vector to be used by Tests later. @@ -167,6 +96,26 @@ class DumpstateListener : public BnDumpstateListener { return binder::Status::ok(); } + binder::Status onProgressUpdated(int32_t progress) override { + dprintf(out_fd_, "\rIn progress %d/%d", progress, max_progress_); + return binder::Status::ok(); + } + + binder::Status onMaxProgressUpdated(int32_t max_progress) override { + std::lock_guard<std::mutex> lock(lock_); + max_progress_ = max_progress; + return binder::Status::ok(); + } + + binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes, + int32_t duration_ms) override { + std::lock_guard<std::mutex> lock(lock_); + if (sections_.get() != nullptr) { + sections_->push_back({name, status, size_bytes, duration_ms}); + } + return binder::Status::ok(); + } + bool getIsFinished() { std::lock_guard<std::mutex> lock(lock_); return is_finished_; @@ -179,6 +128,7 @@ class DumpstateListener : public BnDumpstateListener { private: int out_fd_; + int max_progress_ = 5000; int error_code_ = -1; bool is_finished_ = false; std::shared_ptr<std::vector<SectionInfo>> sections_; @@ -216,8 +166,8 @@ class ZippedBugreportGenerationTest : public Test { duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); } - static const std::string getZipFilePath() { - return ds.GetPath(".zip"); + static const char* getZipFilePath() { + return ds.GetPath(".zip").c_str(); } }; std::shared_ptr<std::vector<SectionInfo>> ZippedBugreportGenerationTest::sections = @@ -226,12 +176,12 @@ Dumpstate& ZippedBugreportGenerationTest::ds = Dumpstate::GetInstance(); std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s; TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) { - EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0); + EXPECT_EQ(access(getZipFilePath(), F_OK), 0); } TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) { struct stat st; - EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0); + EXPECT_EQ(stat(getZipFilePath(), &st), 0); EXPECT_GE(st.st_size, 3000000 /* 3MB */); EXPECT_LE(st.st_size, 30000000 /* 30MB */); } @@ -250,7 +200,7 @@ class ZippedBugReportContentsTest : public Test { public: ZipArchiveHandle handle; void SetUp() { - ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath().c_str(), &handle), 0); + ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath(), &handle), 0); } void TearDown() { CloseArchive(handle); @@ -258,30 +208,29 @@ class ZippedBugReportContentsTest : public Test { void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) { ZipEntry entry; - GetEntry(handle, filename, &entry); + EXPECT_EQ(FindEntry(handle, ZipString(filename), &entry), 0); EXPECT_GT(entry.uncompressed_length, minsize); EXPECT_LT(entry.uncompressed_length, maxsize); } }; TEST_F(ZippedBugReportContentsTest, ContainsMainEntry) { - ZipEntry main_entry; + ZipEntry mainEntryLoc; // contains main entry name file - GetEntry(handle, "main_entry.txt", &main_entry); + EXPECT_EQ(FindEntry(handle, ZipString("main_entry.txt"), &mainEntryLoc), 0); - std::string bugreport_txt_name; - bugreport_txt_name.resize(main_entry.uncompressed_length); - ExtractToMemory(handle, &main_entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()), - main_entry.uncompressed_length); + char* buf = new char[mainEntryLoc.uncompressed_length]; + ExtractToMemory(handle, &mainEntryLoc, (uint8_t*)buf, mainEntryLoc.uncompressed_length); + delete[] buf; // contains main entry file - FileExists(bugreport_txt_name.c_str(), 1000000U, 50000000U); + FileExists(buf, 1000000U, 50000000U); } TEST_F(ZippedBugReportContentsTest, ContainsVersion) { ZipEntry entry; // contains main entry name file - GetEntry(handle, "version.txt", &entry); + EXPECT_EQ(FindEntry(handle, ZipString("version.txt"), &entry), 0); char* buf = new char[entry.uncompressed_length + 1]; ExtractToMemory(handle, &entry, (uint8_t*)buf, entry.uncompressed_length); @@ -295,10 +244,6 @@ TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) { FileExists("dumpstate_board.txt", 100000U, 1000000U); } -TEST_F(ZippedBugReportContentsTest, ContainsProtoFile) { - FileExists("proto/activity.proto", 100000U, 1000000U); -} - // Spot check on some files pulled from the file system TEST_F(ZippedBugReportContentsTest, ContainsSomeFileSystemFiles) { // FS/proc/*/mountinfo size > 0 @@ -313,11 +258,6 @@ TEST_F(ZippedBugReportContentsTest, ContainsSomeFileSystemFiles) { */ class BugreportSectionTest : public Test { public: - static void SetUpTestCase() { - ParseSections(ZippedBugreportGenerationTest::getZipFilePath().c_str(), - ZippedBugreportGenerationTest::sections.get()); - } - int numMatches(const std::string& substring) { int matches = 0; for (auto const& section : *ZippedBugreportGenerationTest::sections) { @@ -327,11 +267,10 @@ class BugreportSectionTest : public Test { } return matches; } - void SectionExists(const std::string& sectionName, int minsize) { for (auto const& section : *ZippedBugreportGenerationTest::sections) { if (sectionName == section.name) { - EXPECT_GE(section.size_bytes, minsize) << " for section:" << sectionName; + EXPECT_GE(section.size_bytes, minsize); return; } } @@ -339,59 +278,71 @@ class BugreportSectionTest : public Test { } }; +// Test all sections are generated without timeouts or errors +TEST_F(BugreportSectionTest, GeneratedWithoutErrors) { + for (auto const& section : *ZippedBugreportGenerationTest::sections) { + EXPECT_EQ(section.status, 0) << section.name << " failed with status " << section.status; + } +} + TEST_F(BugreportSectionTest, Atleast3CriticalDumpsysSectionsGenerated) { - int numSections = numMatches("CRITICAL"); + int numSections = numMatches("DUMPSYS CRITICAL"); EXPECT_GE(numSections, 3); } TEST_F(BugreportSectionTest, Atleast2HighDumpsysSectionsGenerated) { - int numSections = numMatches("HIGH"); + int numSections = numMatches("DUMPSYS HIGH"); EXPECT_GE(numSections, 2); } TEST_F(BugreportSectionTest, Atleast50NormalDumpsysSectionsGenerated) { - int allSections = ZippedBugreportGenerationTest::sections->size(); - int criticalSections = numMatches("CRITICAL"); - int highSections = numMatches("HIGH"); + int allSections = numMatches("DUMPSYS"); + int criticalSections = numMatches("DUMPSYS CRITICAL"); + int highSections = numMatches("DUMPSYS HIGH"); int normalSections = allSections - criticalSections - highSections; EXPECT_GE(normalSections, 50) << "Total sections less than 50 (Critical:" << criticalSections << "High:" << highSections << "Normal:" << normalSections << ")"; } +TEST_F(BugreportSectionTest, Atleast1ProtoDumpsysSectionGenerated) { + int numSections = numMatches("proto/"); + EXPECT_GE(numSections, 1); +} + // Test if some critical sections are being generated. TEST_F(BugreportSectionTest, CriticalSurfaceFlingerSectionGenerated) { - SectionExists("CRITICAL SurfaceFlinger", /* bytes= */ 10000); + SectionExists("DUMPSYS CRITICAL - SurfaceFlinger", /* bytes= */ 10000); } TEST_F(BugreportSectionTest, ActivitySectionsGenerated) { - SectionExists("CRITICAL activity", /* bytes= */ 5000); - SectionExists("activity", /* bytes= */ 10000); + SectionExists("DUMPSYS CRITICAL - activity", /* bytes= */ 5000); + SectionExists("DUMPSYS - activity", /* bytes= */ 10000); } TEST_F(BugreportSectionTest, CpuinfoSectionGenerated) { - SectionExists("CRITICAL cpuinfo", /* bytes= */ 1000); + SectionExists("DUMPSYS CRITICAL - cpuinfo", /* bytes= */ 1000); } TEST_F(BugreportSectionTest, WindowSectionGenerated) { - SectionExists("CRITICAL window", /* bytes= */ 20000); + SectionExists("DUMPSYS CRITICAL - window", /* bytes= */ 20000); } TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) { - SectionExists("HIGH connectivity", /* bytes= */ 3000); - SectionExists("connectivity", /* bytes= */ 5000); + SectionExists("DUMPSYS HIGH - connectivity", /* bytes= */ 5000); + SectionExists("DUMPSYS - connectivity", /* bytes= */ 5000); } TEST_F(BugreportSectionTest, MeminfoSectionGenerated) { - SectionExists("HIGH meminfo", /* bytes= */ 100000); + SectionExists("DUMPSYS HIGH - meminfo", /* bytes= */ 100000); } TEST_F(BugreportSectionTest, BatteryStatsSectionGenerated) { - SectionExists("batterystats", /* bytes= */ 1000); + SectionExists("DUMPSYS - batterystats", /* bytes= */ 1000); } TEST_F(BugreportSectionTest, WifiSectionGenerated) { - SectionExists("wifi", /* bytes= */ 100000); + SectionExists("DUMPSYS - wifi", /* bytes= */ 100000); } class DumpstateBinderTest : public Test { diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index cff1d439d9..71d15f4761 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -62,6 +62,10 @@ class DumpstateListenerMock : public IDumpstateListener { MOCK_METHOD1(onProgress, binder::Status(int32_t progress)); MOCK_METHOD1(onError, binder::Status(int32_t error_code)); MOCK_METHOD0(onFinished, binder::Status()); + MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress)); + MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress)); + MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status, + int32_t size, int32_t durationMs)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); @@ -101,8 +105,9 @@ class DumpstateBaseTest : public Test { protected: const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str()); - const std::string kTestDataPath = kTestPath + "/tests/testdata/"; - const std::string kSimpleCommand = kTestPath + "/dumpstate_test_fixture"; + const std::string kFixturesPath = kTestPath + "/../dumpstate_test_fixture/"; + const std::string kTestDataPath = kFixturesPath + "tests/testdata/"; + const std::string kSimpleCommand = kFixturesPath + "dumpstate_test_fixture"; const std::string kEchoCommand = "/system/bin/echo"; /* @@ -586,6 +591,7 @@ class DumpstateTest : public DumpstateBaseTest { SetDryRun(false); SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)")); ds.progress_.reset(new Progress()); + ds.update_progress_threshold_ = 0; ds.options_.reset(new Dumpstate::DumpOptions()); } @@ -610,9 +616,10 @@ class DumpstateTest : public DumpstateBaseTest { return status; } - void SetProgress(long progress, long initial_max) { - ds.last_reported_percent_progress_ = 0; + void SetProgress(long progress, long initial_max, long threshold = 0) { ds.options_->do_progress_updates = true; + ds.update_progress_threshold_ = threshold; + ds.last_updated_progress_ = 0; ds.progress_.reset(new Progress(initial_max, progress, 1.2)); } @@ -657,8 +664,7 @@ TEST_F(DumpstateTest, RunCommandNoTitle) { TEST_F(DumpstateTest, RunCommandWithTitle) { EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand})); EXPECT_THAT(err, StrEq("stderr\n")); - // The duration may not get output, depending on how long it takes, - // so we just check the prefix. + // We don't know the exact duration, so we check the prefix and suffix EXPECT_THAT(out, StartsWith("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n")); } @@ -693,8 +699,7 @@ TEST_F(DumpstateTest, RunCommandWithMultipleArgs) { TEST_F(DumpstateTest, RunCommandDryRun) { SetDryRun(true); EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand})); - // The duration may not get output, depending on how long it takes, - // so we just check the prefix. + // We don't know the exact duration, so we check the prefix and suffix EXPECT_THAT(out, StartsWith("------ I AM GROOT (" + kSimpleCommand + ") ------\n\t(skipped on dry run)\n")); EXPECT_THAT(err, IsEmpty()); @@ -790,36 +795,73 @@ TEST_F(DumpstateTest, RunCommandProgress) { ds.listener_name_ = "FoxMulder"; SetProgress(0, 30); + EXPECT_CALL(*listener, onProgressUpdated(20)); EXPECT_CALL(*listener, onProgress(66)); // 20/30 % EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build())); std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); - EXPECT_CALL(*listener, onProgress(80)); // 24/30 % - EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 24, 30); + EXPECT_CALL(*listener, onProgressUpdated(30)); + EXPECT_CALL(*listener, onProgress(100)); // 35/35 % + EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build())); + progress_message = GetProgressMessage(ds.listener_name_, 30, 30); + EXPECT_THAT(out, StrEq("stdout\n")); + EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); + + // Run a command that will increase maximum timeout. + EXPECT_CALL(*listener, onProgressUpdated(31)); + EXPECT_CALL(*listener, onMaxProgressUpdated(37)); + EXPECT_CALL(*listener, onProgress(83)); // 31/37 % + EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build())); + progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); // Make sure command ran while in dry_run is counted. SetDryRun(true); - EXPECT_CALL(*listener, onProgress(90)); // 27/30 % - EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 27, 30); + EXPECT_CALL(*listener, onProgressUpdated(35)); + EXPECT_CALL(*listener, onProgress(94)); // 35/37 % + EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build())); + progress_message = GetProgressMessage(ds.listener_name_, 35, 37); EXPECT_THAT(out, IsEmpty()); EXPECT_THAT(err, StrEq(progress_message)); - SetDryRun(false); - EXPECT_CALL(*listener, onProgress(96)); // 29/30 % - EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 29, 30); + ds.listener_.clear(); +} + +TEST_F(DumpstateTest, RunCommandProgressIgnoreThreshold) { + sp<DumpstateListenerMock> listener(new DumpstateListenerMock()); + ds.listener_ = listener; + ds.listener_name_ = "FoxMulder"; + SetProgress(0, 8, 5); // 8 max, 5 threshold + + // First update should always be sent. + EXPECT_CALL(*listener, onProgressUpdated(1)); + EXPECT_CALL(*listener, onProgress(12)); // 1/12 % + EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build())); + std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); - EXPECT_CALL(*listener, onProgress(100)); // 30/30 % + // Fourth update should be ignored because it's between the threshold (5 -1 = 4 < 5). + EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build())); + EXPECT_THAT(out, StrEq("stdout\n")); + EXPECT_THAT(err, StrEq("stderr\n")); + + // Third update should be sent because it reaches threshold (6 - 1 = 5). + EXPECT_CALL(*listener, onProgressUpdated(6)); + EXPECT_CALL(*listener, onProgress(75)); // 6/8 % EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 30, 30); + progress_message = GetProgressMessage(ds.listener_name_, 6, 8); + EXPECT_THAT(out, StrEq("stdout\n")); + EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); + + // Fourth update should be ignored because it's between the threshold (9 - 6 = 3 < 5). + // But max update should be sent. + EXPECT_CALL(*listener, onMaxProgressUpdated(10)); // 9 * 120% = 10.8 = 10 + EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build())); + progress_message = GetProgressMessage(ds.listener_name_, 9, 10, 8, false); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); @@ -995,8 +1037,7 @@ TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) { TEST_F(DumpstateTest, DumpFileNotFoundWithTitle) { EXPECT_EQ(-1, DumpFile("Y U NO EXIST?", "/I/cant/believe/I/exist")); EXPECT_THAT(err, IsEmpty()); - // The duration may not get output, depending on how long it takes, - // so we just check the prefix. + // We don't know the exact duration, so we check the prefix and suffix EXPECT_THAT(out, StartsWith("*** Error dumping /I/cant/believe/I/exist (Y U NO EXIST?): No " "such file or directory\n")); } @@ -1047,6 +1088,7 @@ TEST_F(DumpstateTest, DumpFileUpdateProgress) { ds.listener_name_ = "FoxMulder"; SetProgress(0, 30); + EXPECT_CALL(*listener, onProgressUpdated(5)); EXPECT_CALL(*listener, onProgress(16)); // 5/30 % EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt")); @@ -1362,6 +1404,14 @@ class DumpstateUtilTest : public DumpstateBaseTest { return status; } + // Find out the pid of the process_name + int FindPidOfProcess(const std::string& process_name) { + CaptureStderr(); + int status = GetPidByName(process_name); + err = GetCapturedStderr(); + return status; + } + int fd; // 'fd` output and `stderr` from the last command ran. @@ -1711,6 +1761,18 @@ TEST_F(DumpstateUtilTest, DumpFileOnDryRun) { EXPECT_THAT(out, EndsWith("skipped on dry run\n")); } +TEST_F(DumpstateUtilTest, FindingPidWithExistingProcess) { + // init process always has pid 1. + EXPECT_EQ(1, FindPidOfProcess("init")); + EXPECT_THAT(err, IsEmpty()); +} + +TEST_F(DumpstateUtilTest, FindingPidWithNotExistingProcess) { + // find the process with abnormal name. + EXPECT_EQ(-1, FindPidOfProcess("abcdef12345-543")); + EXPECT_THAT(err, StrEq("can't find the pid\n")); +} + } // namespace dumpstate } // namespace os } // namespace android diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp new file mode 100644 index 0000000000..0bb80dcfba --- /dev/null +++ b/cmds/dumpstate/utils.cpp @@ -0,0 +1,1012 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "dumpstate" + +#include "dumpstate.h" + +#include <dirent.h> +#include <fcntl.h> +#include <libgen.h> +#include <math.h> +#include <poll.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/capability.h> +#include <sys/inotify.h> +#include <sys/klog.h> +#include <sys/prctl.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +#include <memory> +#include <set> +#include <string> +#include <vector> + +#include <android-base/file.h> +#include <android-base/properties.h> +#include <android-base/stringprintf.h> +#include <android-base/strings.h> +#include <android-base/unique_fd.h> +#include <cutils/properties.h> +#include <cutils/sockets.h> +#include <log/log.h> +#include <private/android_filesystem_config.h> + +#include "DumpstateInternal.h" + +// TODO: remove once moved to namespace +using android::os::dumpstate::CommandOptions; +using android::os::dumpstate::DumpFileToFd; +using android::os::dumpstate::PropertiesHelper; + +// Keep in sync with +// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java +static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds + +/* Most simple commands have 10 as timeout, so 5 is a good estimate */ +static const int32_t WEIGHT_FILE = 5; + +// TODO: temporary variables and functions used during C++ refactoring +static Dumpstate& ds = Dumpstate::GetInstance(); +static int RunCommand(const std::string& title, const std::vector<std::string>& full_command, + const CommandOptions& options = CommandOptions::DEFAULT) { + return ds.RunCommand(title, full_command, options); +} + +// Reasonable value for max stats. +static const int STATS_MAX_N_RUNS = 1000; +static const long STATS_MAX_AVERAGE = 100000; + +CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build(); + +// TODO(111441001): Default DumpOptions to sensible values. +Dumpstate::Dumpstate(const std::string& version) + : pid_(getpid()), + options_(new Dumpstate::DumpOptions()), + version_(version), + now_(time(nullptr)) { +} + +Dumpstate& Dumpstate::GetInstance() { + static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT)); + return singleton_; +} + +DurationReporter::DurationReporter(const std::string& title, bool logcat_only) + : title_(title), logcat_only_(logcat_only) { + if (!title_.empty()) { + started_ = Nanotime(); + } +} + +DurationReporter::~DurationReporter() { + if (!title_.empty()) { + float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC; + if (elapsed < .5f) { + return; + } + MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed); + if (logcat_only_) { + return; + } + // Use "Yoda grammar" to make it easier to grep|sort sections. + printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str()); + } +} + +const int32_t Progress::kDefaultMax = 5000; + +Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) { +} + +Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor) + : Progress(initial_max, growth_factor, "") { + progress_ = progress; +} + +Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path) + : initial_max_(initial_max), + progress_(0), + max_(initial_max), + growth_factor_(growth_factor), + n_runs_(0), + average_max_(0), + path_(path) { + if (!path_.empty()) { + Load(); + } +} + +void Progress::Load() { + MYLOGD("Loading stats from %s\n", path_.c_str()); + std::string content; + if (!android::base::ReadFileToString(path_, &content)) { + MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_); + return; + } + if (content.empty()) { + MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_); + return; + } + std::vector<std::string> lines = android::base::Split(content, "\n"); + + if (lines.size() < 1) { + MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(), + (int)lines.size(), max_); + return; + } + char* ptr; + n_runs_ = strtol(lines[0].c_str(), &ptr, 10); + average_max_ = strtol(ptr, nullptr, 10); + if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS || + average_max_ > STATS_MAX_AVERAGE) { + MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str()); + initial_max_ = Progress::kDefaultMax; + } else { + initial_max_ = average_max_; + } + max_ = initial_max_; + + MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_); +} + +void Progress::Save() { + int32_t total = n_runs_ * average_max_ + progress_; + int32_t runs = n_runs_ + 1; + int32_t average = floor(((float)total) / runs); + MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average, + path_.c_str()); + if (path_.empty()) { + return; + } + + std::string content = android::base::StringPrintf("%d %d\n", runs, average); + if (!android::base::WriteStringToFile(content, path_)) { + MYLOGE("Could not save stats on %s\n", path_.c_str()); + } +} + +int32_t Progress::Get() const { + return progress_; +} + +bool Progress::Inc(int32_t delta_sec) { + bool changed = false; + if (delta_sec >= 0) { + progress_ += delta_sec; + if (progress_ > max_) { + int32_t old_max = max_; + max_ = floor((float)progress_ * growth_factor_); + MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_); + changed = true; + } + } + return changed; +} + +int32_t Progress::GetMax() const { + return max_; +} + +int32_t Progress::GetInitialMax() const { + return initial_max_; +} + +void Progress::Dump(int fd, const std::string& prefix) const { + const char* pr = prefix.c_str(); + dprintf(fd, "%sprogress: %d\n", pr, progress_); + dprintf(fd, "%smax: %d\n", pr, max_); + dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_); + dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_); + dprintf(fd, "%spath: %s\n", pr, path_.c_str()); + dprintf(fd, "%sn_runs: %d\n", pr, n_runs_); + dprintf(fd, "%saverage_max: %d\n", pr, average_max_); +} + +bool Dumpstate::IsZipping() const { + return zip_writer_ != nullptr; +} + +std::string Dumpstate::GetPath(const std::string& suffix) const { + return GetPath(bugreport_internal_dir_, suffix); +} + +std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const { + return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(), + name_.c_str(), suffix.c_str()); +} + +void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) { + progress_ = std::move(progress); +} + +void for_each_userid(void (*func)(int), const char *header) { + std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf( + "for_each_userid(%s)", header); + DurationReporter duration_reporter(title); + if (PropertiesHelper::IsDryRun()) return; + + DIR *d; + struct dirent *de; + + if (header) printf("\n------ %s ------\n", header); + func(0); + + if (!(d = opendir("/data/system/users"))) { + printf("Failed to open /data/system/users (%s)\n", strerror(errno)); + return; + } + + while ((de = readdir(d))) { + int userid; + if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) { + continue; + } + func(userid); + } + + closedir(d); +} + +static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) { + DIR *d; + struct dirent *de; + + if (!(d = opendir("/proc"))) { + printf("Failed to open /proc (%s)\n", strerror(errno)); + return; + } + + if (header) printf("\n------ %s ------\n", header); + while ((de = readdir(d))) { + if (ds.IsUserConsentDenied()) { + MYLOGE( + "Returning early because user denied consent to share bugreport with calling app."); + closedir(d); + return; + } + int pid; + int fd; + char cmdpath[255]; + char cmdline[255]; + + if (!(pid = atoi(de->d_name))) { + continue; + } + + memset(cmdline, 0, sizeof(cmdline)); + + snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/cmdline", pid); + if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) { + TEMP_FAILURE_RETRY(read(fd, cmdline, sizeof(cmdline) - 2)); + close(fd); + if (cmdline[0]) { + helper(pid, cmdline, arg); + continue; + } + } + + // if no cmdline, a kernel thread has comm + snprintf(cmdpath, sizeof(cmdpath), "/proc/%d/comm", pid); + if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) >= 0) { + TEMP_FAILURE_RETRY(read(fd, cmdline + 1, sizeof(cmdline) - 4)); + close(fd); + if (cmdline[1]) { + cmdline[0] = '['; + size_t len = strcspn(cmdline, "\f\b\r\n"); + cmdline[len] = ']'; + cmdline[len+1] = '\0'; + } + } + if (!cmdline[0]) { + strcpy(cmdline, "N/A"); + } + helper(pid, cmdline, arg); + } + + closedir(d); +} + +static void for_each_pid_helper(int pid, const char *cmdline, void *arg) { + for_each_pid_func *func = (for_each_pid_func*) arg; + func(pid, cmdline); +} + +void for_each_pid(for_each_pid_func func, const char *header) { + std::string title = header == nullptr ? "for_each_pid" + : android::base::StringPrintf("for_each_pid(%s)", header); + DurationReporter duration_reporter(title); + if (PropertiesHelper::IsDryRun()) return; + + __for_each_pid(for_each_pid_helper, header, (void *) func); +} + +static void for_each_tid_helper(int pid, const char *cmdline, void *arg) { + DIR *d; + struct dirent *de; + char taskpath[255]; + for_each_tid_func *func = (for_each_tid_func *) arg; + + snprintf(taskpath, sizeof(taskpath), "/proc/%d/task", pid); + + if (!(d = opendir(taskpath))) { + printf("Failed to open %s (%s)\n", taskpath, strerror(errno)); + return; + } + + func(pid, pid, cmdline); + + while ((de = readdir(d))) { + if (ds.IsUserConsentDenied()) { + MYLOGE( + "Returning early because user denied consent to share bugreport with calling app."); + closedir(d); + return; + } + int tid; + int fd; + char commpath[255]; + char comm[255]; + + if (!(tid = atoi(de->d_name))) { + continue; + } + + if (tid == pid) + continue; + + snprintf(commpath, sizeof(commpath), "/proc/%d/comm", tid); + memset(comm, 0, sizeof(comm)); + if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) { + strcpy(comm, "N/A"); + } else { + char *c; + TEMP_FAILURE_RETRY(read(fd, comm, sizeof(comm) - 2)); + close(fd); + + c = strrchr(comm, '\n'); + if (c) { + *c = '\0'; + } + } + func(pid, tid, comm); + } + + closedir(d); +} + +void for_each_tid(for_each_tid_func func, const char *header) { + std::string title = header == nullptr ? "for_each_tid" + : android::base::StringPrintf("for_each_tid(%s)", header); + DurationReporter duration_reporter(title); + + if (PropertiesHelper::IsDryRun()) return; + + __for_each_pid(for_each_tid_helper, header, (void *) func); +} + +void show_wchan(int pid, int tid, const char *name) { + if (PropertiesHelper::IsDryRun()) return; + + char path[255]; + char buffer[255]; + int fd, ret, save_errno; + char name_buffer[255]; + + memset(buffer, 0, sizeof(buffer)); + + snprintf(path, sizeof(path), "/proc/%d/wchan", tid); + if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) { + printf("Failed to open '%s' (%s)\n", path, strerror(errno)); + return; + } + + ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); + save_errno = errno; + close(fd); + + if (ret < 0) { + printf("Failed to read '%s' (%s)\n", path, strerror(save_errno)); + return; + } + + snprintf(name_buffer, sizeof(name_buffer), "%*s%s", + pid == tid ? 0 : 3, "", name); + + printf("%-7d %-32s %s\n", tid, name_buffer, buffer); + + return; +} + +// print time in centiseconds +static void snprcent(char *buffer, size_t len, size_t spc, + unsigned long long time) { + static long hz; // cache discovered hz + + if (hz <= 0) { + hz = sysconf(_SC_CLK_TCK); + if (hz <= 0) { + hz = 1000; + } + } + + // convert to centiseconds + time = (time * 100 + (hz / 2)) / hz; + + char str[16]; + + snprintf(str, sizeof(str), " %llu.%02u", + time / 100, (unsigned)(time % 100)); + size_t offset = strlen(buffer); + snprintf(buffer + offset, (len > offset) ? len - offset : 0, + "%*s", (spc > offset) ? (int)(spc - offset) : 0, str); +} + +// print permille as a percent +static void snprdec(char *buffer, size_t len, size_t spc, unsigned permille) { + char str[16]; + + snprintf(str, sizeof(str), " %u.%u%%", permille / 10, permille % 10); + size_t offset = strlen(buffer); + snprintf(buffer + offset, (len > offset) ? len - offset : 0, + "%*s", (spc > offset) ? (int)(spc - offset) : 0, str); +} + +void show_showtime(int pid, const char *name) { + if (PropertiesHelper::IsDryRun()) return; + + char path[255]; + char buffer[1023]; + int fd, ret, save_errno; + + memset(buffer, 0, sizeof(buffer)); + + snprintf(path, sizeof(path), "/proc/%d/stat", pid); + if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) { + printf("Failed to open '%s' (%s)\n", path, strerror(errno)); + return; + } + + ret = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); + save_errno = errno; + close(fd); + + if (ret < 0) { + printf("Failed to read '%s' (%s)\n", path, strerror(save_errno)); + return; + } + + // field 14 is utime + // field 15 is stime + // field 42 is iotime + unsigned long long utime = 0, stime = 0, iotime = 0; + if (sscanf(buffer, + "%*u %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d " + "%*d %*d %llu %llu %*d %*d %*d %*d %*d %*d " + "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " + "%*d %*d %*d %*d %*d %*d %*d %*d %*d %llu ", + &utime, &stime, &iotime) != 3) { + return; + } + + unsigned long long total = utime + stime; + if (!total) { + return; + } + + unsigned permille = (iotime * 1000 + (total / 2)) / total; + if (permille > 1000) { + permille = 1000; + } + + // try to beautify and stabilize columns at <80 characters + snprintf(buffer, sizeof(buffer), "%-6d%s", pid, name); + if ((name[0] != '[') || utime) { + snprcent(buffer, sizeof(buffer), 57, utime); + } + snprcent(buffer, sizeof(buffer), 65, stime); + if ((name[0] != '[') || iotime) { + snprcent(buffer, sizeof(buffer), 73, iotime); + } + if (iotime) { + snprdec(buffer, sizeof(buffer), 79, permille); + } + puts(buffer); // adds a trailing newline + + return; +} + +void do_dmesg() { + const char *title = "KERNEL LOG (dmesg)"; + DurationReporter duration_reporter(title); + printf("------ %s ------\n", title); + + if (PropertiesHelper::IsDryRun()) return; + + /* Get size of kernel buffer */ + int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0); + if (size <= 0) { + printf("Unexpected klogctl return value: %d\n\n", size); + return; + } + char *buf = (char *) malloc(size + 1); + if (buf == nullptr) { + printf("memory allocation failed\n\n"); + return; + } + int retval = klogctl(KLOG_READ_ALL, buf, size); + if (retval < 0) { + printf("klogctl failure\n\n"); + free(buf); + return; + } + buf[retval] = '\0'; + printf("%s\n\n", buf); + free(buf); + return; +} + +void do_showmap(int pid, const char *name) { + char title[255]; + char arg[255]; + + snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name); + snprintf(arg, sizeof(arg), "%d", pid); + RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT); +} + +int Dumpstate::DumpFile(const std::string& title, const std::string& path) { + DurationReporter duration_reporter(title); + + int status = DumpFileToFd(STDOUT_FILENO, title, path); + + UpdateProgress(WEIGHT_FILE); + + return status; +} + +int read_file_as_long(const char *path, long int *output) { + int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)); + if (fd < 0) { + int err = errno; + MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err)); + return -1; + } + char buffer[50]; + ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); + if (bytes_read == -1) { + MYLOGE("Error reading file %s: %s\n", path, strerror(errno)); + return -2; + } + if (bytes_read == 0) { + MYLOGE("File %s is empty\n", path); + return -3; + } + *output = atoi(buffer); + return 0; +} + +/* calls skip to gate calling dump_from_fd recursively + * in the specified directory. dump_from_fd defaults to + * dump_file_from_fd above when set to NULL. skip defaults + * to false when set to NULL. dump_from_fd will always be + * called with title NULL. + */ +int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path), + int (*dump_from_fd)(const char* title, const char* path, int fd)) { + DurationReporter duration_reporter(title); + DIR *dirp; + struct dirent *d; + char *newpath = nullptr; + const char *slash = "/"; + int retval = 0; + + if (!title.empty()) { + printf("------ %s (%s) ------\n", title.c_str(), dir); + } + if (PropertiesHelper::IsDryRun()) return 0; + + if (dir[strlen(dir) - 1] == '/') { + ++slash; + } + dirp = opendir(dir); + if (dirp == nullptr) { + retval = -errno; + MYLOGE("%s: %s\n", dir, strerror(errno)); + return retval; + } + + if (!dump_from_fd) { + dump_from_fd = dump_file_from_fd; + } + for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) { + if ((d->d_name[0] == '.') + && (((d->d_name[1] == '.') && (d->d_name[2] == '\0')) + || (d->d_name[1] == '\0'))) { + continue; + } + asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name, + (d->d_type == DT_DIR) ? "/" : ""); + if (!newpath) { + retval = -errno; + continue; + } + if (skip && (*skip)(newpath)) { + continue; + } + if (d->d_type == DT_DIR) { + int ret = dump_files("", newpath, skip, dump_from_fd); + if (ret < 0) { + retval = ret; + } + continue; + } + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC))); + if (fd.get() < 0) { + retval = -1; + printf("*** %s: %s\n", newpath, strerror(errno)); + continue; + } + (*dump_from_fd)(nullptr, newpath, fd.get()); + } + closedir(dirp); + if (!title.empty()) { + printf("\n"); + } + return retval; +} + +/* fd must have been opened with the flag O_NONBLOCK. With this flag set, + * it's possible to avoid issues where opening the file itself can get + * stuck. + */ +int dump_file_from_fd(const char *title, const char *path, int fd) { + if (PropertiesHelper::IsDryRun()) return 0; + + int flags = fcntl(fd, F_GETFL); + if (flags == -1) { + printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno)); + return -1; + } else if (!(flags & O_NONBLOCK)) { + printf("*** %s: fd must have O_NONBLOCK set.\n", path); + return -1; + } + return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun()); +} + +int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command, + const CommandOptions& options) { + DurationReporter duration_reporter(title); + + int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options); + + /* TODO: for now we're simplifying the progress calculation by using the + * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys, + * where its weight should be much higher proportionally to its timeout. + * Ideally, it should use a options.EstimatedDuration() instead...*/ + UpdateProgress(options.Timeout()); + + return status; +} + +void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args, + const CommandOptions& options, long dumpsysTimeoutMs) { + long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs(); + std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)}; + dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end()); + RunCommand(title, dumpsys, options); +} + +int open_socket(const char *service) { + int s = android_get_control_socket(service); + if (s < 0) { + MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno)); + return -1; + } + fcntl(s, F_SETFD, FD_CLOEXEC); + if (listen(s, 4) < 0) { + MYLOGE("listen(control socket): %s\n", strerror(errno)); + return -1; + } + + struct sockaddr addr; + socklen_t alen = sizeof(addr); + int fd = accept(s, &addr, &alen); + if (fd < 0) { + MYLOGE("accept(control socket): %s\n", strerror(errno)); + return -1; + } + + return fd; +} + +/* redirect output to a service control socket */ +bool redirect_to_socket(FILE* redirect, const char* service) { + int fd = open_socket(service); + if (fd == -1) { + return false; + } + fflush(redirect); + // TODO: handle dup2 failure + TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect))); + close(fd); + return true; +} + +// TODO: should call is_valid_output_file and/or be merged into it. +void create_parent_dirs(const char *path) { + char *chp = const_cast<char *> (path); + + /* skip initial slash */ + if (chp[0] == '/') + chp++; + + /* create leading directories, if necessary */ + struct stat dir_stat; + while (chp && chp[0]) { + chp = strchr(chp, '/'); + if (chp) { + *chp = 0; + if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) { + MYLOGI("Creating directory %s\n", path); + if (mkdir(path, 0770)) { /* drwxrwx--- */ + MYLOGE("Unable to create directory %s: %s\n", path, strerror(errno)); + } else if (chown(path, AID_SHELL, AID_SHELL)) { + MYLOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno)); + } + } + *chp++ = '/'; + } + } +} + +bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) { + create_parent_dirs(path); + + int fd = TEMP_FAILURE_RETRY(open(path, + O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); + if (fd < 0) { + MYLOGE("%s: %s\n", path, strerror(errno)); + return false; + } + + TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect))); + close(fd); + return true; +} + +bool redirect_to_file(FILE* redirect, char* path) { + return _redirect_to_file(redirect, path, O_TRUNC); +} + +bool redirect_to_existing_file(FILE* redirect, char* path) { + return _redirect_to_file(redirect, path, O_APPEND); +} + +void dump_route_tables() { + DurationReporter duration_reporter("DUMP ROUTE TABLES"); + if (PropertiesHelper::IsDryRun()) return; + const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables"; + ds.DumpFile("RT_TABLES", RT_TABLES_PATH); + FILE* fp = fopen(RT_TABLES_PATH, "re"); + if (!fp) { + printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno)); + return; + } + char table[16]; + // Each line has an integer (the table number), a space, and a string (the table name). We only + // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name. + // Add a fixed max limit so this doesn't go awry. + for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) { + RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table}); + RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table}); + } + fclose(fp); +} + +// TODO: make this function thread safe if sections are generated in parallel. +void Dumpstate::UpdateProgress(int32_t delta_sec) { + if (progress_ == nullptr) { + MYLOGE("UpdateProgress: progress_ not set\n"); + return; + } + + // Always update progess so stats can be tuned... + bool max_changed = progress_->Inc(delta_sec); + + // ...but only notifiy listeners when necessary. + if (!options_->do_progress_updates) return; + + int progress = progress_->Get(); + int max = progress_->GetMax(); + + // adjusts max on the fly + if (max_changed && listener_ != nullptr) { + listener_->onMaxProgressUpdated(max); + } + + int32_t last_update_delta = progress - last_updated_progress_; + if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) { + return; + } + last_updated_progress_ = progress; + + if (control_socket_fd_ >= 0) { + dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max); + fsync(control_socket_fd_); + } + + int percent = 100 * progress / max; + if (listener_ != nullptr) { + if (percent % 5 == 0) { + // We don't want to spam logcat, so only log multiples of 5. + MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max, + percent); + } else { + // stderr is ignored on normal invocations, but useful when calling + // /system/bin/dumpstate directly for debuggging. + fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), + progress, max, percent); + } + // TODO(b/111441001): Remove in favor of onProgress + listener_->onProgressUpdated(progress); + + listener_->onProgress(percent); + } +} + +void Dumpstate::TakeScreenshot(const std::string& path) { + const std::string& real_path = path.empty() ? screenshot_path_ : path; + int status = + RunCommand("", {"/system/bin/screencap", "-p", real_path}, + CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); + if (status == 0) { + MYLOGD("Screenshot saved on %s\n", real_path.c_str()); + } else { + MYLOGE("Failed to take screenshot on %s\n", real_path.c_str()); + } +} + +bool is_dir(const char* pathname) { + struct stat info; + if (stat(pathname, &info) == -1) { + return false; + } + return S_ISDIR(info.st_mode); +} + +time_t get_mtime(int fd, time_t default_mtime) { + struct stat info; + if (fstat(fd, &info) == -1) { + return default_mtime; + } + return info.st_mtime; +} + +void dump_emmc_ecsd(const char *ext_csd_path) { + // List of interesting offsets + struct hex { + char str[2]; + }; + static const size_t EXT_CSD_REV = 192 * sizeof(hex); + static const size_t EXT_PRE_EOL_INFO = 267 * sizeof(hex); + static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_A = 268 * sizeof(hex); + static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_B = 269 * sizeof(hex); + + std::string buffer; + if (!android::base::ReadFileToString(ext_csd_path, &buffer)) { + return; + } + + printf("------ %s Extended CSD ------\n", ext_csd_path); + + if (buffer.length() < (EXT_CSD_REV + sizeof(hex))) { + printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length()); + return; + } + + int ext_csd_rev = 0; + std::string sub = buffer.substr(EXT_CSD_REV, sizeof(hex)); + if (sscanf(sub.c_str(), "%2x", &ext_csd_rev) != 1) { + printf("*** %s: EXT_CSD_REV parse error \"%s\"\n\n", ext_csd_path, sub.c_str()); + return; + } + + static const char *ver_str[] = { + "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0" + }; + printf("rev 1.%d (MMC %s)\n", ext_csd_rev, + (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ? ver_str[ext_csd_rev] + : "Unknown"); + if (ext_csd_rev < 7) { + printf("\n"); + return; + } + + if (buffer.length() < (EXT_PRE_EOL_INFO + sizeof(hex))) { + printf("*** %s: truncated content %zu\n\n", ext_csd_path, buffer.length()); + return; + } + + int ext_pre_eol_info = 0; + sub = buffer.substr(EXT_PRE_EOL_INFO, sizeof(hex)); + if (sscanf(sub.c_str(), "%2x", &ext_pre_eol_info) != 1) { + printf("*** %s: PRE_EOL_INFO parse error \"%s\"\n\n", ext_csd_path, sub.c_str()); + return; + } + + static const char *eol_str[] = { + "Undefined", + "Normal", + "Warning (consumed 80% of reserve)", + "Urgent (consumed 90% of reserve)" + }; + printf( + "PRE_EOL_INFO %d (MMC %s)\n", ext_pre_eol_info, + eol_str[(ext_pre_eol_info < (int)(sizeof(eol_str) / sizeof(eol_str[0]))) ? ext_pre_eol_info + : 0]); + + for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A; + lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B; + lifetime += sizeof(hex)) { + int ext_device_life_time_est; + static const char *est_str[] = { + "Undefined", + "0-10% of device lifetime used", + "10-20% of device lifetime used", + "20-30% of device lifetime used", + "30-40% of device lifetime used", + "40-50% of device lifetime used", + "50-60% of device lifetime used", + "60-70% of device lifetime used", + "70-80% of device lifetime used", + "80-90% of device lifetime used", + "90-100% of device lifetime used", + "Exceeded the maximum estimated device lifetime", + }; + + if (buffer.length() < (lifetime + sizeof(hex))) { + printf("*** %s: truncated content %zu\n", ext_csd_path, buffer.length()); + break; + } + + ext_device_life_time_est = 0; + sub = buffer.substr(lifetime, sizeof(hex)); + if (sscanf(sub.c_str(), "%2x", &ext_device_life_time_est) != 1) { + printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%s\"\n", ext_csd_path, + (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A', + sub.c_str()); + continue; + } + printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n", + (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A', + ext_device_life_time_est, + est_str[(ext_device_life_time_est < (int)(sizeof(est_str) / sizeof(est_str[0]))) + ? ext_device_life_time_est + : 0]); + } + + printf("\n"); +} diff --git a/cmds/dumpsys/TEST_MAPPING b/cmds/dumpsys/TEST_MAPPING deleted file mode 100644 index dc88ada034..0000000000 --- a/cmds/dumpsys/TEST_MAPPING +++ /dev/null @@ -1,13 +0,0 @@ -{ - "presubmit": [ - { - // small test which assumes the output format of dumpsys, however - // there are many other parts of Android that expect the output - // to be a specific way (see b/141728094) - "name": "timezone_data_e2e_tests" - }, - { - "name": "dumpsys_test" - } - ] -} diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index abdf168233..4811927106 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -59,13 +59,12 @@ static void usage() { "usage: dumpsys\n" " To dump all services.\n" "or:\n" - " dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--help | -l | --skip SERVICES " - "| SERVICE [ARGS]]\n" + " dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | " + "SERVICE [ARGS]]\n" " --help: shows this help\n" " -l: only list services, do not dump them\n" " -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n" " -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n" - " --pid: dump PID instead of usual dump\n" " --proto: filter services that support dumping data in proto format. Dumps\n" " will be in proto format.\n" " --priority LEVEL: filter services based on specified priority\n" @@ -121,11 +120,9 @@ int Dumpsys::main(int argc, char* const argv[]) { bool showListOnly = false; bool skipServices = false; bool asProto = false; - Type type = Type::DUMP; int timeoutArgMs = 10000; int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL; - static struct option longOptions[] = {{"pid", no_argument, 0, 0}, - {"priority", required_argument, 0, 0}, + static struct option longOptions[] = {{"priority", required_argument, 0, 0}, {"proto", no_argument, 0, 0}, {"skip", no_argument, 0, 0}, {"help", no_argument, 0, 0}, @@ -160,8 +157,6 @@ int Dumpsys::main(int argc, char* const argv[]) { usage(); return -1; } - } else if (!strcmp(longOptions[optionIndex].name, "pid")) { - type = Type::PID; } break; @@ -206,13 +201,7 @@ int Dumpsys::main(int argc, char* const argv[]) { if (i == optind) { services.add(String16(argv[i])); } else { - const String16 arg(argv[i]); - args.add(arg); - // For backward compatible, if the proto argument is passed to the service, the - // dump request is also considered to use proto. - if (!asProto && !arg.compare(String16(PriorityDumper::PROTO_ARG))) { - asProto = true; - } + args.add(String16(argv[i])); } } } @@ -251,7 +240,7 @@ int Dumpsys::main(int argc, char* const argv[]) { const String16& serviceName = services[i]; if (IsSkipped(skippedServices, serviceName)) continue; - if (startDumpThread(type, serviceName, args) == OK) { + if (startDumpThread(serviceName, args) == OK) { bool addSeparator = (N > 1); if (addSeparator) { writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags); @@ -318,18 +307,7 @@ void Dumpsys::setServiceArgs(Vector<String16>& args, bool asProto, int priorityF } } -static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd) { - pid_t pid; - status_t status = service->getDebugPid(&pid); - if (status != OK) { - return status; - } - WriteStringToFd(std::to_string(pid) + "\n", fd.get()); - return OK; -} - -status_t Dumpsys::startDumpThread(Type type, const String16& serviceName, - const Vector<String16>& args) { +status_t Dumpsys::startDumpThread(const String16& serviceName, const Vector<String16>& args) { sp<IBinder> service = sm_->checkService(serviceName); if (service == nullptr) { aerr << "Can't find service: " << serviceName << endl; @@ -349,22 +327,16 @@ status_t Dumpsys::startDumpThread(Type type, const String16& serviceName, // dump blocks until completion, so spawn a thread.. activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable { - status_t err = 0; + int err = service->dump(remote_end.get(), args); - switch (type) { - case Type::DUMP: - err = service->dump(remote_end.get(), args); - break; - case Type::PID: - err = dumpPidToFd(service, remote_end); - break; - default: - aerr << "Unknown dump type" << static_cast<int>(type) << endl; - return; - } + // It'd be nice to be able to close the remote end of the socketpair before the dump + // call returns, to terminate our reads if the other end closes their copy of the + // file descriptor, but then hangs for some reason. There doesn't seem to be a good + // way to do this, though. + remote_end.reset(); - if (err != OK) { - aerr << "Error dumping service info status_t: (" << err << ") " + if (err != 0) { + aerr << "Error dumping service info: (" << strerror(err) << ") " << serviceName << endl; } }); diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h index 929c55c364..c48a1e959b 100644 --- a/cmds/dumpsys/dumpsys.h +++ b/cmds/dumpsys/dumpsys.h @@ -51,11 +51,6 @@ class Dumpsys { */ static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags); - enum class Type { - DUMP, // dump using `dump` function - PID, // dump pid of server only - }; - /** * Starts a thread to connect to a service and get its dump output. The thread redirects * the output to a pipe. Thread must be stopped by a subsequent callto {@code @@ -66,8 +61,7 @@ class Dumpsys { * {@code NAME_NOT_FOUND} service could not be found. * {@code != OK} error */ - status_t startDumpThread(Type type, const String16& serviceName, - const Vector<String16>& args); + status_t startDumpThread(const String16& serviceName, const Vector<String16>& args); /** * Writes a section header to a file descriptor. diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index b9395ba4e2..3ada15398c 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -53,8 +53,7 @@ class ServiceManagerMock : public IServiceManager { MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&)); MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int)); MOCK_METHOD1(listServices, Vector<String16>(int)); - MOCK_METHOD1(waitForService, sp<IBinder>(const String16&)); - MOCK_METHOD1(isDeclared, bool(const String16&)); + protected: MOCK_METHOD0(onAsBinder, IBinder*()); }; @@ -195,7 +194,7 @@ class DumpsysTest : public Test { CaptureStdout(); CaptureStderr(); dump_.setServiceArgs(args, supportsProto, priorityFlags); - status_t status = dump_.startDumpThread(Dumpsys::Type::DUMP, serviceName, args); + status_t status = dump_.startDumpThread(serviceName, args); EXPECT_THAT(status, Eq(0)); status = dump_.writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(500), false, elapsedDuration, bytesWritten); @@ -540,27 +539,6 @@ TEST_F(DumpsysTest, DumpWithPriorityHighAndProto) { AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH); } -// Tests 'dumpsys --pid' -TEST_F(DumpsysTest, ListAllServicesWithPid) { - ExpectListServices({"Locksmith", "Valet"}); - ExpectCheckService("Locksmith"); - ExpectCheckService("Valet"); - - CallMain({"--pid"}); - - AssertRunningServices({"Locksmith", "Valet"}); - AssertOutputContains(std::to_string(getpid())); -} - -// Tests 'dumpsys --pid service_name' -TEST_F(DumpsysTest, ListServiceWithPid) { - ExpectCheckService("Locksmith"); - - CallMain({"--pid", "Locksmith"}); - - AssertOutput(std::to_string(getpid()) + "\n"); -} - TEST_F(DumpsysTest, GetBytesWritten) { const char* serviceName = "service2"; const char* dumpContents = "dump1"; @@ -585,4 +563,4 @@ TEST_F(DumpsysTest, WriteDumpWithoutThreadStart) { dump_.writeDump(STDOUT_FILENO, String16("service"), std::chrono::milliseconds(500), /* as_proto = */ false, elapsedDuration, bytesWritten); EXPECT_THAT(status, Eq(INVALID_OPERATION)); -} +}
\ No newline at end of file diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp deleted file mode 100644 index 40b8dc74f7..0000000000 --- a/cmds/idlcli/Android.bp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -cc_defaults { - name: "idlcli-defaults", - shared_libs: [ - "android.hardware.vibrator@1.0", - "android.hardware.vibrator@1.1", - "android.hardware.vibrator@1.2", - "android.hardware.vibrator@1.3", - "libbase", - "libhidlbase", - "liblog", - "libutils", - ], - cflags: [ - "-DLOG_TAG=\"idlcli\"", - ], -} - -cc_library { - name: "libidlcli", - defaults: ["idlcli-defaults"], - srcs: [ - "CommandVibrator.cpp", - "vibrator/CommandOff.cpp", - "vibrator/CommandOn.cpp", - "vibrator/CommandPerform.cpp", - "vibrator/CommandSetAmplitude.cpp", - "vibrator/CommandSetExternalControl.cpp", - "vibrator/CommandSupportsAmplitudeControl.cpp", - "vibrator/CommandSupportsExternalControl.cpp", - ], - visibility: [":__subpackages__"], -} - -cc_binary { - name: "idlcli", - defaults: ["idlcli-defaults"], - srcs: ["main.cpp"], - whole_static_libs: ["libidlcli"], -} diff --git a/cmds/idlcli/CommandVibrator.cpp b/cmds/idlcli/CommandVibrator.cpp deleted file mode 100644 index a7a70c38af..0000000000 --- a/cmds/idlcli/CommandVibrator.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" - -namespace android { -namespace idlcli { - -class IdlCli; - -class CommandVibrator : public CommandWithSubcommands<CommandVibrator> { - std::string getDescription() const override { return "Invoke Vibrator HIDL APIs."; } - - std::string getUsageSummary() const override { return "<api> [arguments]"; } - - UsageDetails getUsageDetails() const override { - UsageDetails details{ - {"<api>", CommandRegistry<CommandVibrator>::List()}, - }; - return details; - } -}; - -static const auto Command = CommandRegistry<IdlCli>::Register<CommandVibrator>("vibrator"); - -} // namespace idlcli -} // namespace android diff --git a/cmds/idlcli/IdlCli.h b/cmds/idlcli/IdlCli.h deleted file mode 100644 index dd8430415e..0000000000 --- a/cmds/idlcli/IdlCli.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_IDLCLI_H_ -#define FRAMEWORK_NATIVE_CMDS_IDLCLI_IDLCLI_H_ - -#include "utils.h" - -namespace android { -namespace idlcli { - -class IdlCli : public CommandWithSubcommands<IdlCli> { - std::string getDescription() const override { return "Invoke IDL APIs."; } - - std::string getUsageSummary() const override { return "<idl> [arguments]"; } - - UsageDetails getUsageDetails() const override { - UsageDetails details{ - {"<idl>", CommandRegistry<IdlCli>::List()}, - }; - return details; - } -}; - -} // namespace idlcli -} // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_IDLCLI_IDLCLI_H_ diff --git a/cmds/idlcli/main.cpp b/cmds/idlcli/main.cpp deleted file mode 100644 index 9ed9d8216a..0000000000 --- a/cmds/idlcli/main.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2019 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 "IdlCli.h" -#include "utils.h" - -int main(const int argc, const char* const argv[]) { - using namespace ::android::idlcli; - return IdlCli{}.main(Args{argc, argv}); -} diff --git a/cmds/idlcli/utils.h b/cmds/idlcli/utils.h deleted file mode 100644 index a8e595470d..0000000000 --- a/cmds/idlcli/utils.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_ -#define FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_ - -#include <hidl/HidlSupport.h> - -#include <iomanip> -#include <iostream> -#include <map> -#include <sstream> -#include <string> -#include <vector> - -namespace android { -namespace idlcli { - -namespace overrides { - -namespace details { - -template <typename T> -inline std::istream &operator>>(std::istream &stream, T &out) { - auto pos = stream.tellg(); - auto tmp = +out; - auto min = +std::numeric_limits<T>::min(); - auto max = +std::numeric_limits<T>::max(); - stream >> tmp; - if (!stream) { - return stream; - } - if (tmp < min || tmp > max) { - stream.seekg(pos); - stream.setstate(std::ios_base::failbit); - return stream; - } - out = tmp; - return stream; -} - -} // namespace details - -// override for default behavior of treating as a character -inline std::istream &operator>>(std::istream &stream, int8_t &out) { - return details::operator>>(stream, out); -} - -// override for default behavior of treating as a character -inline std::istream &operator>>(std::istream &stream, uint8_t &out) { - return details::operator>>(stream, out); -} - -} // namespace overrides - -template <typename T, typename R = hardware::hidl_enum_range<T>> -inline std::istream &operator>>(std::istream &stream, T &out) { - using overrides::operator>>; - auto validRange = R(); - auto pos = stream.tellg(); - std::underlying_type_t<T> in; - T tmp; - stream >> in; - if (!stream) { - return stream; - } - tmp = static_cast<T>(in); - if (tmp < *validRange.begin() || tmp > *std::prev(validRange.end())) { - stream.seekg(pos); - stream.setstate(std::ios_base::failbit); - return stream; - } - out = tmp; - return stream; -} - -enum Status : unsigned int { - OK, - USAGE, - UNAVAILABLE, - ERROR, -}; - -class Args { -public: - Args(const int argc, const char *const argv[]) { - for (int argi = 0; argi < argc; argi++) { - mArgs.emplace_back(std::string_view(argv[argi])); - } - } - - template <typename T = std::string> - std::optional<T> get() { - return get<T>(false); - } - - template <typename T = std::string> - std::optional<T> pop() { - return get<T>(true); - } - - bool empty() { return mArgs.empty(); } - -private: - template <typename T> - std::optional<T> get(bool erase) { - using idlcli::operator>>; - using overrides::operator>>; - T retValue; - - if (mArgs.empty()) { - return {}; - } - - std::stringstream stream{std::string{mArgs.front()}}; - stream >> std::setbase(0) >> retValue; - if (!stream || !stream.eof()) { - return {}; - } - - if (erase) { - mArgs.erase(mArgs.begin()); - } - - return retValue; - } - - std::vector<std::string_view> mArgs; -}; - -class Command { -protected: - struct Usage { - std::string name; - std::vector<std::string> details; - }; - using UsageDetails = std::vector<Usage>; - -public: - virtual ~Command() = default; - - Status main(Args &&args) { - Status status = doArgsAndMain(std::move(args)); - if (status == USAGE) { - printUsage(); - return ERROR; - } - if (status == UNAVAILABLE) { - std::cerr << "The requested operation is unavailable." << std::endl; - return ERROR; - } - return status; - } - -private: - virtual std::string getDescription() const = 0; - virtual std::string getUsageSummary() const = 0; - virtual UsageDetails getUsageDetails() const = 0; - virtual Status doArgs(Args &args) = 0; - virtual Status doMain(Args &&args) = 0; - - void printUsage() const { - std::cerr << "Description:\n " << getDescription() << std::endl; - std::cerr << "Usage:\n " << mName << " " << getUsageSummary() << std::endl; - - std::cerr << "Details:" << std::endl; - size_t entryNameWidth = 0; - for (auto &entry : getUsageDetails()) { - entryNameWidth = std::max(entryNameWidth, entry.name.length()); - } - for (auto &entry : getUsageDetails()) { - auto prefix = entry.name; - for (auto &line : entry.details) { - std::cerr << " " << std::left << std::setw(entryNameWidth + 8) << prefix << line - << std::endl; - prefix = ""; - } - } - } - - Status doArgsAndMain(Args &&args) { - Status status; - mName = *args.pop(); - if ((status = doArgs(args)) != OK) { - return status; - } - if ((status = doMain(std::move(args))) != OK) { - return status; - } - return OK; - } - -protected: - std::string mName; -}; - -template <typename T> -class CommandRegistry { -private: - using CommandCreator = std::function<std::unique_ptr<Command>()>; - -public: - template <typename U> - static CommandCreator Register(const std::string name) { - Instance()->mCommands[name] = [] { return std::make_unique<U>(); }; - return Instance()->mCommands[name]; - } - - static std::unique_ptr<Command> Create(const std::string name) { - auto it = Instance()->mCommands.find(name); - if (it == Instance()->mCommands.end()) { - return nullptr; - } - return it->second(); - } - - static auto List() { - std::vector<std::string> list; - for (auto &it : Instance()->mCommands) { - list.push_back(it.first); - } - std::sort(list.begin(), list.end()); - return list; - } - -private: - static CommandRegistry *Instance() { - static CommandRegistry sRegistry; - return &sRegistry; - } - -private: - std::map<const std::string, CommandCreator> mCommands; -}; - -template <typename T> -class CommandWithSubcommands : public Command { -private: - Status doArgs(Args &args) override { - mCommand = CommandRegistry<T>::Create(*args.get()); - if (!mCommand) { - std::cerr << "Invalid Command!" << std::endl; - return USAGE; - } - return OK; - } - - Status doMain(Args &&args) override { return mCommand->main(std::move(args)); } - -protected: - std::unique_ptr<Command> mCommand; -}; - -} // namespace idlcli -} // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_ diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h deleted file mode 100644 index bcb207b7d0..0000000000 --- a/cmds/idlcli/vibrator.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_ -#define FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_ - -#include <android/hardware/vibrator/1.3/IVibrator.h> - -#include "utils.h" - -#include "log/log.h" - -namespace android { - -using hardware::Return; - -static constexpr int NUM_TRIES = 2; - -// Creates a Return<R> with STATUS::EX_NULL_POINTER. -template <class R> -inline Return<R> NullptrStatus() { - using ::android::hardware::Status; - return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)}; -} - -template <typename I> -class HalWrapper { -public: - static std::unique_ptr<HalWrapper> Create() { - // Assume that if getService returns a nullptr, HAL is not available on the - // device. - auto hal = I::getService(); - return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr; - } - - template <class R, class... Args0, class... Args1> - Return<R> call(Return<R> (I::*fn)(Args0...), Args1&&... args1) { - return (*mHal.*fn)(std::forward<Args1>(args1)...); - } - -private: - HalWrapper(sp<I>&& hal) : mHal(std::move(hal)) {} - -private: - sp<I> mHal; -}; - -template <typename I> -static auto getHal() { - static auto sHalWrapper = HalWrapper<I>::Create(); - return sHalWrapper.get(); -} - -template <class R, class I, class... Args0, class... Args1> -Return<R> halCall(Return<R> (I::*fn)(Args0...), Args1&&... args1) { - auto hal = getHal<I>(); - return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>(); -} - -namespace idlcli { -namespace vibrator { - -namespace V1_0 = ::android::hardware::vibrator::V1_0; -namespace V1_1 = ::android::hardware::vibrator::V1_1; -namespace V1_2 = ::android::hardware::vibrator::V1_2; -namespace V1_3 = ::android::hardware::vibrator::V1_3; - -} // namespace vibrator -} // namespace idlcli - -} // namespace android - -#endif // FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_ diff --git a/cmds/idlcli/vibrator/CommandOff.cpp b/cmds/idlcli/vibrator/CommandOff.cpp deleted file mode 100644 index a674f0192f..0000000000 --- a/cmds/idlcli/vibrator/CommandOff.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" -#include "vibrator.h" - -namespace android { -namespace idlcli { - -class CommandVibrator; - -namespace vibrator { - -class CommandOff : public Command { - std::string getDescription() const override { return "Turn off vibrator."; } - - std::string getUsageSummary() const override { return ""; } - - UsageDetails getUsageDetails() const override { - UsageDetails details{}; - return details; - } - - Status doArgs(Args &args) override { - if (!args.empty()) { - std::cerr << "Unexpected Arguments!" << std::endl; - return USAGE; - } - return OK; - } - - Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_0::IVibrator::off); - - if (!ret.isOk()) { - return UNAVAILABLE; - } - - std::cout << "Status: " << toString(ret) << std::endl; - - return ret == V1_0::Status::OK ? OK : ERROR; - } -}; - -static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandOff>("off"); - -} // namespace vibrator -} // namespace idlcli -} // namespace android diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp deleted file mode 100644 index 2164b7d149..0000000000 --- a/cmds/idlcli/vibrator/CommandOn.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" -#include "vibrator.h" - -namespace android { -namespace idlcli { - -class CommandVibrator; - -namespace vibrator { - -class CommandOn : public Command { - std::string getDescription() const override { return "Turn on vibrator."; } - - std::string getUsageSummary() const override { return "<duration>"; } - - UsageDetails getUsageDetails() const override { - UsageDetails details{ - {"<duration>", {"In milliseconds."}}, - }; - return details; - } - - Status doArgs(Args &args) override { - if (auto duration = args.pop<decltype(mDuration)>()) { - mDuration = *duration; - } else { - std::cerr << "Missing or Invalid Duration!" << std::endl; - return USAGE; - } - if (!args.empty()) { - std::cerr << "Unexpected Arguments!" << std::endl; - return USAGE; - } - return OK; - } - - Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_0::IVibrator::on, mDuration); - - if (!ret.isOk()) { - return UNAVAILABLE; - } - - std::cout << "Status: " << toString(ret) << std::endl; - - return ret == V1_0::Status::OK ? OK : ERROR; - } - - uint32_t mDuration; -}; - -static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandOn>("on"); - -} // namespace vibrator -} // namespace idlcli -} // namespace android diff --git a/cmds/idlcli/vibrator/CommandPerform.cpp b/cmds/idlcli/vibrator/CommandPerform.cpp deleted file mode 100644 index 688cbd87a1..0000000000 --- a/cmds/idlcli/vibrator/CommandPerform.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" -#include "vibrator.h" - -namespace android { -namespace idlcli { - -class CommandVibrator; - -namespace vibrator { - -using V1_0::EffectStrength; -using V1_3::Effect; - -class CommandPerform : public Command { - std::string getDescription() const override { return "Perform vibration effect."; } - - std::string getUsageSummary() const override { return "<effect> <strength>"; } - - UsageDetails getUsageDetails() const override { - UsageDetails details{ - {"<effect>", {"Effect ID."}}, - {"<strength>", {"0-2."}}, - }; - return details; - } - - Status doArgs(Args &args) override { - if (auto effect = args.pop<decltype(mEffect)>()) { - mEffect = *effect; - std::cout << "Effect: " << toString(mEffect) << std::endl; - } else { - std::cerr << "Missing or Invalid Effect!" << std::endl; - return USAGE; - } - if (auto strength = args.pop<decltype(mStrength)>()) { - mStrength = *strength; - std::cout << "Strength: " << toString(mStrength) << std::endl; - } else { - std::cerr << "Missing or Invalid Strength!" << std::endl; - return USAGE; - } - if (!args.empty()) { - std::cerr << "Unexpected Arguments!" << std::endl; - return USAGE; - } - return OK; - } - - Status doMain(Args && /*args*/) override { - Return<void> ret; - V1_0::Status status; - uint32_t lengthMs; - auto callback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) { - status = retStatus; - lengthMs = retLengthMs; - }; - - if (auto hal = getHal<V1_3::IVibrator>()) { - ret = hal->call(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(mEffect), - mStrength, callback); - } else if (auto hal = getHal<V1_2::IVibrator>()) { - ret = hal->call(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(mEffect), - mStrength, callback); - } else if (auto hal = getHal<V1_1::IVibrator>()) { - ret = hal->call(&V1_1::IVibrator::perform_1_1, static_cast<V1_1::Effect_1_1>(mEffect), - mStrength, callback); - } else if (auto hal = getHal<V1_0::IVibrator>()) { - ret = hal->call(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(mEffect), - mStrength, callback); - } else { - ret = NullptrStatus<void>(); - } - - if (!ret.isOk()) { - return UNAVAILABLE; - } - - std::cout << "Status: " << toString(status) << std::endl; - std::cout << "Length: " << lengthMs << std::endl; - - return status == V1_0::Status::OK ? OK : ERROR; - } - - Effect mEffect; - EffectStrength mStrength; -}; - -static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandPerform>("perform"); - -} // namespace vibrator -} // namespace idlcli -} // namespace android diff --git a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp deleted file mode 100644 index 38a1dc279b..0000000000 --- a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" -#include "vibrator.h" - -namespace android { -namespace idlcli { - -class CommandVibrator; - -namespace vibrator { - -class CommandSetAmplitude : public Command { - std::string getDescription() const override { return "Set vibration amplitude."; } - - std::string getUsageSummary() const override { return "<amplitude>"; } - - UsageDetails getUsageDetails() const override { - UsageDetails details{ - {"<amplitude>", {"1-255."}}, - }; - return details; - } - - Status doArgs(Args &args) override { - if (auto amplitude = args.pop<decltype(mAmplitude)>()) { - mAmplitude = *amplitude; - } else { - std::cerr << "Missing or Invalid Amplitude!" << std::endl; - return USAGE; - } - if (!args.empty()) { - std::cerr << "Unexpected Arguments!" << std::endl; - return USAGE; - } - return OK; - } - - Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_0::IVibrator::setAmplitude, mAmplitude); - - if (!ret.isOk()) { - return UNAVAILABLE; - } - - std::cout << "Status: " << toString(ret) << std::endl; - - return ret == V1_0::Status::OK ? OK : ERROR; - } - - uint8_t mAmplitude; -}; - -static const auto Command = - CommandRegistry<CommandVibrator>::Register<CommandSetAmplitude>("setAmplitude"); - -} // namespace vibrator -} // namespace idlcli -} // namespace android diff --git a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp deleted file mode 100644 index 5fb1faca16..0000000000 --- a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" -#include "vibrator.h" - -namespace android { -namespace idlcli { - -class CommandVibrator; - -namespace vibrator { - -class CommandSetExternalControl : public Command { - std::string getDescription() const override { - return "Enable/disable vibration external control."; - } - - std::string getUsageSummary() const override { return "<enable>"; } - - UsageDetails getUsageDetails() const override { - UsageDetails details{ - {"<enable>", {"0/1."}}, - }; - return details; - } - - Status doArgs(Args &args) override { - if (auto enable = args.pop<decltype(mEnable)>()) { - mEnable = *enable; - } else { - std::cerr << "Missing Enable!" << std::endl; - return USAGE; - } - return OK; - } - - Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_3::IVibrator::setExternalControl, mEnable); - - if (!ret.isOk()) { - return UNAVAILABLE; - } - - std::cout << "Status: " << toString(ret) << std::endl; - - return ret == V1_0::Status::OK ? OK : ERROR; - } - - bool mEnable; -}; - -static const auto Command = - CommandRegistry<CommandVibrator>::Register<CommandSetExternalControl>("setExternalControl"); - -} // namespace vibrator -} // namespace idlcli -} // namespace android diff --git a/cmds/idlcli/vibrator/CommandSupportsAmplitudeControl.cpp b/cmds/idlcli/vibrator/CommandSupportsAmplitudeControl.cpp deleted file mode 100644 index cdc529a2f3..0000000000 --- a/cmds/idlcli/vibrator/CommandSupportsAmplitudeControl.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" -#include "vibrator.h" - -namespace android { -namespace idlcli { - -class CommandVibrator; - -namespace vibrator { - -class CommandSupportsAmplitudeControl : public Command { - std::string getDescription() const override { return "Check support for amplitude control."; } - - std::string getUsageSummary() const override { return ""; } - - UsageDetails getUsageDetails() const override { - UsageDetails details{}; - return details; - } - - Status doArgs(Args &args) override { - if (!args.empty()) { - std::cerr << "Unexpected Arguments!" << std::endl; - return USAGE; - } - return OK; - } - - Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_0::IVibrator::supportsAmplitudeControl); - - if (!ret.isOk()) { - return UNAVAILABLE; - } - - std::cout << "Result: " << std::boolalpha << ret << std::endl; - - return OK; - } -}; - -static const auto Command = - CommandRegistry<CommandVibrator>::Register<CommandSupportsAmplitudeControl>( - "supportsAmplitudeControl"); - -} // namespace vibrator -} // namespace idlcli -} // namespace android diff --git a/cmds/idlcli/vibrator/CommandSupportsExternalControl.cpp b/cmds/idlcli/vibrator/CommandSupportsExternalControl.cpp deleted file mode 100644 index ed15d76286..0000000000 --- a/cmds/idlcli/vibrator/CommandSupportsExternalControl.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" -#include "vibrator.h" - -namespace android { -namespace idlcli { - -class CommandVibrator; - -namespace vibrator { - -class CommandSupportsExternalControl : public Command { - std::string getDescription() const override { return "Check support for external control."; } - - std::string getUsageSummary() const override { return ""; } - - UsageDetails getUsageDetails() const override { - UsageDetails details{}; - return details; - } - - Status doArgs(Args &args) override { - if (!args.empty()) { - std::cerr << "Unexpected Arguments!" << std::endl; - return USAGE; - } - return OK; - } - - Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_3::IVibrator::supportsExternalControl); - - if (!ret.isOk()) { - return UNAVAILABLE; - } - - std::cout << "Result: " << std::boolalpha << ret << std::endl; - - return OK; - } -}; - -static const auto Command = - CommandRegistry<CommandVibrator>::Register<CommandSupportsExternalControl>( - "supportsExternalControl"); - -} // namespace vibrator -} // namespace idlcli -} // namespace android diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp index 75dec371bc..c80ae3bbf6 100644 --- a/cmds/installd/Android.bp +++ b/cmds/installd/Android.bp @@ -138,7 +138,6 @@ cc_binary { cc_binary { name: "otapreopt_chroot", - defaults: ["libapexd-deps"], cflags: [ "-Wall", "-Werror", @@ -151,11 +150,20 @@ cc_binary { ], shared_libs: [ "libbase", + "libbinder", "liblog", + "libprotobuf-cpp-full", + "libselinux", "libutils", + "libziparchive", ], static_libs: [ + "libapex", "libapexd", + "lib_apex_manifest_proto", + "libavb", + "libdm", + "libvold_binder", ], } @@ -164,7 +172,6 @@ filegroup { srcs: [ "binder/android/os/IInstalld.aidl", ], - path: "binder", } // diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 4026f29208..34727270e4 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -832,7 +832,7 @@ static int32_t copy_directory_recursive(const char* from, const char* to) { }; LOG(DEBUG) << "Copying " << from << " to " << to; - return logwrap_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, LOG_ALOG, false, nullptr); + return android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true); } binder::Status InstalldNativeService::snapshotAppData( @@ -2107,15 +2107,10 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t CHECK_ARGUMENT_PATH(dexMetadataPath); std::lock_guard<std::recursive_mutex> lock(mLock); - const char* oat_dir = getCStr(outputPath); - const char* instruction_set = instructionSet.c_str(); - if (oat_dir != nullptr && !createOatDir(oat_dir, instruction_set).isOk()) { - // Can't create oat dir - let dexopt use cache dir. - oat_dir = nullptr; - } - const char* apk_path = apkPath.c_str(); const char* pkgname = getCStr(packageName, "*"); + const char* instruction_set = instructionSet.c_str(); + const char* oat_dir = getCStr(outputPath); const char* compiler_filter = compilerFilter.c_str(); const char* volume_uuid = getCStr(uuid); const char* class_loader_context = getCStr(classLoaderContext); @@ -2141,26 +2136,6 @@ binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath, return *_aidl_return ? ok() : error("viewcompiler failed"); } -binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) { - ENFORCE_UID(AID_SYSTEM); - std::lock_guard<std::recursive_mutex> lock(mLock); - - const char* instruction_set = instructionSet.c_str(); - - char boot_marker_path[PKG_PATH_MAX]; - sprintf(boot_marker_path, - "%s/%s/%s/.booting", - android_data_dir.c_str(), - DALVIK_CACHE, - instruction_set); - - ALOGV("mark_boot_complete : %s", boot_marker_path); - if (unlink(boot_marker_path) != 0) { - return error(StringPrintf("Failed to unlink %s", boot_marker_path)); - } - return ok(); -} - binder::Status InstalldNativeService::linkNativeLibraryDirectory( const std::unique_ptr<std::string>& uuid, const std::string& packageName, const std::string& nativeLibPath32, int32_t userId) { diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 2b7bf33cbc..eba966d4ab 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -123,7 +123,6 @@ public: int32_t uid); binder::Status removeIdmap(const std::string& overlayApkPath); binder::Status rmPackageDir(const std::string& packageDir); - binder::Status markBootComplete(const std::string& instructionSet); binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags); binder::Status linkNativeLibraryDirectory(const std::unique_ptr<std::string>& uuid, diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS index 9a21104131..56739181bb 100644 --- a/cmds/installd/OWNERS +++ b/cmds/installd/OWNERS @@ -4,9 +4,7 @@ agampe@google.com calin@google.com jsharkey@android.com maco@google.com -mast@google.com mathieuc@google.com narayan@google.com ngeoffray@google.com -rpl@google.com toddke@google.com diff --git a/cmds/installd/art_helper/Android.bp b/cmds/installd/art_helper/Android.bp new file mode 100644 index 0000000000..c47dd722f9 --- /dev/null +++ b/cmds/installd/art_helper/Android.bp @@ -0,0 +1,12 @@ +// Inherit image values. +art_global_defaults { + name: "libartimagevalues_defaults", +} + +cc_library_static { + name: "libartimagevalues", + defaults: ["libartimagevalues_defaults"], + srcs: ["art_image_values.cpp"], + export_include_dirs: ["."], + cflags: ["-Wconversion"], +} diff --git a/cmds/installd/art_helper/art_image_values.cpp b/cmds/installd/art_helper/art_image_values.cpp new file mode 100644 index 0000000000..a139049d9f --- /dev/null +++ b/cmds/installd/art_helper/art_image_values.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "art_image_values.h" + +namespace android { +namespace installd { +namespace art { + +uint32_t GetImageBaseAddress() { + return ART_BASE_ADDRESS; +} +int32_t GetImageMinBaseAddressDelta() { + return ART_BASE_ADDRESS_MIN_DELTA; +} +int32_t GetImageMaxBaseAddressDelta() { + return ART_BASE_ADDRESS_MAX_DELTA; +} + +static_assert(ART_BASE_ADDRESS_MIN_DELTA < ART_BASE_ADDRESS_MAX_DELTA, "Inconsistent setup"); + +} // namespace art +} // namespace installd +} // namespace android diff --git a/services/inputflinger/dispatcher/InputDispatcherFactory.cpp b/cmds/installd/art_helper/art_image_values.h index 8d7fa7573b..20c44c953f 100644 --- a/services/inputflinger/dispatcher/InputDispatcherFactory.cpp +++ b/cmds/installd/art_helper/art_image_values.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,21 @@ * limitations under the License. */ -#include "InputDispatcherFactory.h" -#include "InputDispatcher.h" +#ifndef FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H +#define FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H + +#include <cstdint> namespace android { +namespace installd { +namespace art { + +uint32_t GetImageBaseAddress(); +int32_t GetImageMinBaseAddressDelta(); +int32_t GetImageMaxBaseAddressDelta(); -sp<InputDispatcherInterface> createInputDispatcher( - const sp<InputDispatcherPolicyInterface>& policy) { - return new android::inputdispatcher::InputDispatcher(policy); -} +} // namespace art +} // namespace installd +} // namespace android -} // namespace android +#endif // FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 26e9984f11..b795c02648 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -75,7 +75,6 @@ interface IInstalld { void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid); void removeIdmap(@utf8InCpp String overlayApkPath); void rmPackageDir(@utf8InCpp String packageDir); - void markBootComplete(@utf8InCpp String instructionSet); void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes, long cacheReservedBytes, int flags); void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid, diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 838d11d6d8..5fb13a5c56 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -303,9 +303,6 @@ static const char* ENABLE_APEX_IMAGE = "enable_apex_image"; // Location of the apex image. static const char* kApexImage = "/system/framework/apex.art"; -// Phenotype property name for enabling profiling the boot class path. -static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath"; - class RunDex2Oat : public ExecVHelper { public: RunDex2Oat(int zip_fd, @@ -339,6 +336,10 @@ class RunDex2Oat : public ExecVHelper { ? "dalvik.vm.dex2oat-threads" : "dalvik.vm.boot-dex2oat-threads"; std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s"); + const char* cpu_set_property = post_bootcomplete + ? "dalvik.vm.dex2oat-cpu-set" + : "dalvik.vm.boot-dex2oat-cpu-set"; + std::string dex2oat_cpu_set_arg = MapPropertyToArg(cpu_set_property, "--cpu-set=%s"); std::string bootclasspath; char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH"); @@ -405,15 +406,7 @@ class RunDex2Oat : public ExecVHelper { server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE, ENABLE_APEX_IMAGE, /*default_value=*/ ""); - - std::string profile_boot_class_path = GetProperty("dalvik.vm.profilebootclasspath", ""); - profile_boot_class_path = - server_configurable_flags::GetServerConfigurableFlag( - RUNTIME_NATIVE_BOOT_NAMESPACE, - PROFILE_BOOT_CLASS_PATH, - /*default_value=*/ profile_boot_class_path); - - if (use_apex_image == "true" || profile_boot_class_path == "true") { + if (use_apex_image == "true") { boot_image = StringPrintf("-Ximage:%s", kApexImage); } else { boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s"); @@ -518,6 +511,7 @@ class RunDex2Oat : public ExecVHelper { AddArg(image_block_size_arg); AddArg(dex2oat_compiler_filter_arg); AddArg(dex2oat_threads_arg); + AddArg(dex2oat_cpu_set_arg); AddArg(dex2oat_swap_fd); AddArg(dex2oat_image_fd); @@ -720,7 +714,8 @@ class RunProfman : public ExecVHelper { 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 copy_and_update, + bool store_aggregation_counters) { // 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 @@ -752,6 +747,10 @@ class RunProfman : public ExecVHelper { AddArg("--copy-and-update-profile-key"); } + if (store_aggregation_counters) { + AddArg("--store-aggregation-counters"); + } + // Do not add after dex2oat_flags, they should override others for debugging. PrepareArgs(profman_bin); } @@ -759,12 +758,14 @@ class RunProfman : public ExecVHelper { void SetupMerge(const std::vector<unique_fd>& profiles_fd, const unique_fd& reference_profile_fd, const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(), - const std::vector<std::string>& dex_locations = std::vector<std::string>()) { + const std::vector<std::string>& dex_locations = std::vector<std::string>(), + bool store_aggregation_counters = false) { SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations, - /*copy_and_update=*/false); + /*copy_and_update=*/false, + store_aggregation_counters); } void SetupCopyAndUpdate(unique_fd&& profile_fd, @@ -781,7 +782,8 @@ class RunProfman : public ExecVHelper { reference_profile_fd_, apk_fds_, dex_locations, - /*copy_and_update=*/true); + /*copy_and_update=*/true, + /*store_aggregation_counters=*/false); } void SetupDump(const std::vector<unique_fd>& profiles_fd, @@ -795,7 +797,8 @@ class RunProfman : public ExecVHelper { reference_profile_fd, apk_fds, dex_locations, - /*copy_and_update=*/false); + /*copy_and_update=*/false, + /*store_aggregation_counters=*/false); } void Exec() { @@ -2119,20 +2122,14 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins // Create a swap file if necessary. unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path); - // Open the reference profile if needed. - Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile( - pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex); - - if (reference_profile_fd.get() == -1) { - // We don't create an app image without reference profile since there is no speedup from - // loading it in that case and instead will be a small overhead. - generate_app_image = false; - } - // Create the app image file if needed. Dex2oatFileWrapper image_fd = maybe_open_app_image( out_oat_path, generate_app_image, is_public, uid, is_secondary_dex); + // Open the reference profile if needed. + Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile( + pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex); + unique_fd dex_metadata_fd; if (dex_metadata_path != nullptr) { dex_metadata_fd.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW))); @@ -2830,7 +2827,8 @@ static bool create_boot_image_profile_snapshot(const std::string& package_name, args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, - dex_locations); + dex_locations, + /*store_aggregation_counters=*/true); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h index ef739bafd4..a8c48c564e 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -32,15 +32,15 @@ static constexpr int DEX2OAT_FROM_SCRATCH = 1; static constexpr int DEX2OAT_FOR_BOOT_IMAGE = 2; static constexpr int DEX2OAT_FOR_FILTER = 3; -#define ANDROID_ART_APEX_BIN "/apex/com.android.art/bin" +#define ANDROID_RUNTIME_APEX_BIN "/apex/com.android.runtime/bin" // Location of binaries in the Android Runtime APEX. -static constexpr const char* kDex2oatPath = ANDROID_ART_APEX_BIN "/dex2oat"; -static constexpr const char* kDex2oatDebugPath = ANDROID_ART_APEX_BIN "/dex2oatd"; -static constexpr const char* kProfmanPath = ANDROID_ART_APEX_BIN "/profman"; -static constexpr const char* kProfmanDebugPath = ANDROID_ART_APEX_BIN "/profmand"; -static constexpr const char* kDexoptanalyzerPath = ANDROID_ART_APEX_BIN "/dexoptanalyzer"; -static constexpr const char* kDexoptanalyzerDebugPath = ANDROID_ART_APEX_BIN "/dexoptanalyzerd"; -#undef ANDROID_ART_APEX_BIN +static constexpr const char* kDex2oatPath = ANDROID_RUNTIME_APEX_BIN "/dex2oat"; +static constexpr const char* kDex2oatDebugPath = ANDROID_RUNTIME_APEX_BIN "/dex2oatd"; +static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profman"; +static constexpr const char* kProfmanDebugPath = ANDROID_RUNTIME_APEX_BIN "/profmand"; +static constexpr const char* kDexoptanalyzerPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzer"; +static constexpr const char* kDexoptanalyzerDebugPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzerd"; +#undef ANDROID_RUNTIME_APEX_BIN // Clear the reference profile identified by the given profile name. bool clear_primary_reference_profile(const std::string& pkgname, const std::string& profile_name); diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp index b5bc28c1d3..673ff0d513 100644 --- a/cmds/installd/installd.cpp +++ b/cmds/installd/installd.cpp @@ -74,7 +74,7 @@ static int initialize_directories() { // Read current filesystem layout version to handle upgrade paths char version_path[PATH_MAX]; - snprintf(version_path, PATH_MAX, "%smisc/installd/layout_version", android_data_dir.c_str()); + snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str()); int oldVersion; if (fs_read_atomic_int(version_path, &oldVersion) == -1) { diff --git a/cmds/installd/migrate_legacy_obb_data.sh b/cmds/installd/migrate_legacy_obb_data.sh index 0e6d7b9c62..10756881be 100644 --- a/cmds/installd/migrate_legacy_obb_data.sh +++ b/cmds/installd/migrate_legacy_obb_data.sh @@ -15,17 +15,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -rm -rf /data/media/Android/obb/test_probe -mkdir -p /data/media/Android/obb/ -touch /data/media/Android/obb/test_probe +rm -rf /sdcard/Android/obb/test_probe +mkdir -p /sdcard/Android/obb/ +touch /sdcard/Android/obb/test_probe if ! test -f /data/media/0/Android/obb/test_probe ; then log -p i -t migrate_legacy_obb_data "No support for 'unshared_obb'. Not migrating" - rm -rf /data/media/Android/obb/test_probe + rm -rf /sdcard/Android/obb/test_probe exit 0 fi # Delete the test file, and remove the obb folder if it is empty -rm -rf /data/media/Android/obb/test_probe +rm -rf /sdcard/Android/obb/test_probe rmdir /data/media/obb if ! test -d /data/media/obb ; then diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index db36ce3c9e..9bc5fc81d4 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -445,11 +445,9 @@ private: } cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str())); - int32_t base_offset = ChooseRelocationOffsetDelta( - art::imagevalues::GetImageMinBaseAddressDelta(), - art::imagevalues::GetImageMaxBaseAddressDelta()); - cmd.push_back(StringPrintf("--base=0x%x", - art::imagevalues::GetImageBaseAddress() + base_offset)); + int32_t base_offset = ChooseRelocationOffsetDelta(art::GetImageMinBaseAddressDelta(), + art::GetImageMaxBaseAddressDelta()); + cmd.push_back(StringPrintf("--base=0x%x", art::GetImageBaseAddress() + base_offset)); cmd.push_back(StringPrintf("--instruction-set=%s", isa)); @@ -466,7 +464,7 @@ private: "--compiler-filter=", false, cmd); - cmd.push_back("--profile-file=/system/etc/boot-image.prof"); + cmd.push_back("--image-classes=/system/etc/preloaded-classes"); // TODO: Compiled-classes. const std::string* extra_opts = system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags"); @@ -480,6 +478,10 @@ private: "-j", false, cmd); + AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-cpu-set", + "--cpu-set=", + false, + cmd); AddCompilerOptionFromSystemProperty( StringPrintf("dalvik.vm.isa.%s.variant", isa).c_str(), "--instruction-set-variant=", diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index 3ff9d11806..2e2cc182ec 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -64,18 +64,16 @@ static std::vector<apex::ApexFile> ActivateApexPackages() { // system/apex/apexd/apexd_main.cpp. // // Only scan the APEX directory under /system (within the chroot dir). - // Cast call to void to suppress warn_unused_result. - static_cast<void>(apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir)); + apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir); return apex::getActivePackages(); } static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) { for (const apex::ApexFile& apex_file : active_packages) { const std::string& package_path = apex_file.GetPath(); - base::Result<void> status = apex::deactivatePackage(package_path); - if (!status) { - LOG(ERROR) << "Failed to deactivate " << package_path << ": " - << status.error(); + apex::Status status = apex::deactivatePackage(package_path); + if (!status.Ok()) { + LOG(ERROR) << "Failed to deactivate " << package_path << ": " << status.ErrorMessage(); } } } @@ -233,21 +231,9 @@ static int otapreopt_chroot(const int argc, char **arg) { } // Try to mount APEX packages in "/apex" in the chroot dir. We need at least - // the ART APEX, as it is required by otapreopt to run dex2oat. + // the Android Runtime APEX, as it is required by otapreopt to run dex2oat. std::vector<apex::ApexFile> active_packages = ActivateApexPackages(); - // Check that an ART APEX has been activated; clean up and exit - // early otherwise. - if (std::none_of(active_packages.begin(), - active_packages.end(), - [](const apex::ApexFile& package){ - return package.GetManifest().name() == "com.android.art"; - })) { - LOG(FATAL_WITHOUT_ABORT) << "No activated com.android.art APEX package."; - DeactivateApexPackages(active_packages); - exit(217); - } - // Now go on and run otapreopt. // Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp index bd45005fd1..aa79fdc100 100644 --- a/cmds/installd/tests/Android.bp +++ b/cmds/installd/tests/Android.bp @@ -89,8 +89,6 @@ cc_test { "libinstalld", "liblog", "liblogwrap", - "libziparchive", - "libz", ], test_config: "installd_dexopt_test.xml", } diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp index 5a5cb53431..db0907017c 100644 --- a/cmds/installd/tests/installd_cache_test.cpp +++ b/cmds/installd/tests/installd_cache_test.cpp @@ -67,29 +67,29 @@ bool create_cache_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED, } static void mkdir(const char* path) { - const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path); - ::mkdir(fullPath.c_str(), 0755); + const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str(); + ::mkdir(fullPath, 0755); } static void touch(const char* path, int len, int time) { - const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path); - int fd = ::open(fullPath.c_str(), O_RDWR | O_CREAT, 0644); + const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str(); + int fd = ::open(fullPath, O_RDWR | O_CREAT, 0644); ::fallocate(fd, 0, 0, len); ::close(fd); struct utimbuf times; times.actime = times.modtime = std::time(0) + time; - ::utime(fullPath.c_str(), ×); + ::utime(fullPath, ×); } static int exists(const char* path) { - const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path); - return ::access(fullPath.c_str(), F_OK); + const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str(); + return ::access(fullPath, F_OK); } static int64_t size(const char* path) { - const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path); + const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str(); struct stat buf; - if (!stat(fullPath.c_str(), &buf)) { + if (!stat(fullPath, &buf)) { return buf.st_size; } else { return -1; @@ -107,8 +107,8 @@ static int64_t free() { } static void setxattr(const char* path, const char* key) { - const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path); - ::setxattr(fullPath.c_str(), key, "", 0, 0); + const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str(); + ::setxattr(fullPath, key, "", 0, 0); } class CacheTest : public testing::Test { diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index 0212bc5564..fa2b0d9660 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -41,7 +41,6 @@ #include "globals.h" #include "tests/test_utils.h" #include "utils.h" -#include "ziparchive/zip_writer.h" using android::base::ReadFully; using android::base::unique_fd; @@ -196,7 +195,6 @@ protected: std::unique_ptr<std::string> volume_uuid_; std::string package_name_; std::string apk_path_; - std::string empty_dm_file_; std::string app_apk_dir_; std::string app_private_dir_ce_; std::string app_private_dir_de_; @@ -241,14 +239,18 @@ protected: } ::testing::AssertionResult create_mock_app() { + // Create the oat dir. + app_oat_dir_ = app_apk_dir_ + "/oat"; // For debug mode, the directory might already exist. Avoid erroring out. if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0 && !kDebug) { return ::testing::AssertionFailure() << "Could not create app dir " << app_apk_dir_ << " : " << strerror(errno); } - - // Initialize the oat dir path. - app_oat_dir_ = app_apk_dir_ + "/oat"; + binder::Status status = service_->createOatDir(app_oat_dir_, kRuntimeIsa); + if (!status.isOk()) { + return ::testing::AssertionFailure() << "Could not create oat dir: " + << status.toString8().c_str(); + } // Copy the primary apk. apk_path_ = app_apk_dir_ + "/base.jar"; @@ -258,28 +260,8 @@ protected: << " : " << error_msg; } - // Create an empty dm file. - empty_dm_file_ = apk_path_ + ".dm"; - { - int fd = open(empty_dm_file_.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); - if (fd < 0) { - return ::testing::AssertionFailure() << "Could not open " << empty_dm_file_; - } - FILE* file = fdopen(fd, "wb"); - if (file == nullptr) { - return ::testing::AssertionFailure() << "Null file for " << empty_dm_file_ - << " fd=" << fd; - } - ZipWriter writer(file); - // Add vdex to zip. - writer.StartEntry("primary.prof", ZipWriter::kCompress); - writer.FinishEntry(); - writer.Finish(); - fclose(file); - } - // Create the app user data. - binder::Status status = service_->createAppData( + status = service_->createAppData( volume_uuid_, package_name_, kTestUserId, @@ -497,7 +479,7 @@ protected: bool prof_result; ASSERT_BINDER_SUCCESS(service_->prepareAppProfile( package_name_, kTestUserId, kTestAppId, *profile_name_ptr, apk_path_, - dm_path_ptr, &prof_result)); + /*dex_metadata*/ nullptr, &prof_result)); ASSERT_TRUE(prof_result); binder::Status result = service_->dexopt(apk_path_, @@ -643,16 +625,6 @@ TEST_F(DexoptTest, DexoptPrimaryPublic) { DEX2OAT_FROM_SCRATCH); } -TEST_F(DexoptTest, DexoptPrimaryPublicCreateOatDir) { - LOG(INFO) << "DexoptPrimaryPublic"; - ASSERT_BINDER_SUCCESS(service_->createOatDir(app_oat_dir_, kRuntimeIsa)); - CompilePrimaryDexOk("verify", - DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC, - app_oat_dir_.c_str(), - kTestAppGid, - DEX2OAT_FROM_SCRATCH); -} - TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) { LOG(INFO) << "DexoptPrimaryFailedInvalidFilter"; binder::Status status; @@ -673,9 +645,7 @@ TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) { DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_GENERATE_APP_IMAGE, app_oat_dir_.c_str(), kTestAppGid, - DEX2OAT_FROM_SCRATCH, - /*binder_result=*/nullptr, - empty_dm_file_.c_str()); + DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryProfilePublic) { @@ -685,9 +655,7 @@ TEST_F(DexoptTest, DexoptPrimaryProfilePublic) { DEXOPT_GENERATE_APP_IMAGE, app_oat_dir_.c_str(), kTestAppGid, - DEX2OAT_FROM_SCRATCH, - /*binder_result=*/nullptr, - empty_dm_file_.c_str()); + DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, DexoptPrimaryBackgroundOk) { @@ -697,9 +665,7 @@ TEST_F(DexoptTest, DexoptPrimaryBackgroundOk) { DEXOPT_GENERATE_APP_IMAGE, app_oat_dir_.c_str(), kTestAppGid, - DEX2OAT_FROM_SCRATCH, - /*binder_result=*/nullptr, - empty_dm_file_.c_str()); + DEX2OAT_FROM_SCRATCH); } TEST_F(DexoptTest, ResolveStartupConstStrings) { @@ -718,9 +684,7 @@ TEST_F(DexoptTest, ResolveStartupConstStrings) { DEXOPT_GENERATE_APP_IMAGE, app_oat_dir_.c_str(), kTestAppGid, - DEX2OAT_FROM_SCRATCH, - /*binder_result=*/nullptr, - empty_dm_file_.c_str()); + DEX2OAT_FROM_SCRATCH); run_cmd_and_process_output( "oatdump --header-only --oat-file=" + odex, [&](const std::string& line) { @@ -737,9 +701,7 @@ TEST_F(DexoptTest, ResolveStartupConstStrings) { DEXOPT_GENERATE_APP_IMAGE, app_oat_dir_.c_str(), kTestAppGid, - DEX2OAT_FROM_SCRATCH, - /*binder_result=*/nullptr, - empty_dm_file_.c_str()); + DEX2OAT_FROM_SCRATCH); run_cmd_and_process_output( "oatdump --header-only --oat-file=" + odex, [&](const std::string& line) { diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp index 5afae4b7d3..93d878b607 100644 --- a/cmds/lshal/Android.bp +++ b/cmds/lshal/Android.bp @@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_library_static { +cc_library_shared { name: "liblshal", shared_libs: [ "libbase", "libcutils", "libutils", "libhidlbase", + "libhidltransport", "libhidl-gen-hash", "libhidl-gen-utils", "libvintf", @@ -35,7 +36,6 @@ cc_library_static { "TableEntry.cpp", "TextTable.cpp", "utils.cpp", - "WaitCommand.cpp", ], cflags: [ "-Wall", @@ -47,15 +47,13 @@ cc_defaults { name: "lshal_defaults", shared_libs: [ "libbase", - "libcutils", - "libutils", "libhidlbase", - "libhidl-gen-hash", "libhidl-gen-utils", - "libvintf", + "libhidltransport", + "liblshal", + "libutils", ], static_libs: [ - "liblshal", "libprocpartition", ], cflags: ["-Wall", "-Werror"], @@ -71,16 +69,14 @@ cc_binary { cc_test { name: "lshal_test", - test_suites: ["device-tests"], defaults: ["lshal_defaults"], gtest: true, static_libs: [ - "android.hardware.tests.baz@1.0", - "libgmock", + "libgmock" ], shared_libs: [ - "libhidlbase", "libvintf", + "android.hardware.tests.baz@1.0" ], srcs: [ "test.cpp" diff --git a/cmds/lshal/Command.h b/cmds/lshal/Command.h index 84809d9a5d..e19e3f7fc2 100644 --- a/cmds/lshal/Command.h +++ b/cmds/lshal/Command.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_ #include "utils.h" @@ -47,3 +48,5 @@ protected: } // namespace lshal } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_ diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp index af22ac9b3d..0952db6e72 100644 --- a/cmds/lshal/DebugCommand.cpp +++ b/cmds/lshal/DebugCommand.cpp @@ -79,7 +79,7 @@ void DebugCommand::usage() const { " lshal debug [-E] <interface> [options [options [...]]] \n" " Print debug information of a specified interface.\n" " -E: excludes debug output if HAL is actually a subclass.\n" - " <interface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n" + " <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n" " If instance name is missing `default` is used.\n" " options: space separated options to IBase::debug.\n"; @@ -88,3 +88,4 @@ void DebugCommand::usage() const { } // namespace lshal } // namespace android + diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h index cd57e31bfc..3c3f56fde5 100644 --- a/cmds/lshal/DebugCommand.h +++ b/cmds/lshal/DebugCommand.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_ #include <string> @@ -52,3 +53,5 @@ private: } // namespace lshal } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_ diff --git a/cmds/lshal/HelpCommand.h b/cmds/lshal/HelpCommand.h index bfa850075d..da0cba6f42 100644 --- a/cmds/lshal/HelpCommand.h +++ b/cmds/lshal/HelpCommand.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_ #include <string> @@ -43,3 +44,5 @@ public: } // namespace lshal } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_ diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index a7ccf64c50..c706d911ec 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -163,11 +163,11 @@ template <typename ObjectType> VintfInfo getVintfInfo(const std::shared_ptr<const ObjectType>& object, const FqInstance& fqInstance, vintf::TransportArch ta, VintfInfo value) { bool found = false; - (void)object->forEachHidlInstanceOfVersion(fqInstance.getPackage(), fqInstance.getVersion(), - [&](const auto& instance) { - found = match(instance, fqInstance, ta); - return !found; // continue if not found - }); + (void)object->forEachInstanceOfVersion(fqInstance.getPackage(), fqInstance.getVersion(), + [&](const auto& instance) { + found = match(instance, fqInstance, ta); + return !found; // continue if not found + }); return found ? value : VINTF_INFO_EMPTY; } @@ -453,7 +453,7 @@ bool ListCommand::addEntryWithoutInstance(const TableEntry& entry, } bool found = false; - (void)manifest->forEachHidlInstanceOfVersion(package, version, [&found](const auto&) { + (void)manifest->forEachInstanceOfVersion(package, version, [&found](const auto&) { found = true; return false; // break }); @@ -797,9 +797,9 @@ Status ListCommand::fetchManifestHals() { std::map<std::string, TableEntry> entries; - manifest->forEachHidlInstance([&] (const vintf::ManifestInstance& manifestInstance) { + manifest->forEachInstance([&] (const vintf::ManifestInstance& manifestInstance) { TableEntry entry{ - .interfaceName = manifestInstance.description(), + .interfaceName = manifestInstance.getFqInstance().string(), .transport = manifestInstance.transport(), .arch = manifestInstance.arch(), // TODO(b/71555570): Device manifest does not distinguish HALs from vendor or ODM. @@ -975,8 +975,7 @@ void ListCommand::registerAllOptions() { " - DM: if the HAL is in the device manifest\n" " - DC: if the HAL is in the device compatibility matrix\n" " - FM: if the HAL is in the framework manifest\n" - " - FC: if the HAL is in the framework compatibility matrix\n" - " - X: if the HAL is in none of the above lists"}); + " - FC: if the HAL is in the framework compatibility matrix"}); mOptions.push_back({'S', "service-status", no_argument, v++, [](ListCommand* thiz, const char*) { thiz->mSelectedColumns.push_back(TableColumnType::SERVICE_STATUS); return OK; diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h index b3ed23d1fc..85195fcc54 100644 --- a/cmds/lshal/ListCommand.h +++ b/cmds/lshal/ListCommand.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_ #include <getopt.h> #include <stdint.h> @@ -205,3 +206,5 @@ private: } // namespace lshal } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_ diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp index 132b31ebc3..8c83457d3b 100644 --- a/cmds/lshal/Lshal.cpp +++ b/cmds/lshal/Lshal.cpp @@ -26,9 +26,7 @@ #include <hidl/HidlTransportUtils.h> #include "DebugCommand.h" -#include "HelpCommand.h" #include "ListCommand.h" -#include "WaitCommand.h" #include "PipeRelay.h" namespace android { @@ -51,7 +49,6 @@ Lshal::Lshal(std::ostream &out, std::ostream &err, mRegisteredCommands.push_back({std::make_unique<ListCommand>(*this)}); mRegisteredCommands.push_back({std::make_unique<DebugCommand>(*this)}); mRegisteredCommands.push_back({std::make_unique<HelpCommand>(*this)}); - mRegisteredCommands.push_back({std::make_unique<WaitCommand>(*this)}); } void Lshal::forEachCommand(const std::function<void(const Command* c)>& f) const { diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h index 830bd872ff..9457f1e563 100644 --- a/cmds/lshal/Lshal.h +++ b/cmds/lshal/Lshal.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_ #include <iostream> #include <string> @@ -24,6 +25,7 @@ #include <utils/StrongPointer.h> #include "Command.h" +#include "HelpCommand.h" #include "NullableOStream.h" #include "utils.h" @@ -74,3 +76,5 @@ private: } // namespace lshal } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_ diff --git a/cmds/lshal/NullableOStream.h b/cmds/lshal/NullableOStream.h index 7cffcf8193..737d3a2963 100644 --- a/cmds/lshal/NullableOStream.h +++ b/cmds/lshal/NullableOStream.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_ #include <iostream> @@ -68,3 +69,5 @@ private: } // namespace lshal } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_ diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h index 8350160419..8dc3093742 100644 --- a/cmds/lshal/PipeRelay.h +++ b/cmds/lshal/PipeRelay.h @@ -14,7 +14,9 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_ + +#define FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_ #include <android-base/macros.h> #include <ostream> @@ -51,3 +53,6 @@ private: } // namespace lshal } // namespace android + +#endif // FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_ + diff --git a/cmds/lshal/TEST_MAPPING b/cmds/lshal/TEST_MAPPING deleted file mode 100644 index 0320624699..0000000000 --- a/cmds/lshal/TEST_MAPPING +++ /dev/null @@ -1,8 +0,0 @@ -{ - "presubmit": [ - { - "name": "lshal_test" - } - ] -} - diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h index 0ff0c96d38..601b7e25f9 100644 --- a/cmds/lshal/TableEntry.h +++ b/cmds/lshal/TableEntry.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_ #include <stdint.h> @@ -156,3 +157,5 @@ private: } // namespace lshal } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_ diff --git a/cmds/lshal/TextTable.h b/cmds/lshal/TextTable.h index be41a08251..301b4bd969 100644 --- a/cmds/lshal/TextTable.h +++ b/cmds/lshal/TextTable.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_ #include <iostream> #include <string> @@ -79,3 +80,5 @@ private: } // namespace lshal } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_ diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h index e8d22d9b58..46d817759d 100644 --- a/cmds/lshal/Timeout.h +++ b/cmds/lshal/Timeout.h @@ -14,8 +14,6 @@ * limitations under the License. */ -#pragma once - #include <condition_variable> #include <chrono> #include <functional> diff --git a/cmds/lshal/WaitCommand.cpp b/cmds/lshal/WaitCommand.cpp deleted file mode 100644 index 65b41b95d2..0000000000 --- a/cmds/lshal/WaitCommand.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2019 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 "WaitCommand.h" - -#include "Lshal.h" - -#include <hidl/ServiceManagement.h> -#include <hidl-util/FQName.h> - -namespace android { -namespace lshal { - -std::string WaitCommand::getName() const { - return "wait"; -} - -std::string WaitCommand::getSimpleDescription() const { - return "Wait for HAL to start if it is not already started."; -} - -Status WaitCommand::parseArgs(const Arg &arg) { - if (optind + 1 != arg.argc) { - return USAGE; - } - - mInterfaceName = arg.argv[optind]; - ++optind; - return OK; -} - -Status WaitCommand::main(const Arg &arg) { - Status status = parseArgs(arg); - if (status != OK) { - return status; - } - - auto [interface, instance] = splitFirst(mInterfaceName, '/'); - instance = instance.empty() ? "default" : instance; - - FQName fqName; - if (!FQName::parse(interface, &fqName) || fqName.isIdentifier() || !fqName.isFullyQualified()) { - mLshal.err() << "Invalid fully-qualified name '" << interface << "'\n\n"; - return USAGE; - } - - using android::hidl::manager::V1_0::IServiceManager; - - using android::hardware::details::getRawServiceInternal; - auto service = getRawServiceInternal(interface, instance, true /*retry*/, false /*getStub*/); - - if (service == nullptr) { - mLshal.err() << "Service not found (missing permissions or not in VINTF manifest?).\n"; - return NO_INTERFACE; - } - - return OK; -} - -void WaitCommand::usage() const { - static const std::string debug = - "wait:\n" - " lshal wait <interface/instance> \n" - " For a HAL that is on the device, wait for the HAL to start.\n" - " This will not start a HAL unless it is configured as a lazy HAL.\n" - " <interface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n" - " If instance name is missing `default` is used.\n"; - - mLshal.err() << debug; -} - -} // namespace lshal -} // namespace android - diff --git a/cmds/lshal/WaitCommand.h b/cmds/lshal/WaitCommand.h deleted file mode 100644 index c9f67c2b27..0000000000 --- a/cmds/lshal/WaitCommand.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2019 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 <string> - -#include <android-base/macros.h> - -#include "Command.h" -#include "utils.h" - -namespace android { -namespace lshal { - -class Lshal; - -class WaitCommand : public Command { -public: - explicit WaitCommand(Lshal &lshal) : Command(lshal) {} - ~WaitCommand() = default; - Status main(const Arg &arg) override; - void usage() const override; - std::string getSimpleDescription() const override; - std::string getName() const override; -private: - Status parseArgs(const Arg &arg); - - std::string mInterfaceName; - - DISALLOW_COPY_AND_ASSIGN(WaitCommand); -}; - - -} // namespace lshal -} // namespace android diff --git a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h index ca1e690694..7e864327af 100644 --- a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h +++ b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_ #include <sys/types.h> @@ -43,3 +44,5 @@ Partition getPartition(pid_t pid); } // namespace procpartition } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_ diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp index 3d550babf4..fc8d58b3d8 100644 --- a/cmds/lshal/test.cpp +++ b/cmds/lshal/test.cpp @@ -452,7 +452,7 @@ TEST_F(ListTest, Fetch) { } TEST_F(ListTest, DumpVintf) { - const std::string expected = "<manifest version=\"2.0\" type=\"device\">\n" + const std::string expected = "<manifest version=\"1.0\" type=\"device\">\n" " <hal format=\"hidl\">\n" " <name>a.h.foo1</name>\n" " <transport>hwbinder</transport>\n" @@ -493,19 +493,19 @@ TEST_F(ListTest, DumpVintf) { TEST_F(ListTest, DumpDefault) { const std::string expected = "[fake description 0]\n" - "VINTF R Interface Thread Use Server Clients\n" - "X N a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n" - "X Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n" + "R Interface Thread Use Server Clients\n" + "N a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n" + "Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n" "\n" "[fake description 1]\n" - "VINTF R Interface Thread Use Server Clients\n" - "X ? a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n" - "X ? a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n" + "R Interface Thread Use Server Clients\n" + "? a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n" + "? a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n" "\n" "[fake description 2]\n" - "VINTF R Interface Thread Use Server Clients\n" - "X ? a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n" - "X ? a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n" + "R Interface Thread Use Server Clients\n" + "? a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n" + "? a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n" "\n"; optind = 1; // mimic Lshal::parseArg() diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h index 04f52726e3..240155e4d0 100644 --- a/cmds/lshal/utils.h +++ b/cmds/lshal/utils.h @@ -14,7 +14,8 @@ * limitations under the License. */ -#pragma once +#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_ +#define FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_ #include <iomanip> #include <iostream> @@ -87,3 +88,5 @@ void replaceAll(std::string *s, char from, char to); } // namespace lshal } // namespace android + +#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_ diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp index a5b1ac5c5f..9513ec1c23 100644 --- a/cmds/service/Android.bp +++ b/cmds/service/Android.bp @@ -4,7 +4,6 @@ cc_binary { srcs: ["service.cpp"], shared_libs: [ - "libcutils", "libutils", "libbinder", ], @@ -23,7 +22,6 @@ cc_binary { srcs: ["service.cpp"], shared_libs: [ - "libcutils", "libutils", "libbinder", ], diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp index 18b6b58a9e..d5dc6b741d 100644 --- a/cmds/service/service.cpp +++ b/cmds/service/service.cpp @@ -18,18 +18,13 @@ #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <binder/TextOutput.h> -#include <cutils/ashmem.h> #include <getopt.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> -#include <sys/mman.h> #include <sys/time.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> using namespace android; @@ -75,7 +70,7 @@ int main(int argc, char* const argv[]) { bool wantsUsage = false; int result = 0; - + while (1) { int ic = getopt(argc, argv, "h?"); if (ic < 0) @@ -102,7 +97,7 @@ int main(int argc, char* const argv[]) aerr << "service: Unable to get default service manager!" << endl; return 20; } - + if (optind >= argc) { wantsUsage = true; } else if (!wantsUsage) { @@ -124,8 +119,8 @@ int main(int argc, char* const argv[]) for (unsigned i = 0; i < services.size(); i++) { String16 name = services[i]; sp<IBinder> service = sm->checkService(name); - aout << i - << "\t" << good_old_string(name) + aout << i + << "\t" << good_old_string(name) << ": [" << good_old_string(get_interface_name(service)) << "]" << endl; } @@ -192,120 +187,69 @@ int main(int argc, char* const argv[]) } else if (strcmp(argv[optind], "null") == 0) { optind++; data.writeStrongBinder(nullptr); - } else if (strcmp(argv[optind], "fd") == 0) { - optind++; - if (optind >= argc) { - aerr << "service: no path supplied for 'fd'" << endl; - wantsUsage = true; - result = 10; - break; - } - const char *path = argv[optind++]; - int fd = open(path, O_RDONLY); - if (fd < 0) { - aerr << "service: could not open '" << path << "'" << endl; - wantsUsage = true; - result = 10; - break; - } - data.writeFileDescriptor(fd, true /* take ownership */); - } else if (strcmp(argv[optind], "afd") == 0) { - optind++; - if (optind >= argc) { - aerr << "service: no path supplied for 'afd'" << endl; - wantsUsage = true; - result = 10; - break; - } - const char *path = argv[optind++]; - int fd = open(path, O_RDONLY); - struct stat statbuf; - if (fd < 0 || fstat(fd, &statbuf) != 0) { - aerr << "service: could not open or stat '" << path << "'" << endl; - wantsUsage = true; - result = 10; - break; - } - int afd = ashmem_create_region("test", statbuf.st_size); - void* ptr = mmap(NULL, statbuf.st_size, - PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0); - read(fd, ptr, statbuf.st_size); - close(fd); - data.writeFileDescriptor(afd, true /* take ownership */); - } else if (strcmp(argv[optind], "nfd") == 0) { - optind++; - if (optind >= argc) { - aerr << "service: no file descriptor supplied for 'nfd'" << endl; - wantsUsage = true; - result = 10; - break; - } - data.writeFileDescriptor( - atoi(argv[optind++]), true /* take ownership */); - } else if (strcmp(argv[optind], "intent") == 0) { - - char* action = nullptr; - char* dataArg = nullptr; - char* type = nullptr; - int launchFlags = 0; - char* component = nullptr; - int categoryCount = 0; - char* categories[16]; - - char* context1 = nullptr; - + + char* action = nullptr; + char* dataArg = nullptr; + char* type = nullptr; + int launchFlags = 0; + char* component = nullptr; + int categoryCount = 0; + char* categories[16]; + + char* context1 = nullptr; + optind++; - - while (optind < argc) - { - char* key = strtok_r(argv[optind], "=", &context1); - char* value = strtok_r(nullptr, "=", &context1); - + + while (optind < argc) + { + char* key = strtok_r(argv[optind], "=", &context1); + char* value = strtok_r(nullptr, "=", &context1); + // we have reached the end of the XXX=XXX args. if (key == nullptr) break; - - if (strcmp(key, "action") == 0) - { - action = value; - } - else if (strcmp(key, "data") == 0) - { - dataArg = value; - } - else if (strcmp(key, "type") == 0) - { - type = value; - } - else if (strcmp(key, "launchFlags") == 0) - { - launchFlags = atoi(value); - } - else if (strcmp(key, "component") == 0) - { - component = value; - } - else if (strcmp(key, "categories") == 0) - { - char* context2 = nullptr; - categories[categoryCount] = strtok_r(value, ",", &context2); - - while (categories[categoryCount] != nullptr) - { - categoryCount++; - categories[categoryCount] = strtok_r(nullptr, ",", &context2); - } - } - + + if (strcmp(key, "action") == 0) + { + action = value; + } + else if (strcmp(key, "data") == 0) + { + dataArg = value; + } + else if (strcmp(key, "type") == 0) + { + type = value; + } + else if (strcmp(key, "launchFlags") == 0) + { + launchFlags = atoi(value); + } + else if (strcmp(key, "component") == 0) + { + component = value; + } + else if (strcmp(key, "categories") == 0) + { + char* context2 = nullptr; + categories[categoryCount] = strtok_r(value, ",", &context2); + + while (categories[categoryCount] != nullptr) + { + categoryCount++; + categories[categoryCount] = strtok_r(nullptr, ",", &context2); + } + } + optind++; - } - + } + writeString16(data, action); writeString16(data, dataArg); writeString16(data, type); - data.writeInt32(launchFlags); + data.writeInt32(launchFlags); writeString16(data, component); - + if (categoryCount > 0) { data.writeInt32(categoryCount); @@ -317,10 +261,10 @@ int main(int argc, char* const argv[]) else { data.writeInt32(0); - } - + } + // for now just set the extra field to be null. - data.writeInt32(-1); + data.writeInt32(-1); } else { aerr << "service: unknown option " << argv[optind] << endl; wantsUsage = true; @@ -328,7 +272,7 @@ int main(int argc, char* const argv[]) break; } } - + service->transact(code, data, &reply); aout << "Result: " << reply << endl; } else { @@ -351,29 +295,23 @@ int main(int argc, char* const argv[]) result = 10; } } - + if (wantsUsage) { aout << "Usage: service [-h|-?]\n" " service list\n" " service check SERVICE\n" - " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null" - " | fd f | nfd n | afd f ] ...\n" + " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n" "Options:\n" " i32: Write the 32-bit integer N into the send parcel.\n" " i64: Write the 64-bit integer N into the send parcel.\n" " f: Write the 32-bit single-precision number N into the send parcel.\n" " d: Write the 64-bit double-precision number N into the send parcel.\n" - " s16: Write the UTF-16 string STR into the send parcel.\n" - " null: Write a null binder into the send parcel.\n" - " fd: Write a file descriptor for the file f to the send parcel.\n" - " nfd: Write file descriptor n to the send parcel.\n" - " afd: Write an ashmem file descriptor for a region containing the data from" - " file f to the send parcel.\n"; + " s16: Write the UTF-16 string STR into the send parcel.\n"; // " intent: Write and Intent int the send parcel. ARGS can be\n" // " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n"; return result; } - + return result; } diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp deleted file mode 100644 index b7e520f2f1..0000000000 --- a/cmds/servicemanager/Access.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2019 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 "Access.h" - -#include <android-base/logging.h> -#include <binder/IPCThreadState.h> -#include <log/log_safetynet.h> -#include <selinux/android.h> -#include <selinux/avc.h> - -namespace android { - -#ifdef VENDORSERVICEMANAGER -constexpr bool kIsVendor = true; -#else -constexpr bool kIsVendor = false; -#endif - -static std::string getPidcon(pid_t pid) { - android_errorWriteLog(0x534e4554, "121035042"); - - char* lookup = nullptr; - if (getpidcon(pid, &lookup) < 0) { - LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context"; - return ""; - } - std::string result = lookup; - freecon(lookup); - return result; -} - -static struct selabel_handle* getSehandle() { - static struct selabel_handle* gSehandle = nullptr; - - if (gSehandle != nullptr && selinux_status_updated()) { - selabel_close(gSehandle); - gSehandle = nullptr; - } - - if (gSehandle == nullptr) { - gSehandle = kIsVendor - ? selinux_android_vendor_service_context_handle() - : selinux_android_service_context_handle(); - } - - CHECK(gSehandle != nullptr); - return gSehandle; -} - -struct AuditCallbackData { - const Access::CallingContext* context; - const std::string* tname; -}; - -static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) { - const AuditCallbackData* ad = reinterpret_cast<AuditCallbackData*>(data); - - if (!ad) { - LOG(ERROR) << "No service manager audit data"; - return 0; - } - - snprintf(buf, len, "pid=%d uid=%d name=%s", ad->context->debugPid, ad->context->uid, - ad->tname->c_str()); - return 0; -} - -Access::Access() { - union selinux_callback cb; - - cb.func_audit = auditCallback; - selinux_set_callback(SELINUX_CB_AUDIT, cb); - - cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback; - selinux_set_callback(SELINUX_CB_LOG, cb); - - CHECK(selinux_status_open(true /*fallback*/) >= 0); - - CHECK(getcon(&mThisProcessContext) == 0); -} - -Access::~Access() { - freecon(mThisProcessContext); -} - -Access::CallingContext Access::getCallingContext() { - IPCThreadState* ipc = IPCThreadState::self(); - - const char* callingSid = ipc->getCallingSid(); - pid_t callingPid = ipc->getCallingPid(); - - return CallingContext { - .debugPid = callingPid, - .uid = ipc->getCallingUid(), - .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid), - }; -} - -bool Access::canFind(const CallingContext& ctx,const std::string& name) { - return actionAllowedFromLookup(ctx, name, "find"); -} - -bool Access::canAdd(const CallingContext& ctx, const std::string& name) { - return actionAllowedFromLookup(ctx, name, "add"); -} - -bool Access::canList(const CallingContext& ctx) { - return actionAllowed(ctx, mThisProcessContext, "list", "service_manager"); -} - -bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm, - const std::string& tname) { - const char* tclass = "service_manager"; - - AuditCallbackData data = { - .context = &sctx, - .tname = &tname, - }; - - return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, - reinterpret_cast<void*>(&data)); -} - -bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) { - char *tctx = nullptr; - if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) { - LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n"; - return false; - } - - bool allowed = actionAllowed(sctx, tctx, perm, name); - freecon(tctx); - return allowed; -} - -} // android diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h deleted file mode 100644 index 77c2cd4ed6..0000000000 --- a/cmds/servicemanager/Access.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2019 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 <string> -#include <sys/types.h> - -namespace android { - -// singleton -class Access { -public: - Access(); - virtual ~Access(); - - Access(const Access&) = delete; - Access& operator=(const Access&) = delete; - Access(Access&&) = delete; - Access& operator=(Access&&) = delete; - - struct CallingContext { - pid_t debugPid; - uid_t uid; - std::string sid; - }; - - virtual CallingContext getCallingContext(); - - virtual bool canFind(const CallingContext& ctx, const std::string& name); - virtual bool canAdd(const CallingContext& ctx, const std::string& name); - virtual bool canList(const CallingContext& ctx); - -private: - bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm, - const std::string& tname); - bool actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, - const char *perm); - - char* mThisProcessContext = nullptr; -}; - -}; diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 7277e85d99..428561bc8a 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -1,58 +1,51 @@ cc_defaults { - name: "servicemanager_defaults", + name: "servicemanager_flags", cflags: [ "-Wall", "-Wextra", "-Werror", ], + product_variables: { + binder32bit: { + cflags: ["-DBINDER_IPC_32BIT=1"], + }, + }, - srcs: [ - "Access.cpp", - "ServiceManager.cpp", - ], + shared_libs: ["liblog"], +} - shared_libs: [ - "libbase", - "libbinder", // also contains servicemanager_interface - "libvintf", - "libcutils", - "liblog", - "libutils", - "libselinux", +cc_binary { + name: "bctest", + defaults: ["servicemanager_flags"], + srcs: [ + "bctest.c", + "binder.c", ], - - target: { - vendor: { - exclude_shared_libs: ["libvintf"], - }, - }, } cc_binary { name: "servicemanager", - defaults: ["servicemanager_defaults"], + defaults: ["servicemanager_flags"], + srcs: [ + "service_manager.c", + "binder.c", + ], + shared_libs: ["libcutils", "libselinux"], init_rc: ["servicemanager.rc"], - srcs: ["main.cpp"], } cc_binary { name: "vndservicemanager", - defaults: ["servicemanager_defaults"], - init_rc: ["vndservicemanager.rc"], + defaults: ["servicemanager_flags"], vendor: true, + srcs: [ + "service_manager.c", + "binder.c", + ], cflags: [ "-DVENDORSERVICEMANAGER=1", ], - srcs: ["main.cpp"], -} - -cc_test { - name: "servicemanager_test", - test_suites: ["device-tests"], - defaults: ["servicemanager_defaults"], - srcs: [ - "test_sm.cpp", - ], - static_libs: ["libgmock"], + shared_libs: ["libcutils", "libselinux"], + init_rc: ["vndservicemanager.rc"], } diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp deleted file mode 100644 index 861401c979..0000000000 --- a/cmds/servicemanager/ServiceManager.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (C) 2019 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 "ServiceManager.h" - -#include <android-base/logging.h> -#include <android-base/properties.h> -#include <binder/Stability.h> -#include <cutils/android_filesystem_config.h> -#include <cutils/multiuser.h> -#include <thread> - -#ifndef VENDORSERVICEMANAGER -#include <vintf/VintfObject.h> -#include <vintf/constants.h> -#endif // !VENDORSERVICEMANAGER - -using ::android::binder::Status; -using ::android::internal::Stability; - -namespace android { - -#ifndef VENDORSERVICEMANAGER -static bool isVintfDeclared(const std::string& name) { - size_t firstSlash = name.find('/'); - size_t lastDot = name.rfind('.', firstSlash); - if (firstSlash == std::string::npos || lastDot == std::string::npos) { - LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. " - << "some.package.foo.IFoo/default) but got: " << name; - return false; - } - const std::string package = name.substr(0, lastDot); - const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1); - const std::string instance = name.substr(firstSlash+1); - - for (const auto& manifest : { - vintf::VintfObject::GetDeviceHalManifest(), - vintf::VintfObject::GetFrameworkHalManifest() - }) { - if (manifest != nullptr && manifest->hasAidlInstance(package, iface, instance)) { - return true; - } - } - LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance - << " in the VINTF manifest."; - return false; -} - -static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) { - if (!Stability::requiresVintfDeclaration(binder)) { - return true; - } - - return isVintfDeclared(name); -} -#endif // !VENDORSERVICEMANAGER - -ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {} -ServiceManager::~ServiceManager() { - // this should only happen in tests - - for (const auto& [name, callbacks] : mNameToCallback) { - CHECK(!callbacks.empty()) << name; - for (const auto& callback : callbacks) { - CHECK(callback != nullptr) << name; - } - } - - for (const auto& [name, service] : mNameToService) { - CHECK(service.binder != nullptr) << name; - } -} - -Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) { - *outBinder = tryGetService(name, true); - // returns ok regardless of result for legacy reasons - return Status::ok(); -} - -Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) { - *outBinder = tryGetService(name, false); - // returns ok regardless of result for legacy reasons - return Status::ok(); -} - -sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) { - auto ctx = mAccess->getCallingContext(); - - sp<IBinder> out; - if (auto it = mNameToService.find(name); it != mNameToService.end()) { - const Service& service = it->second; - - if (!service.allowIsolated) { - uid_t appid = multiuser_get_app_id(ctx.uid); - bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; - - if (isIsolated) { - return nullptr; - } - } - out = service.binder; - } - - if (!mAccess->canFind(ctx, name)) { - return nullptr; - } - - if (!out && startIfNotFound) { - tryStartService(name); - } - - return out; -} - -bool isValidServiceName(const std::string& name) { - if (name.size() == 0) return false; - if (name.size() > 127) return false; - - for (char c : name) { - if (c == '_' || c == '-' || c == '.' || c == '/') continue; - if (c >= 'a' && c <= 'z') continue; - if (c >= 'A' && c <= 'Z') continue; - if (c >= '0' && c <= '9') continue; - return false; - } - - return true; -} - -Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) { - auto ctx = mAccess->getCallingContext(); - - // apps cannot add services - if (multiuser_get_app_id(ctx.uid) >= AID_APP) { - return Status::fromExceptionCode(Status::EX_SECURITY); - } - - if (!mAccess->canAdd(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY); - } - - if (binder == nullptr) { - return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); - } - - if (!isValidServiceName(name)) { - LOG(ERROR) << "Invalid service name: " << name; - return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); - } - -#ifndef VENDORSERVICEMANAGER - if (!meetsDeclarationRequirements(binder, name)) { - // already logged - return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); - } -#endif // !VENDORSERVICEMANAGER - - // implicitly unlinked when the binder is removed - if (binder->remoteBinder() != nullptr && binder->linkToDeath(this) != OK) { - LOG(ERROR) << "Could not linkToDeath when adding " << name; - return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); - } - - mNameToService[name] = Service { - .binder = binder, - .allowIsolated = allowIsolated, - .dumpPriority = dumpPriority, - }; - - auto it = mNameToCallback.find(name); - if (it != mNameToCallback.end()) { - for (const sp<IServiceCallback>& cb : it->second) { - // permission checked in registerForNotifications - cb->onRegistration(name, binder); - } - } - - return Status::ok(); -} - -Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::string>* outList) { - if (!mAccess->canList(mAccess->getCallingContext())) { - return Status::fromExceptionCode(Status::EX_SECURITY); - } - - size_t toReserve = 0; - for (auto const& [name, service] : mNameToService) { - (void) name; - - if (service.dumpPriority & dumpPriority) ++toReserve; - } - - CHECK(outList->empty()); - - outList->reserve(toReserve); - for (auto const& [name, service] : mNameToService) { - (void) service; - - if (service.dumpPriority & dumpPriority) { - outList->push_back(name); - } - } - - return Status::ok(); -} - -Status ServiceManager::registerForNotifications( - const std::string& name, const sp<IServiceCallback>& callback) { - auto ctx = mAccess->getCallingContext(); - - if (!mAccess->canFind(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY); - } - - if (!isValidServiceName(name)) { - LOG(ERROR) << "Invalid service name: " << name; - return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); - } - - if (callback == nullptr) { - return Status::fromExceptionCode(Status::EX_NULL_POINTER); - } - - if (OK != IInterface::asBinder(callback)->linkToDeath(this)) { - LOG(ERROR) << "Could not linkToDeath when adding " << name; - return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); - } - - mNameToCallback[name].push_back(callback); - - if (auto it = mNameToService.find(name); it != mNameToService.end()) { - const sp<IBinder>& binder = it->second.binder; - - // never null if an entry exists - CHECK(binder != nullptr) << name; - callback->onRegistration(name, binder); - } - - return Status::ok(); -} -Status ServiceManager::unregisterForNotifications( - const std::string& name, const sp<IServiceCallback>& callback) { - auto ctx = mAccess->getCallingContext(); - - if (!mAccess->canFind(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY); - } - - bool found = false; - - auto it = mNameToCallback.find(name); - if (it != mNameToCallback.end()) { - removeCallback(IInterface::asBinder(callback), &it, &found); - } - - if (!found) { - LOG(ERROR) << "Trying to unregister callback, but none exists " << name; - return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); - } - - return Status::ok(); -} - -Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) { - auto ctx = mAccess->getCallingContext(); - - if (!mAccess->canFind(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY); - } - - *outReturn = false; - -#ifndef VENDORSERVICEMANAGER - *outReturn = isVintfDeclared(name); -#endif - return Status::ok(); -} - -void ServiceManager::removeCallback(const wp<IBinder>& who, - CallbackMap::iterator* it, - bool* found) { - std::vector<sp<IServiceCallback>>& listeners = (*it)->second; - - for (auto lit = listeners.begin(); lit != listeners.end();) { - if (IInterface::asBinder(*lit) == who) { - if(found) *found = true; - lit = listeners.erase(lit); - } else { - ++lit; - } - } - - if (listeners.empty()) { - *it = mNameToCallback.erase(*it); - } else { - it++; - } -} - -void ServiceManager::binderDied(const wp<IBinder>& who) { - for (auto it = mNameToService.begin(); it != mNameToService.end();) { - if (who == it->second.binder) { - it = mNameToService.erase(it); - } else { - ++it; - } - } - - for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) { - removeCallback(who, &it, nullptr /*found*/); - } -} - -void ServiceManager::tryStartService(const std::string& name) { - ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service", - name.c_str()); - - std::thread([=] { - (void)base::SetProperty("ctl.interface_start", "aidl/" + name); - }).detach(); -} - -} // namespace android diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h deleted file mode 100644 index 7dcdaa4661..0000000000 --- a/cmds/servicemanager/ServiceManager.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2019 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 <android/os/BnServiceManager.h> -#include <android/os/IServiceCallback.h> - -#include "Access.h" - -namespace android { - -using os::IServiceCallback; - -class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { -public: - ServiceManager(std::unique_ptr<Access>&& access); - ~ServiceManager(); - - // getService will try to start any services it cannot find - binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override; - binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override; - binder::Status addService(const std::string& name, const sp<IBinder>& binder, - bool allowIsolated, int32_t dumpPriority) override; - binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override; - binder::Status registerForNotifications(const std::string& name, - const sp<IServiceCallback>& callback) override; - binder::Status unregisterForNotifications(const std::string& name, - const sp<IServiceCallback>& callback) override; - binder::Status isDeclared(const std::string& name, bool* outReturn) override; - - void binderDied(const wp<IBinder>& who) override; - -protected: - virtual void tryStartService(const std::string& name); - -private: - struct Service { - sp<IBinder> binder; // not null - bool allowIsolated; - int32_t dumpPriority; - }; - - using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>; - using ServiceMap = std::map<std::string, Service>; - - // removes a callback from mNameToCallback, removing it if the vector is empty - // this updates iterator to the next location - void removeCallback(const wp<IBinder>& who, - CallbackMap::iterator* it, - bool* found); - sp<IBinder> tryGetService(const std::string& name, bool startIfNotFound); - - CallbackMap mNameToCallback; - ServiceMap mNameToService; - - std::unique_ptr<Access> mAccess; -}; - -} // namespace android diff --git a/cmds/servicemanager/TEST_MAPPING b/cmds/servicemanager/TEST_MAPPING deleted file mode 100644 index 739740aa21..0000000000 --- a/cmds/servicemanager/TEST_MAPPING +++ /dev/null @@ -1,12 +0,0 @@ -{ - "presubmit": [ - { - "name": "servicemanager_test" - } - ], - "imports": [ - { - "path": "frameworks/native/libs/binder" - } - ] -} diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c new file mode 100644 index 0000000000..354df670e5 --- /dev/null +++ b/cmds/servicemanager/bctest.c @@ -0,0 +1,107 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "binder.h" + +uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) +{ + uint32_t handle; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bio_init(&msg, iodata, sizeof(iodata), 4); + bio_put_uint32(&msg, 0); // strict mode header + bio_put_string16_x(&msg, SVC_MGR_NAME); + bio_put_string16_x(&msg, name); + + if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) + return 0; + + handle = bio_get_ref(&reply); + + if (handle) + binder_acquire(bs, handle); + + binder_done(bs, &msg, &reply); + + return handle; +} + +int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) +{ + int status; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bio_init(&msg, iodata, sizeof(iodata), 4); + bio_put_uint32(&msg, 0); // strict mode header + bio_put_string16_x(&msg, SVC_MGR_NAME); + bio_put_string16_x(&msg, name); + bio_put_obj(&msg, ptr); + + if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) + return -1; + + status = bio_get_uint32(&reply); + + binder_done(bs, &msg, &reply); + + return status; +} + +unsigned token; + +int main(int argc, char **argv) +{ + struct binder_state *bs; + uint32_t svcmgr = BINDER_SERVICE_MANAGER; + uint32_t handle; + + bs = binder_open("/dev/binder", 128*1024); + if (!bs) { + fprintf(stderr, "failed to open binder driver\n"); + return -1; + } + + argc--; + argv++; + while (argc > 0) { + if (!strcmp(argv[0],"alt")) { + handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); + if (!handle) { + fprintf(stderr,"cannot find alt_svc_mgr\n"); + return -1; + } + svcmgr = handle; + fprintf(stderr,"svcmgr is via %x\n", handle); + } else if (!strcmp(argv[0],"lookup")) { + if (argc < 2) { + fprintf(stderr,"argument required\n"); + return -1; + } + handle = svcmgr_lookup(bs, svcmgr, argv[1]); + fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle); + argc--; + argv++; + } else if (!strcmp(argv[0],"publish")) { + if (argc < 2) { + fprintf(stderr,"argument required\n"); + return -1; + } + svcmgr_publish(bs, svcmgr, argv[1], &token); + argc--; + argv++; + } else { + fprintf(stderr,"unknown command %s\n", argv[0]); + return -1; + } + argc--; + argv++; + } + return 0; +} diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c new file mode 100644 index 0000000000..cf3b1728b6 --- /dev/null +++ b/cmds/servicemanager/binder.c @@ -0,0 +1,682 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#define LOG_TAG "Binder" + +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> + +#include <log/log.h> + +#include "binder.h" + +#define MAX_BIO_SIZE (1 << 30) + +#define TRACE 0 + +void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn); + +#if TRACE +void hexdump(void *_data, size_t len) +{ + unsigned char *data = _data; + size_t count; + + for (count = 0; count < len; count++) { + if ((count & 15) == 0) + fprintf(stderr,"%04zu:", count); + fprintf(stderr," %02x %c", *data, + (*data < 32) || (*data > 126) ? '.' : *data); + data++; + if ((count & 15) == 15) + fprintf(stderr,"\n"); + } + if ((count & 15) != 0) + fprintf(stderr,"\n"); +} + +void binder_dump_txn(struct binder_transaction_data *txn) +{ + struct flat_binder_object *obj; + binder_size_t *offs = (binder_size_t *)(uintptr_t)txn->data.ptr.offsets; + size_t count = txn->offsets_size / sizeof(binder_size_t); + + fprintf(stderr," target %016"PRIx64" cookie %016"PRIx64" code %08x flags %08x\n", + (uint64_t)txn->target.ptr, (uint64_t)txn->cookie, txn->code, txn->flags); + fprintf(stderr," pid %8d uid %8d data %"PRIu64" offs %"PRIu64"\n", + txn->sender_pid, txn->sender_euid, (uint64_t)txn->data_size, (uint64_t)txn->offsets_size); + hexdump((void *)(uintptr_t)txn->data.ptr.buffer, txn->data_size); + while (count--) { + obj = (struct flat_binder_object *) (((char*)(uintptr_t)txn->data.ptr.buffer) + *offs++); + fprintf(stderr," - type %08x flags %08x ptr %016"PRIx64" cookie %016"PRIx64"\n", + obj->type, obj->flags, (uint64_t)obj->binder, (uint64_t)obj->cookie); + } +} + +#define NAME(n) case n: return #n +const char *cmd_name(uint32_t cmd) +{ + switch(cmd) { + NAME(BR_NOOP); + NAME(BR_TRANSACTION_COMPLETE); + NAME(BR_INCREFS); + NAME(BR_ACQUIRE); + NAME(BR_RELEASE); + NAME(BR_DECREFS); + NAME(BR_TRANSACTION); + NAME(BR_REPLY); + NAME(BR_FAILED_REPLY); + NAME(BR_DEAD_REPLY); + NAME(BR_DEAD_BINDER); + default: return "???"; + } +} +#else +#define hexdump(a,b) do{} while (0) +#define binder_dump_txn(txn) do{} while (0) +#endif + +#define BIO_F_SHARED 0x01 /* needs to be buffer freed */ +#define BIO_F_OVERFLOW 0x02 /* ran out of space */ +#define BIO_F_IOERROR 0x04 +#define BIO_F_MALLOCED 0x08 /* needs to be free()'d */ + +struct binder_state +{ + int fd; + void *mapped; + size_t mapsize; +}; + +struct binder_state *binder_open(const char* driver, size_t mapsize) +{ + struct binder_state *bs; + struct binder_version vers; + + bs = malloc(sizeof(*bs)); + if (!bs) { + errno = ENOMEM; + return NULL; + } + + bs->fd = open(driver, O_RDWR | O_CLOEXEC); + if (bs->fd < 0) { + fprintf(stderr,"binder: cannot open %s (%s)\n", + driver, strerror(errno)); + goto fail_open; + } + + if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || + (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { + fprintf(stderr, + "binder: kernel driver version (%d) differs from user space version (%d)\n", + vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); + goto fail_open; + } + + bs->mapsize = mapsize; + bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); + if (bs->mapped == MAP_FAILED) { + fprintf(stderr,"binder: cannot map device (%s)\n", + strerror(errno)); + goto fail_map; + } + + return bs; + +fail_map: + close(bs->fd); +fail_open: + free(bs); + return NULL; +} + +void binder_close(struct binder_state *bs) +{ + munmap(bs->mapped, bs->mapsize); + close(bs->fd); + free(bs); +} + +int binder_become_context_manager(struct binder_state *bs) +{ + struct flat_binder_object obj; + memset(&obj, 0, sizeof(obj)); + obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX; + + int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj); + + // fallback to original method + if (result != 0) { + android_errorWriteLog(0x534e4554, "121035042"); + + result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); + } + return result; +} + +int binder_write(struct binder_state *bs, void *data, size_t len) +{ + struct binder_write_read bwr; + int res; + + bwr.write_size = len; + bwr.write_consumed = 0; + bwr.write_buffer = (uintptr_t) data; + bwr.read_size = 0; + bwr.read_consumed = 0; + bwr.read_buffer = 0; + res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); + if (res < 0) { + fprintf(stderr,"binder_write: ioctl failed (%s)\n", + strerror(errno)); + } + return res; +} + +void binder_free_buffer(struct binder_state *bs, + binder_uintptr_t buffer_to_free) +{ + struct { + uint32_t cmd_free; + binder_uintptr_t buffer; + } __attribute__((packed)) data; + data.cmd_free = BC_FREE_BUFFER; + data.buffer = buffer_to_free; + binder_write(bs, &data, sizeof(data)); +} + +void binder_send_reply(struct binder_state *bs, + struct binder_io *reply, + binder_uintptr_t buffer_to_free, + int status) +{ + struct { + uint32_t cmd_free; + binder_uintptr_t buffer; + uint32_t cmd_reply; + struct binder_transaction_data txn; + } __attribute__((packed)) data; + + data.cmd_free = BC_FREE_BUFFER; + data.buffer = buffer_to_free; + data.cmd_reply = BC_REPLY; + data.txn.target.ptr = 0; + data.txn.cookie = 0; + data.txn.code = 0; + if (status) { + data.txn.flags = TF_STATUS_CODE; + data.txn.data_size = sizeof(int); + data.txn.offsets_size = 0; + data.txn.data.ptr.buffer = (uintptr_t)&status; + data.txn.data.ptr.offsets = 0; + } else { + data.txn.flags = 0; + data.txn.data_size = reply->data - reply->data0; + data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0); + data.txn.data.ptr.buffer = (uintptr_t)reply->data0; + data.txn.data.ptr.offsets = (uintptr_t)reply->offs0; + } + binder_write(bs, &data, sizeof(data)); +} + +int binder_parse(struct binder_state *bs, struct binder_io *bio, + uintptr_t ptr, size_t size, binder_handler func) +{ + int r = 1; + uintptr_t end = ptr + (uintptr_t) size; + + while (ptr < end) { + uint32_t cmd = *(uint32_t *) ptr; + ptr += sizeof(uint32_t); +#if TRACE + fprintf(stderr,"%s:\n", cmd_name(cmd)); +#endif + switch(cmd) { + case BR_NOOP: + break; + case BR_TRANSACTION_COMPLETE: + break; + case BR_INCREFS: + case BR_ACQUIRE: + case BR_RELEASE: + case BR_DECREFS: +#if TRACE + fprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *))); +#endif + ptr += sizeof(struct binder_ptr_cookie); + break; + case BR_TRANSACTION_SEC_CTX: + case BR_TRANSACTION: { + struct binder_transaction_data_secctx txn; + if (cmd == BR_TRANSACTION_SEC_CTX) { + if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) { + ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n"); + return -1; + } + memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx)); + ptr += sizeof(struct binder_transaction_data_secctx); + } else /* BR_TRANSACTION */ { + if ((end - ptr) < sizeof(struct binder_transaction_data)) { + ALOGE("parse: txn too small (binder_transaction_data)!\n"); + return -1; + } + memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data)); + ptr += sizeof(struct binder_transaction_data); + + txn.secctx = 0; + } + + binder_dump_txn(&txn.transaction_data); + if (func) { + unsigned rdata[256/4]; + struct binder_io msg; + struct binder_io reply; + int res; + + bio_init(&reply, rdata, sizeof(rdata), 4); + bio_init_from_txn(&msg, &txn.transaction_data); + res = func(bs, &txn, &msg, &reply); + if (txn.transaction_data.flags & TF_ONE_WAY) { + binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer); + } else { + binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res); + } + } + break; + } + case BR_REPLY: { + struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr; + if ((end - ptr) < sizeof(*txn)) { + ALOGE("parse: reply too small!\n"); + return -1; + } + binder_dump_txn(txn); + if (bio) { + bio_init_from_txn(bio, txn); + bio = 0; + } else { + /* todo FREE BUFFER */ + } + ptr += sizeof(*txn); + r = 0; + break; + } + case BR_DEAD_BINDER: { + struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr; + ptr += sizeof(binder_uintptr_t); + death->func(bs, death->ptr); + break; + } + case BR_FAILED_REPLY: + r = -1; + break; + case BR_DEAD_REPLY: + r = -1; + break; + default: + ALOGE("parse: OOPS %d\n", cmd); + return -1; + } + } + + return r; +} + +void binder_acquire(struct binder_state *bs, uint32_t target) +{ + uint32_t cmd[2]; + cmd[0] = BC_ACQUIRE; + cmd[1] = target; + binder_write(bs, cmd, sizeof(cmd)); +} + +void binder_release(struct binder_state *bs, uint32_t target) +{ + uint32_t cmd[2]; + cmd[0] = BC_RELEASE; + cmd[1] = target; + binder_write(bs, cmd, sizeof(cmd)); +} + +void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death) +{ + struct { + uint32_t cmd; + struct binder_handle_cookie payload; + } __attribute__((packed)) data; + + data.cmd = BC_REQUEST_DEATH_NOTIFICATION; + data.payload.handle = target; + data.payload.cookie = (uintptr_t) death; + binder_write(bs, &data, sizeof(data)); +} + +int binder_call(struct binder_state *bs, + struct binder_io *msg, struct binder_io *reply, + uint32_t target, uint32_t code) +{ + int res; + struct binder_write_read bwr; + struct { + uint32_t cmd; + struct binder_transaction_data txn; + } __attribute__((packed)) writebuf; + unsigned readbuf[32]; + + if (msg->flags & BIO_F_OVERFLOW) { + fprintf(stderr,"binder: txn buffer overflow\n"); + goto fail; + } + + writebuf.cmd = BC_TRANSACTION; + writebuf.txn.target.handle = target; + writebuf.txn.code = code; + writebuf.txn.flags = 0; + writebuf.txn.data_size = msg->data - msg->data0; + writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0); + writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0; + writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0; + + bwr.write_size = sizeof(writebuf); + bwr.write_consumed = 0; + bwr.write_buffer = (uintptr_t) &writebuf; + + hexdump(msg->data0, msg->data - msg->data0); + for (;;) { + bwr.read_size = sizeof(readbuf); + bwr.read_consumed = 0; + bwr.read_buffer = (uintptr_t) readbuf; + + res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); + + if (res < 0) { + fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); + goto fail; + } + + res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); + if (res == 0) return 0; + if (res < 0) goto fail; + } + +fail: + memset(reply, 0, sizeof(*reply)); + reply->flags |= BIO_F_IOERROR; + return -1; +} + +void binder_loop(struct binder_state *bs, binder_handler func) +{ + int res; + struct binder_write_read bwr; + uint32_t readbuf[32]; + + bwr.write_size = 0; + bwr.write_consumed = 0; + bwr.write_buffer = 0; + + readbuf[0] = BC_ENTER_LOOPER; + binder_write(bs, readbuf, sizeof(uint32_t)); + + for (;;) { + bwr.read_size = sizeof(readbuf); + bwr.read_consumed = 0; + bwr.read_buffer = (uintptr_t) readbuf; + + res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); + + if (res < 0) { + ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); + break; + } + + res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); + if (res == 0) { + ALOGE("binder_loop: unexpected reply?!\n"); + break; + } + if (res < 0) { + ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); + break; + } + } +} + +void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn) +{ + bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer; + bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets; + bio->data_avail = txn->data_size; + bio->offs_avail = txn->offsets_size / sizeof(size_t); + bio->flags = BIO_F_SHARED; +} + +void bio_init(struct binder_io *bio, void *data, + size_t maxdata, size_t maxoffs) +{ + size_t n = maxoffs * sizeof(size_t); + + if (n > maxdata) { + bio->flags = BIO_F_OVERFLOW; + bio->data_avail = 0; + bio->offs_avail = 0; + return; + } + + bio->data = bio->data0 = (char *) data + n; + bio->offs = bio->offs0 = data; + bio->data_avail = maxdata - n; + bio->offs_avail = maxoffs; + bio->flags = 0; +} + +static void *bio_alloc(struct binder_io *bio, size_t size) +{ + size = (size + 3) & (~3); + if (size > bio->data_avail) { + bio->flags |= BIO_F_OVERFLOW; + return NULL; + } else { + void *ptr = bio->data; + bio->data += size; + bio->data_avail -= size; + return ptr; + } +} + +void binder_done(struct binder_state *bs, + __unused struct binder_io *msg, + struct binder_io *reply) +{ + struct { + uint32_t cmd; + uintptr_t buffer; + } __attribute__((packed)) data; + + if (reply->flags & BIO_F_SHARED) { + data.cmd = BC_FREE_BUFFER; + data.buffer = (uintptr_t) reply->data0; + binder_write(bs, &data, sizeof(data)); + reply->flags = 0; + } +} + +static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio) +{ + struct flat_binder_object *obj; + + obj = bio_alloc(bio, sizeof(*obj)); + + if (obj && bio->offs_avail) { + bio->offs_avail--; + *bio->offs++ = ((char*) obj) - ((char*) bio->data0); + return obj; + } + + bio->flags |= BIO_F_OVERFLOW; + return NULL; +} + +void bio_put_uint32(struct binder_io *bio, uint32_t n) +{ + uint32_t *ptr = bio_alloc(bio, sizeof(n)); + if (ptr) + *ptr = n; +} + +void bio_put_obj(struct binder_io *bio, void *ptr) +{ + struct flat_binder_object *obj; + + obj = bio_alloc_obj(bio); + if (!obj) + return; + + obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; + obj->hdr.type = BINDER_TYPE_BINDER; + obj->binder = (uintptr_t)ptr; + obj->cookie = 0; +} + +void bio_put_ref(struct binder_io *bio, uint32_t handle) +{ + struct flat_binder_object *obj; + + if (handle) + obj = bio_alloc_obj(bio); + else + obj = bio_alloc(bio, sizeof(*obj)); + + if (!obj) + return; + + obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; + obj->hdr.type = BINDER_TYPE_HANDLE; + obj->handle = handle; + obj->cookie = 0; +} + +void bio_put_string16(struct binder_io *bio, const uint16_t *str) +{ + size_t len; + uint16_t *ptr; + + if (!str) { + bio_put_uint32(bio, 0xffffffff); + return; + } + + len = 0; + while (str[len]) len++; + + if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { + bio_put_uint32(bio, 0xffffffff); + return; + } + + /* Note: The payload will carry 32bit size instead of size_t */ + bio_put_uint32(bio, (uint32_t) len); + len = (len + 1) * sizeof(uint16_t); + ptr = bio_alloc(bio, len); + if (ptr) + memcpy(ptr, str, len); +} + +void bio_put_string16_x(struct binder_io *bio, const char *_str) +{ + unsigned char *str = (unsigned char*) _str; + size_t len; + uint16_t *ptr; + + if (!str) { + bio_put_uint32(bio, 0xffffffff); + return; + } + + len = strlen(_str); + + if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { + bio_put_uint32(bio, 0xffffffff); + return; + } + + /* Note: The payload will carry 32bit size instead of size_t */ + bio_put_uint32(bio, len); + ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t)); + if (!ptr) + return; + + while (*str) + *ptr++ = *str++; + *ptr++ = 0; +} + +static void *bio_get(struct binder_io *bio, size_t size) +{ + size = (size + 3) & (~3); + + if (bio->data_avail < size){ + bio->data_avail = 0; + bio->flags |= BIO_F_OVERFLOW; + return NULL; + } else { + void *ptr = bio->data; + bio->data += size; + bio->data_avail -= size; + return ptr; + } +} + +uint32_t bio_get_uint32(struct binder_io *bio) +{ + uint32_t *ptr = bio_get(bio, sizeof(*ptr)); + return ptr ? *ptr : 0; +} + +uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz) +{ + size_t len; + + /* Note: The payload will carry 32bit size instead of size_t */ + len = (size_t) bio_get_uint32(bio); + if (sz) + *sz = len; + return bio_get(bio, (len + 1) * sizeof(uint16_t)); +} + +static struct flat_binder_object *_bio_get_obj(struct binder_io *bio) +{ + size_t n; + size_t off = bio->data - bio->data0; + + /* TODO: be smarter about this? */ + for (n = 0; n < bio->offs_avail; n++) { + if (bio->offs[n] == off) + return bio_get(bio, sizeof(struct flat_binder_object)); + } + + bio->data_avail = 0; + bio->flags |= BIO_F_OVERFLOW; + return NULL; +} + +uint32_t bio_get_ref(struct binder_io *bio) +{ + struct flat_binder_object *obj; + + obj = _bio_get_obj(bio); + if (!obj) + return 0; + + if (obj->hdr.type == BINDER_TYPE_HANDLE) + return obj->handle; + + return 0; +} diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h new file mode 100644 index 0000000000..a9ccc74130 --- /dev/null +++ b/cmds/servicemanager/binder.h @@ -0,0 +1,94 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#ifndef _BINDER_H_ +#define _BINDER_H_ + +#include <linux/android/binder.h> +#include <sys/ioctl.h> + +struct binder_state; + +struct binder_io +{ + char *data; /* pointer to read/write from */ + binder_size_t *offs; /* array of offsets */ + size_t data_avail; /* bytes available in data buffer */ + size_t offs_avail; /* entries available in offsets array */ + + char *data0; /* start of data buffer */ + binder_size_t *offs0; /* start of offsets buffer */ + uint32_t flags; + uint32_t unused; +}; + +struct binder_death { + void (*func)(struct binder_state *bs, void *ptr); + void *ptr; +}; + +/* the one magic handle */ +#define BINDER_SERVICE_MANAGER 0U + +#define SVC_MGR_NAME "android.os.IServiceManager" + +enum { + /* Must match definitions in IBinder.h and IServiceManager.h */ + PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), + SVC_MGR_GET_SERVICE = 1, + SVC_MGR_CHECK_SERVICE, + SVC_MGR_ADD_SERVICE, + SVC_MGR_LIST_SERVICES, +}; + +typedef int (*binder_handler)(struct binder_state *bs, + struct binder_transaction_data_secctx *txn, + struct binder_io *msg, + struct binder_io *reply); + +struct binder_state *binder_open(const char* driver, size_t mapsize); +void binder_close(struct binder_state *bs); + +/* initiate a blocking binder call + * - returns zero on success + */ +int binder_call(struct binder_state *bs, + struct binder_io *msg, struct binder_io *reply, + uint32_t target, uint32_t code); + +/* release any state associate with the binder_io + * - call once any necessary data has been extracted from the + * binder_io after binder_call() returns + * - can safely be called even if binder_call() fails + */ +void binder_done(struct binder_state *bs, + struct binder_io *msg, struct binder_io *reply); + +/* manipulate strong references */ +void binder_acquire(struct binder_state *bs, uint32_t target); +void binder_release(struct binder_state *bs, uint32_t target); + +void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death); + +void binder_loop(struct binder_state *bs, binder_handler func); + +int binder_become_context_manager(struct binder_state *bs); + +/* allocate a binder_io, providing a stack-allocated working + * buffer, size of the working buffer, and how many object + * offset entries to reserve from the buffer + */ +void bio_init(struct binder_io *bio, void *data, + size_t maxdata, size_t maxobjects); + +void bio_put_obj(struct binder_io *bio, void *ptr); +void bio_put_ref(struct binder_io *bio, uint32_t handle); +void bio_put_uint32(struct binder_io *bio, uint32_t n); +void bio_put_string16(struct binder_io *bio, const uint16_t *str); +void bio_put_string16_x(struct binder_io *bio, const char *_str); + +uint32_t bio_get_uint32(struct binder_io *bio); +uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz); +uint32_t bio_get_ref(struct binder_io *bio); + +#endif diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp deleted file mode 100644 index 4b12fc6e72..0000000000 --- a/cmds/servicemanager/main.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <android-base/logging.h> -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <binder/Status.h> -#include <utils/StrongPointer.h> - -#include "Access.h" -#include "ServiceManager.h" - -using ::android::Access; -using ::android::IPCThreadState; -using ::android::ProcessState; -using ::android::ServiceManager; -using ::android::os::IServiceManager; -using ::android::sp; - -int main(int argc, char** argv) { - if (argc > 2) { - LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; - } - - const char* driver = argc == 2 ? argv[1] : "/dev/binder"; - - sp<ProcessState> ps = ProcessState::initWithDriver(driver); - ps->setThreadPoolMaxThreadCount(0); - ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); - - sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>()); - if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) { - LOG(ERROR) << "Could not self register servicemanager"; - } - - IPCThreadState::self()->setTheContextObject(manager); - ps->becomeContextManager(nullptr, nullptr); - - IPCThreadState::self()->joinThreadPool(); - - // should not be reached - return EXIT_FAILURE; -} diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c new file mode 100644 index 0000000000..ec3fac538d --- /dev/null +++ b/cmds/servicemanager/service_manager.c @@ -0,0 +1,442 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <cutils/android_filesystem_config.h> +#include <cutils/multiuser.h> + +#include <selinux/android.h> +#include <selinux/avc.h> + +#include "binder.h" + +#ifdef VENDORSERVICEMANAGER +#define LOG_TAG "VendorServiceManager" +#else +#define LOG_TAG "ServiceManager" +#endif +#include <log/log.h> + +struct audit_data { + pid_t pid; + uid_t uid; + const char *name; +}; + +const char *str8(const uint16_t *x, size_t x_len) +{ + static char buf[128]; + size_t max = 127; + char *p = buf; + + if (x_len < max) { + max = x_len; + } + + if (x) { + while ((max > 0) && (*x != '\0')) { + *p++ = *x++; + max--; + } + } + *p++ = 0; + return buf; +} + +int str16eq(const uint16_t *a, const char *b) +{ + while (*a && *b) + if (*a++ != *b++) return 0; + if (*a || *b) + return 0; + return 1; +} + +static char *service_manager_context; +static struct selabel_handle* sehandle; + +static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name) +{ + char *lookup_sid = NULL; + const char *class = "service_manager"; + bool allowed; + struct audit_data ad; + + if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) { + ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); + return false; + } + + ad.pid = spid; + ad.uid = uid; + ad.name = name; + + if (sid == NULL) { + android_errorWriteLog(0x534e4554, "121035042"); + } + + int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad); + allowed = (result == 0); + + freecon(lookup_sid); + return allowed; +} + +static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm) +{ + return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL); +} + +static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name) +{ + bool allowed; + char *tctx = NULL; + + if (!sehandle) { + ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); + abort(); + } + + if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { + ALOGE("SELinux: No match for %s in service_contexts.\n", name); + return false; + } + + allowed = check_mac_perms(spid, sid, uid, tctx, perm, name); + freecon(tctx); + return allowed; +} + +static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) +{ + const char *perm = "add"; + + if (multiuser_get_app_id(uid) >= AID_APP) { + return 0; /* Don't allow apps to register services */ + } + + return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; +} + +static int svc_can_list(pid_t spid, const char* sid, uid_t uid) +{ + const char *perm = "list"; + return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0; +} + +static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) +{ + const char *perm = "find"; + return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; +} + +struct svcinfo +{ + struct svcinfo *next; + uint32_t handle; + struct binder_death death; + int allow_isolated; + uint32_t dumpsys_priority; + size_t len; + uint16_t name[0]; +}; + +struct svcinfo *svclist = NULL; + +struct svcinfo *find_svc(const uint16_t *s16, size_t len) +{ + struct svcinfo *si; + + for (si = svclist; si; si = si->next) { + if ((len == si->len) && + !memcmp(s16, si->name, len * sizeof(uint16_t))) { + return si; + } + } + return NULL; +} + +void svcinfo_death(struct binder_state *bs, void *ptr) +{ + struct svcinfo *si = (struct svcinfo* ) ptr; + + ALOGI("service '%s' died\n", str8(si->name, si->len)); + if (si->handle) { + binder_release(bs, si->handle); + si->handle = 0; + } +} + +uint16_t svcmgr_id[] = { + 'a','n','d','r','o','i','d','.','o','s','.', + 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' +}; + + +uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid) +{ + struct svcinfo *si = find_svc(s, len); + + if (!si || !si->handle) { + return 0; + } + + if (!si->allow_isolated) { + // If this service doesn't allow access from isolated processes, + // then check the uid to see if it is isolated. + uid_t appid = uid % AID_USER; + if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { + return 0; + } + } + + if (!svc_can_find(s, len, spid, sid, uid)) { + return 0; + } + + return si->handle; +} + +int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, + uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) { + struct svcinfo *si; + + //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, + // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); + + if (!handle || (len == 0) || (len > 127)) + return -1; + + if (!svc_can_register(s, len, spid, sid, uid)) { + ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", + str8(s, len), handle, uid); + return -1; + } + + si = find_svc(s, len); + if (si) { + if (si->handle) { + ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", + str8(s, len), handle, uid); + svcinfo_death(bs, si); + } + si->handle = handle; + } else { + si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); + if (!si) { + ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", + str8(s, len), handle, uid); + return -1; + } + si->handle = handle; + si->len = len; + memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); + si->name[len] = '\0'; + si->death.func = (void*) svcinfo_death; + si->death.ptr = si; + si->allow_isolated = allow_isolated; + si->dumpsys_priority = dumpsys_priority; + si->next = svclist; + svclist = si; + } + + binder_acquire(bs, handle); + binder_link_to_death(bs, handle, &si->death); + return 0; +} + +int svcmgr_handler(struct binder_state *bs, + struct binder_transaction_data_secctx *txn_secctx, + struct binder_io *msg, + struct binder_io *reply) +{ + struct svcinfo *si; + uint16_t *s; + size_t len; + uint32_t handle; + uint32_t strict_policy; + int allow_isolated; + uint32_t dumpsys_priority; + + struct binder_transaction_data *txn = &txn_secctx->transaction_data; + + //ALOGI("target=%p code=%d pid=%d uid=%d\n", + // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); + + if (txn->target.ptr != BINDER_SERVICE_MANAGER) + return -1; + + if (txn->code == PING_TRANSACTION) + return 0; + + // Equivalent to Parcel::enforceInterface(), reading the RPC + // header with the strict mode policy mask and the interface name. + // Note that we ignore the strict_policy and don't propagate it + // further (since we do no outbound RPCs anyway). + strict_policy = bio_get_uint32(msg); + bio_get_uint32(msg); // Ignore worksource header. + s = bio_get_string16(msg, &len); + if (s == NULL) { + return -1; + } + + if ((len != (sizeof(svcmgr_id) / 2)) || + memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { + fprintf(stderr,"invalid id %s\n", str8(s, len)); + return -1; + } + + if (sehandle && selinux_status_updated() > 0) { +#ifdef VENDORSERVICEMANAGER + struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle(); +#else + struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle(); +#endif + if (tmp_sehandle) { + selabel_close(sehandle); + sehandle = tmp_sehandle; + } + } + + switch(txn->code) { + case SVC_MGR_GET_SERVICE: + case SVC_MGR_CHECK_SERVICE: + s = bio_get_string16(msg, &len); + if (s == NULL) { + return -1; + } + handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid, + (const char*) txn_secctx->secctx); + if (!handle) + break; + bio_put_ref(reply, handle); + return 0; + + case SVC_MGR_ADD_SERVICE: + s = bio_get_string16(msg, &len); + if (s == NULL) { + return -1; + } + handle = bio_get_ref(msg); + allow_isolated = bio_get_uint32(msg) ? 1 : 0; + dumpsys_priority = bio_get_uint32(msg); + if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, + txn->sender_pid, (const char*) txn_secctx->secctx)) + return -1; + break; + + case SVC_MGR_LIST_SERVICES: { + uint32_t n = bio_get_uint32(msg); + uint32_t req_dumpsys_priority = bio_get_uint32(msg); + + if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) { + ALOGE("list_service() uid=%d - PERMISSION DENIED\n", + txn->sender_euid); + return -1; + } + si = svclist; + // walk through the list of services n times skipping services that + // do not support the requested priority + while (si) { + if (si->dumpsys_priority & req_dumpsys_priority) { + if (n == 0) break; + n--; + } + si = si->next; + } + if (si) { + bio_put_string16(reply, si->name); + return 0; + } + return -1; + } + default: + ALOGE("unknown code %d\n", txn->code); + return -1; + } + + bio_put_uint32(reply, 0); + return 0; +} + + +static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len) +{ + struct audit_data *ad = (struct audit_data *)data; + + if (!ad || !ad->name) { + ALOGE("No service manager audit data"); + return 0; + } + + snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid); + return 0; +} + +int main(int argc, char** argv) +{ + struct binder_state *bs; + union selinux_callback cb; + char *driver; + + if (argc > 1) { + driver = argv[1]; + } else { + driver = "/dev/binder"; + } + + bs = binder_open(driver, 128*1024); + if (!bs) { +#ifdef VENDORSERVICEMANAGER + ALOGW("failed to open binder driver %s\n", driver); + while (true) { + sleep(UINT_MAX); + } +#else + ALOGE("failed to open binder driver %s\n", driver); +#endif + return -1; + } + + if (binder_become_context_manager(bs)) { + ALOGE("cannot become context manager (%s)\n", strerror(errno)); + return -1; + } + + cb.func_audit = audit_callback; + selinux_set_callback(SELINUX_CB_AUDIT, cb); +#ifdef VENDORSERVICEMANAGER + cb.func_log = selinux_vendor_log_callback; +#else + cb.func_log = selinux_log_callback; +#endif + selinux_set_callback(SELINUX_CB_LOG, cb); + +#ifdef VENDORSERVICEMANAGER + sehandle = selinux_android_vendor_service_context_handle(); +#else + sehandle = selinux_android_service_context_handle(); +#endif + selinux_status_open(true); + + if (sehandle == NULL) { + ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); + abort(); + } + + if (getcon(&service_manager_context) != 0) { + ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); + abort(); + } + + + binder_loop(bs, svcmgr_handler); + + return 0; +} diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp deleted file mode 100644 index 25245beaf7..0000000000 --- a/cmds/servicemanager/test_sm.cpp +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <android/os/BnServiceCallback.h> -#include <binder/Binder.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> -#include <cutils/android_filesystem_config.h> -#include <gtest/gtest.h> -#include <gmock/gmock.h> - -#include "Access.h" -#include "ServiceManager.h" - -using android::sp; -using android::Access; -using android::BBinder; -using android::IBinder; -using android::ServiceManager; -using android::binder::Status; -using android::os::BnServiceCallback; -using android::os::IServiceManager; -using testing::_; -using testing::ElementsAre; -using testing::NiceMock; -using testing::Return; - -static sp<IBinder> getBinder() { - class LinkableBinder : public BBinder { - android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override { - // let SM linkToDeath - return android::OK; - } - }; - - return new LinkableBinder; -} - -class MockAccess : public Access { -public: - MOCK_METHOD0(getCallingContext, CallingContext()); - MOCK_METHOD2(canAdd, bool(const CallingContext&, const std::string& name)); - MOCK_METHOD2(canFind, bool(const CallingContext&, const std::string& name)); - MOCK_METHOD1(canList, bool(const CallingContext&)); -}; - -class MockServiceManager : public ServiceManager { - public: - MockServiceManager(std::unique_ptr<Access>&& access) : ServiceManager(std::move(access)) {} - MOCK_METHOD1(tryStartService, void(const std::string& name)); -}; - -static sp<ServiceManager> getPermissiveServiceManager() { - std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); - - ON_CALL(*access, getCallingContext()).WillByDefault(Return(Access::CallingContext{})); - ON_CALL(*access, canAdd(_, _)).WillByDefault(Return(true)); - ON_CALL(*access, canFind(_, _)).WillByDefault(Return(true)); - ON_CALL(*access, canList(_)).WillByDefault(Return(true)); - - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); - return sm; -} - -TEST(AddService, HappyHappy) { - auto sm = getPermissiveServiceManager(); - EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); -} - -TEST(AddService, EmptyNameDisallowed) { - auto sm = getPermissiveServiceManager(); - EXPECT_FALSE(sm->addService("", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); -} - -TEST(AddService, JustShortEnoughServiceNameHappy) { - auto sm = getPermissiveServiceManager(); - EXPECT_TRUE(sm->addService(std::string(127, 'a'), getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); -} - -TEST(AddService, TooLongNameDisallowed) { - auto sm = getPermissiveServiceManager(); - EXPECT_FALSE(sm->addService(std::string(128, 'a'), getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); -} - -TEST(AddService, WeirdCharactersDisallowed) { - auto sm = getPermissiveServiceManager(); - EXPECT_FALSE(sm->addService("happy$foo$foo", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); -} - -TEST(AddService, AddNullServiceDisallowed) { - auto sm = getPermissiveServiceManager(); - EXPECT_FALSE(sm->addService("foo", nullptr, false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); -} - -TEST(AddService, AddDisallowedFromApp) { - for (uid_t uid : { AID_APP_START, AID_APP_START + 1, AID_APP_END }) { - std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); - EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{ - .debugPid = 1337, - .uid = uid, - })); - EXPECT_CALL(*access, canAdd(_, _)).Times(0); - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); - - EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - } - -} - -TEST(AddService, HappyOverExistingService) { - auto sm = getPermissiveServiceManager(); - EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); -} - -TEST(AddService, NoPermissions) { - std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); - - EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); - EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(false)); - - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); - - EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); -} - -TEST(GetService, HappyHappy) { - auto sm = getPermissiveServiceManager(); - sp<IBinder> service = getBinder(); - - EXPECT_TRUE(sm->addService("foo", service, false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - - sp<IBinder> out; - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(service, out); -} - -TEST(GetService, NonExistant) { - auto sm = getPermissiveServiceManager(); - - sp<IBinder> out; - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(nullptr, out.get()); -} - -TEST(GetService, NoPermissionsForGettingService) { - std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); - - EXPECT_CALL(*access, getCallingContext()).WillRepeatedly(Return(Access::CallingContext{})); - EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); - EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(false)); - - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); - - EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - - sp<IBinder> out; - // returns nullptr but has OK status for legacy compatibility - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(nullptr, out.get()); -} - -TEST(GetService, AllowedFromIsolated) { - std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); - - EXPECT_CALL(*access, getCallingContext()) - // something adds it - .WillOnce(Return(Access::CallingContext{})) - // next call is from isolated app - .WillOnce(Return(Access::CallingContext{ - .uid = AID_ISOLATED_START, - })); - EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); - EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true)); - - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); - - sp<IBinder> service = getBinder(); - EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - - sp<IBinder> out; - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(service, out.get()); -} - -TEST(GetService, NotAllowedFromIsolated) { - std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); - - EXPECT_CALL(*access, getCallingContext()) - // something adds it - .WillOnce(Return(Access::CallingContext{})) - // next call is from isolated app - .WillOnce(Return(Access::CallingContext{ - .uid = AID_ISOLATED_START, - })); - EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); - - // TODO(b/136023468): when security check is first, this should be called first - // EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true)); - - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); - - EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - - sp<IBinder> out; - // returns nullptr but has OK status for legacy compatibility - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(nullptr, out.get()); -} - -TEST(ListServices, NoPermissions) { - std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); - - EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); - EXPECT_CALL(*access, canList(_)).WillOnce(Return(false)); - - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); - - std::vector<std::string> out; - EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); - EXPECT_TRUE(out.empty()); -} - -TEST(ListServices, AllServices) { - auto sm = getPermissiveServiceManager(); - - EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); - EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); - EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); - - std::vector<std::string> out; - EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); - - // all there and in the right order - EXPECT_THAT(out, ElementsAre("sa", "sb", "sc", "sd")); -} - -TEST(ListServices, CriticalServices) { - auto sm = getPermissiveServiceManager(); - - EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); - EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); - EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, - IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); - - std::vector<std::string> out; - EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, &out).isOk()); - - // all there and in the right order - EXPECT_THAT(out, ElementsAre("sa")); -} - -class CallbackHistorian : public BnServiceCallback { - Status onRegistration(const std::string& name, const sp<IBinder>& binder) override { - registrations.push_back(name); - binders.push_back(binder); - return Status::ok(); - } - - android::status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override { - // let SM linkToDeath - return android::OK; - } - -public: - std::vector<std::string> registrations; - std::vector<sp<IBinder>> binders; -}; - -TEST(ServiceNotifications, NoPermissionsRegister) { - std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); - - EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); - EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false)); - - sp<ServiceManager> sm = new ServiceManager(std::move(access)); - - sp<CallbackHistorian> cb = new CallbackHistorian; - - EXPECT_EQ(sm->registerForNotifications("foofoo", cb).exceptionCode(), - Status::EX_SECURITY); -} - -TEST(ServiceNotifications, NoPermissionsUnregister) { - std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); - - EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); - EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false)); - - sp<ServiceManager> sm = new ServiceManager(std::move(access)); - - sp<CallbackHistorian> cb = new CallbackHistorian; - - // should always hit security error first - EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), - Status::EX_SECURITY); -} - -TEST(ServiceNotifications, InvalidName) { - auto sm = getPermissiveServiceManager(); - - sp<CallbackHistorian> cb = new CallbackHistorian; - - EXPECT_EQ(sm->registerForNotifications("foo@foo", cb).exceptionCode(), - Status::EX_ILLEGAL_ARGUMENT); -} - -TEST(ServiceNotifications, NullCallback) { - auto sm = getPermissiveServiceManager(); - - EXPECT_EQ(sm->registerForNotifications("foofoo", nullptr).exceptionCode(), - Status::EX_NULL_POINTER); -} - -TEST(ServiceNotifications, Unregister) { - auto sm = getPermissiveServiceManager(); - - sp<CallbackHistorian> cb = new CallbackHistorian; - - EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk()); - EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), 0); -} - -TEST(ServiceNotifications, UnregisterWhenNoRegistrationExists) { - auto sm = getPermissiveServiceManager(); - - sp<CallbackHistorian> cb = new CallbackHistorian; - - EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), - Status::EX_ILLEGAL_STATE); -} - -TEST(ServiceNotifications, NoNotification) { - auto sm = getPermissiveServiceManager(); - - sp<CallbackHistorian> cb = new CallbackHistorian; - - EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk()); - EXPECT_TRUE(sm->addService("otherservice", getBinder(), - false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - - EXPECT_THAT(cb->registrations, ElementsAre()); - EXPECT_THAT(cb->binders, ElementsAre()); -} - -TEST(ServiceNotifications, GetNotification) { - auto sm = getPermissiveServiceManager(); - - sp<CallbackHistorian> cb = new CallbackHistorian; - - sp<IBinder> service = getBinder(); - - EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk()); - EXPECT_TRUE(sm->addService("asdfasdf", service, - false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - - EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf")); - EXPECT_THAT(cb->binders, ElementsAre(service)); -} - -TEST(ServiceNotifications, GetNotificationForAlreadyRegisteredService) { - auto sm = getPermissiveServiceManager(); - - sp<CallbackHistorian> cb = new CallbackHistorian; - - sp<IBinder> service = getBinder(); - - EXPECT_TRUE(sm->addService("asdfasdf", service, - false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - - EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk()); - - EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf")); - EXPECT_THAT(cb->binders, ElementsAre(service)); -} - -TEST(ServiceNotifications, GetMultipleNotification) { - auto sm = getPermissiveServiceManager(); - - sp<CallbackHistorian> cb = new CallbackHistorian; - - sp<IBinder> binder1 = getBinder(); - sp<IBinder> binder2 = getBinder(); - - EXPECT_TRUE(sm->registerForNotifications("asdfasdf", cb).isOk()); - EXPECT_TRUE(sm->addService("asdfasdf", binder1, - false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - EXPECT_TRUE(sm->addService("asdfasdf", binder2, - false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - - EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf")); - EXPECT_THAT(cb->registrations, ElementsAre("asdfasdf", "asdfasdf")); -} diff --git a/data/etc/android.hardware.se.omapi.ese.xml b/data/etc/android.hardware.se.omapi.ese.xml deleted file mode 100644 index 3b1d81cd87..0000000000 --- a/data/etc/android.hardware.se.omapi.ese.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 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 feature indicates that the device supports The device supports - Open Mobile API capable ESE-based secure elements--> -<permissions> - <feature name="android.hardware.se.omapi.ese" /> -</permissions> diff --git a/data/etc/android.hardware.se.omapi.sd.xml b/data/etc/android.hardware.se.omapi.sd.xml deleted file mode 100644 index 8fc2869d23..0000000000 --- a/data/etc/android.hardware.se.omapi.sd.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 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 feature indicates that the device supports The device supports - Open Mobile API capable SD-based secure elements--> -<permissions> - <feature name="android.hardware.se.omapi.sd" /> -</permissions> diff --git a/data/etc/android.hardware.se.omapi.uicc.xml b/data/etc/android.hardware.se.omapi.uicc.xml deleted file mode 100644 index 9c6f143990..0000000000 --- a/data/etc/android.hardware.se.omapi.uicc.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 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 feature indicates that the device supports The device supports - Open Mobile API capable UICC-based secure elements--> -<permissions> - <feature name="android.hardware.se.omapi.uicc" /> -</permissions> diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h index 8cc9d365a2..c87ee5655e 100644 --- a/headers/media_plugin/media/cas/CasAPI.h +++ b/headers/media_plugin/media/cas/CasAPI.h @@ -56,11 +56,6 @@ typedef void (*CasPluginCallbackExt)( size_t size, const CasSessionId *sessionId); -typedef void (*CasPluginStatusCallback)( - void *appData, - int32_t event, - int32_t arg); - struct CasFactory { CasFactory() {} virtual ~CasFactory() {} @@ -96,10 +91,6 @@ struct CasPlugin { CasPlugin() {} virtual ~CasPlugin() {} - // Provide a callback to report plugin status - virtual status_t setStatusCallback( - CasPluginStatusCallback callback) = 0; - // Provide the CA private data from a CA_descriptor in the conditional // access table to a CasPlugin. virtual status_t setPrivateData( @@ -109,11 +100,6 @@ struct CasPlugin { // streams. virtual status_t openSession(CasSessionId *sessionId) = 0; - // Open a session with intend and mode for descrambling a program, or one - // or more elementary streams. - virtual status_t openSession(uint32_t intent, uint32_t mode, - CasSessionId *sessionId) = 0; - // Close a previously opened session. virtual status_t closeSession(const CasSessionId &sessionId) = 0; diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h index 81ee5fb2e5..b6edaa900e 100644 --- a/headers/media_plugin/media/openmax/OMX_Video.h +++ b/headers/media_plugin/media/openmax/OMX_Video.h @@ -90,7 +90,6 @@ typedef enum OMX_VIDEO_CODINGTYPE { OMX_VIDEO_CodingHEVC, /**< ITU H.265/HEVC */ OMX_VIDEO_CodingDolbyVision,/**< Dolby Vision */ OMX_VIDEO_CodingImageHEIC, /**< HEIF image encoded with HEVC */ - OMX_VIDEO_CodingAV1, /**< AV1 */ OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_CodingMax = 0x7FFFFFFF diff --git a/include/android/choreographer.h b/include/android/choreographer.h index 346861f0a8..44883cc498 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -59,8 +59,6 @@ typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* dat /** * Get the AChoreographer instance for the current thread. This must be called * on an ALooper thread. - * - * Available since API level 24. */ AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24); @@ -84,8 +82,6 @@ void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, /** * Power a callback to be run on the next frame. The data pointer provided will * be passed to the callback function when it's called. - * - * Available since API level 29. */ void AChoreographer_postFrameCallback64(AChoreographer* chroreographer, AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29); @@ -94,8 +90,6 @@ void AChoreographer_postFrameCallback64(AChoreographer* chroreographer, * Post a callback to be run on the frame following the specified delay. The * data pointer provided will be passed to the callback function when it's * called. - * - * Available since API level 29. */ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29); diff --git a/include/android/configuration.h b/include/android/configuration.h index 331072238b..ef6c5a2f81 100644 --- a/include/android/configuration.h +++ b/include/android/configuration.h @@ -675,52 +675,50 @@ int32_t AConfiguration_getUiModeNight(AConfiguration* config); */ void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight); +#if __ANDROID_API__ >= 13 /** * Return the current configuration screen width in dp units, or * ACONFIGURATION_SCREEN_WIDTH_DP_ANY if not set. */ -int32_t AConfiguration_getScreenWidthDp(AConfiguration* config); +int32_t AConfiguration_getScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13); /** * Set the configuration's current screen width in dp units. */ -void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value); +void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13); /** * Return the current configuration screen height in dp units, or * ACONFIGURATION_SCREEN_HEIGHT_DP_ANY if not set. */ -int32_t AConfiguration_getScreenHeightDp(AConfiguration* config); +int32_t AConfiguration_getScreenHeightDp(AConfiguration* config) __INTRODUCED_IN(13); /** * Set the configuration's current screen width in dp units. */ -void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value); +void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13); /** * Return the configuration's smallest screen width in dp units, or * ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY if not set. */ -int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config); +int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13); /** * Set the configuration's smallest screen width in dp units. */ -void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value); +void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13); +#endif /* __ANDROID_API__ >= 13 */ #if __ANDROID_API__ >= 17 /** * Return the configuration's layout direction, or * ACONFIGURATION_LAYOUTDIR_ANY if not set. - * - * Available since API level 17. */ int32_t AConfiguration_getLayoutDirection(AConfiguration* config) __INTRODUCED_IN(17); /** * Set the configuration's layout direction. - * - * Available since API level 17. */ void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) __INTRODUCED_IN(17); #endif /* __ANDROID_API__ >= 17 */ diff --git a/include/android/font.h b/include/android/font.h index 1618096d69..435a573f51 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -16,7 +16,7 @@ /** * @addtogroup Font - * @{ + * { */ /** @@ -96,8 +96,6 @@ struct AFont; /** * Close an AFont. * - * Available since API level 29. - * * \param font a font returned by ASystemFontIterator_next or AFontMatchert_match. * Do nothing if NULL is passed. */ @@ -118,8 +116,6 @@ void AFont_close(AFont* _Nullable font) __INTRODUCED_IN(29); * The font file returned is guaranteed to be opend with O_RDONLY. * Note that the returned pointer is valid until AFont_close() is called for the given font. * - * Available since API level 29. - * * \param font a font object. Passing NULL is not allowed. * \return a string of the font file path. */ @@ -188,8 +184,6 @@ const char* _Nonnull AFont_getFontFilePath(const AFont* _Nonnull font) __INTRODU * * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass) * - * Available since API level 29. - * * \param font a font object. Passing NULL is not allowed. * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned. */ @@ -198,8 +192,6 @@ uint16_t AFont_getWeight(const AFont* _Nonnull font) __INTRODUCED_IN(29); /** * Return true if the current font is italic, otherwise returns false. * - * Available since API level 29. - * * \param font a font object. Passing NULL is not allowed. * \return true if italic, otherwise false. */ @@ -212,8 +204,6 @@ bool AFont_isItalic(const AFont* _Nonnull font) __INTRODUCED_IN(29); * * Note that the returned pointer is valid until AFont_close() is called. * - * Available since API level 29. - * * \param font a font object. Passing NULL is not allowed. * \return a IETF BCP47 compliant language tag or nullptr if not available. */ @@ -226,8 +216,6 @@ const char* _Nullable AFont_getLocale(const AFont* _Nonnull font) __INTRODUCED_I * returns a non-negative value as an font offset in the collection. This * always returns 0 if the target font file is a regular font. * - * Available since API level 29. - * * \param font a font object. Passing NULL is not allowed. * \return a font collection index. */ @@ -259,8 +247,6 @@ size_t AFont_getCollectionIndex(const AFont* _Nonnull font) __INTRODUCED_IN(29); * * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar) * - * Available since API level 29. - * * \param font a font object. Passing NULL is not allowed. * \return a number of font variation settings. */ @@ -272,8 +258,6 @@ size_t AFont_getAxisCount(const AFont* _Nonnull font) __INTRODUCED_IN(29); * * See AFont_getAxisCount for more details. * - * Available since API level 29. - * * \param font a font object. Passing NULL is not allowed. * \param axisIndex an index to the font variation settings. Passing value larger than or * equal to {@link AFont_getAxisCount} is not allowed. @@ -287,8 +271,6 @@ uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex) * * See AFont_getAxisCount for more details. * - * Available since API level 29. - * * \param font a font object. Passing NULL is not allowed. * \param axisIndex an index to the font variation settings. Passing value larger than or * equal to {@link ASYstemFont_getAxisCount} is not allwed. diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index d4bd892bf6..e286a4c812 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -16,7 +16,7 @@ /** * @addtogroup Font - * @{ + * { */ /** @@ -130,17 +130,13 @@ struct AFontMatcher; */ /** - * Creates a new AFontMatcher object. - * - * Available since API level 29. + * Creates a new AFontMatcher object */ AFontMatcher* _Nonnull AFontMatcher_create() __INTRODUCED_IN(29); /** * Destroy the matcher object. * - * Available since API level 29. - * * \param matcher a matcher object. Passing NULL is not allowed. */ void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29); @@ -151,8 +147,6 @@ void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29); * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL} * with non-italic style. * - * Available since API level 29. - * * \param matcher a matcher object. Passing NULL is not allowed. * \param weight a font weight value. Only from 0 to 1000 value is valid * \param italic true if italic, otherwise false. @@ -167,8 +161,6 @@ void AFontMatcher_setStyle( * * If this function is not called, the matcher performs with empty locale list. * - * Available since API level 29. - * * \param matcher a matcher object. Passing NULL is not allowed. * \param languageTags a null character terminated comma separated IETF BCP47 compliant language * tags. @@ -182,8 +174,6 @@ void AFontMatcher_setLocales( * * If this function is not called, the matcher performs with {@link AFAMILY_VARIANT_DEFAULT}. * - * Available since API level 29. - * * \param matcher a matcher object. Passing NULL is not allowed. * \param familyVariant Must be one of {@link AFAMILY_VARIANT_DEFAULT}, * {@link AFAMILY_VARIANT_COMPACT} or {@link AFAMILY_VARIANT_ELEGANT} is valid. @@ -200,8 +190,6 @@ void AFontMatcher_setFamilyVariant( * Even if no font can render the given text, this function will return a non-null result for * drawing Tofu character. * - * Available since API level 29. - * * \param matcher a matcher object. Passing NULL is not allowed. * \param familyName a null character terminated font family name * \param text a UTF-16 encoded text buffer to be rendered. Do not pass empty string. diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h index 293e5ac469..aedf36903d 100644 --- a/include/android/hardware_buffer_jni.h +++ b/include/android/hardware_buffer_jni.h @@ -42,8 +42,6 @@ __BEGIN_DECLS * that is returned. To keep the AHardwareBuffer live after the Java * HardwareBuffer object got garbage collected, be sure to use AHardwareBuffer_acquire() * to acquire an additional reference. - * - * Available since API level 26. */ AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env, jobject hardwareBufferObj) __INTRODUCED_IN(26); @@ -51,8 +49,6 @@ AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env, /** * Return a new Java HardwareBuffer object that wraps the passed native * AHardwareBuffer object. - * - * Available since API level 26. */ jobject AHardwareBuffer_toHardwareBuffer(JNIEnv* env, AHardwareBuffer* hardwareBuffer) __INTRODUCED_IN(26); diff --git a/include/android/input.h b/include/android/input.h index ce439c6d75..cfade6c806 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -986,8 +986,10 @@ int32_t AMotionEvent_getFlags(const AInputEvent* motion_event); */ int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event); +#if __ANDROID_API__ >= 14 /** Get the button state of all buttons that are pressed. */ -int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event); +int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event) __INTRODUCED_IN(14); +#endif /** * Get a bitfield indicating which edges, if any, were touched by this motion event. @@ -1052,12 +1054,14 @@ size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event); */ int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index); +#if __ANDROID_API__ >= 14 /** * Get the tool type of a pointer for the given pointer index. * The tool type indicates the type of tool used to make contact such as a * finger or stylus, if known. */ -int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index); +int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index) __INTRODUCED_IN(14); +#endif /** * Get the original raw X coordinate of this event. @@ -1147,9 +1151,11 @@ float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_ */ float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index); +#if __ANDROID_API__ >= 13 /** Get the value of the request axis for the given pointer index. */ float AMotionEvent_getAxisValue(const AInputEvent* motion_event, - int32_t axis, size_t pointer_index); + int32_t axis, size_t pointer_index) __INTRODUCED_IN(13); +#endif /** * Get the number of historical points in this event. These are movements that @@ -1280,12 +1286,14 @@ float AMotionEvent_getHistoricalToolMinor(const AInputEvent* motion_event, size_ float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); +#if __ANDROID_API__ >= 13 /** * Get the historical value of the request axis for the given pointer index * that occurred between this event and the previous motion event. */ float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event, - int32_t axis, size_t pointer_index, size_t history_index); + int32_t axis, size_t pointer_index, size_t history_index) __INTRODUCED_IN(13); +#endif struct AInputQueue; diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h index 59b1deb595..d31d1f122f 100644 --- a/include/android/multinetwork.h +++ b/include/android/multinetwork.h @@ -69,7 +69,6 @@ typedef uint64_t net_handle_t; * * This is the equivalent of: [android.net.Network#bindSocket()](https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket)) * - * Available since API level 23. */ int android_setsocknetwork(net_handle_t network, int fd) __INTRODUCED_IN(23); @@ -87,7 +86,6 @@ int android_setsocknetwork(net_handle_t network, int fd) __INTRODUCED_IN(23); * * This is the equivalent of: [android.net.ConnectivityManager#setProcessDefaultNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network)) * - * Available since API level 23. */ int android_setprocnetwork(net_handle_t network) __INTRODUCED_IN(23); @@ -105,7 +103,6 @@ int android_setprocnetwork(net_handle_t network) __INTRODUCED_IN(23); * * This is the equivalent of: [android.net.Network#getAllByName()](https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String)) * - * Available since API level 23. */ int android_getaddrinfofornetwork(net_handle_t network, const char *node, const char *service, @@ -147,8 +144,6 @@ enum ResNsendFlags : uint32_t { * * Returns a file descriptor to watch for read events, or a negative * POSIX error code (see errno.h) if an immediate error occurs. - * - * Available since API level 29. */ int android_res_nquery(net_handle_t network, const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29); @@ -160,8 +155,6 @@ int android_res_nquery(net_handle_t network, * * Returns a file descriptor to watch for read events, or a negative * POSIX error code (see errno.h) if an immediate error occurs. - * - * Available since API level 29. */ int android_res_nsend(net_handle_t network, const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29); @@ -170,8 +163,6 @@ int android_res_nsend(net_handle_t network, * Read a result for the query associated with the |fd| descriptor. * Closes |fd| before returning. * - * Available since 29. - * * Returns: * < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set. * >= 0: length of |answer|. |rcode| is the resolver return code (e.g., ns_r_nxdomain) @@ -182,8 +173,6 @@ int android_res_nresult(int fd, /** * Attempts to cancel the in-progress query associated with the |nsend_fd| * descriptor. - * - * Available since API level 29. */ void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29); diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h index 3a77ffe86b..0c196b9671 100644 --- a/include/android/native_window_jni.h +++ b/include/android/native_window_jni.h @@ -51,8 +51,6 @@ ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); * the ANativeWindow; maintains it through general Java object's life cycle; * and will automatically release the reference when the Java object gets garbage * collected. - * - * Available since API level 26. */ jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) __INTRODUCED_IN(26); #endif diff --git a/include/android/sensor.h b/include/android/sensor.h index 3ebe79fd2e..e9d5c16d0d 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -564,7 +564,6 @@ ASensorManager* ASensorManager_getInstance(); * * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz"); * - * Available since API level 26. */ ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26); #endif @@ -584,8 +583,6 @@ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type /** * Returns the default sensor with the given type and wakeUp properties or NULL if no sensor * of this type and wakeUp properties exists. - * - * Available since API level 21. */ ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp) __INTRODUCED_IN(21); #endif @@ -612,8 +609,6 @@ int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY} to be used * for configuring sensor direct report. * - * Available since API level 26. - * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. * \param fd file descriptor representing a shared memory created by @@ -632,8 +627,6 @@ int ASensorManager_createSharedMemoryDirectChannel(ASensorManager* manager, int * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER} type to be used * for configuring sensor direct report. * - * Available since API level 26. - * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. * \param buffer {@link AHardwareBuffer} instance created by {@link AHardwareBuffer_allocate}. @@ -653,8 +646,6 @@ int ASensorManager_createHardwareBufferDirectChannel( * The buffer used for creating direct channel does not get destroyed with * {@link ASensorManager_destroy} and has to be close or released separately. * - * Available since API level 26. - * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. * \param channelId channel id (a positive integer) returned from @@ -687,8 +678,6 @@ void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) * * ASensorManager_configureDirectReport(manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST); * - * Available since API level 26. - * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. * \param sensor a {@link ASensor} to denote which sensor to be operate. It can be NULL if rate @@ -791,7 +780,7 @@ int ASensorEventQueue_hasEvents(ASensorEventQueue* queue); */ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count); -#if __ANDROID_API__ >= 29 +#if __ANDROID_API__ >= __ANDROID_API_Q__ /** * Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on * the given {@link ASensorEventQueue}. @@ -807,15 +796,13 @@ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* even * {@link AAdditionalInfoEvent#type}, as new values may be defined in the future * and may delivered to the client. * - * Available since API level 29. - * * \param queue {@link ASensorEventQueue} to configure * \param enable true to request {@link ASENSOR_TYPE_ADDITIONAL_INFO} events, * false to stop receiving events * \return 0 on success or a negative error code on failure */ -int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable) __INTRODUCED_IN(29); -#endif /* __ANDROID_API__ >= 29 */ +int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable); +#endif /* __ANDROID_API__ >= __ANDRDOID_API_Q__ */ /*****************************************************************************/ @@ -850,36 +837,26 @@ int ASensor_getMinDelay(ASensor const* sensor); /** * Returns the maximum size of batches for this sensor. Batches will often be * smaller, as the hardware fifo might be used for other sensors. - * - * Available since API level 21. */ int ASensor_getFifoMaxEventCount(ASensor const* sensor) __INTRODUCED_IN(21); /** * Returns the hardware batch fifo size reserved to this sensor. - * - * Available since API level 21. */ int ASensor_getFifoReservedEventCount(ASensor const* sensor) __INTRODUCED_IN(21); /** * Returns this sensor's string type. - * - * Available since API level 21. */ const char* ASensor_getStringType(ASensor const* sensor) __INTRODUCED_IN(21); /** * Returns the reporting mode for this sensor. One of AREPORTING_MODE_* constants. - * - * Available since API level 21. */ int ASensor_getReportingMode(ASensor const* sensor) __INTRODUCED_IN(21); /** * Returns true if this is a wake up sensor, false otherwise. - * - * Available since API level 21. */ bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21); #endif /* __ANDROID_API__ >= 21 */ @@ -888,8 +865,6 @@ bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21); /** * Test if sensor supports a certain type of direct channel. * - * Available since API level 26. - * * \param sensor a {@link ASensor} to denote the sensor to be checked. * \param channelType Channel type constant, either * {@ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY} @@ -899,9 +874,7 @@ bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21); bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType) __INTRODUCED_IN(26); /** - * Get the highest direct rate level that a sensor supports. - * - * Available since API level 26. + * Get the highest direct rate level that a sensor support. * * \param sensor a {@link ASensor} to denote the sensor to be checked. * @@ -912,7 +885,7 @@ bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26); #endif /* __ANDROID_API__ >= 26 */ -#if __ANDROID_API__ >= 29 +#if __ANDROID_API__ >= __ANDROID_API_Q__ /** * Returns the sensor's handle. * @@ -926,11 +899,9 @@ int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_ * It is important to note that the value returned by {@link ASensor_getHandle} is not the same as * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists * between the values. - * - * Available since API level 29. */ -int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(29); -#endif /* __ANDROID_API__ >= 29 */ +int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(__ANDROID_API_Q__); +#endif /* __ANDROID_API__ >= ANDROID_API_Q__ */ #ifdef __cplusplus }; diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 90e565359e..ef2ad9998c 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -46,7 +46,7 @@ struct ASurfaceControl; */ typedef struct ASurfaceControl ASurfaceControl; -/** +/* * Creates an ASurfaceControl with either ANativeWindow or an ASurfaceControl as its parent. * |debug_name| is a debug name associated with this surface. It can be used to * identify this surface in the SurfaceFlinger's layer tree. It must not be @@ -54,17 +54,10 @@ typedef struct ASurfaceControl ASurfaceControl; * * The caller takes ownership of the ASurfaceControl returned and must release it * using ASurfaceControl_release below. - * - * Available since API level 29. */ ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name) __INTRODUCED_IN(29); -/** - * See ASurfaceControl_createFromWindow. - * - * Available since API level 29. - */ ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name) __INTRODUCED_IN(29); @@ -72,8 +65,6 @@ ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* deb * Releases the |surface_control| object. After releasing the ASurfaceControl the caller no longer * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long * as their parent remains on display. - * - * Available since API level 29. */ void ASurfaceControl_release(ASurfaceControl* surface_control) __INTRODUCED_IN(29); @@ -88,15 +79,11 @@ typedef struct ASurfaceTransaction ASurfaceTransaction; /** * The caller takes ownership of the transaction and must release it using * ASurfaceControl_delete below. - * - * Available since API level 29. */ ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29); /** * Destroys the |transaction| object. - * - * Available since API level 29. */ void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29); @@ -106,8 +93,6 @@ void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_I * Note that the transaction is guaranteed to be applied atomically. The * transactions which are applied on the same thread are also guaranteed to be * applied in order. - * - * Available since API level 29. */ void ASurfaceTransaction_apply(ASurfaceTransaction* transaction) __INTRODUCED_IN(29); @@ -131,8 +116,6 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; * * THREADING * The transaction completed callback can be invoked on any thread. - * - * Available since API level 29. */ typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats) __INTRODUCED_IN(29); @@ -140,8 +123,6 @@ typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactio /** * Returns the timestamp of when the frame was latched by the framework. Once a frame is * latched by the framework, it is presented at the following hardware vsync. - * - * Available since API level 29. */ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_transaction_stats) __INTRODUCED_IN(29); @@ -150,8 +131,6 @@ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_ * Returns a sync fence that signals when the transaction has been presented. * The recipient of the callback takes ownership of the fence and is responsible for closing * it. - * - * Available since API level 29. */ int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats) __INTRODUCED_IN(29); @@ -162,8 +141,6 @@ int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface * When the client is done using the array, it must release it by calling * ASurfaceTransactionStats_releaseASurfaceControls. * - * Available since API level 29. - * * |outASurfaceControlsSize| returns the size of the ASurfaceControls array. */ void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surface_transaction_stats, @@ -173,8 +150,6 @@ void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surf /** * Releases the array of ASurfaceControls that were returned by * ASurfaceTransactionStats_getASurfaceControls. - * - * Available since API level 29. */ void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_controls) __INTRODUCED_IN(29); @@ -183,8 +158,6 @@ void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_ * Returns the timestamp of when the CURRENT buffer was acquired. A buffer is considered * acquired when its acquire_fence_fd has signaled. A buffer cannot be latched or presented until * it is acquired. If no acquire_fence_fd was provided, this timestamp will be set to -1. - * - * Available since API level 29. */ int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surface_transaction_stats, ASurfaceControl* surface_control) @@ -207,8 +180,6 @@ int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surfac * * The client must ensure that all pending refs on a buffer are released before attempting to reuse * this buffer, otherwise synchronization errors may occur. - * - * Available since API level 29. */ int ASurfaceTransactionStats_getPreviousReleaseFenceFd( ASurfaceTransactionStats* surface_transaction_stats, @@ -219,8 +190,6 @@ int ASurfaceTransactionStats_getPreviousReleaseFenceFd( * Sets the callback that will be invoked when the updates from this transaction * are presented. For details on the callback semantics and data, see the * comments on the ASurfaceTransaction_OnComplete declaration above. - * - * Available since API level 29. */ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context, ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29); @@ -230,8 +199,6 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* c * Any children of the* reparented |surface_control| will remain children of the |surface_control|. * * The |new_parent| can be null. Surface controls with a null parent do not appear on the display. - * - * Available since API level 29. */ void ASurfaceTransaction_reparent(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, ASurfaceControl* new_parent) @@ -246,8 +213,6 @@ enum { * Updates the visibility of |surface_control|. If show is set to * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the |surface_control| and all surfaces in its subtree will * be hidden. - * - * Available since API level 29. */ void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, int8_t visibility) @@ -259,8 +224,6 @@ void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction, * the same z order is undefined. * * Z orders may be from MIN_INT32 to MAX_INT32. A layer's default z order index is 0. - * - * Available since API level 29. */ void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, int32_t z_order) @@ -273,8 +236,6 @@ void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction, * * The frameworks takes ownership of the |acquire_fence_fd| passed and is responsible * for closing it. - * - * Available since API level 29. */ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, AHardwareBuffer* buffer, @@ -285,8 +246,6 @@ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction, * ASurfaceControl visible in transparent regions of the surface. Colors |r|, |g|, * and |b| must be within the range that is valid for |dataspace|. |dataspace| and |alpha| * will be the dataspace and alpha set for the background color layer. - * - * Available since API level 29. */ void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float r, float g, float b, @@ -305,8 +264,6 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction, * |transform| the transform applied after the source rect is applied to the buffer. This parameter * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_* * enum. - * - * Available since API level 29. */ void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, const ARect& source, @@ -324,8 +281,6 @@ enum { * Updates whether the content for the buffer associated with this surface is * completely opaque. If true, every pixel of content inside the buffer must be * opaque or visual errors can occur. - * - * Available since API level 29. */ void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, @@ -335,8 +290,6 @@ void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction, /** * Updates the region for the content on this surface updated in this * transaction. If unspecified, the complete surface is assumed to be damaged. - * - * Available since API level 29. */ void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, const ARect rects[], @@ -351,8 +304,6 @@ void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction, * * If an earlier transaction has a desired present time of x, and a later transaction has a desired * present time that is before x, the later transaction will not preempt the earlier transaction. - * - * Available since API level 29. */ void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction, int64_t desiredPresentTime) __INTRODUCED_IN(29); @@ -361,8 +312,6 @@ void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction, * Sets the alpha for the buffer. It uses a premultiplied blending. * * The |alpha| must be between 0.0 and 1.0. - * - * Available since API level 29. */ void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float alpha) @@ -372,8 +321,6 @@ void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction, * Sets the data space of the surface_control's buffers. * * If no data space is set, the surface control defaults to ADATASPACE_SRGB. - * - * Available since API level 29. */ void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, ADataSpace data_space) @@ -384,8 +331,6 @@ void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction, * * When |metadata| is set to null, the framework does not use any smpte2086 metadata when rendering * the surface's buffer. - * - * Available since API level 29. */ void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, @@ -397,8 +342,6 @@ void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transacti * * When |metadata| is set to null, the framework does not use any cta861.3 metadata when rendering * the surface's buffer. - * - * Available since API level 29. */ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h index dde7eaa0b6..540d23a4c7 100644 --- a/include/android/surface_texture.h +++ b/include/android/surface_texture.h @@ -65,9 +65,6 @@ typedef struct ASurfaceTexture ASurfaceTexture; * Release the reference to the native ASurfaceTexture acquired with * ASurfaceTexture_fromSurfaceTexture(). * Failing to do so will result in leaked memory and graphic resources. - * - * Available since API level 28. - * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() */ void ASurfaceTexture_release(ASurfaceTexture* st) __INTRODUCED_IN(28); @@ -76,8 +73,6 @@ void ASurfaceTexture_release(ASurfaceTexture* st) __INTRODUCED_IN(28); * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture. * This is equivalent to Java's: Surface sur = new Surface(surfaceTexture); * - * Available since API level 28. - * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * @return A reference to an ANativeWindow. This reference MUST BE released when no longer needed * using ANativeWindow_release(). Failing to do so will result in leaked resources. nullptr is @@ -95,8 +90,6 @@ ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) __INTRO * contexts. Note, however, that the image contents are only accessible from one OpenGL ES * context at a time. * - * Available since API level 28. - * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * \param texName The name of the OpenGL ES texture that will be created. This texture name * must be unusued in the OpenGL ES context that is current on the calling thread. @@ -115,8 +108,6 @@ int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName) __I * contexts. Note, however, that the image contents are only accessible from one OpenGL ES * context at a time. * - * Available since API level 28. - * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * \return 0 on success, negative posix error code otherwise (see <errno.h>) */ @@ -127,8 +118,6 @@ int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) __INTRODUCED_IN(28) * called while the OpenGL ES context that owns the texture is current on the calling thread. * It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target. * - * Available since API level 28. - * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * \return 0 on success, negative posix error code otherwise (see <errno.h>) */ @@ -146,8 +135,6 @@ int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) __INTRODUCED_IN(28); * The matrix is stored in column-major order so that it may be passed directly to OpenGL ES via * the glLoadMatrixf or glUniformMatrix4fv functions. * - * Available since API level 28. - * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * \param mtx the array into which the 4x4 matrix will be stored. The array must have exactly * 16 elements. @@ -169,8 +156,6 @@ void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) __IN * For EGL/Vulkan producers, this timestamp is the desired present time set with the * EGL_ANDROID_presentation_time or VK_GOOGLE_display_timing extensions * - * Available since API level 28. - * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() */ int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) __INTRODUCED_IN(28); diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h index 2266d541f6..b0e1edd590 100644 --- a/include/android/surface_texture_jni.h +++ b/include/android/surface_texture_jni.h @@ -32,8 +32,6 @@ __BEGIN_DECLS -#if __ANDROID_API__ >= 28 - /** * Get a reference to the native ASurfaceTexture from the corresponding java object. * @@ -42,17 +40,13 @@ __BEGIN_DECLS * properly once the Java object gets finalized. * However, this will not result in program termination. * - * Available since API level 28. - * * \param env JNI environment * \param surfacetexture Instance of Java SurfaceTexture object * \return native ASurfaceTexture reference or nullptr if the java object is not a SurfaceTexture. * The returned reference MUST BE released when it's no longer needed using * ASurfaceTexture_release(). */ -ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) __INTRODUCED_IN(28); - -#endif +ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture); __END_DECLS diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h index 6fd7d2c0ab..dde9055c7a 100644 --- a/include/android/system_fonts.h +++ b/include/android/system_fonts.h @@ -16,7 +16,7 @@ /** * @addtogroup Font - * @{ + * { */ /** @@ -102,8 +102,6 @@ struct ASystemFontIterator; * * Use ASystemFont_close() to close the iterator. * - * Available since API level 29. - * * \return a pointer for a newly allocated iterator, nullptr on failure. */ ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29); @@ -111,8 +109,6 @@ ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29); /** * Close an opened system font iterator, freeing any related resources. * - * Available since API level 29. - * * \param iterator a pointer of an iterator for the system fonts. Do nothing if NULL is passed. */ void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTRODUCED_IN(29); @@ -120,8 +116,6 @@ void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTROD /** * Move to the next system font. * - * Available since API level 29. - * * \param iterator an iterator for the system fonts. Passing NULL is not allowed. * \return a font. If no more font is available, returns nullptr. You need to release the returned * font by ASystemFont_close when it is no longer needed. diff --git a/include/android/trace.h b/include/android/trace.h index d59690ab2e..bb7ff28f79 100644 --- a/include/android/trace.h +++ b/include/android/trace.h @@ -74,7 +74,7 @@ void ATrace_endSection() __INTRODUCED_IN(23); #endif /* __ANDROID_API__ >= 23 */ -#if __ANDROID_API__ >= 29 +#if __ANDROID_API__ >= __ANDROID_API_Q__ /** * Writes a trace message to indicate that a given section of code has @@ -83,8 +83,6 @@ void ATrace_endSection() __INTRODUCED_IN(23); * asynchronous events do not need to be nested. The name and cookie used to * begin an event must be used to end it. * - * Available since API level 29. - * * \param sectionName The method name to appear in the trace. * \param cookie Unique identifier for distinguishing simultaneous events */ @@ -95,8 +93,6 @@ void ATrace_beginAsyncSection(const char* sectionName, int32_t cookie) __INTRODU * Must be called exactly once for each call to {@link ATrace_beginAsyncSection} * using the same name and cookie. * - * Available since API level 29. - * * \param methodName The method name to appear in the trace. * \param cookie Unique identifier for distinguishing simultaneous events */ @@ -105,8 +101,6 @@ void ATrace_endAsyncSection(const char* sectionName, int32_t cookie) __INTRODUCE /** * Writes trace message to indicate the value of a given counter. * - * Available since API level 29. - * * \param counterName The counter name to appear in the trace. * \param counterValue The counter value. */ diff --git a/include/audiomanager/OWNERS b/include/audiomanager/OWNERS deleted file mode 100644 index 2bd527cc3f..0000000000 --- a/include/audiomanager/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -elaurent@google.com -jmtrivi@google.com diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h index 4365a3c4e3..d23e3b7767 100644 --- a/include/input/IInputFlinger.h +++ b/include/input/IInputFlinger.h @@ -37,7 +37,6 @@ public: virtual void setInputWindows(const std::vector<InputWindowInfo>& inputHandles, const sp<ISetInputWindowsListener>& setInputWindowsListener) = 0; - virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0; virtual void registerInputChannel(const sp<InputChannel>& channel) = 0; virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0; }; @@ -51,8 +50,7 @@ public: enum { SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, REGISTER_INPUT_CHANNEL_TRANSACTION, - UNREGISTER_INPUT_CHANNEL_TRANSACTION, - TRANSFER_TOUCH_FOCUS + UNREGISTER_INPUT_CHANNEL_TRANSACTION }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp deleted file mode 100644 index 9cf014380c..0000000000 --- a/libs/adbd_auth/Android.bp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -cc_library { - name: "libadbd_auth", - cflags: [ - "-Wall", - "-Wextra", - "-Wthread-safety", - "-Werror", - ], - srcs: ["adbd_auth.cpp"], - export_include_dirs: ["include"], - - version_script: "libadbd_auth.map.txt", - stubs: { - symbol_file: "libadbd_auth.map.txt", - }, - - host_supported: true, - recovery_available: true, - target: { - darwin: { - enabled: false, - } - }, - - shared_libs: [ - "libbase", - "libcutils", - "liblog", - ], -} diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp deleted file mode 100644 index 64791098ee..0000000000 --- a/libs/adbd_auth/adbd_auth.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION - -#include "include/adbd_auth.h" - -#include <inttypes.h> -#include <sys/epoll.h> -#include <sys/eventfd.h> -#include <sys/uio.h> - -#include <chrono> -#include <deque> -#include <string> -#include <string_view> -#include <tuple> -#include <unordered_map> -#include <utility> -#include <variant> -#include <vector> - -#include <android-base/file.h> -#include <android-base/logging.h> -#include <android-base/macros.h> -#include <android-base/strings.h> -#include <android-base/thread_annotations.h> -#include <android-base/unique_fd.h> -#include <cutils/sockets.h> - -using android::base::unique_fd; - -struct AdbdAuthPacketAuthenticated { - std::string public_key; -}; - -struct AdbdAuthPacketDisconnected { - std::string public_key; -}; - -struct AdbdAuthPacketRequestAuthorization { - std::string public_key; -}; - -using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected, - AdbdAuthPacketRequestAuthorization>; - -struct AdbdAuthContext { - static constexpr uint64_t kEpollConstSocket = 0; - static constexpr uint64_t kEpollConstEventFd = 1; - static constexpr uint64_t kEpollConstFramework = 2; - -public: - explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) { - epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC)); - if (epoll_fd_ == -1) { - PLOG(FATAL) << "failed to create epoll fd"; - } - - event_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); - if (event_fd_ == -1) { - PLOG(FATAL) << "failed to create eventfd"; - } - - sock_fd_.reset(android_get_control_socket("adbd")); - if (sock_fd_ == -1) { - PLOG(ERROR) << "failed to get adbd authentication socket"; - } else { - if (fcntl(sock_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) { - PLOG(FATAL) << "failed to make adbd authentication socket cloexec"; - } - - if (fcntl(sock_fd_.get(), F_SETFL, O_NONBLOCK) != 0) { - PLOG(FATAL) << "failed to make adbd authentication socket nonblocking"; - } - - if (listen(sock_fd_.get(), 4) != 0) { - PLOG(FATAL) << "failed to listen on adbd authentication socket"; - } - } - } - - AdbdAuthContext(const AdbdAuthContext& copy) = delete; - AdbdAuthContext(AdbdAuthContext&& move) = delete; - AdbdAuthContext& operator=(const AdbdAuthContext& copy) = delete; - AdbdAuthContext& operator=(AdbdAuthContext&& move) = delete; - - uint64_t NextId() { return next_id_++; } - - void DispatchPendingPrompt() REQUIRES(mutex_) { - if (dispatched_prompt_) { - LOG(INFO) << "adbd_auth: prompt currently pending, skipping"; - return; - } - - if (pending_prompts_.empty()) { - LOG(INFO) << "adbd_auth: no prompts to send"; - return; - } - - LOG(INFO) << "adbd_auth: prompting user for adb authentication"; - auto [id, public_key, arg] = std::move(pending_prompts_.front()); - pending_prompts_.pop_front(); - - this->output_queue_.emplace_back( - AdbdAuthPacketRequestAuthorization{.public_key = public_key}); - - Interrupt(); - dispatched_prompt_ = std::make_tuple(id, public_key, arg); - } - - void UpdateFrameworkWritable() REQUIRES(mutex_) { - // This might result in redundant calls to EPOLL_CTL_MOD if, for example, we get notified - // at the same time as a framework connection, but that's unlikely and this doesn't need to - // be fast anyway. - if (framework_fd_ != -1) { - struct epoll_event event; - event.events = EPOLLIN; - if (!output_queue_.empty()) { - LOG(INFO) << "marking framework writable"; - event.events |= EPOLLOUT; - } - event.data.u64 = kEpollConstFramework; - CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_MOD, framework_fd_.get(), &event)); - } - } - - void ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) { - LOG(INFO) << "received new framework fd " << new_fd.get() - << " (current = " << framework_fd_.get() << ")"; - - // If we already had a framework fd, clean up after ourselves. - if (framework_fd_ != -1) { - output_queue_.clear(); - dispatched_prompt_.reset(); - CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, framework_fd_.get(), nullptr)); - framework_fd_.reset(); - } - - if (new_fd != -1) { - struct epoll_event event; - event.events = EPOLLIN; - if (!output_queue_.empty()) { - LOG(INFO) << "marking framework writable"; - event.events |= EPOLLOUT; - } - event.data.u64 = kEpollConstFramework; - CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, new_fd.get(), &event)); - framework_fd_ = std::move(new_fd); - } - } - - void HandlePacket(std::string_view packet) REQUIRES(mutex_) { - LOG(INFO) << "received packet: " << packet; - - if (packet.length() < 2) { - LOG(ERROR) << "received packet of invalid length"; - ReplaceFrameworkFd(unique_fd()); - } - - if (packet[0] == 'O' && packet[1] == 'K') { - CHECK(this->dispatched_prompt_.has_value()); - auto& [id, key, arg] = *this->dispatched_prompt_; - keys_.emplace(id, std::move(key)); - - this->callbacks_.key_authorized(arg, id); - this->dispatched_prompt_ = std::nullopt; - } else if (packet[0] == 'N' && packet[1] == 'O') { - CHECK_EQ(2UL, packet.length()); - // TODO: Do we want a callback if the key is denied? - this->dispatched_prompt_ = std::nullopt; - DispatchPendingPrompt(); - } else { - LOG(ERROR) << "unhandled packet: " << packet; - ReplaceFrameworkFd(unique_fd()); - } - } - - bool SendPacket() REQUIRES(mutex_) { - if (output_queue_.empty()) { - return false; - } - - CHECK_NE(-1, framework_fd_.get()); - - auto& packet = output_queue_.front(); - struct iovec iovs[2]; - if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) { - iovs[0].iov_base = const_cast<char*>("CK"); - iovs[0].iov_len = 2; - iovs[1].iov_base = p->public_key.data(); - iovs[1].iov_len = p->public_key.size(); - } else if (auto* p = std::get_if<AdbdAuthPacketDisconnected>(&packet)) { - iovs[0].iov_base = const_cast<char*>("DC"); - iovs[0].iov_len = 2; - iovs[1].iov_base = p->public_key.data(); - iovs[1].iov_len = p->public_key.size(); - } else if (auto* p = std::get_if<AdbdAuthPacketRequestAuthorization>(&packet)) { - iovs[0].iov_base = const_cast<char*>("PK"); - iovs[0].iov_len = 2; - iovs[1].iov_base = p->public_key.data(); - iovs[1].iov_len = p->public_key.size(); - } else { - LOG(FATAL) << "unhandled packet type?"; - } - - output_queue_.pop_front(); - - ssize_t rc = writev(framework_fd_.get(), iovs, 2); - if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { - PLOG(ERROR) << "failed to write to framework fd"; - ReplaceFrameworkFd(unique_fd()); - return false; - } - - return true; - } - - void Run() { - if (sock_fd_ == -1) { - LOG(ERROR) << "adbd authentication socket unavailable, disabling user prompts"; - } else { - struct epoll_event event; - event.events = EPOLLIN; - event.data.u64 = kEpollConstSocket; - CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, sock_fd_.get(), &event)); - } - - { - struct epoll_event event; - event.events = EPOLLIN; - event.data.u64 = kEpollConstEventFd; - CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event)); - } - - while (true) { - struct epoll_event events[3]; - int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 3, -1)); - if (rc == -1) { - PLOG(FATAL) << "epoll_wait failed"; - } else if (rc == 0) { - LOG(FATAL) << "epoll_wait returned 0"; - } - - bool restart = false; - for (int i = 0; i < rc; ++i) { - if (restart) { - break; - } - - struct epoll_event& event = events[i]; - switch (event.data.u64) { - case kEpollConstSocket: { - unique_fd new_framework_fd(accept4(sock_fd_.get(), nullptr, nullptr, - SOCK_CLOEXEC | SOCK_NONBLOCK)); - if (new_framework_fd == -1) { - PLOG(FATAL) << "failed to accept framework fd"; - } - - LOG(INFO) << "adbd_auth: received a new framework connection"; - std::lock_guard<std::mutex> lock(mutex_); - ReplaceFrameworkFd(std::move(new_framework_fd)); - - // Stop iterating over events: one of the later ones might be the old - // framework fd. - restart = false; - break; - } - - case kEpollConstEventFd: { - // We were woken up to write something. - uint64_t dummy; - int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy))); - if (rc != 8) { - PLOG(FATAL) << "failed to read from eventfd (rc = " << rc << ")"; - } - - std::lock_guard<std::mutex> lock(mutex_); - UpdateFrameworkWritable(); - break; - } - - case kEpollConstFramework: { - char buf[4096]; - if (event.events & EPOLLIN) { - int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf))); - if (rc == -1) { - LOG(FATAL) << "failed to read from framework fd"; - } else if (rc == 0) { - LOG(INFO) << "hit EOF on framework fd"; - std::lock_guard<std::mutex> lock(mutex_); - ReplaceFrameworkFd(unique_fd()); - } else { - std::lock_guard<std::mutex> lock(mutex_); - HandlePacket(std::string_view(buf, rc)); - } - } - - if (event.events & EPOLLOUT) { - std::lock_guard<std::mutex> lock(mutex_); - while (SendPacket()) { - continue; - } - UpdateFrameworkWritable(); - } - - break; - } - } - } - } - } - - static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"}; - void IteratePublicKeys(bool (*callback)(const char*, size_t, void*), void* arg) { - for (const auto& path : key_paths) { - if (access(path, R_OK) == 0) { - LOG(INFO) << "Loading keys from " << path; - std::string content; - if (!android::base::ReadFileToString(path, &content)) { - PLOG(ERROR) << "Couldn't read " << path; - continue; - } - for (const auto& line : android::base::Split(content, "\n")) { - if (!callback(line.data(), line.size(), arg)) { - return; - } - } - } - } - } - - uint64_t PromptUser(std::string_view public_key, void* arg) EXCLUDES(mutex_) { - uint64_t id = NextId(); - - std::lock_guard<std::mutex> lock(mutex_); - pending_prompts_.emplace_back(id, public_key, arg); - DispatchPendingPrompt(); - return id; - } - - uint64_t NotifyAuthenticated(std::string_view public_key) EXCLUDES(mutex_) { - uint64_t id = NextId(); - std::lock_guard<std::mutex> lock(mutex_); - keys_.emplace(id, public_key); - output_queue_.emplace_back( - AdbdAuthPacketDisconnected{.public_key = std::string(public_key)}); - return id; - } - - void NotifyDisconnected(uint64_t id) EXCLUDES(mutex_) { - std::lock_guard<std::mutex> lock(mutex_); - auto it = keys_.find(id); - if (it == keys_.end()) { - LOG(DEBUG) << "couldn't find public key to notify disconnection, skipping"; - return; - } - output_queue_.emplace_back(AdbdAuthPacketDisconnected{.public_key = std::move(it->second)}); - keys_.erase(it); - } - - // Interrupt the worker thread to do some work. - void Interrupt() { - uint64_t value = 1; - ssize_t rc = write(event_fd_.get(), &value, sizeof(value)); - if (rc == -1) { - PLOG(FATAL) << "write to eventfd failed"; - } else if (rc != sizeof(value)) { - LOG(FATAL) << "write to eventfd returned short (" << rc << ")"; - } - } - - unique_fd epoll_fd_; - unique_fd event_fd_; - unique_fd sock_fd_; - unique_fd framework_fd_; - - std::atomic<uint64_t> next_id_; - AdbdAuthCallbacksV1 callbacks_; - - std::mutex mutex_; - std::unordered_map<uint64_t, std::string> keys_ GUARDED_BY(mutex_); - - // We keep two separate queues: one to handle backpressure from the socket (output_queue_) - // and one to make sure we only dispatch one authrequest at a time (pending_prompts_). - std::deque<AdbdAuthPacket> output_queue_; - - std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_); - std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_); -}; - -AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) { - if (callbacks->version != 1) { - LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version; - return nullptr; - } - - return new AdbdAuthContext(&callbacks->callbacks.v1); -} - -void adbd_auth_delete(AdbdAuthContext* ctx) { - delete ctx; -} - -void adbd_auth_run(AdbdAuthContext* ctx) { - return ctx->Run(); -} - -void adbd_auth_get_public_keys(AdbdAuthContext* ctx, - bool (*callback)(const char* public_key, size_t len, void* arg), - void* arg) { - ctx->IteratePublicKeys(callback, arg); -} - -uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) { - return ctx->NotifyAuthenticated(std::string_view(public_key, len)); -} - -void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) { - return ctx->NotifyDisconnected(id); -} - -void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, - void* arg) { - ctx->PromptUser(std::string_view(public_key, len), arg); -} - -bool adbd_auth_supports_feature(AdbdAuthFeature) { - return false; -} diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h deleted file mode 100644 index b7c1cb88cc..0000000000 --- a/libs/adbd_auth/include/adbd_auth.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -/* - * Copyright (C) 2019 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 <stdbool.h> -#include <stdint.h> -#include <sys/types.h> - -extern "C" { - -struct AdbdAuthCallbacksV1 { - // Callback for a successful user authorization. - void (*key_authorized)(void* arg, uint64_t id); -}; - -struct AdbdAuthCallbacks { - uint32_t version; - union { - AdbdAuthCallbacksV1 v1; - } callbacks; -}; - -struct AdbdAuthContext; - -AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks); -void adbd_auth_delete(AdbdAuthContext* ctx); - -void adbd_auth_run(AdbdAuthContext* ctx); - -// Iterate through the list of authorized public keys. -// Return false from the callback to stop iteration. -void adbd_auth_get_public_keys(AdbdAuthContext* ctx, - bool (*callback)(const char* public_key, size_t len, void* arg), - void* arg); - -// Let system_server know that a key has been successfully used for authentication. -uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len); - -// Let system_server know that a connection has been closed. -void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id); - -// Prompt the user to authorize a public key. -// When this happens, a callback will be run on the auth thread with the result. -void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg); - -enum AdbdAuthFeature { -}; - -bool adbd_auth_supports_feature(AdbdAuthFeature f); - -} diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt deleted file mode 100644 index d01233c960..0000000000 --- a/libs/adbd_auth/libadbd_auth.map.txt +++ /dev/null @@ -1,13 +0,0 @@ -LIBADBD_AUTH { - global: - adbd_auth_new; # apex - adbd_auth_delete; # apex - adbd_auth_run; # apex - adbd_auth_get_public_keys; #apex - adbd_auth_notify_auth; # apex - adbd_auth_notify_disconnect; # apex - adbd_auth_prompt_user; # apex - adbd_auth_supports_feature; # apex - local: - *; -}; diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp index 09a5f39130..9284acbff3 100644 --- a/libs/android_runtime_lazy/Android.bp +++ b/libs/android_runtime_lazy/Android.bp @@ -34,7 +34,6 @@ cc_library { name: "libandroid_runtime_lazy", vendor_available: true, double_loadable: true, - host_supported: true, cflags: [ "-Wall", @@ -52,6 +51,10 @@ cc_library { "libutils", ], + required: [ + "libandroid_runtime", + ], + export_include_dirs: [ "include", ], diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index 2518b1427d..ad8287c203 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -13,18 +13,13 @@ // limitations under the License. ndk_headers { - name: "libarect_headers_for_ndk", + name: "libarect_headers", from: "include/android", to: "android", srcs: ["include/android/*.h"], license: "NOTICE", } -cc_library_headers { - name: "libarect_headers", - export_include_dirs: ["include"], -} - cc_library_static { name: "libarect", host_supported: true, diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp index 5e4c98fc7a..49a94146db 100644 --- a/libs/binder/ActivityManager.cpp +++ b/libs/binder/ActivityManager.cpp @@ -114,4 +114,4 @@ status_t ActivityManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recip return INVALID_OPERATION; } -} // namespace android +}; // namespace android diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 7ee4882b6a..aedf6b0d18 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -16,8 +16,6 @@ cc_library_headers { name: "libbinder_headers", export_include_dirs: ["include"], vendor_available: true, - host_supported: true, - header_libs: [ "libbase_headers", "libcutils_headers", @@ -30,28 +28,7 @@ cc_library_headers { ], } -// These interfaces are android-specific implementation unrelated to binder -// transport itself and should be moved to AIDL or in domain-specific libs. -// -// Currently, these are only on system android (not vendor, not host) -libbinder_device_interface_sources = [ - "ActivityManager.cpp", - "AppOpsManager.cpp", - "IActivityManager.cpp", - "IAppOpsCallback.cpp", - "IAppOpsService.cpp", - "IBatteryStats.cpp", - "IMediaResourceMonitor.cpp", - "IPermissionController.cpp", - "IProcessInfoService.cpp", - "IUidObserver.cpp", - "PermissionCache.cpp", - "PermissionController.cpp", - "ProcessInfoService.cpp", - "IpPrefix.cpp", -] - -cc_library { +cc_library_shared { name: "libbinder", // for vndbinder @@ -60,61 +37,65 @@ cc_library { enabled: true, }, double_loadable: true, - host_supported: true, - - // TODO(b/31559095): get headers from bionic on host - include_dirs: [ - "bionic/libc/kernel/android/uapi/", - "bionic/libc/kernel/uapi/", - ], - - // libbinder does not offer a stable wire protocol. - // if a second copy of it is installed, then it may break after security - // or dessert updates. Instead, apex users should use libbinder_ndk. - apex_available: [ - "//apex_available:platform", - "com.android.vndk.current", - // TODO(b/139016109) remove these three - "com.android.media.swcodec", - "test_com.android.media.swcodec", - ], srcs: [ + "ActivityManager.cpp", + "AppOpsManager.cpp", "Binder.cpp", "BpBinder.cpp", "BufferedTextOutput.cpp", "Debug.cpp", + "IActivityManager.cpp", + "IAppOpsCallback.cpp", + "IAppOpsService.cpp", + "IBatteryStats.cpp", "IInterface.cpp", + "IMediaResourceMonitor.cpp", "IMemory.cpp", "IPCThreadState.cpp", + "IPermissionController.cpp", + "IProcessInfoService.cpp", "IResultReceiver.cpp", "IServiceManager.cpp", "IShellCallback.cpp", + "IUidObserver.cpp", "MemoryBase.cpp", "MemoryDealer.cpp", "MemoryHeapBase.cpp", "Parcel.cpp", "ParcelFileDescriptor.cpp", + "PermissionCache.cpp", + "PermissionController.cpp", "PersistableBundle.cpp", + "ProcessInfoService.cpp", "ProcessState.cpp", "Static.cpp", - "Stability.cpp", "Status.cpp", "TextOutput.cpp", + "IpPrefix.cpp", + "Value.cpp", ":libbinder_aidl", ], target: { - android: { - srcs: libbinder_device_interface_sources, - - // NOT static to keep the wire protocol unfrozen - static: { - enabled: false, - }, - }, vendor: { - exclude_srcs: libbinder_device_interface_sources, + exclude_srcs: [ + "ActivityManager.cpp", + "AppOpsManager.cpp", + "IActivityManager.cpp", + "IAppOpsCallback.cpp", + "IAppOpsService.cpp", + "IBatteryStats.cpp", + "IMediaResourceMonitor.cpp", + "IPermissionController.cpp", + "IProcessInfoService.cpp", + "IUidObserver.cpp", + "PermissionCache.cpp", + "PermissionController.cpp", + "ProcessInfoService.cpp", + "IpPrefix.cpp", + ":libbinder_aidl", + ], }, }, @@ -135,6 +116,7 @@ cc_library { }, shared_libs: [ + "libbase", "liblog", "libcutils", "libutils", @@ -160,21 +142,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", - "aidl/android/os/IServiceCallback.aidl", - "aidl/android/os/IServiceManager.aidl", ], - path: "aidl", } -aidl_interface { - name: "libbinder_aidl_test_stub", - local_include_dir: "aidl", - srcs: [":libbinder_aidl"], - visibility: [":__subpackages__"], - vendor_available: true, - backend: { - java: { - enabled: false, - }, - }, -} +subdirs = ["tests"] diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 0a6685e14a..525685c35e 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -147,4 +147,4 @@ int32_t AppOpsManager::permissionToOpCode(const String16& permission) { } -} // namespace android +}; // namespace android diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 2f6e9c3a1b..cb0e08d123 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -81,50 +81,6 @@ status_t IBinder::shellCommand(const sp<IBinder>& target, int in, int out, int e return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply); } -status_t IBinder::getExtension(sp<IBinder>* out) { - BBinder* local = this->localBinder(); - if (local != nullptr) { - *out = local->getExtension(); - return OK; - } - - BpBinder* proxy = this->remoteBinder(); - LOG_ALWAYS_FATAL_IF(proxy == nullptr); - - Parcel data; - Parcel reply; - status_t status = transact(EXTENSION_TRANSACTION, data, &reply); - if (status != OK) return status; - - return reply.readNullableStrongBinder(out); -} - -status_t IBinder::getDebugPid(pid_t* out) { - BBinder* local = this->localBinder(); - if (local != nullptr) { - *out = local->getDebugPid(); - return OK; - } - - BpBinder* proxy = this->remoteBinder(); - LOG_ALWAYS_FATAL_IF(proxy == nullptr); - - Parcel data; - Parcel reply; - status_t status = transact(DEBUG_PID_TRANSACTION, data, &reply); - if (status != OK) return status; - - int32_t pid; - status = reply.readInt32(&pid); - if (status != OK) return status; - - if (pid < 0 || pid > std::numeric_limits<pid_t>::max()) { - return BAD_VALUE; - } - *out = pid; - return OK; -} - // --------------------------------------------------------------------------- class BBinder::Extras @@ -132,7 +88,6 @@ class BBinder::Extras public: // unlocked objects bool mRequestingSid = false; - sp<IBinder> mExtension; // for below objects Mutex mLock; @@ -173,20 +128,13 @@ status_t BBinder::transact( status_t err = NO_ERROR; switch (code) { case PING_TRANSACTION: - err = pingBinder(); - break; - case EXTENSION_TRANSACTION: - err = reply->writeStrongBinder(getExtension()); - break; - case DEBUG_PID_TRANSACTION: - err = reply->writeInt32(getDebugPid()); + reply->writeInt32(pingBinder()); break; default: err = onTransact(code, data, reply, flags); break; } - // In case this is being transacted on in the same process. if (reply != nullptr) { reply->setDataPosition(0); } @@ -273,21 +221,6 @@ void BBinder::setRequestingSid(bool requestingSid) e->mRequestingSid = requestingSid; } -sp<IBinder> BBinder::getExtension() { - Extras* e = mExtras.load(std::memory_order_acquire); - if (e == nullptr) return nullptr; - return e->mExtension; -} - -pid_t BBinder::getDebugPid() { - return getpid(); -} - -void BBinder::setExtension(const sp<IBinder>& extension) { - Extras* e = getOrCreateExtras(); - e->mExtension = extension; -} - BBinder::~BBinder() { Extras* e = mExtras.load(std::memory_order_relaxed); @@ -419,4 +352,4 @@ bool BpRefBase::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 238c9dcc7f..ec170f7a65 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -21,7 +21,6 @@ #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> -#include <binder/Stability.h> #include <cutils/compiler.h> #include <utils/Log.h> @@ -149,10 +148,6 @@ BpBinder::BpBinder(int32_t handle, int32_t trackedUid) IPCThreadState::self()->incWeakHandle(handle, this); } -int32_t BpBinder::handle() const { - return mHandle; -} - bool BpBinder::isDescriptorCached() const { Mutex::Autolock _l(mLock); return mDescriptorCache.size() ? true : false; @@ -191,7 +186,10 @@ status_t BpBinder::pingBinder() { Parcel send; Parcel reply; - return transact(PING_TRANSACTION, send, &reply); + status_t err = transact(PING_TRANSACTION, send, &reply); + if (err != NO_ERROR) return err; + if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA; + return (status_t)reply.readInt32(); } status_t BpBinder::dump(int fd, const Vector<String16>& args) @@ -214,29 +212,9 @@ status_t BpBinder::transact( { // Once a binder has died, it will never come back to life. if (mAlive) { - bool privateVendor = flags & FLAG_PRIVATE_VENDOR; - // don't send userspace flags to the kernel - flags = flags & ~FLAG_PRIVATE_VENDOR; - - // user transactions require a given stability level - if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) { - using android::internal::Stability; - - auto stability = Stability::get(this); - auto required = privateVendor ? Stability::VENDOR : Stability::kLocalStability; - - if (CC_UNLIKELY(!Stability::check(stability, required))) { - ALOGE("Cannot do a user transaction on a %s binder in a %s context.", - Stability::stabilityString(stability).c_str(), - Stability::stabilityString(required).c_str()); - return BAD_TYPE; - } - } - status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; - return status; } @@ -409,6 +387,21 @@ BpBinder::~BpBinder() } } + mLock.lock(); + Vector<Obituary>* obits = mObituaries; + if(obits != nullptr) { + if (ipc) ipc->clearDeathNotification(mHandle, this); + mObituaries = nullptr; + } + mLock.unlock(); + + if (obits != nullptr) { + // XXX Should we tell any remaining DeathRecipient + // objects that the last strong ref has gone away, so they + // are no longer linked? + delete obits; + } + if (ipc) { ipc->expungeHandle(mHandle, this); ipc->decWeakHandle(mHandle); @@ -430,25 +423,6 @@ void BpBinder::onLastStrongRef(const void* /*id*/) } IPCThreadState* ipc = IPCThreadState::self(); if (ipc) ipc->decStrongHandle(mHandle); - - mLock.lock(); - Vector<Obituary>* obits = mObituaries; - if(obits != nullptr) { - if (!obits->isEmpty()) { - ALOGI("onLastStrongRef automatically unlinking death recipients"); - } - - if (ipc) ipc->clearDeathNotification(mHandle, this); - mObituaries = nullptr; - } - mLock.unlock(); - - if (obits != nullptr) { - // XXX Should we tell any remaining DeathRecipient - // objects that the last strong ref has gone away, so they - // are no longer linked? - delete obits; - } } bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) @@ -496,4 +470,4 @@ void BpBinder::setBinderProxyCountWatermarks(int high, int low) { // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp index fb424fdcfb..2978b539d7 100644 --- a/libs/binder/BufferedTextOutput.cpp +++ b/libs/binder/BufferedTextOutput.cpp @@ -23,12 +23,12 @@ #include <utils/RefBase.h> #include <utils/Vector.h> +#include <private/binder/Static.h> + #include <pthread.h> #include <stdio.h> #include <stdlib.h> -#include "Static.h" - // --------------------------------------------------------------------------- namespace android { @@ -49,9 +49,10 @@ struct BufferedTextOutput::BufferState : public RefBase } status_t append(const char* txt, size_t len) { + if (len > SIZE_MAX - bufferPos) return NO_MEMORY; // overflow if ((len+bufferPos) > bufferSize) { + if ((len + bufferPos) > SIZE_MAX / 3) return NO_MEMORY; // overflow size_t newSize = ((len+bufferPos)*3)/2; - if (newSize < (len+bufferPos)) return NO_MEMORY; // overflow void* b = realloc(buffer, newSize); if (!b) return NO_MEMORY; buffer = (char*)b; @@ -280,4 +281,4 @@ BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const return mGlobalState; } -} // namespace android +}; // namespace android diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp index 64c1ff68c0..a1c2a8be08 100644 --- a/libs/binder/Debug.cpp +++ b/libs/binder/Debug.cpp @@ -308,5 +308,5 @@ ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf) { return proc->getKernelReferences(count, buf); } -} // namespace android +}; // namespace android diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index 1eb5363ae2..377f604d44 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -110,4 +110,4 @@ public: IMPLEMENT_META_INTERFACE(ActivityManager, "android.app.IActivityManager"); -} // namespace android +}; // namespace android diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp index 0ce1dd59cf..aba49673b1 100644 --- a/libs/binder/IAppOpsCallback.cpp +++ b/libs/binder/IAppOpsCallback.cpp @@ -22,6 +22,8 @@ #include <binder/Parcel.h> #include <utils/String8.h> +#include <private/binder/Static.h> + namespace android { // ---------------------------------------------------------------------- @@ -66,4 +68,4 @@ status_t BnAppOpsCallback::onTransact( } } -} // namespace android +}; // namespace android diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index b2bd9e50b0..66d6e31902 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -22,6 +22,8 @@ #include <binder/Parcel.h> #include <utils/String8.h> +#include <private/binder/Static.h> + namespace android { // ---------------------------------------------------------------------- @@ -239,4 +241,4 @@ status_t BnAppOpsService::onTransact( } } -} // namespace android +}; // namespace android diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp index a47dbaccfe..b307e3e7b5 100644 --- a/libs/binder/IBatteryStats.cpp +++ b/libs/binder/IBatteryStats.cpp @@ -20,6 +20,8 @@ #include <binder/Parcel.h> #include <utils/String8.h> +#include <private/binder/Static.h> + namespace android { // ---------------------------------------------------------------------- @@ -240,4 +242,4 @@ status_t BnBatteryStats::onTransact( } } -} // namespace android +}; // namespace android diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp index b19004d454..59d51ed94a 100644 --- a/libs/binder/IInterface.cpp +++ b/libs/binder/IInterface.cpp @@ -46,4 +46,4 @@ sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface) // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp index 4198e49259..77e3d239bc 100644 --- a/libs/binder/IMediaResourceMonitor.cpp +++ b/libs/binder/IMediaResourceMonitor.cpp @@ -59,4 +59,4 @@ status_t BnMediaResourceMonitor::onTransact( uint32_t code, const Parcel& data, // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index 222b32c921..caf2318281 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -149,10 +149,6 @@ void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const return static_cast<char*>(base) + offset; } -void* IMemory::unsecurePointer() const { - return pointer(); -} - void* IMemory::pointer() const { ssize_t offset; sp<IMemoryHeap> heap = getMemory(&offset); @@ -514,4 +510,4 @@ void HeapCache::dump_heaps() // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 4981d7a111..9a561cba64 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -31,8 +31,8 @@ #include <utils/threads.h> #include <private/binder/binder_module.h> +#include <private/binder/Static.h> -#include <atomic> #include <errno.h> #include <inttypes.h> #include <pthread.h> @@ -43,8 +43,6 @@ #include <sys/resource.h> #include <unistd.h> -#include "Static.h" - #if LOG_NDEBUG #define IF_LOG_TRANSACTIONS() if (false) @@ -118,7 +116,7 @@ static const int64_t kWorkSourcePropagatedBitIndex = 32; static const char* getReturnString(uint32_t cmd) { - size_t idx = cmd & _IOC_NRMASK; + size_t idx = cmd & 0xff; if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0])) return kReturnStrings[idx]; else @@ -280,14 +278,14 @@ static const void* printCommand(TextOutput& out, const void* _cmd) } static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; -static std::atomic<bool> gHaveTLS(false); +static bool gHaveTLS = false; static pthread_key_t gTLS = 0; -static std::atomic<bool> gShutdown = false; -static std::atomic<bool> gDisableBackgroundScheduling = false; +static bool gShutdown = false; +static bool gDisableBackgroundScheduling = false; IPCThreadState* IPCThreadState::self() { - if (gHaveTLS.load(std::memory_order_acquire)) { + if (gHaveTLS) { restart: const pthread_key_t k = gTLS; IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); @@ -295,14 +293,13 @@ restart: return new IPCThreadState; } - // Racey, heuristic test for simultaneous shutdown. - if (gShutdown.load(std::memory_order_relaxed)) { + if (gShutdown) { ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n"); return nullptr; } pthread_mutex_lock(&gTLSMutex); - if (!gHaveTLS.load(std::memory_order_relaxed)) { + if (!gHaveTLS) { int key_create_value = pthread_key_create(&gTLS, threadDestructor); if (key_create_value != 0) { pthread_mutex_unlock(&gTLSMutex); @@ -310,7 +307,7 @@ restart: strerror(key_create_value)); return nullptr; } - gHaveTLS.store(true, std::memory_order_release); + gHaveTLS = true; } pthread_mutex_unlock(&gTLSMutex); goto restart; @@ -318,7 +315,7 @@ restart: IPCThreadState* IPCThreadState::selfOrNull() { - if (gHaveTLS.load(std::memory_order_acquire)) { + if (gHaveTLS) { const pthread_key_t k = gTLS; IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); return st; @@ -328,9 +325,9 @@ IPCThreadState* IPCThreadState::selfOrNull() void IPCThreadState::shutdown() { - gShutdown.store(true, std::memory_order_relaxed); + gShutdown = true; - if (gHaveTLS.load(std::memory_order_acquire)) { + if (gHaveTLS) { // XXX Need to wait for all thread pool threads to exit! IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS); if (st) { @@ -338,18 +335,18 @@ void IPCThreadState::shutdown() pthread_setspecific(gTLS, nullptr); } pthread_key_delete(gTLS); - gHaveTLS.store(false, std::memory_order_release); + gHaveTLS = false; } } void IPCThreadState::disableBackgroundScheduling(bool disable) { - gDisableBackgroundScheduling.store(disable, std::memory_order_relaxed); + gDisableBackgroundScheduling = disable; } bool IPCThreadState::backgroundSchedulingDisabled() { - return gDisableBackgroundScheduling.load(std::memory_order_relaxed); + return gDisableBackgroundScheduling; } sp<ProcessState> IPCThreadState::process() @@ -465,7 +462,7 @@ void IPCThreadState::clearCaller() void IPCThreadState::flushCommands() { - if (mProcess->mDriverFD < 0) + if (mProcess->mDriverFD <= 0) return; talkWithDriver(false); // The flush could have caused post-write refcount decrements to have @@ -597,8 +594,9 @@ void IPCThreadState::joinThreadPool(bool isMain) result = getAndExecuteCommand(); if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) { - LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting", + ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting", mProcess->mDriverFD, result); + abort(); } // Let this thread exit the thread pool if it is no longer @@ -617,7 +615,7 @@ void IPCThreadState::joinThreadPool(bool isMain) int IPCThreadState::setupPolling(int* fd) { - if (mProcess->mDriverFD < 0) { + if (mProcess->mDriverFD <= 0) { return -EBADF; } @@ -676,11 +674,11 @@ status_t IPCThreadState::transact(int32_t handle, if ((flags & TF_ONE_WAY) == 0) { if (UNLIKELY(mCallRestriction != ProcessState::CallRestriction::NONE)) { if (mCallRestriction == ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY) { - ALOGE("Process making non-oneway call (code: %u) but is restricted.", code); + ALOGE("Process making non-oneway call but is restricted."); CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(), ANDROID_LOG_ERROR); } else /* FATAL_IF_NOT_ONEWAY */ { - LOG_ALWAYS_FATAL("Process may not make oneway calls (code: %u).", code); + LOG_ALWAYS_FATAL("Process may not make oneway calls."); } } @@ -923,7 +921,7 @@ finish: status_t IPCThreadState::talkWithDriver(bool doReceive) { - if (mProcess->mDriverFD < 0) { + if (mProcess->mDriverFD <= 0) { return -EBADF; } @@ -981,7 +979,7 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) #else err = INVALID_OPERATION; #endif - if (mProcess->mDriverFD < 0) { + if (mProcess->mDriverFD <= 0) { err = -EBADF; } IF_LOG_COMMANDS() { @@ -998,7 +996,7 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) if (err >= NO_ERROR) { if (bwr.write_consumed > 0) { if (bwr.write_consumed < mOut.dataSize()) - LOG_ALWAYS_FATAL("Driver did not consume write buffer"); + mOut.remove(0, bwr.write_consumed); else { mOut.setDataSize(0); processPostWriteDerefs(); @@ -1062,7 +1060,7 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, sp<BBinder> the_context_object; -void IPCThreadState::setTheContextObject(sp<BBinder> obj) +void setTheContextObject(sp<BBinder> obj) { the_context_object = obj; } @@ -1300,7 +1298,7 @@ void IPCThreadState::threadDestructor(void *st) if (self) { self->flushCommands(); #if defined(__ANDROID__) - if (self->mProcess->mDriverFD >= 0) { + if (self->mProcess->mDriverFD > 0) { ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0); } #endif @@ -1325,4 +1323,4 @@ void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, state->mOut.writePointer((uintptr_t)data); } -} // namespace android +}; // namespace android diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp index d9bf3cc7b6..6b99150edf 100644 --- a/libs/binder/IPermissionController.cpp +++ b/libs/binder/IPermissionController.cpp @@ -22,6 +22,8 @@ #include <binder/Parcel.h> #include <utils/String8.h> +#include <private/binder/Static.h> + namespace android { // ---------------------------------------------------------------------- @@ -172,4 +174,4 @@ status_t BnPermissionController::onTransact( } } -} // namespace android +}; // namespace android diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp index a38a27ad39..96e1a8c239 100644 --- a/libs/binder/IProcessInfoService.cpp +++ b/libs/binder/IProcessInfoService.cpp @@ -88,4 +88,4 @@ IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService"); // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp index 556288c5dd..159763d5bf 100644 --- a/libs/binder/IResultReceiver.cpp +++ b/libs/binder/IResultReceiver.cpp @@ -22,6 +22,8 @@ #include <binder/Parcel.h> #include <utils/String8.h> +#include <private/binder/Static.h> + namespace android { // ---------------------------------------------------------------------- @@ -65,4 +67,4 @@ status_t BnResultReceiver::onTransact( } } -} // namespace android +}; // namespace android diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 4f47db199e..4ba6c2a923 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -18,86 +18,31 @@ #include <binder/IServiceManager.h> -#include <android/os/BnServiceCallback.h> -#include <android/os/IServiceManager.h> -#include <binder/IPCThreadState.h> -#include <binder/Parcel.h> #include <utils/Log.h> -#include <utils/String8.h> -#include <utils/SystemClock.h> - +#include <binder/IPCThreadState.h> #ifndef __ANDROID_VNDK__ #include <binder/IPermissionController.h> #endif - -#ifdef __ANDROID__ +#include <binder/Parcel.h> #include <cutils/properties.h> -#endif +#include <utils/String8.h> +#include <utils/SystemClock.h> -#include "Static.h" +#include <private/binder/Static.h> #include <unistd.h> namespace android { -using AidlServiceManager = android::os::IServiceManager; -using android::binder::Status; - -// libbinder's IServiceManager.h can't rely on the values generated by AIDL -// because many places use its headers via include_dirs (meaning, without -// declaring the dependency in the build system). So, for now, we can just check -// the values here. -static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_CRITICAL == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL); -static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_HIGH == IServiceManager::DUMP_FLAG_PRIORITY_HIGH); -static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_NORMAL == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL); -static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_DEFAULT == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT); -static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_ALL == IServiceManager::DUMP_FLAG_PRIORITY_ALL); -static_assert(AidlServiceManager::DUMP_FLAG_PROTO == IServiceManager::DUMP_FLAG_PROTO); - -const String16& IServiceManager::getInterfaceDescriptor() const { - return AidlServiceManager::descriptor; -} -IServiceManager::IServiceManager() {} -IServiceManager::~IServiceManager() {} - -// From the old libbinder IServiceManager interface to IServiceManager. -class ServiceManagerShim : public IServiceManager -{ -public: - explicit ServiceManagerShim (const sp<AidlServiceManager>& impl); - - sp<IBinder> getService(const String16& name) const override; - sp<IBinder> checkService(const String16& name) const override; - status_t addService(const String16& name, const sp<IBinder>& service, - bool allowIsolated, int dumpsysPriority) override; - Vector<String16> listServices(int dumpsysPriority) override; - sp<IBinder> waitForService(const String16& name16) override; - bool isDeclared(const String16& name) override; - - // for legacy ABI - const String16& getInterfaceDescriptor() const override { - return mTheRealServiceManager->getInterfaceDescriptor(); - } - IBinder* onAsBinder() override { - return IInterface::asBinder(mTheRealServiceManager).get(); - } -private: - sp<AidlServiceManager> mTheRealServiceManager; -}; - sp<IServiceManager> defaultServiceManager() { - static Mutex gDefaultServiceManagerLock; - static sp<IServiceManager> gDefaultServiceManager; - if (gDefaultServiceManager != nullptr) return gDefaultServiceManager; { AutoMutex _l(gDefaultServiceManagerLock); while (gDefaultServiceManager == nullptr) { - gDefaultServiceManager = new ServiceManagerShim( - interface_cast<AidlServiceManager>( - ProcessState::self()->getContextObject(nullptr))); + gDefaultServiceManager = interface_cast<IServiceManager>( + ProcessState::self()->getContextObject(nullptr)); if (gDefaultServiceManager == nullptr) sleep(1); } @@ -106,7 +51,7 @@ sp<IServiceManager> defaultServiceManager() return gDefaultServiceManager; } -#if !defined(__ANDROID_VNDK__) && defined(__ANDROID__) +#ifndef __ANDROID_VNDK__ // IPermissionController is not accessible to vendors bool checkCallingPermission(const String16& permission) @@ -129,13 +74,10 @@ bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t bool checkPermission(const String16& permission, pid_t pid, uid_t uid) { - static Mutex gPermissionControllerLock; - static sp<IPermissionController> gPermissionController; - sp<IPermissionController> pc; - gPermissionControllerLock.lock(); + gDefaultServiceManagerLock.lock(); pc = gPermissionController; - gPermissionControllerLock.unlock(); + gDefaultServiceManagerLock.unlock(); int64_t startTime = 0; @@ -159,11 +101,11 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid) } // Object is dead! - gPermissionControllerLock.lock(); + gDefaultServiceManagerLock.lock(); if (gPermissionController == pc) { gPermissionController = nullptr; } - gPermissionControllerLock.unlock(); + gDefaultServiceManagerLock.unlock(); } // Need to retrieve the permission controller. @@ -179,9 +121,9 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid) } else { pc = interface_cast<IPermissionController>(binder); // Install the new permission controller, and try again. - gPermissionControllerLock.lock(); + gDefaultServiceManagerLock.lock(); gPermissionController = pc; - gPermissionControllerLock.unlock(); + gDefaultServiceManagerLock.unlock(); } } } @@ -190,144 +132,84 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid) // ---------------------------------------------------------------------- -ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl) - : mTheRealServiceManager(impl) -{} - -sp<IBinder> ServiceManagerShim::getService(const String16& name) const +class BpServiceManager : public BpInterface<IServiceManager> { - static bool gSystemBootCompleted = false; - - sp<IBinder> svc = checkService(name); - if (svc != nullptr) return svc; - - const bool isVendorService = - strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0; - const long timeout = uptimeMillis() + 5000; - // Vendor code can't access system properties - if (!gSystemBootCompleted && !isVendorService) { -#ifdef __ANDROID__ - char bootCompleted[PROPERTY_VALUE_MAX]; - property_get("sys.boot_completed", bootCompleted, "0"); - gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false; -#else - gSystemBootCompleted = true; -#endif +public: + explicit BpServiceManager(const sp<IBinder>& impl) + : BpInterface<IServiceManager>(impl) + { } - // retry interval in millisecond; note that vendor services stay at 100ms - const long sleepTime = gSystemBootCompleted ? 1000 : 100; - - int n = 0; - while (uptimeMillis() < timeout) { - n++; - ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(), - ProcessState::self()->getDriverName().c_str()); - usleep(1000*sleepTime); + virtual sp<IBinder> getService(const String16& name) const + { sp<IBinder> svc = checkService(name); if (svc != nullptr) return svc; - } - ALOGW("Service %s didn't start. Returning NULL", String8(name).string()); - return nullptr; -} - -sp<IBinder> ServiceManagerShim::checkService(const String16& name) const -{ - sp<IBinder> ret; - if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { - return nullptr; - } - return ret; -} - -status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service, - bool allowIsolated, int dumpsysPriority) -{ - Status status = mTheRealServiceManager->addService( - String8(name).c_str(), service, allowIsolated, dumpsysPriority); - return status.exceptionCode(); -} - -Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority) -{ - std::vector<std::string> ret; - if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) { - return {}; - } - - Vector<String16> res; - res.setCapacity(ret.size()); - for (const std::string& name : ret) { - res.push(String16(name.c_str())); - } - return res; -} -sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) -{ - class Waiter : public android::os::BnServiceCallback { - Status onRegistration(const std::string& /*name*/, - const sp<IBinder>& binder) override { - std::unique_lock<std::mutex> lock(mMutex); - mBinder = binder; - lock.unlock(); - mCv.notify_one(); - return Status::ok(); + const bool isVendorService = + strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0; + const long timeout = uptimeMillis() + 5000; + if (!gSystemBootCompleted && !isVendorService) { + // Vendor code can't access system properties + char bootCompleted[PROPERTY_VALUE_MAX]; + property_get("sys.boot_completed", bootCompleted, "0"); + gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false; } - public: - sp<IBinder> mBinder; - std::mutex mMutex; - std::condition_variable mCv; - }; - - const std::string name = String8(name16).c_str(); - - sp<IBinder> out; - if (!mTheRealServiceManager->getService(name, &out).isOk()) { + // retry interval in millisecond; note that vendor services stay at 100ms + const long sleepTime = gSystemBootCompleted ? 1000 : 100; + + int n = 0; + while (uptimeMillis() < timeout) { + n++; + ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(), + ProcessState::self()->getDriverName().c_str()); + usleep(1000*sleepTime); + + sp<IBinder> svc = checkService(name); + if (svc != nullptr) return svc; + } + ALOGW("Service %s didn't start. Returning NULL", String8(name).string()); return nullptr; } - if(out != nullptr) return out; - sp<Waiter> waiter = new Waiter; - if (!mTheRealServiceManager->registerForNotifications( - name, waiter).isOk()) { - return nullptr; + virtual sp<IBinder> checkService( const String16& name) const + { + Parcel data, reply; + data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); + data.writeString16(name); + remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); + return reply.readStrongBinder(); } - while(true) { - { - std::unique_lock<std::mutex> lock(waiter->mMutex); - using std::literals::chrono_literals::operator""s; - waiter->mCv.wait_for(lock, 1s, [&] { - return waiter->mBinder != nullptr; - }); - if (waiter->mBinder != nullptr) return waiter->mBinder; - } + virtual status_t addService(const String16& name, const sp<IBinder>& service, + bool allowIsolated, int dumpsysPriority) { + Parcel data, reply; + data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); + data.writeString16(name); + data.writeStrongBinder(service); + data.writeInt32(allowIsolated ? 1 : 0); + data.writeInt32(dumpsysPriority); + status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); + return err == NO_ERROR ? reply.readExceptionCode() : err; + } - // Handle race condition for lazy services. Here is what can happen: - // - the service dies (not processed by init yet). - // - sm processes death notification. - // - sm gets getService and calls init to start service. - // - init gets the start signal, but the service already appears - // started, so it does nothing. - // - init gets death signal, but doesn't know it needs to restart - // the service - // - we need to request service again to get it to start - if (!mTheRealServiceManager->getService(name, &out).isOk()) { - return nullptr; + virtual Vector<String16> listServices(int dumpsysPriority) { + Vector<String16> res; + int n = 0; + + for (;;) { + Parcel data, reply; + data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); + data.writeInt32(n++); + data.writeInt32(dumpsysPriority); + status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); + if (err != NO_ERROR) + break; + res.add(reply.readString16()); } - if(out != nullptr) return out; - - ALOGW("Waited one second for %s", name.c_str()); + return res; } -} +}; -bool ServiceManagerShim::isDeclared(const String16& name) { - bool declared; - if (!mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared).isOk()) { - return false; - } - return declared; -} +IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); -} // namespace android +}; // namespace android diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp index a3e2b67bc6..6c697decca 100644 --- a/libs/binder/IShellCallback.cpp +++ b/libs/binder/IShellCallback.cpp @@ -25,6 +25,8 @@ #include <binder/Parcel.h> #include <utils/String8.h> +#include <private/binder/Static.h> + namespace android { // ---------------------------------------------------------------------- @@ -85,4 +87,4 @@ status_t BnShellCallback::onTransact( } } -} // namespace android +}; // namespace android diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp index 038e6bf6ea..82f9047595 100644 --- a/libs/binder/IUidObserver.cpp +++ b/libs/binder/IUidObserver.cpp @@ -112,4 +112,4 @@ status_t BnUidObserver::onTransact( } } -} // namespace android +}; // namespace android diff --git a/libs/binder/IpPrefix.cpp b/libs/binder/IpPrefix.cpp index 8d622668cc..3a8a63c46e 100644 --- a/libs/binder/IpPrefix.cpp +++ b/libs/binder/IpPrefix.cpp @@ -30,6 +30,7 @@ using android::NO_ERROR; using android::Parcel; using android::status_t; using android::UNEXPECTED_NULL; +using namespace ::android::binder; namespace android { diff --git a/libs/binder/MemoryBase.cpp b/libs/binder/MemoryBase.cpp index 32300dfbb6..033066bea3 100644 --- a/libs/binder/MemoryBase.cpp +++ b/libs/binder/MemoryBase.cpp @@ -43,4 +43,4 @@ MemoryBase::~MemoryBase() } // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp index ebf91f925e..eacad3b6b3 100644 --- a/libs/binder/MemoryDealer.cpp +++ b/libs/binder/MemoryDealer.cpp @@ -481,4 +481,4 @@ void SimpleBestFitAllocator::dump_l(String8& result, } -} // namespace android +}; // namespace android diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp index e4ea60f699..4c300b47c6 100644 --- a/libs/binder/MemoryHeapBase.cpp +++ b/libs/binder/MemoryHeapBase.cpp @@ -181,4 +181,4 @@ off_t MemoryHeapBase::getOffset() const { } // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 9be06cdd19..11441eca64 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -35,9 +35,9 @@ #include <binder/IPCThreadState.h> #include <binder/Parcel.h> #include <binder/ProcessState.h> -#include <binder/Stability.h> #include <binder/Status.h> #include <binder/TextOutput.h> +#include <binder/Value.h> #include <cutils/ashmem.h> #include <utils/Debug.h> @@ -48,7 +48,11 @@ #include <utils/String16.h> #include <private/binder/binder_module.h> -#include "Static.h" +#include <private/binder/Static.h> + +#ifndef INT32_MAX +#define INT32_MAX ((int32_t)(2147483647)) +#endif #define LOG_REFS(...) //#define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) @@ -63,8 +67,8 @@ #define PAD_SIZE_UNSAFE(s) (((s)+3)&~3) static size_t pad_size(size_t s) { - if (s > (std::numeric_limits<size_t>::max() - 3)) { - LOG_ALWAYS_FATAL("pad size too big %zu", s); + if (s > (SIZE_T_MAX - 3)) { + abort(); } return PAD_SIZE_UNSAFE(s); } @@ -74,9 +78,6 @@ static size_t pad_size(size_t s) { namespace android { -// many things compile this into prebuilts on the stack -static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120); - static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER; static size_t gParcelGlobalAllocSize = 0; static size_t gParcelGlobalAllocCount = 0; @@ -92,7 +93,7 @@ enum { BLOB_ASHMEM_MUTABLE = 2, }; -static void acquire_object(const sp<ProcessState>& proc, +void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who, size_t* outAshmemSize) { switch (obj.hdr.type) { @@ -102,6 +103,10 @@ static void acquire_object(const sp<ProcessState>& proc, reinterpret_cast<IBinder*>(obj.cookie)->incStrong(who); } return; + case BINDER_TYPE_WEAK_BINDER: + if (obj.binder) + reinterpret_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who); + return; case BINDER_TYPE_HANDLE: { const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle); if (b != nullptr) { @@ -110,6 +115,11 @@ static void acquire_object(const sp<ProcessState>& proc, } return; } + case BINDER_TYPE_WEAK_HANDLE: { + const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle); + if (b != nullptr) b.get_refs()->incWeak(who); + return; + } case BINDER_TYPE_FD: { if ((obj.cookie != 0) && (outAshmemSize != nullptr) && ashmem_valid(obj.handle)) { // If we own an ashmem fd, keep track of how much memory it refers to. @@ -125,6 +135,12 @@ static void acquire_object(const sp<ProcessState>& proc, ALOGD("Invalid object type 0x%08x", obj.hdr.type); } +void acquire_object(const sp<ProcessState>& proc, + const flat_binder_object& obj, const void* who) +{ + acquire_object(proc, obj, who, nullptr); +} + static void release_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who, size_t* outAshmemSize) { @@ -135,6 +151,10 @@ static void release_object(const sp<ProcessState>& proc, reinterpret_cast<IBinder*>(obj.cookie)->decStrong(who); } return; + case BINDER_TYPE_WEAK_BINDER: + if (obj.binder) + reinterpret_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who); + return; case BINDER_TYPE_HANDLE: { const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle); if (b != nullptr) { @@ -143,6 +163,11 @@ static void release_object(const sp<ProcessState>& proc, } return; } + case BINDER_TYPE_WEAK_HANDLE: { + const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle); + if (b != nullptr) b.get_refs()->decWeak(who); + return; + } case BINDER_TYPE_FD: { if (obj.cookie != 0) { // owned if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) { @@ -164,31 +189,20 @@ static void release_object(const sp<ProcessState>& proc, ALOGE("Invalid object type 0x%08x", obj.hdr.type); } -status_t Parcel::finishFlattenBinder( - const sp<IBinder>& binder, const flat_binder_object& flat) +void release_object(const sp<ProcessState>& proc, + const flat_binder_object& obj, const void* who) { - status_t status = writeObject(flat, false); - if (status != OK) return status; - - internal::Stability::tryMarkCompilationUnit(binder.get()); - return writeInt32(internal::Stability::get(binder.get())); + release_object(proc, obj, who, nullptr); } -status_t Parcel::finishUnflattenBinder( - const sp<IBinder>& binder, sp<IBinder>* out) const +inline static status_t finish_flatten_binder( + const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out) { - int32_t stability; - status_t status = readInt32(&stability); - if (status != OK) return status; - - status = internal::Stability::set(binder.get(), stability, true /*log*/); - if (status != OK) return status; - - *out = binder; - return OK; + return out->writeObject(flat, false); } -status_t Parcel::flattenBinder(const sp<IBinder>& binder) +status_t flatten_binder(const sp<ProcessState>& /*proc*/, + const sp<IBinder>& binder, Parcel* out) { flat_binder_object obj; @@ -226,24 +240,108 @@ status_t Parcel::flattenBinder(const sp<IBinder>& binder) obj.cookie = 0; } - return finishFlattenBinder(binder, obj); + return finish_flatten_binder(binder, obj, out); +} + +status_t flatten_binder(const sp<ProcessState>& /*proc*/, + const wp<IBinder>& binder, Parcel* out) +{ + flat_binder_object obj; + + obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; + if (binder != nullptr) { + sp<IBinder> real = binder.promote(); + if (real != nullptr) { + IBinder *local = real->localBinder(); + if (!local) { + BpBinder *proxy = real->remoteBinder(); + if (proxy == nullptr) { + ALOGE("null proxy"); + } + const int32_t handle = proxy ? proxy->handle() : 0; + obj.hdr.type = BINDER_TYPE_WEAK_HANDLE; + obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */ + obj.handle = handle; + obj.cookie = 0; + } else { + obj.hdr.type = BINDER_TYPE_WEAK_BINDER; + obj.binder = reinterpret_cast<uintptr_t>(binder.get_refs()); + obj.cookie = reinterpret_cast<uintptr_t>(binder.unsafe_get()); + } + return finish_flatten_binder(real, obj, out); + } + + // XXX How to deal? In order to flatten the given binder, + // we need to probe it for information, which requires a primary + // reference... but we don't have one. + // + // The OpenBinder implementation uses a dynamic_cast<> here, + // but we can't do that with the different reference counting + // implementation we are using. + ALOGE("Unable to unflatten Binder weak reference!"); + obj.hdr.type = BINDER_TYPE_BINDER; + obj.binder = 0; + obj.cookie = 0; + return finish_flatten_binder(nullptr, obj, out); + + } else { + obj.hdr.type = BINDER_TYPE_BINDER; + obj.binder = 0; + obj.cookie = 0; + return finish_flatten_binder(nullptr, obj, out); + } +} + +inline static status_t finish_unflatten_binder( + BpBinder* /*proxy*/, const flat_binder_object& /*flat*/, + const Parcel& /*in*/) +{ + return NO_ERROR; } -status_t Parcel::unflattenBinder(sp<IBinder>* out) const +status_t unflatten_binder(const sp<ProcessState>& proc, + const Parcel& in, sp<IBinder>* out) { - const flat_binder_object* flat = readObject(false); + const flat_binder_object* flat = in.readObject(false); if (flat) { switch (flat->hdr.type) { - case BINDER_TYPE_BINDER: { - sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie); - return finishUnflattenBinder(binder, out); - } - case BINDER_TYPE_HANDLE: { - sp<IBinder> binder = - ProcessState::self()->getStrongProxyForHandle(flat->handle); - return finishUnflattenBinder(binder, out); - } + case BINDER_TYPE_BINDER: + *out = reinterpret_cast<IBinder*>(flat->cookie); + return finish_unflatten_binder(nullptr, *flat, in); + case BINDER_TYPE_HANDLE: + *out = proc->getStrongProxyForHandle(flat->handle); + return finish_unflatten_binder( + static_cast<BpBinder*>(out->get()), *flat, in); + } + } + return BAD_TYPE; +} + +status_t unflatten_binder(const sp<ProcessState>& proc, + const Parcel& in, wp<IBinder>* out) +{ + const flat_binder_object* flat = in.readObject(false); + + if (flat) { + switch (flat->hdr.type) { + case BINDER_TYPE_BINDER: + *out = reinterpret_cast<IBinder*>(flat->cookie); + return finish_unflatten_binder(nullptr, *flat, in); + case BINDER_TYPE_WEAK_BINDER: + if (flat->binder != 0) { + out->set_object_and_refs( + reinterpret_cast<IBinder*>(flat->cookie), + reinterpret_cast<RefBase::weakref_type*>(flat->binder)); + } else { + *out = nullptr; + } + return finish_unflatten_binder(nullptr, *flat, in); + case BINDER_TYPE_HANDLE: + case BINDER_TYPE_WEAK_HANDLE: + *out = proc->getWeakProxyForHandle(flat->handle); + return finish_unflatten_binder( + static_cast<BpBinder*>(out->unsafe_get()), *flat, in); } } return BAD_TYPE; @@ -291,7 +389,7 @@ size_t Parcel::dataAvail() const { size_t result = dataSize() - dataPosition(); if (result > INT32_MAX) { - LOG_ALWAYS_FATAL("result too big: %zu", result); + abort(); } return result; } @@ -328,7 +426,7 @@ void Parcel::setDataPosition(size_t pos) const if (pos > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. - LOG_ALWAYS_FATAL("pos too big: %zu", pos); + abort(); } mDataPos = pos; @@ -422,8 +520,10 @@ status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) const sp<ProcessState> proc(ProcessState::self()); // grow objects if (mObjectsCapacity < mObjectsSize + numObjects) { + if ((size_t) numObjects > SIZE_MAX - mObjectsSize) return NO_MEMORY; // overflow + if (mObjectsSize + numObjects > SIZE_MAX / 3) return NO_MEMORY; // overflow size_t newSize = ((mObjectsSize + numObjects)*3)/2; - if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow + if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow binder_size_t *objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t)); if (objects == (binder_size_t*)nullptr) { @@ -505,12 +605,6 @@ void Parcel::updateWorkSourceRequestHeaderPosition() const { } } -#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)) -constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R'); -#else -constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T'); -#endif - // Write RPC headers. (previously just the interface token) status_t Parcel::writeInterfaceToken(const String16& interface) { @@ -519,7 +613,6 @@ status_t Parcel::writeInterfaceToken(const String16& interface) updateWorkSourceRequestHeaderPosition(); writeInt32(threadState->shouldPropagateWorkSource() ? threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource); - writeInt32(kHeader); // currently the interface identification token is just its name as a string return writeString16(interface); } @@ -537,7 +630,7 @@ bool Parcel::replaceCallingWorkSourceUid(uid_t uid) return err == NO_ERROR; } -uid_t Parcel::readCallingWorkSourceUid() const +uid_t Parcel::readCallingWorkSourceUid() { if (!mRequestHeaderPresent) { return IPCThreadState::kUnsetWorkSource; @@ -577,12 +670,6 @@ bool Parcel::enforceInterface(const String16& interface, updateWorkSourceRequestHeaderPosition(); int32_t workSource = readInt32(); threadState->setCallingWorkSourceUidWithoutPropagation(workSource); - // vendor header - int32_t header = readInt32(); - if (header != kHeader) { - ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader, header); - return false; - } // Interface descriptor. const String16 str(readString16()); if (str == interface) { @@ -594,6 +681,11 @@ bool Parcel::enforceInterface(const String16& interface, } } +const binder_size_t* Parcel::objects() const +{ + return mObjects; +} + size_t Parcel::objectsCount() const { return mObjectsSize; @@ -746,37 +838,61 @@ status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) { return writeUtf8AsUtf16(*str); } -status_t Parcel::writeByteVectorInternal(const int8_t* data, size_t size) { - if (size > std::numeric_limits<int32_t>::max()) { - return BAD_VALUE; +namespace { + +template<typename T> +status_t writeByteVectorInternal(Parcel* parcel, const std::vector<T>& val) +{ + status_t status; + if (val.size() > std::numeric_limits<int32_t>::max()) { + status = BAD_VALUE; + return status; } - status_t status = writeInt32(size); + status = parcel->writeInt32(val.size()); if (status != OK) { return status; } - return write(data, size); + void* data = parcel->writeInplace(val.size()); + if (!data) { + status = BAD_VALUE; + return status; + } + + memcpy(data, val.data(), val.size()); + return status; +} + +template<typename T> +status_t writeByteVectorInternalPtr(Parcel* parcel, + const std::unique_ptr<std::vector<T>>& val) +{ + if (!val) { + return parcel->writeInt32(-1); + } + + return writeByteVectorInternal(parcel, *val); } +} // namespace + status_t Parcel::writeByteVector(const std::vector<int8_t>& val) { - return writeByteVectorInternal(val.data(), val.size()); + return writeByteVectorInternal(this, val); } status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val) { - if (!val) return writeInt32(-1); - return writeByteVectorInternal(val->data(), val->size()); + return writeByteVectorInternalPtr(this, val); } status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) { - return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size()); + return writeByteVectorInternal(this, val); } status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val) { - if (!val) return writeInt32(-1); - return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size()); + return writeByteVectorInternalPtr(this, val); } status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val) @@ -1019,7 +1135,7 @@ status_t Parcel::writeString16(const char16_t* str, size_t len) status_t Parcel::writeStrongBinder(const sp<IBinder>& val) { - return flattenBinder(val); + return flatten_binder(ProcessState::self(), val, this); } status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val) @@ -1040,6 +1156,11 @@ status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const { return readTypedVector(val, &Parcel::readStrongBinder); } +status_t Parcel::writeWeakBinder(const wp<IBinder>& val) +{ + return flatten_binder(ProcessState::self(), val, this); +} + status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) { if (!parcelable) { return writeInt32(0); @@ -1056,6 +1177,10 @@ status_t Parcel::writeParcelable(const Parcelable& parcelable) { return parcelable.writeToParcel(this); } +status_t Parcel::writeValue(const binder::Value& value) { + return value.writeToParcel(this); +} + status_t Parcel::writeNativeHandle(const native_handle* handle) { if (!handle || handle->version != sizeof(native_handle)) @@ -1276,8 +1401,10 @@ restart_write: if (err != NO_ERROR) return err; } if (!enoughObjects) { + if (mObjectsSize > SIZE_MAX - 2) return NO_MEMORY; // overflow + if ((mObjectsSize + 2) > SIZE_MAX / 3) return NO_MEMORY; // overflow size_t newSize = ((mObjectsSize+2)*3)/2; - if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow + if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t)); if (objects == nullptr) return NO_MEMORY; mObjects = objects; @@ -1293,6 +1420,125 @@ status_t Parcel::writeNoException() return status.writeToParcel(this); } +status_t Parcel::writeMap(const ::android::binder::Map& map_in) +{ + using ::std::map; + using ::android::binder::Value; + using ::android::binder::Map; + + Map::const_iterator iter; + status_t ret; + + ret = writeInt32(map_in.size()); + + if (ret != NO_ERROR) { + return ret; + } + + for (iter = map_in.begin(); iter != map_in.end(); ++iter) { + ret = writeValue(Value(iter->first)); + if (ret != NO_ERROR) { + return ret; + } + + ret = writeValue(iter->second); + if (ret != NO_ERROR) { + return ret; + } + } + + return ret; +} + +status_t Parcel::writeNullableMap(const std::unique_ptr<binder::Map>& map) +{ + if (map == nullptr) { + return writeInt32(-1); + } + + return writeMap(*map.get()); +} + +status_t Parcel::readMap(::android::binder::Map* map_out)const +{ + using ::std::map; + using ::android::String16; + using ::android::String8; + using ::android::binder::Value; + using ::android::binder::Map; + + status_t ret = NO_ERROR; + int32_t count; + + ret = readInt32(&count); + if (ret != NO_ERROR) { + return ret; + } + + if (count < 0) { + ALOGE("readMap: Unexpected count: %d", count); + return (count == -1) + ? UNEXPECTED_NULL + : BAD_VALUE; + } + + map_out->clear(); + + while (count--) { + Map::key_type key; + Value value; + + ret = readValue(&value); + if (ret != NO_ERROR) { + return ret; + } + + if (!value.getString(&key)) { + ALOGE("readMap: Key type not a string (parcelType = %d)", value.parcelType()); + return BAD_VALUE; + } + + ret = readValue(&value); + if (ret != NO_ERROR) { + return ret; + } + + (*map_out)[key] = value; + } + + return ret; +} + +status_t Parcel::readNullableMap(std::unique_ptr<binder::Map>* map) const +{ + const size_t start = dataPosition(); + int32_t count; + status_t status = readInt32(&count); + map->reset(); + + if (status != OK || count == -1) { + return status; + } + + setDataPosition(start); + map->reset(new binder::Map()); + + status = readMap(map->get()); + + if (status != OK) { + map->reset(); + } + + return status; +} + + + +void Parcel::remove(size_t /*start*/, size_t /*amt*/) +{ + LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!"); +} + status_t Parcel::validateReadData(size_t upperBound) const { // Don't allow non-object reads on object data @@ -1449,38 +1695,81 @@ restart_write: return err; } +namespace { + +template<typename T> +status_t readByteVectorInternal(const Parcel* parcel, + std::vector<T>* val) { + val->clear(); + + int32_t size; + status_t status = parcel->readInt32(&size); + + if (status != OK) { + return status; + } + + if (size < 0) { + status = UNEXPECTED_NULL; + return status; + } + if (size_t(size) > parcel->dataAvail()) { + status = BAD_VALUE; + return status; + } + + T* data = const_cast<T*>(reinterpret_cast<const T*>(parcel->readInplace(size))); + if (!data) { + status = BAD_VALUE; + return status; + } + val->reserve(size); + val->insert(val->end(), data, data + size); + + return status; +} + +template<typename T> +status_t readByteVectorInternalPtr( + const Parcel* parcel, + std::unique_ptr<std::vector<T>>* val) { + const int32_t start = parcel->dataPosition(); + int32_t size; + status_t status = parcel->readInt32(&size); + val->reset(); + + if (status != OK || size < 0) { + return status; + } + + parcel->setDataPosition(start); + val->reset(new (std::nothrow) std::vector<T>()); + + status = readByteVectorInternal(parcel, val->get()); + + if (status != OK) { + val->reset(); + } + + return status; +} + +} // namespace + status_t Parcel::readByteVector(std::vector<int8_t>* val) const { - size_t size; - if (status_t status = reserveOutVector(val, &size); status != OK) return status; - return readByteVectorInternal(val, size); + return readByteVectorInternal(this, val); } status_t Parcel::readByteVector(std::vector<uint8_t>* val) const { - size_t size; - if (status_t status = reserveOutVector(val, &size); status != OK) return status; - return readByteVectorInternal(val, size); + return readByteVectorInternal(this, val); } status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const { - size_t size; - if (status_t status = reserveOutVector(val, &size); status != OK) return status; - if (val->get() == nullptr) { - // reserveOutVector does not create the out vector if size is < 0. - // This occurs when writing a null byte vector. - return OK; - } - return readByteVectorInternal(val->get(), size); + return readByteVectorInternalPtr(this, val); } status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const { - size_t size; - if (status_t status = reserveOutVector(val, &size); status != OK) return status; - if (val->get() == nullptr) { - // reserveOutVector does not create the out vector if size is < 0. - // This occurs when writing a null byte vector. - return OK; - } - return readByteVectorInternal(val->get(), size); + return readByteVectorInternalPtr(this, val); } status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const { @@ -1922,7 +2211,7 @@ status_t Parcel::readStrongBinder(sp<IBinder>* val) const status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const { - return unflattenBinder(val); + return unflatten_binder(ProcessState::self(), *this, val); } sp<IBinder> Parcel::readStrongBinder() const @@ -1935,6 +2224,13 @@ sp<IBinder> Parcel::readStrongBinder() const return val; } +wp<IBinder> Parcel::readWeakBinder() const +{ + wp<IBinder> val; + unflatten_binder(ProcessState::self(), *this, &val); + return val; +} + status_t Parcel::readParcelable(Parcelable* parcelable) const { int32_t have_parcelable = 0; status_t status = readInt32(&have_parcelable); @@ -1947,6 +2243,10 @@ status_t Parcel::readParcelable(Parcelable* parcelable) const { return parcelable->readFromParcel(this); } +status_t Parcel::readValue(binder::Value* value) const { + return value->readFromParcel(this); +} + int32_t Parcel::readExceptionCode() const { binder::Status status; @@ -2298,7 +2598,7 @@ void Parcel::print(TextOutput& to, uint32_t /*flags*/) const } else if (dataSize() > 0) { const uint8_t* DATA = data(); to << indent << HexDump(DATA, dataSize()) << dedent; - const binder_size_t* OBJS = mObjects; + const binder_size_t* OBJS = objects(); const size_t N = objectsCount(); for (size_t i=0; i<N; i++) { const flat_binder_object* flat @@ -2389,6 +2689,8 @@ status_t Parcel::growData(size_t len) return BAD_VALUE; } + if (len > SIZE_MAX - mDataSize) return NO_MEMORY; // overflow + if (mDataSize + len > SIZE_MAX / 3) return NO_MEMORY; // overflow size_t newSize = ((mDataSize+len)*3)/2; return (newSize <= mDataSize) ? (status_t) NO_MEMORY @@ -2543,11 +2845,13 @@ status_t Parcel::continueWrite(size_t desired) if (objectsSize == 0) { free(mObjects); mObjects = nullptr; + mObjectsCapacity = 0; } else { binder_size_t* objects = (binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t)); if (objects) { mObjects = objects; + mObjectsCapacity = objectsSize; } } mObjectsSize = objectsSize; @@ -2706,4 +3010,4 @@ void Parcel::Blob::clear() { mMutable = false; } -} // namespace android +}; // namespace android diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp index 75a6d22969..a4c28ad74e 100644 --- a/libs/binder/PermissionCache.cpp +++ b/libs/binder/PermissionCache.cpp @@ -110,4 +110,4 @@ bool PermissionCache::checkPermission( } // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android diff --git a/libs/binder/PermissionController.cpp b/libs/binder/PermissionController.cpp index 0c8924503d..34b2ca5170 100644 --- a/libs/binder/PermissionController.cpp +++ b/libs/binder/PermissionController.cpp @@ -85,4 +85,4 @@ int PermissionController::getPackageUid(const String16& package, int flags) return service != nullptr ? service->getPackageUid(package, flags) : -1; } -} // namespace android +}; // namespace android diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp index 97a6c94635..c0aec0a979 100644 --- a/libs/binder/PersistableBundle.cpp +++ b/libs/binder/PersistableBundle.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "PersistableBundle" #include <binder/PersistableBundle.h> +#include <private/binder/ParcelValTypes.h> #include <limits> @@ -25,8 +26,6 @@ #include <log/log.h> #include <utils/Errors.h> -#include "ParcelValTypes.h" - using android::BAD_TYPE; using android::BAD_VALUE; using android::NO_ERROR; diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp index 00d6eefabe..5cb2033b07 100644 --- a/libs/binder/ProcessInfoService.cpp +++ b/libs/binder/ProcessInfoService.cpp @@ -101,4 +101,4 @@ void ProcessInfoService::updateBinderLocked() { ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService); -} // namespace android +}; // namespace android diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index ea61dc5aff..63f49ddba7 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -21,14 +21,14 @@ #include <binder/BpBinder.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> -#include <binder/Stability.h> #include <cutils/atomic.h> #include <utils/Log.h> #include <utils/String8.h> +#include <utils/String8.h> #include <utils/threads.h> #include <private/binder/binder_module.h> -#include "Static.h" +#include <private/binder/Static.h> #include <errno.h> #include <fcntl.h> @@ -108,15 +108,56 @@ sp<ProcessState> ProcessState::selfOrNull() return gProcess; } +void ProcessState::setContextObject(const sp<IBinder>& object) +{ + setContextObject(object, String16("default")); +} + sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/) { - sp<IBinder> context = getStrongProxyForHandle(0); + return getStrongProxyForHandle(0); +} + +void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name) +{ + AutoMutex _l(mLock); + mContexts.add(name, object); +} - // The root object is special since we get it directly from the driver, it is never - // written by Parcell::writeStrongBinder. - internal::Stability::tryMarkCompilationUnit(context.get()); +sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller) +{ + mLock.lock(); + sp<IBinder> object( + mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : nullptr); + mLock.unlock(); + + //printf("Getting context object %s for %p\n", String8(name).string(), caller.get()); + + if (object != nullptr) return object; - return context; + // Don't attempt to retrieve contexts if we manage them + if (mManagesContexts) { + ALOGE("getContextObject(%s) failed, but we manage the contexts!\n", + String8(name).string()); + return nullptr; + } + + IPCThreadState* ipc = IPCThreadState::self(); + { + Parcel data, reply; + // no interface token on this magic transaction + data.writeString16(name); + data.writeStrongBinder(caller); + status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0); + if (result == NO_ERROR) { + object = reply.readStrongBinder(); + } + } + + ipc->flushCommands(); + + if (object != nullptr) setContextObject(object, name); + return object; } void ProcessState::startThreadPool() @@ -128,33 +169,41 @@ void ProcessState::startThreadPool() } } +bool ProcessState::isContextManager(void) const +{ + return mManagesContexts; +} + bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData) { - AutoMutex _l(mLock); - mBinderContextCheckFunc = checkFunc; - mBinderContextUserData = userData; + if (!mManagesContexts) { + AutoMutex _l(mLock); + mBinderContextCheckFunc = checkFunc; + mBinderContextUserData = userData; - flat_binder_object obj { - .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX, - }; + flat_binder_object obj { + .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX, + }; - int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj); + status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj); - // fallback to original method - if (result != 0) { - android_errorWriteLog(0x534e4554, "121035042"); + // fallback to original method + if (result != 0) { + android_errorWriteLog(0x534e4554, "121035042"); - int dummy = 0; - result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy); - } + int dummy = 0; + result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy); + } - if (result == -1) { - mBinderContextCheckFunc = nullptr; - mBinderContextUserData = nullptr; - ALOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno)); + if (result == 0) { + mManagesContexts = true; + } else if (result == -1) { + mBinderContextCheckFunc = nullptr; + mBinderContextUserData = nullptr; + ALOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno)); + } } - - return result == 0; + return mManagesContexts; } // Get references to userspace objects held by the kernel binder driver @@ -188,33 +237,8 @@ ssize_t ProcessState::getKernelReferences(size_t buf_count, uintptr_t* buf) return count; } -// Queries the driver for the current strong reference count of the node -// that the handle points to. Can only be used by the servicemanager. -// -// Returns -1 in case of failure, otherwise the strong reference count. -ssize_t ProcessState::getStrongRefCountForNodeByHandle(int32_t handle) { - binder_node_info_for_ref info; - memset(&info, 0, sizeof(binder_node_info_for_ref)); - - info.handle = handle; - - status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info); - - if (result != OK) { - static bool logged = false; - if (!logged) { - ALOGW("Kernel does not support BINDER_GET_NODE_INFO_FOR_REF."); - logged = true; - } - return -1; - } - - return info.strong_count; -} - void ProcessState::setCallRestriction(CallRestriction restriction) { - LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull() != nullptr, - "Call restrictions must be set before the threadpool is started."); + LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull(), "Call restrictions must be set before the threadpool is started."); mCallRestriction = restriction; } @@ -242,12 +266,8 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) if (e != nullptr) { // We need to create a new BpBinder if there isn't currently one, OR we - // are unable to acquire a weak reference on this current one. The - // attemptIncWeak() is safe because we know the BpBinder destructor will always - // call expungeHandle(), which acquires the same lock we are holding now. - // We need to do this because there is a race condition between someone - // releasing a reference on this BpBinder, and a new reference on its handle - // arriving from the driver. + // are unable to acquire a weak reference on this current one. See comment + // in getWeakProxyForHandle() for more info about this. IBinder* b = e->binder; if (b == nullptr || !e->refs->attemptIncWeak(this)) { if (handle == 0) { @@ -293,6 +313,37 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) return result; } +wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle) +{ + wp<IBinder> result; + + AutoMutex _l(mLock); + + handle_entry* e = lookupHandleLocked(handle); + + if (e != nullptr) { + // We need to create a new BpBinder if there isn't currently one, OR we + // are unable to acquire a weak reference on this current one. The + // attemptIncWeak() is safe because we know the BpBinder destructor will always + // call expungeHandle(), which acquires the same lock we are holding now. + // We need to do this because there is a race condition between someone + // releasing a reference on this BpBinder, and a new reference on its handle + // arriving from the driver. + IBinder* b = e->binder; + if (b == nullptr || !e->refs->attemptIncWeak(this)) { + b = BpBinder::create(handle); + result = b; + e->binder = b; + if (b) e->refs = b->getWeakRefs(); + } else { + result = b; + e->refs->decWeak(this); + } + } + + return result; +} + void ProcessState::expungeHandle(int32_t handle, IBinder* binder) { AutoMutex _l(mLock); @@ -379,6 +430,7 @@ ProcessState::ProcessState(const char *driver) , mExecutingThreadsCount(0) , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mStarvationStartTimeMs(0) + , mManagesContexts(false) , mBinderContextCheckFunc(nullptr) , mBinderContextUserData(nullptr) , mThreadPoolStarted(false) @@ -397,7 +449,7 @@ ProcessState::ProcessState(const char *driver) } } - LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened. Terminating.", driver); + LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating."); } ProcessState::~ProcessState() @@ -411,4 +463,4 @@ ProcessState::~ProcessState() mDriverFD = -1; } -} // namespace android +}; // namespace android diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp deleted file mode 100644 index 7ce5e36292..0000000000 --- a/libs/binder/Stability.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2019 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 <binder/Stability.h> - -namespace android { -namespace internal { - -void Stability::markCompilationUnit(IBinder* binder) { - status_t result = set(binder, kLocalStability, true /*log*/); - LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); -} - -void Stability::markVintf(IBinder* binder) { - status_t result = set(binder, Level::VINTF, true /*log*/); - LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); -} - -void Stability::debugLogStability(const std::string& tag, const sp<IBinder>& binder) { - ALOGE("%s: stability is %s", tag.c_str(), stabilityString(get(binder.get())).c_str()); -} - -void Stability::markVndk(IBinder* binder) { - status_t result = set(binder, Level::VENDOR, true /*log*/); - LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); -} - -bool Stability::requiresVintfDeclaration(const sp<IBinder>& binder) { - return check(get(binder.get()), Level::VINTF); -} - -void Stability::tryMarkCompilationUnit(IBinder* binder) { - (void) set(binder, kLocalStability, false /*log*/); -} - -status_t Stability::set(IBinder* binder, int32_t stability, bool log) { - Level currentStability = get(binder); - - // null binder is always written w/ 'UNDECLARED' stability - if (binder == nullptr) { - if (stability == UNDECLARED) { - return OK; - } else { - if (log) { - ALOGE("Null binder written with stability %s.", - stabilityString(stability).c_str()); - } - return BAD_TYPE; - } - } - - if (!isDeclaredStability(stability)) { - if (log) { - ALOGE("Can only set known stability, not %d.", stability); - } - return BAD_TYPE; - } - - if (currentStability != Level::UNDECLARED && currentStability != stability) { - if (log) { - ALOGE("Interface being set with %s but it is already marked as %s.", - stabilityString(stability).c_str(), stabilityString(currentStability).c_str()); - } - return BAD_TYPE; - } - - if (currentStability == stability) return OK; - - binder->attachObject( - reinterpret_cast<void*>(&Stability::get), - reinterpret_cast<void*>(stability), - nullptr /*cleanupCookie*/, - nullptr /*cleanup function*/); - - return OK; -} - -Stability::Level Stability::get(IBinder* binder) { - if (binder == nullptr) return UNDECLARED; - - return static_cast<Level>(reinterpret_cast<intptr_t>( - binder->findObject(reinterpret_cast<void*>(&Stability::get)))); -} - -bool Stability::check(int32_t provided, Level required) { - bool stable = (provided & required) == required; - - if (!isDeclaredStability(provided) && provided != UNDECLARED) { - ALOGE("Unknown stability when checking interface stability %d.", provided); - - stable = false; - } - - return stable; -} - -bool Stability::isDeclaredStability(int32_t stability) { - return stability == VENDOR || stability == SYSTEM || stability == VINTF; -} - -std::string Stability::stabilityString(int32_t stability) { - switch (stability) { - case Level::UNDECLARED: return "undeclared stability"; - case Level::VENDOR: return "vendor stability"; - case Level::SYSTEM: return "system stability"; - case Level::VINTF: return "vintf stability"; - } - return "unknown stability " + std::to_string(stability); -} - -} // namespace internal -} // namespace stability diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp index bd40536884..bd0e6f9a11 100644 --- a/libs/binder/Static.cpp +++ b/libs/binder/Static.cpp @@ -17,7 +17,7 @@ // All static variables go here, to control initialization and // destruction order in the library. -#include "Static.h" +#include <private/binder/Static.h> #include <binder/BufferedTextOutput.h> #include <binder/IPCThreadState.h> @@ -54,9 +54,7 @@ public: protected: virtual status_t writeLines(const struct iovec& vec, size_t N) { - ssize_t ret = writev(mFD, &vec, N); - if (ret == -1) return -errno; - if (static_cast<size_t>(ret) != N) return UNKNOWN_ERROR; + writev(mFD, &vec, N); return NO_ERROR; } @@ -77,4 +75,13 @@ TextOutput& aerr(gStderrTextOutput); Mutex& gProcessMutex = *new Mutex; sp<ProcessState> gProcess; +// ------------ IServiceManager.cpp + +Mutex gDefaultServiceManagerLock; +sp<IServiceManager> gDefaultServiceManager; +#ifndef __ANDROID_VNDK__ +sp<IPermissionController> gPermissionController; +#endif +bool gSystemBootCompleted = false; + } // namespace android diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING deleted file mode 100644 index b3afd817c1..0000000000 --- a/libs/binder/TEST_MAPPING +++ /dev/null @@ -1,25 +0,0 @@ -{ - "presubmit": [ - { - "name": "binderSafeInterfaceTest" - }, - { - "name": "binderVendorDoubleLoadTest" - }, - { - "name": "binderDriverInterfaceTest" - }, - { - "name": "binderTextOutputTest" - }, - { - "name": "binderLibTest" - }, - { - "name": "binderStabilityTest" - }, - { - "name": "CtsNdkBinderTestCases" - } - ] -} diff --git a/libs/binder/TextOutput.cpp b/libs/binder/TextOutput.cpp index 684a7dcc51..101eba318f 100644 --- a/libs/binder/TextOutput.cpp +++ b/libs/binder/TextOutput.cpp @@ -69,4 +69,4 @@ TextOutput& operator<<(TextOutput& to, const HexDump& val) return to; } -} // namespace android +}; // namespace android diff --git a/libs/binder/Value.cpp b/libs/binder/Value.cpp new file mode 100644 index 0000000000..19c57ba128 --- /dev/null +++ b/libs/binder/Value.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Value" + +#include <binder/Value.h> + +#include <limits> + +#include <binder/IBinder.h> +#include <binder/Parcel.h> +#include <binder/Map.h> +#include <private/binder/ParcelValTypes.h> +#include <log/log.h> +#include <utils/Errors.h> + +using android::BAD_TYPE; +using android::BAD_VALUE; +using android::NO_ERROR; +using android::UNEXPECTED_NULL; +using android::Parcel; +using android::sp; +using android::status_t; +using std::map; +using std::set; +using std::vector; +using android::binder::Value; +using android::IBinder; +using android::os::PersistableBundle; +using namespace android::binder; + +// ==================================================================== + +#define RETURN_IF_FAILED(calledOnce) \ + do { \ + status_t returnStatus = calledOnce; \ + if (returnStatus) { \ + ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ + return returnStatus; \ + } \ + } while(false) + +// ==================================================================== + +/* These `internal_type_ptr()` functions allow this + * class to work without C++ RTTI support. This technique + * only works properly when called directly from this file, + * but that is OK because that is the only place we will + * be calling them from. */ +template<class T> const void* internal_type_ptr() +{ + static const T *marker; + return (void*)▮ +} + +/* Allows the type to be specified by the argument + * instead of inside angle brackets. */ +template<class T> const void* internal_type_ptr(const T&) +{ + return internal_type_ptr<T>(); +} + +// ==================================================================== + +namespace android { + +namespace binder { + +class Value::ContentBase { +public: + virtual ~ContentBase() = default; + virtual const void* type_ptr() const = 0; + virtual ContentBase * clone() const = 0; + virtual bool operator==(const ContentBase& rhs) const = 0; + +#ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO + virtual const std::type_info &type() const = 0; +#endif + + template<typename T> bool get(T* out) const; +}; + +/* This is the actual class that holds the value. */ +template<typename T> class Value::Content : public Value::ContentBase { +public: + Content() = default; + explicit Content(const T & value) : mValue(value) { } + + virtual ~Content() = default; + +#ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO + virtual const std::type_info &type() const override + { + return typeid(T); + } +#endif + + virtual const void* type_ptr() const override + { + return internal_type_ptr<T>(); + } + + virtual ContentBase * clone() const override + { + return new Content(mValue); + }; + + virtual bool operator==(const ContentBase& rhs) const override + { + if (type_ptr() != rhs.type_ptr()) { + return false; + } + return mValue == static_cast<const Content<T>* >(&rhs)->mValue; + } + + T mValue; +}; + +template<typename T> bool Value::ContentBase::get(T* out) const +{ + if (internal_type_ptr(*out) != type_ptr()) + { + return false; + } + + *out = static_cast<const Content<T>*>(this)->mValue; + + return true; +} + +// ==================================================================== + +Value::Value() : mContent(nullptr) +{ +} + +Value::Value(const Value& value) + : mContent(value.mContent ? value.mContent->clone() : nullptr) +{ +} + +Value::~Value() +{ + delete mContent; +} + +bool Value::operator==(const Value& rhs) const +{ + const Value& lhs(*this); + + if (lhs.empty() && rhs.empty()) { + return true; + } + + if ( (lhs.mContent == nullptr) + || (rhs.mContent == nullptr) + ) { + return false; + } + + return *lhs.mContent == *rhs.mContent; +} + +Value& Value::swap(Value &rhs) +{ + std::swap(mContent, rhs.mContent); + return *this; +} + +Value& Value::operator=(const Value& rhs) +{ + if (this != &rhs) { + delete mContent; + mContent = rhs.mContent + ? rhs.mContent->clone() + : nullptr; + } + return *this; +} + +bool Value::empty() const +{ + return mContent == nullptr; +} + +void Value::clear() +{ + delete mContent; + mContent = nullptr; +} + +int32_t Value::parcelType() const +{ + const void* t_info(mContent ? mContent->type_ptr() : nullptr); + + if (t_info == internal_type_ptr<bool>()) return VAL_BOOLEAN; + if (t_info == internal_type_ptr<uint8_t>()) return VAL_BYTE; + if (t_info == internal_type_ptr<int32_t>()) return VAL_INTEGER; + if (t_info == internal_type_ptr<int64_t>()) return VAL_LONG; + if (t_info == internal_type_ptr<double>()) return VAL_DOUBLE; + if (t_info == internal_type_ptr<String16>()) return VAL_STRING; + + if (t_info == internal_type_ptr<vector<bool>>()) return VAL_BOOLEANARRAY; + if (t_info == internal_type_ptr<vector<uint8_t>>()) return VAL_BYTEARRAY; + if (t_info == internal_type_ptr<vector<int32_t>>()) return VAL_INTARRAY; + if (t_info == internal_type_ptr<vector<int64_t>>()) return VAL_LONGARRAY; + if (t_info == internal_type_ptr<vector<double>>()) return VAL_DOUBLEARRAY; + if (t_info == internal_type_ptr<vector<String16>>()) return VAL_STRINGARRAY; + + if (t_info == internal_type_ptr<Map>()) return VAL_MAP; + if (t_info == internal_type_ptr<PersistableBundle>()) return VAL_PERSISTABLEBUNDLE; + + return VAL_NULL; +} + +#ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO +const std::type_info& Value::type() const +{ + return mContent != nullptr + ? mContent->type() + : typeid(void); +} +#endif // ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO + +#define DEF_TYPE_ACCESSORS(T, TYPENAME) \ + bool Value::is ## TYPENAME() const \ + { \ + return mContent \ + ? internal_type_ptr<T>() == mContent->type_ptr() \ + : false; \ + } \ + bool Value::get ## TYPENAME(T* out) const \ + { \ + return mContent \ + ? mContent->get(out) \ + : false; \ + } \ + void Value::put ## TYPENAME(const T& in) \ + { \ + *this = in; \ + } \ + Value& Value::operator=(const T& rhs) \ + { \ + delete mContent; \ + mContent = new Content< T >(rhs); \ + return *this; \ + } \ + Value::Value(const T& value) \ + : mContent(new Content< T >(value)) \ + { } + +DEF_TYPE_ACCESSORS(bool, Boolean) +DEF_TYPE_ACCESSORS(int8_t, Byte) +DEF_TYPE_ACCESSORS(int32_t, Int) +DEF_TYPE_ACCESSORS(int64_t, Long) +DEF_TYPE_ACCESSORS(double, Double) +DEF_TYPE_ACCESSORS(String16, String) + +DEF_TYPE_ACCESSORS(std::vector<bool>, BooleanVector) +DEF_TYPE_ACCESSORS(std::vector<uint8_t>, ByteVector) +DEF_TYPE_ACCESSORS(std::vector<int32_t>, IntVector) +DEF_TYPE_ACCESSORS(std::vector<int64_t>, LongVector) +DEF_TYPE_ACCESSORS(std::vector<double>, DoubleVector) +DEF_TYPE_ACCESSORS(std::vector<String16>, StringVector) + +DEF_TYPE_ACCESSORS(::android::binder::Map, Map) +DEF_TYPE_ACCESSORS(PersistableBundle, PersistableBundle) + +bool Value::getString(String8* out) const +{ + String16 val; + bool ret = getString(&val); + if (ret) { + *out = String8(val); + } + return ret; +} + +bool Value::getString(::std::string* out) const +{ + String8 val; + bool ret = getString(&val); + if (ret) { + *out = val.string(); + } + return ret; +} + +status_t Value::writeToParcel(Parcel* parcel) const +{ + // This implementation needs to be kept in sync with the writeValue + // implementation in frameworks/base/core/java/android/os/Parcel.java + +#define BEGIN_HANDLE_WRITE() \ + do { \ + const void* t_info(mContent?mContent->type_ptr():nullptr); \ + if (false) { } +#define HANDLE_WRITE_TYPE(T, TYPEVAL, TYPEMETHOD) \ + else if (t_info == internal_type_ptr<T>()) { \ + RETURN_IF_FAILED(parcel->writeInt32(TYPEVAL)); \ + RETURN_IF_FAILED(parcel->TYPEMETHOD(static_cast<const Content<T>*>(mContent)->mValue)); \ + } +#define HANDLE_WRITE_PARCELABLE(T, TYPEVAL) \ + else if (t_info == internal_type_ptr<T>()) { \ + RETURN_IF_FAILED(parcel->writeInt32(TYPEVAL)); \ + RETURN_IF_FAILED(static_cast<const Content<T>*>(mContent)->mValue.writeToParcel(parcel)); \ + } +#define END_HANDLE_WRITE() \ + else { \ + ALOGE("writeToParcel: Type not supported"); \ + return BAD_TYPE; \ + } \ + } while (false); + + BEGIN_HANDLE_WRITE() + + HANDLE_WRITE_TYPE(bool, VAL_BOOLEAN, writeBool) + HANDLE_WRITE_TYPE(int8_t, VAL_BYTE, writeByte) + HANDLE_WRITE_TYPE(int8_t, VAL_BYTE, writeByte) + HANDLE_WRITE_TYPE(int32_t, VAL_INTEGER, writeInt32) + HANDLE_WRITE_TYPE(int64_t, VAL_LONG, writeInt64) + HANDLE_WRITE_TYPE(double, VAL_DOUBLE, writeDouble) + HANDLE_WRITE_TYPE(String16, VAL_STRING, writeString16) + + HANDLE_WRITE_TYPE(vector<bool>, VAL_BOOLEANARRAY, writeBoolVector) + HANDLE_WRITE_TYPE(vector<uint8_t>, VAL_BYTEARRAY, writeByteVector) + HANDLE_WRITE_TYPE(vector<int8_t>, VAL_BYTEARRAY, writeByteVector) + HANDLE_WRITE_TYPE(vector<int32_t>, VAL_INTARRAY, writeInt32Vector) + HANDLE_WRITE_TYPE(vector<int64_t>, VAL_LONGARRAY, writeInt64Vector) + HANDLE_WRITE_TYPE(vector<double>, VAL_DOUBLEARRAY, writeDoubleVector) + HANDLE_WRITE_TYPE(vector<String16>, VAL_STRINGARRAY, writeString16Vector) + + HANDLE_WRITE_PARCELABLE(PersistableBundle, VAL_PERSISTABLEBUNDLE) + + END_HANDLE_WRITE() + + return NO_ERROR; + +#undef BEGIN_HANDLE_WRITE +#undef HANDLE_WRITE_TYPE +#undef HANDLE_WRITE_PARCELABLE +#undef END_HANDLE_WRITE +} + +status_t Value::readFromParcel(const Parcel* parcel) +{ + // This implementation needs to be kept in sync with the readValue + // implementation in frameworks/base/core/java/android/os/Parcel.javai + +#define BEGIN_HANDLE_READ() \ + switch(value_type) { \ + default: \ + ALOGE("readFromParcel: Parcel type %d is not supported", value_type); \ + return BAD_TYPE; +#define HANDLE_READ_TYPE(T, TYPEVAL, TYPEMETHOD) \ + case TYPEVAL: \ + mContent = new Content<T>(); \ + RETURN_IF_FAILED(parcel->TYPEMETHOD(&static_cast<Content<T>*>(mContent)->mValue)); \ + break; +#define HANDLE_READ_PARCELABLE(T, TYPEVAL) \ + case TYPEVAL: \ + mContent = new Content<T>(); \ + RETURN_IF_FAILED(static_cast<Content<T>*>(mContent)->mValue.readFromParcel(parcel)); \ + break; +#define END_HANDLE_READ() \ + } + + int32_t value_type = VAL_NULL; + + delete mContent; + mContent = nullptr; + + RETURN_IF_FAILED(parcel->readInt32(&value_type)); + + BEGIN_HANDLE_READ() + + HANDLE_READ_TYPE(bool, VAL_BOOLEAN, readBool) + HANDLE_READ_TYPE(int8_t, VAL_BYTE, readByte) + HANDLE_READ_TYPE(int32_t, VAL_INTEGER, readInt32) + HANDLE_READ_TYPE(int64_t, VAL_LONG, readInt64) + HANDLE_READ_TYPE(double, VAL_DOUBLE, readDouble) + HANDLE_READ_TYPE(String16, VAL_STRING, readString16) + + HANDLE_READ_TYPE(vector<bool>, VAL_BOOLEANARRAY, readBoolVector) + HANDLE_READ_TYPE(vector<uint8_t>, VAL_BYTEARRAY, readByteVector) + HANDLE_READ_TYPE(vector<int32_t>, VAL_INTARRAY, readInt32Vector) + HANDLE_READ_TYPE(vector<int64_t>, VAL_LONGARRAY, readInt64Vector) + HANDLE_READ_TYPE(vector<double>, VAL_DOUBLEARRAY, readDoubleVector) + HANDLE_READ_TYPE(vector<String16>, VAL_STRINGARRAY, readString16Vector) + + HANDLE_READ_PARCELABLE(PersistableBundle, VAL_PERSISTABLEBUNDLE) + + END_HANDLE_READ() + + return NO_ERROR; + +#undef BEGIN_HANDLE_READ +#undef HANDLE_READ_TYPE +#undef HANDLE_READ_PARCELABLE +#undef END_HANDLE_READ +} + +} // namespace binder + +} // namespace android + +/* vim: set ts=4 sw=4 tw=0 et :*/ diff --git a/libs/binder/aidl/android/os/IServiceCallback.aidl b/libs/binder/aidl/android/os/IServiceCallback.aidl deleted file mode 100644 index b29dfedf70..0000000000 --- a/libs/binder/aidl/android/os/IServiceCallback.aidl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2019 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.os; - -/** - * @hide - */ -oneway interface IServiceCallback { - /** - * Called when a service is registered. - * - * @param name the service name that has been registered with - * @param binder the binder that is registered - */ - void onRegistration(@utf8InCpp String name, IBinder binder); -} diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl deleted file mode 100644 index 8c7ebbaf36..0000000000 --- a/libs/binder/aidl/android/os/IServiceManager.aidl +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2006 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.os; - -import android.os.IServiceCallback; - -/** - * Basic interface for finding and publishing system services. - * - * You likely want to use android.os.ServiceManager in Java or - * android::IServiceManager in C++ in order to use this interface. - * - * @hide - */ -interface IServiceManager { - /* - * Must update values in IServiceManager.h - */ - /* Allows services to dump sections according to priorities. */ - const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0; - const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1; - const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2; - /** - * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the - * same priority as NORMAL priority but the services are not called with dump priority - * arguments. - */ - const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3; - - const int DUMP_FLAG_PRIORITY_ALL = 15; - // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH - // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT; - - /* Allows services to dump sections in protobuf format. */ - const int DUMP_FLAG_PROTO = 1 << 4; - - /** - * Retrieve an existing service called @a name from the - * service manager. - * - * This is the same as checkService (returns immediately) but - * exists for legacy purposes. - * - * Returns null if the service does not exist. - */ - @UnsupportedAppUsage - IBinder getService(@utf8InCpp String name); - - /** - * Retrieve an existing service called @a name from the service - * manager. Non-blocking. Returns null if the service does not - * exist. - */ - @UnsupportedAppUsage - IBinder checkService(@utf8InCpp String name); - - /** - * Place a new @a service called @a name into the service - * manager. - */ - void addService(@utf8InCpp String name, IBinder service, - boolean allowIsolated, int dumpPriority); - - /** - * Return a list of all currently running services. - */ - @utf8InCpp String[] listServices(int dumpPriority); - - /** - * Request a callback when a service is registered. - */ - void registerForNotifications(@utf8InCpp String name, IServiceCallback callback); - - /** - * Unregisters all requests for notifications for a specific callback. - */ - void unregisterForNotifications(@utf8InCpp String name, IServiceCallback callback); - - /** - * Returns whether a given interface is declared on the device, even if it - * is not started yet. For instance, this could be a service declared in the VINTF - * manifest. - */ - boolean isDeclared(@utf8InCpp String name); -} diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h index 9108e31758..5f324c7965 100644 --- a/libs/binder/include/binder/ActivityManager.h +++ b/libs/binder/include/binder/ActivityManager.h @@ -89,7 +89,7 @@ private: }; -} // namespace android +}; // namespace android // --------------------------------------------------------------------------- #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index b19cde75b6..17493b4252 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -133,7 +133,7 @@ private: }; -} // namespace android +}; // namespace android // --------------------------------------------------------------------------- #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 3be61f9409..cf3ef84caa 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -38,7 +38,7 @@ public: virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags = 0) final; + uint32_t flags = 0); // NOLINTNEXTLINE(google-default-arguments) virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, @@ -54,9 +54,9 @@ public: virtual void attachObject( const void* objectID, void* object, void* cleanupCookie, - object_cleanup_func func) final; - virtual void* findObject(const void* objectID) const final; - virtual void detachObject(const void* objectID) final; + object_cleanup_func func); + virtual void* findObject(const void* objectID) const; + virtual void detachObject(const void* objectID); virtual BBinder* localBinder(); @@ -64,12 +64,6 @@ public: // This must be called before the object is sent to another process. Not thread safe. void setRequestingSid(bool requestSid); - sp<IBinder> getExtension(); - // This must be called before the object is sent to another process. Not thread safe. - void setExtension(const sp<IBinder>& extension); - - pid_t getDebugPid(); - protected: virtual ~BBinder(); @@ -114,7 +108,7 @@ private: std::atomic<int32_t> mState; }; -} // namespace android +}; // namespace android // --------------------------------------------------------------------------- diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h index c17ae6f5fe..9230e89cdf 100644 --- a/libs/binder/include/binder/BinderService.h +++ b/libs/binder/include/binder/BinderService.h @@ -62,6 +62,6 @@ private: }; -} // namespace android +}; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_BINDER_SERVICE_H diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 7dca733b52..1d4f88113a 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -34,7 +34,7 @@ class BpBinder : public IBinder public: static BpBinder* create(int32_t handle); - int32_t handle() const; + inline int32_t handle() const { return mHandle; } virtual const String16& getInterfaceDescriptor() const; virtual bool isBinderAlive() const; @@ -45,7 +45,7 @@ public: virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags = 0) final; + uint32_t flags = 0); // NOLINTNEXTLINE(google-default-arguments) virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, @@ -61,12 +61,13 @@ public: virtual void attachObject( const void* objectID, void* object, void* cleanupCookie, - object_cleanup_func func) final; - virtual void* findObject(const void* objectID) const final; - virtual void detachObject(const void* objectID) final; + object_cleanup_func func); + virtual void* findObject(const void* objectID) const; + virtual void detachObject(const void* objectID); virtual BpBinder* remoteBinder(); + status_t setConstantData(const void* data, size_t size); void sendObituary(); static uint32_t getBinderProxyCount(uint32_t uid); @@ -144,7 +145,7 @@ private: static bool sBinderProxyThrottleCreate; }; -} // namespace android +}; // namespace android // --------------------------------------------------------------------------- diff --git a/libs/binder/include/binder/BufferedTextOutput.h b/libs/binder/include/binder/BufferedTextOutput.h index 1b27bb2249..feae93dea1 100644 --- a/libs/binder/include/binder/BufferedTextOutput.h +++ b/libs/binder/include/binder/BufferedTextOutput.h @@ -62,6 +62,6 @@ private: }; // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_BUFFEREDTEXTOUTPUT_H diff --git a/libs/binder/include/binder/Debug.h b/libs/binder/include/binder/Debug.h index 324e5c1c81..58e2b32b3a 100644 --- a/libs/binder/include/binder/Debug.h +++ b/libs/binder/include/binder/Debug.h @@ -44,6 +44,6 @@ ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf); __END_DECLS // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_BINDER_DEBUG_H diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h index e0248f6624..6abc071c45 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include/binder/IActivityManager.h @@ -51,7 +51,7 @@ public: // ------------------------------------------------------------------------------------ -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h index 76642606fc..b500219e37 100644 --- a/libs/binder/include/binder/IAppOpsCallback.h +++ b/libs/binder/include/binder/IAppOpsCallback.h @@ -52,7 +52,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index b74c623e44..3dbd0d9f7a 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -79,7 +79,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h index b786f89f74..48da865702 100644 --- a/libs/binder/include/binder/IBatteryStats.h +++ b/libs/binder/include/binder/IBatteryStats.h @@ -77,7 +77,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h index 64604b74f0..aa44285b6e 100644 --- a/libs/binder/include/binder/IBinder.h +++ b/libs/binder/include/binder/IBinder.h @@ -22,8 +22,9 @@ #include <utils/String16.h> #include <utils/Vector.h> -// linux/binder.h defines this, but we don't want to include it here in order to -// avoid exporting the kernel headers + +// linux/binder.h already defines this, but we can't just include it from there +// because there are host builds that include this file. #ifndef B_PACK_CHARS #define B_PACK_CHARS(c1, c2, c3, c4) \ ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4)) @@ -58,15 +59,9 @@ public: SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_','C','M','D'), INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'), SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'), - EXTENSION_TRANSACTION = B_PACK_CHARS('_', 'E', 'X', 'T'), - DEBUG_PID_TRANSACTION = B_PACK_CHARS('_', 'P', 'I', 'D'), // Corresponds to TF_ONE_WAY -- an asynchronous call. - FLAG_ONEWAY = 0x00000001, - - // Private userspace flag for transaction which is being requested from - // a vendor context. - FLAG_PRIVATE_VENDOR = 0x10000000, + FLAG_ONEWAY = 0x00000001 }; IBinder(); @@ -91,54 +86,6 @@ public: Vector<String16>& args, const sp<IShellCallback>& callback, const sp<IResultReceiver>& resultReceiver); - /** - * This allows someone to add their own additions to an interface without - * having to modify the original interface. - * - * For instance, imagine if we have this interface: - * interface IFoo { void doFoo(); } - * - * If an unrelated owner (perhaps in a downstream codebase) wants to make a - * change to the interface, they have two options: - * - * A). Historical option that has proven to be BAD! Only the original - * author of an interface should change an interface. If someone - * downstream wants additional functionality, they should not ever - * change the interface or use this method. - * - * BAD TO DO: interface IFoo { BAD TO DO - * BAD TO DO: void doFoo(); BAD TO DO - * BAD TO DO: + void doBar(); // adding a method BAD TO DO - * BAD TO DO: } BAD TO DO - * - * B). Option that this method enables! - * Leave the original interface unchanged (do not change IFoo!). - * Instead, create a new interface in a downstream package: - * - * package com.<name>; // new functionality in a new package - * interface IBar { void doBar(); } - * - * When registering the interface, add: - * sp<MyFoo> foo = new MyFoo; // class in AOSP codebase - * sp<MyBar> bar = new MyBar; // custom extension class - * foo->setExtension(bar); // use method in BBinder - * - * Then, clients of IFoo can get this extension: - * sp<IBinder> binder = ...; - * sp<IFoo> foo = interface_cast<IFoo>(binder); // handle if null - * sp<IBinder> barBinder; - * ... handle error ... = binder->getExtension(&barBinder); - * sp<IBar> bar = interface_cast<IBar>(barBinder); - * // if bar is null, then there is no extension or a different - * // type of extension - */ - status_t getExtension(sp<IBinder>* out); - - /** - * Dump PID for a binder, for debugging. - */ - status_t getDebugPid(pid_t* outPid); - // NOLINTNEXTLINE(google-default-arguments) virtual status_t transact( uint32_t code, const Parcel& data, @@ -246,7 +193,7 @@ protected: private: }; -} // namespace android +}; // namespace android // --------------------------------------------------------------------------- diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 28ffa48e32..0d305608ca 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -88,12 +88,8 @@ private: \ public: \ -#define __IINTF_CONCAT(x, y) (x ## y) #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ - const ::android::StaticString16 \ - I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\ - const ::android::String16 I##INTERFACE::descriptor( \ - I##INTERFACE##_descriptor_static_str16); \ + const ::android::String16 I##INTERFACE::descriptor(NAME); \ const ::android::String16& \ I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ @@ -172,6 +168,6 @@ inline IBinder* BpInterface<INTERFACE>::onAsBinder() // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_IINTERFACE_H diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h index da2b7cf62d..213ee63ea8 100644 --- a/libs/binder/include/binder/IMediaResourceMonitor.h +++ b/libs/binder/include/binder/IMediaResourceMonitor.h @@ -52,7 +52,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h index 98e92c4441..071946f50c 100644 --- a/libs/binder/include/binder/IMemory.h +++ b/libs/binder/include/binder/IMemory.h @@ -76,8 +76,6 @@ public: // NOLINTNEXTLINE(google-default-arguments) virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0; - void* unsecurePointer() const; - // helpers void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const; void* pointer() const; @@ -102,6 +100,6 @@ protected: // ---------------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_IMEMORY_H diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index ff9244e08a..614b0b33dd 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -110,8 +110,6 @@ public: // the maximum number of binder threads threads allowed for this process. void blockUntilThreadAvailable(); - // Service manager registration - void setTheContextObject(sp<BBinder> obj); // Is this thread currently serving a binder call. This method // returns true if while traversing backwards from the function call @@ -196,7 +194,7 @@ private: ProcessState::CallRestriction mCallRestriction; }; -} // namespace android +}; // namespace android // --------------------------------------------------------------------------- diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h index 4b66df8d6e..26a1b23a9a 100644 --- a/libs/binder/include/binder/IPermissionController.h +++ b/libs/binder/include/binder/IPermissionController.h @@ -65,7 +65,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include/binder/IProcessInfoService.h index ca30ad3b95..033c145363 100644 --- a/libs/binder/include/binder/IProcessInfoService.h +++ b/libs/binder/include/binder/IProcessInfoService.h @@ -46,7 +46,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h index 70e99e7c38..00b3d8954c 100644 --- a/libs/binder/include/binder/IResultReceiver.h +++ b/libs/binder/include/binder/IResultReceiver.h @@ -50,7 +50,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_IRESULT_RECEIVER_H diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 2c4326393e..aeea1a2676 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -26,22 +26,12 @@ namespace android { // ---------------------------------------------------------------------- -/** - * Service manager for C++ services. - * - * IInterface is only for legacy ABI compatibility - */ class IServiceManager : public IInterface { public: - // for ABI compatibility - virtual const String16& getInterfaceDescriptor() const; - - IServiceManager(); - virtual ~IServiceManager(); - + DECLARE_META_INTERFACE(ServiceManager) /** - * Must match values in IServiceManager.aidl + * Must match values in IServiceManager.java */ /* Allows services to dump sections according to priorities. */ static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0; @@ -82,59 +72,17 @@ public: // NOLINTNEXTLINE(google-default-arguments) virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0; - /** - * Efficiently wait for a service. - * - * Returns nullptr only for permission problem or fatal error. - */ - virtual sp<IBinder> waitForService(const String16& name) = 0; - - /** - * Check if a service is declared (e.g. VINTF manifest). - * - * If this returns true, waitForService should always be able to return the - * service. - */ - virtual bool isDeclared(const String16& name) = 0; + enum { + GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + CHECK_SERVICE_TRANSACTION, + ADD_SERVICE_TRANSACTION, + LIST_SERVICES_TRANSACTION, + }; }; sp<IServiceManager> defaultServiceManager(); template<typename INTERFACE> -sp<INTERFACE> waitForService(const String16& name) { - const sp<IServiceManager> sm = defaultServiceManager(); - return interface_cast<INTERFACE>(sm->waitForService(name)); -} - -template<typename INTERFACE> -sp<INTERFACE> waitForDeclaredService(const String16& name) { - const sp<IServiceManager> sm = defaultServiceManager(); - if (!sm->isDeclared(name)) return nullptr; - return interface_cast<INTERFACE>(sm->waitForService(name)); -} - -template <typename INTERFACE> -sp<INTERFACE> checkDeclaredService(const String16& name) { - const sp<IServiceManager> sm = defaultServiceManager(); - if (!sm->isDeclared(name)) return nullptr; - return interface_cast<INTERFACE>(sm->checkService(name)); -} - -template<typename INTERFACE> -sp<INTERFACE> waitForVintfService( - const String16& instance = String16("default")) { - return waitForDeclaredService<INTERFACE>( - INTERFACE::descriptor + String16("/") + instance); -} - -template<typename INTERFACE> -sp<INTERFACE> checkVintfService( - const String16& instance = String16("default")) { - return checkDeclaredService<INTERFACE>( - INTERFACE::descriptor + String16("/") + instance); -} - -template<typename INTERFACE> status_t getService(const String16& name, sp<INTERFACE>* outService) { const sp<IServiceManager> sm = defaultServiceManager(); @@ -150,7 +98,7 @@ bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid); bool checkPermission(const String16& permission, pid_t pid, uid_t uid); -} // namespace android +}; // namespace android #endif // ANDROID_ISERVICE_MANAGER_H diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h index b7ab6eab88..67156787d3 100644 --- a/libs/binder/include/binder/IShellCallback.h +++ b/libs/binder/include/binder/IShellCallback.h @@ -51,7 +51,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_ISHELL_CALLBACK_H diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h index 09e50a9de8..a1f530dc71 100644 --- a/libs/binder/include/binder/IUidObserver.h +++ b/libs/binder/include/binder/IUidObserver.h @@ -58,7 +58,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/services/inputflinger/dispatcher/InputDispatcherThread.cpp b/libs/binder/include/binder/Map.h index 18b1b8c10a..96a4f8a2a5 100644 --- a/services/inputflinger/dispatcher/InputDispatcherThread.cpp +++ b/libs/binder/include/binder/Map.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2005 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,20 +14,26 @@ * limitations under the License. */ -#include "InputDispatcherThread.h" +#ifndef ANDROID_MAP_H +#define ANDROID_MAP_H -#include "InputDispatcherInterface.h" +#include <map> +#include <string> +// --------------------------------------------------------------------------- namespace android { +namespace binder { -InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) - : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {} +class Value; -InputDispatcherThread::~InputDispatcherThread() {} - -bool InputDispatcherThread::threadLoop() { - mDispatcher->dispatchOnce(); - return true; -} +/** + * Convenience typedef for ::std::map<::std::string,::android::binder::Value> + */ +typedef ::std::map<::std::string, Value> Map; +} // namespace binder } // namespace android + +// --------------------------------------------------------------------------- + +#endif // ANDROID_MAP_H diff --git a/libs/binder/include/binder/MemoryBase.h b/libs/binder/include/binder/MemoryBase.h index 4dd363808c..463e26d977 100644 --- a/libs/binder/include/binder/MemoryBase.h +++ b/libs/binder/include/binder/MemoryBase.h @@ -46,6 +46,6 @@ private: }; // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_MEMORY_BASE_H diff --git a/libs/binder/include/binder/MemoryDealer.h b/libs/binder/include/binder/MemoryDealer.h index 6c1c4122d8..b483be0fd5 100644 --- a/libs/binder/include/binder/MemoryDealer.h +++ b/libs/binder/include/binder/MemoryDealer.h @@ -59,6 +59,6 @@ private: // ---------------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_MEMORY_DEALER_H diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h index 3fccddcc59..100d784a83 100644 --- a/libs/binder/include/binder/MemoryHeapBase.h +++ b/libs/binder/include/binder/MemoryHeapBase.h @@ -98,6 +98,6 @@ private: }; // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_MEMORY_HEAP_BASE_H diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index d4bb85b102..e5219a5590 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -17,11 +17,11 @@ #ifndef ANDROID_PARCEL_H #define ANDROID_PARCEL_H -#include <map> // for legacy reasons #include <string> -#include <type_traits> #include <vector> +#include <linux/android/binder.h> + #include <android-base/unique_fd.h> #include <cutils/native_handle.h> #include <utils/Errors.h> @@ -32,26 +32,23 @@ #include <binder/IInterface.h> #include <binder/Parcelable.h> - -#ifdef BINDER_IPC_32BIT -typedef unsigned int binder_size_t; -#else -typedef unsigned long long binder_size_t; -#endif - +#include <binder/Map.h> // --------------------------------------------------------------------------- namespace android { template <typename T> class Flattenable; template <typename T> class LightFlattenable; -struct flat_binder_object; class IBinder; class IPCThreadState; class ProcessState; class String8; class TextOutput; +namespace binder { +class Value; +}; + class Parcel { friend class IPCThreadState; public: @@ -70,7 +67,7 @@ public: status_t setDataSize(size_t size); void setDataPosition(size_t pos) const; status_t setDataCapacity(size_t size); - + status_t setData(const uint8_t* buffer, size_t len); status_t appendFrom(const Parcel *parcel, @@ -100,6 +97,10 @@ public: void freeData(); +private: + const binder_size_t* objects() const; + +public: size_t objectsCount() const; status_t errorCheck() const; @@ -120,6 +121,7 @@ public: status_t writeString16(const std::unique_ptr<String16>& str); status_t writeString16(const char16_t* str, size_t len); status_t writeStrongBinder(const sp<IBinder>& val); + status_t writeWeakBinder(const wp<IBinder>& val); status_t writeInt32Array(size_t len, const int32_t *val); status_t writeByteArray(size_t len, const uint8_t *val); status_t writeBool(bool val); @@ -158,18 +160,6 @@ public: status_t writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val); status_t writeStrongBinderVector(const std::vector<sp<IBinder>>& val); - // Write an Enum vector with underlying type int8_t. - // Does not use padding; each byte is contiguous. - template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0> - status_t writeEnumVector(const std::vector<T>& val); - template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0> - status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val); - // Write an Enum vector with underlying type != int8_t. - template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0> - status_t writeEnumVector(const std::vector<T>& val); - template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0> - status_t writeEnumVector(const std::unique_ptr<std::vector<T>>& val); - template<typename T> status_t writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val); template<typename T> @@ -182,6 +172,8 @@ public: status_t writeParcelable(const Parcelable& parcelable); + status_t writeValue(const binder::Value& value); + template<typename T> status_t write(const Flattenable<T>& val); @@ -193,6 +185,9 @@ public: template<typename T> status_t writeVectorSize(const std::unique_ptr<std::vector<T>>& val); + status_t writeMap(const binder::Map& map); + status_t writeNullableMap(const std::unique_ptr<binder::Map>& map); + // Place a native_handle into the parcel (the native_handle's file- // descriptors are dup'ed, so it is safe to delete the native_handle // when this function returns). @@ -249,6 +244,8 @@ public: // Currently the native implementation doesn't do any of the StrictMode // stack gathering and serialization that the Java implementation does. status_t writeNoException(); + + void remove(size_t start, size_t amt); status_t read(void* outData, size_t len) const; const void* readInplace(size_t len) const; @@ -287,19 +284,7 @@ public: sp<IBinder> readStrongBinder() const; status_t readStrongBinder(sp<IBinder>* val) const; status_t readNullableStrongBinder(sp<IBinder>* val) const; - - - // Read an Enum vector with underlying type int8_t. - // Does not use padding; each byte is contiguous. - template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0> - status_t readEnumVector(std::vector<T>* val) const; - template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0> - status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const; - // Read an Enum vector with underlying type != int8_t. - template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0> - status_t readEnumVector(std::vector<T>* val) const; - template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0> - status_t readEnumVector(std::unique_ptr<std::vector<T>>* val) const; + wp<IBinder> readWeakBinder() const; template<typename T> status_t readParcelableVector( @@ -312,6 +297,8 @@ public: template<typename T> status_t readParcelable(std::unique_ptr<T>* parcelable) const; + status_t readValue(binder::Value* value) const; + template<typename T> status_t readStrongBinder(sp<T>* val) const; @@ -356,11 +343,9 @@ public: status_t resizeOutVector(std::vector<T>* val) const; template<typename T> status_t resizeOutVector(std::unique_ptr<std::vector<T>>* val) const; - template<typename T> - status_t reserveOutVector(std::vector<T>* val, size_t* size) const; - template<typename T> - status_t reserveOutVector(std::unique_ptr<std::vector<T>>* val, - size_t* size) const; + + status_t readMap(binder::Map* map)const; + status_t readNullableMap(std::unique_ptr<binder::Map>* map) const; // Like Parcel.java's readExceptionCode(). Reads the first int32 // off of a Parcel's header, returning 0 or the negative error @@ -414,7 +399,8 @@ public: bool replaceCallingWorkSourceUid(uid_t uid); // Returns the work source provided by the caller. This can only be trusted for trusted calling // uid. - uid_t readCallingWorkSourceUid() const; + uid_t readCallingWorkSourceUid(); + void readRequestHeaders() const; private: typedef void (*release_func)(Parcel* parcel, @@ -451,13 +437,7 @@ private: void scanForFds() const; status_t validateReadData(size_t len) const; void updateWorkSourceRequestHeaderPosition() const; - - status_t finishFlattenBinder(const sp<IBinder>& binder, - const flat_binder_object& flat); - status_t finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const; - status_t flattenBinder(const sp<IBinder>& binder); - status_t unflattenBinder(sp<IBinder>* out) const; - + template<class T> status_t readAligned(T *pArg) const; @@ -469,20 +449,6 @@ private: status_t writeRawNullableParcelable(const Parcelable* parcelable); - template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0> - status_t writeEnum(const T& val); - template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0> - status_t writeEnum(const T& val); - - template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0> - status_t readEnum(T* pArg) const; - template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0> - status_t readEnum(T* pArg) const; - - status_t writeByteVectorInternal(const int8_t* data, size_t size); - template<typename T> - status_t readByteVectorInternal(std::vector<T>* val, size_t size) const; - template<typename T, typename U> status_t unsafeReadTypedVector(std::vector<T>* val, status_t(Parcel::*read_func)(U*) const) const; @@ -726,42 +692,6 @@ status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const { } template<typename T> -status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const { - int32_t read_size; - status_t err = readInt32(&read_size); - if (err != NO_ERROR) { - return err; - } - - if (read_size < 0) { - return UNEXPECTED_NULL; - } - *size = static_cast<size_t>(read_size); - val->reserve(*size); - return OK; -} - -template<typename T> -status_t Parcel::reserveOutVector(std::unique_ptr<std::vector<T>>* val, - size_t* size) const { - int32_t read_size; - status_t err = readInt32(&read_size); - if (err != NO_ERROR) { - return err; - } - - if (read_size >= 0) { - *size = static_cast<size_t>(read_size); - val->reset(new std::vector<T>()); - (*val)->reserve(*size); - } else { - val->reset(); - } - - return OK; -} - -template<typename T> status_t Parcel::readStrongBinder(sp<T>* val) const { sp<IBinder> tmp; status_t ret = readStrongBinder(&tmp); @@ -994,79 +924,6 @@ status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::un return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>); } -template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>> -status_t Parcel::writeEnum(const T& val) { - return writeInt32(static_cast<int32_t>(val)); -} -template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>> -status_t Parcel::writeEnum(const T& val) { - return writeInt64(static_cast<int64_t>(val)); -} - -template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> -status_t Parcel::writeEnumVector(const std::vector<T>& val) { - return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size()); -} -template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> -status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) { - if (!val) return writeInt32(-1); - return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size()); -} -template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> -status_t Parcel::writeEnumVector(const std::vector<T>& val) { - return writeTypedVector(val, &Parcel::writeEnum); -} -template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> -status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) { - return writeNullableTypedVector(val, &Parcel::writeEnum); -} - -template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>> -status_t Parcel::readEnum(T* pArg) const { - return readInt32(reinterpret_cast<int32_t *>(pArg)); -} -template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>> -status_t Parcel::readEnum(T* pArg) const { - return readInt64(reinterpret_cast<int64_t *>(pArg)); -} - -template<typename T> -inline status_t Parcel::readByteVectorInternal(std::vector<T>* val, size_t size) const { - // readByteVectorInternal expects a vector that has been reserved (but not - // resized) to have the provided size. - const T* data = reinterpret_cast<const T*>(readInplace(size)); - if (!data) return BAD_VALUE; - val->clear(); - val->insert(val->begin(), data, data+size); - return NO_ERROR; -} - -template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> -status_t Parcel::readEnumVector(std::vector<T>* val) const { - size_t size; - if (status_t status = reserveOutVector(val, &size); status != OK) return status; - return readByteVectorInternal(val, size); -} -template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> -status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const { - size_t size; - if (status_t status = reserveOutVector(val, &size); status != OK) return status; - if (val->get() == nullptr) { - // reserveOutVector does not create the out vector if size is < 0. - // This occurs when writing a null Enum vector. - return OK; - } - return readByteVectorInternal(val->get(), size); -} -template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> -status_t Parcel::readEnumVector(std::vector<T>* val) const { - return readTypedVector(val, &Parcel::readEnum); -} -template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> -status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const { - return readNullableTypedVector(val, &Parcel::readEnum); -} - // --------------------------------------------------------------------------- inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel) @@ -1075,7 +932,24 @@ inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel) return to; } -} // namespace android +// --------------------------------------------------------------------------- + +// Generic acquire and release of objects. +void acquire_object(const sp<ProcessState>& proc, + const flat_binder_object& obj, const void* who); +void release_object(const sp<ProcessState>& proc, + const flat_binder_object& obj, const void* who); + +void flatten_binder(const sp<ProcessState>& proc, + const sp<IBinder>& binder, flat_binder_object* out); +void flatten_binder(const sp<ProcessState>& proc, + const wp<IBinder>& binder, flat_binder_object* out); +status_t unflatten_binder(const sp<ProcessState>& proc, + const flat_binder_object& flat, sp<IBinder>* out); +status_t unflatten_binder(const sp<ProcessState>& proc, + const flat_binder_object& flat, wp<IBinder>* out); + +}; // namespace android // --------------------------------------------------------------------------- diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h index 4635ad84c6..662e56e864 100644 --- a/libs/binder/include/binder/ParcelFileDescriptor.h +++ b/libs/binder/include/binder/ParcelFileDescriptor.h @@ -42,24 +42,6 @@ public: android::status_t writeToParcel(android::Parcel* parcel) const override; android::status_t readFromParcel(const android::Parcel* parcel) override; - inline bool operator!=(const ParcelFileDescriptor& rhs) const { - return mFd != rhs.mFd; - } - inline bool operator<(const ParcelFileDescriptor& rhs) const { - return mFd < rhs.mFd; - } - inline bool operator<=(const ParcelFileDescriptor& rhs) const { - return mFd <= rhs.mFd; - } - inline bool operator==(const ParcelFileDescriptor& rhs) const { - return mFd == rhs.mFd; - } - inline bool operator>(const ParcelFileDescriptor& rhs) const { - return mFd > rhs.mFd; - } - inline bool operator>=(const ParcelFileDescriptor& rhs) const { - return mFd >= rhs.mFd; - } private: android::base::unique_fd mFd; }; diff --git a/libs/binder/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h index c2582150df..95eabff7ac 100644 --- a/libs/binder/include/binder/PermissionCache.h +++ b/libs/binder/include/binder/PermissionCache.h @@ -77,7 +77,7 @@ public: }; // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h index 4db522ab1f..d81f5142bc 100644 --- a/libs/binder/include/binder/PermissionController.h +++ b/libs/binder/include/binder/PermissionController.h @@ -60,7 +60,7 @@ private: }; -} // namespace android +}; // namespace android // --------------------------------------------------------------------------- #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include/binder/ProcessInfoService.h index 6bfd1bc17d..a03aae98ee 100644 --- a/libs/binder/include/binder/ProcessInfoService.h +++ b/libs/binder/include/binder/ProcessInfoService.h @@ -78,7 +78,7 @@ public: // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #else // __ANDROID_VNDK__ #error "This header is not visible to vendors" diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index e57ff1c260..224cb36807 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -45,19 +45,27 @@ public: */ static sp<ProcessState> initWithDriver(const char *driver); + void setContextObject(const sp<IBinder>& object); sp<IBinder> getContextObject(const sp<IBinder>& caller); + + void setContextObject(const sp<IBinder>& object, + const String16& name); + sp<IBinder> getContextObject(const String16& name, + const sp<IBinder>& caller); void startThreadPool(); typedef bool (*context_check_func)(const String16& name, const sp<IBinder>& caller, void* userData); - + + bool isContextManager(void) const; bool becomeContextManager( context_check_func checkFunc, void* userData); sp<IBinder> getStrongProxyForHandle(int32_t handle); + wp<IBinder> getWeakProxyForHandle(int32_t handle); void expungeHandle(int32_t handle, IBinder* binder); void spawnPooledThread(bool isMain); @@ -69,14 +77,6 @@ public: ssize_t getKernelReferences(size_t count, uintptr_t* buf); - // Only usable by the context manager. - // This refcount includes: - // 1. Strong references to the node by this and other processes - // 2. Temporary strong references held by the kernel during a - // transaction on the node. - // It does NOT include local strong references to the node - ssize_t getStrongRefCountForNodeByHandle(int32_t handle); - enum class CallRestriction { // all calls okay NONE, @@ -124,9 +124,14 @@ private: Vector<handle_entry>mHandleToObject; + bool mManagesContexts; context_check_func mBinderContextCheckFunc; void* mBinderContextUserData; + KeyedVector<String16, sp<IBinder> > + mContexts; + + String8 mRootDir; bool mThreadPoolStarted; volatile int32_t mThreadPoolSeq; @@ -134,7 +139,7 @@ private: CallRestriction mCallRestriction; }; -} // namespace android +}; // namespace android // --------------------------------------------------------------------------- diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h deleted file mode 100644 index b2f51d381c..0000000000 --- a/libs/binder/include/binder/Stability.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2019 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 <binder/IBinder.h> -#include <string> - -namespace android { - -class BpBinder; -class ProcessState; - -namespace internal { - -// WARNING: These APIs are only ever expected to be called by auto-generated code. -// Instead of calling them, you should set the stability of a .aidl interface -class Stability final { -public: - // WARNING: This is only ever expected to be called by auto-generated code. You likely want to - // change or modify the stability class of the interface you are using. - // This must be called as soon as the binder in question is constructed. No thread safety - // is provided. - // E.g. stability is according to libbinder compilation unit - static void markCompilationUnit(IBinder* binder); - // WARNING: This is only ever expected to be called by auto-generated code. You likely want to - // change or modify the stability class of the interface you are using. - // This must be called as soon as the binder in question is constructed. No thread safety - // is provided. - // E.g. stability is according to libbinder_ndk or Java SDK AND the interface - // expressed here is guaranteed to be stable for multiple years (Stable AIDL) - static void markVintf(IBinder* binder); - - // WARNING: for debugging only - static void debugLogStability(const std::string& tag, const sp<IBinder>& binder); - - // WARNING: This is only ever expected to be called by auto-generated code or tests. - // You likely want to change or modify the stability of the interface you are using. - // This must be called as soon as the binder in question is constructed. No thread safety - // is provided. - // E.g. stability is according to libbinder_ndk or Java SDK AND the interface - // expressed here is guaranteed to be stable for multiple years (Stable AIDL) - // If this is called when __ANDROID_VNDK__ is not defined, then it is UB and will likely - // break the device during GSI or other tests. - static void markVndk(IBinder* binder); - - // Returns true if the binder needs to be declared in the VINTF manifest or - // else false if the binder is local to the current partition. - static bool requiresVintfDeclaration(const sp<IBinder>& binder); -private: - // Parcel needs to read/write stability level in an unstable format. - friend ::android::Parcel; - - // only expose internal APIs inside of libbinder, for checking stability - friend ::android::BpBinder; - - // so that it can mark the context object (only the root object doesn't go - // through Parcel) - friend ::android::ProcessState; - - static void tryMarkCompilationUnit(IBinder* binder); - - enum Level : int32_t { - UNDECLARED = 0, - - VENDOR = 0b000011, - SYSTEM = 0b001100, - VINTF = 0b111111, - }; - -#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)) - static constexpr Level kLocalStability = Level::VENDOR; -#else - static constexpr Level kLocalStability = Level::SYSTEM; -#endif - - // applies stability to binder if stability level is known - __attribute__((warn_unused_result)) - static status_t set(IBinder* binder, int32_t stability, bool log); - - static Level get(IBinder* binder); - - static bool check(int32_t provided, Level required); - - static bool isDeclaredStability(int32_t stability); - static std::string stabilityString(int32_t stability); - - Stability(); -}; - -} // namespace internal -} // namespace android diff --git a/libs/binder/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h index f66406f7d4..5b5f76688b 100644 --- a/libs/binder/include/binder/TextOutput.h +++ b/libs/binder/include/binder/TextOutput.h @@ -199,6 +199,6 @@ inline size_t HexDump::alignment() const { return mAlignment; } inline bool HexDump::carrayStyle() const { return mCArrayStyle; } // --------------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_TEXTOUTPUT_H diff --git a/libs/binder/include/binder/Value.h b/libs/binder/include/binder/Value.h new file mode 100644 index 0000000000..735f40eb1f --- /dev/null +++ b/libs/binder/include/binder/Value.h @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_VALUE_H +#define ANDROID_VALUE_H + +#include <stdint.h> +#include <map> +#include <set> +#include <vector> +#include <string> + +#include <binder/Parcelable.h> +#include <binder/PersistableBundle.h> +#include <binder/Map.h> +#include <utils/String8.h> +#include <utils/String16.h> +#include <utils/StrongPointer.h> + +namespace android { + +class Parcel; + +namespace binder { + +/** + * A limited C++ generic type. The purpose of this class is to allow C++ + * programs to make use of (or implement) Binder interfaces which make use + * the Java "Object" generic type (either via the use of the Map type or + * some other mechanism). + * + * This class only supports a limited set of types, but additional types + * may be easily added to this class in the future as needed---without + * breaking binary compatability. + * + * This class was written in such a way as to help avoid type errors by + * giving each type their own explicity-named accessor methods (rather than + * overloaded methods). + * + * When reading or writing this class to a Parcel, use the `writeValue()` + * and `readValue()` methods. + */ +class Value { +public: + Value(); + virtual ~Value(); + + Value& swap(Value &); + + bool empty() const; + + void clear(); + +#ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO + const std::type_info& type() const; +#endif + + int32_t parcelType() const; + + bool operator==(const Value& rhs) const; + bool operator!=(const Value& rhs) const { return !this->operator==(rhs); } + + Value(const Value& value); + Value(const bool& value); // NOLINT(google-explicit-constructor) + Value(const int8_t& value); // NOLINT(google-explicit-constructor) + Value(const int32_t& value); // NOLINT(google-explicit-constructor) + Value(const int64_t& value); // NOLINT(google-explicit-constructor) + Value(const double& value); // NOLINT(google-explicit-constructor) + Value(const String16& value); // NOLINT(google-explicit-constructor) + Value(const std::vector<bool>& value); // NOLINT(google-explicit-constructor) + Value(const std::vector<uint8_t>& value); // NOLINT(google-explicit-constructor) + Value(const std::vector<int32_t>& value); // NOLINT(google-explicit-constructor) + Value(const std::vector<int64_t>& value); // NOLINT(google-explicit-constructor) + Value(const std::vector<double>& value); // NOLINT(google-explicit-constructor) + Value(const std::vector<String16>& value); // NOLINT(google-explicit-constructor) + Value(const os::PersistableBundle& value); // NOLINT(google-explicit-constructor) + Value(const binder::Map& value); // NOLINT(google-explicit-constructor) + + Value& operator=(const Value& rhs); + Value& operator=(const int8_t& rhs); + Value& operator=(const bool& rhs); + Value& operator=(const int32_t& rhs); + Value& operator=(const int64_t& rhs); + Value& operator=(const double& rhs); + Value& operator=(const String16& rhs); + Value& operator=(const std::vector<bool>& rhs); + Value& operator=(const std::vector<uint8_t>& rhs); + Value& operator=(const std::vector<int32_t>& rhs); + Value& operator=(const std::vector<int64_t>& rhs); + Value& operator=(const std::vector<double>& rhs); + Value& operator=(const std::vector<String16>& rhs); + Value& operator=(const os::PersistableBundle& rhs); + Value& operator=(const binder::Map& rhs); + + void putBoolean(const bool& value); + void putByte(const int8_t& value); + void putInt(const int32_t& value); + void putLong(const int64_t& value); + void putDouble(const double& value); + void putString(const String16& value); + void putBooleanVector(const std::vector<bool>& value); + void putByteVector(const std::vector<uint8_t>& value); + void putIntVector(const std::vector<int32_t>& value); + void putLongVector(const std::vector<int64_t>& value); + void putDoubleVector(const std::vector<double>& value); + void putStringVector(const std::vector<String16>& value); + void putPersistableBundle(const os::PersistableBundle& value); + void putMap(const binder::Map& value); + + bool getBoolean(bool* out) const; + bool getByte(int8_t* out) const; + bool getInt(int32_t* out) const; + bool getLong(int64_t* out) const; + bool getDouble(double* out) const; + bool getString(String16* out) const; + bool getBooleanVector(std::vector<bool>* out) const; + bool getByteVector(std::vector<uint8_t>* out) const; + bool getIntVector(std::vector<int32_t>* out) const; + bool getLongVector(std::vector<int64_t>* out) const; + bool getDoubleVector(std::vector<double>* out) const; + bool getStringVector(std::vector<String16>* out) const; + bool getPersistableBundle(os::PersistableBundle* out) const; + bool getMap(binder::Map* out) const; + + bool isBoolean() const; + bool isByte() const; + bool isInt() const; + bool isLong() const; + bool isDouble() const; + bool isString() const; + bool isBooleanVector() const; + bool isByteVector() const; + bool isIntVector() const; + bool isLongVector() const; + bool isDoubleVector() const; + bool isStringVector() const; + bool isPersistableBundle() const; + bool isMap() const; + + // String Convenience Adapters + // --------------------------- + + explicit Value(const String8& value): Value(String16(value)) { } + explicit Value(const ::std::string& value): Value(String8(value.c_str())) { } + void putString(const String8& value) { return putString(String16(value)); } + void putString(const ::std::string& value) { return putString(String8(value.c_str())); } + Value& operator=(const String8& rhs) { return *this = String16(rhs); } + Value& operator=(const ::std::string& rhs) { return *this = String8(rhs.c_str()); } + bool getString(String8* out) const; + bool getString(::std::string* out) const; + +private: + + // This allows ::android::Parcel to call the two methods below. + friend class ::android::Parcel; + + // This is called by ::android::Parcel::writeValue() + status_t writeToParcel(Parcel* parcel) const; + + // This is called by ::android::Parcel::readValue() + status_t readFromParcel(const Parcel* parcel); + + template<typename T> class Content; + class ContentBase; + + ContentBase* mContent; +}; + +} // namespace binder + +} // namespace android + +#endif // ANDROID_VALUE_H diff --git a/libs/binder/ParcelValTypes.h b/libs/binder/include/private/binder/ParcelValTypes.h index 666d22a57f..666d22a57f 100644 --- a/libs/binder/ParcelValTypes.h +++ b/libs/binder/include/private/binder/ParcelValTypes.h diff --git a/libs/binder/Static.h b/libs/binder/include/private/binder/Static.h index f8e0ee5f8d..171be7791e 100644 --- a/libs/binder/Static.h +++ b/libs/binder/include/private/binder/Static.h @@ -21,6 +21,10 @@ #include <binder/IBinder.h> #include <binder/ProcessState.h> +#ifndef __ANDROID_VNDK__ +#include <binder/IPermissionController.h> +#endif +#include <binder/IServiceManager.h> namespace android { @@ -31,4 +35,12 @@ extern Vector<int32_t> gTextBuffers; extern Mutex& gProcessMutex; extern sp<ProcessState> gProcess; +// For IServiceManager.cpp +extern Mutex gDefaultServiceManagerLock; +extern sp<IServiceManager> gDefaultServiceManager; +#ifndef __ANDROID_VNDK__ +extern sp<IPermissionController> gPermissionController; +#endif +extern bool gSystemBootCompleted; + } // namespace android diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h index c22be9f786..2f11622e70 100644 --- a/libs/binder/include/private/binder/binder_module.h +++ b/libs/binder/include/private/binder/binder_module.h @@ -23,16 +23,6 @@ namespace android { /* obtain structures and constants from the kernel header */ -// TODO(b/31559095): bionic on host -#ifndef __ANDROID__ -#define __packed __attribute__((__packed__)) -#endif - -// TODO(b/31559095): bionic on host -#if defined(B_PACK_CHARS) && !defined(_UAPI_LINUX_BINDER_H) -#undef B_PACK_CHARS -#endif - #include <sys/ioctl.h> #include <linux/android/binder.h> diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index c0ea6d7b1e..21bef2e930 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -14,30 +14,13 @@ * limitations under the License. */ -// TODO(b/31559095): bionic on host should define this -cc_defaults { - name: "libbinder_ndk_host_user", - target: { - host: { - cflags: [ - "-D__INTRODUCED_IN(n)=", - "-D__assert(a,b,c)=", - // We want all the APIs to be available on the host. - "-D__ANDROID_API__=10000", - ], - }, - }, -} - -cc_library_shared { +cc_library { name: "libbinder_ndk", - - defaults: ["libbinder_ndk_host_user"], - host_supported: true, + vendor_available: true, export_include_dirs: [ "include_ndk", - "include_platform", + "include_apex", ], cflags: [ @@ -51,7 +34,6 @@ cc_library_shared { "ibinder_jni.cpp", "parcel.cpp", "process.cpp", - "stability.cpp", "status.cpp", "service_manager.cpp", ], @@ -70,17 +52,10 @@ cc_library_shared { "jni_headers", ], - target: { - linux: { - version_script: "libbinder_ndk.map.txt", - }, - }, + version_script: "libbinder_ndk.map.txt", stubs: { symbol_file: "libbinder_ndk.map.txt", - versions: [ - "29", - "30", - ], + versions: ["29"], }, } @@ -99,12 +74,3 @@ ndk_library { symbol_file: "libbinder_ndk.map.txt", first_version: "29", } - -llndk_library { - name: "libbinder_ndk", - symbol_file: "libbinder_ndk.map.txt", - export_include_dirs: [ - "include_ndk", - "include_platform", - ], -} diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index e752c45d60..bd6886d1ee 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -17,7 +17,6 @@ #include <android/binder_ibinder.h> #include "ibinder_internal.h" -#include <android/binder_stability.h> #include <android/binder_status.h> #include "parcel_internal.h" #include "status_internal.h" @@ -543,8 +542,7 @@ binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, APa return STATUS_UNKNOWN_TRANSACTION; } - constexpr binder_flags_t kAllFlags = FLAG_PRIVATE_VENDOR | FLAG_ONEWAY; - if ((flags & ~kAllFlags) != 0) { + if ((flags & ~FLAG_ONEWAY) != 0) { LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags; return STATUS_BAD_VALUE; } @@ -591,40 +589,3 @@ void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) { recipient->decStrong(nullptr); } - -binder_status_t AIBinder_getExtension(AIBinder* binder, AIBinder** outExt) { - if (binder == nullptr || outExt == nullptr) { - if (outExt != nullptr) { - *outExt = nullptr; - } - return STATUS_UNEXPECTED_NULL; - } - - sp<IBinder> ext; - status_t res = binder->getBinder()->getExtension(&ext); - - if (res != android::OK) { - *outExt = nullptr; - return PruneStatusT(res); - } - - sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(ext); - if (ret != nullptr) ret->incStrong(binder); - - *outExt = ret.get(); - return STATUS_OK; -} - -binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) { - if (binder == nullptr || ext == nullptr) { - return STATUS_UNEXPECTED_NULL; - } - - ABBinder* rawBinder = binder->asABBinder(); - if (rawBinder == nullptr) { - return STATUS_INVALID_OPERATION; - } - - rawBinder->setExtension(ext->getBinder()); - return STATUS_OK; -} diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h index 055c79bca1..055c79bca1 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_apex/android/binder_manager.h diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_apex/android/binder_process.h index fdefbb4b8a..69e6387bcb 100644 --- a/libs/binder/ndk/include_platform/android/binder_process.h +++ b/libs/binder/ndk/include_apex/android/binder_process.h @@ -27,7 +27,7 @@ __BEGIN_DECLS void ABinderProcess_startThreadPool(); /** * This sets the maximum number of threads that can be started in the threadpool. By default, after - * startThreadPool is called, this is 15. If it is called additional times, it will only prevent + * startThreadPool is called, this is one. If it is called additional times, it will only prevent * the kernel from starting new threads and will not delete already existing threads. */ bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads); diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h index 946ccb79a5..c6868b07ef 100644 --- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h @@ -21,7 +21,7 @@ /** * @file binder_auto_utils.h - * @brief These objects provide a more C++-like thin interface to the binder. + * @brief These objects provide a more C++-like thin interface to the . */ #pragma once @@ -159,17 +159,13 @@ class ScopedAResource { */ T* getR() { return &mT; } - // copy-constructing/assignment is disallowed + // copy-constructing, or move/copy assignment is disallowed ScopedAResource(const ScopedAResource&) = delete; ScopedAResource& operator=(const ScopedAResource&) = delete; + ScopedAResource& operator=(ScopedAResource&&) = delete; - // move-constructing/assignment is okay + // move-constructing is okay ScopedAResource(ScopedAResource&& other) : mT(std::move(other.mT)) { other.mT = DEFAULT; } - ScopedAResource& operator=(ScopedAResource&& other) { - set(other.mT); - other.mT = DEFAULT; - return *this; - } private: T mT; @@ -201,54 +197,16 @@ class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delet explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {} ~ScopedAStatus() {} ScopedAStatus(ScopedAStatus&&) = default; - ScopedAStatus& operator=(ScopedAStatus&&) = default; /** * See AStatus_isOk. */ - bool isOk() const { return get() != nullptr && AStatus_isOk(get()); } - - /** - * See AStatus_getExceptionCode - */ - binder_exception_t getExceptionCode() const { return AStatus_getExceptionCode(get()); } + bool isOk() { return get() != nullptr && AStatus_isOk(get()); } /** - * See AStatus_getServiceSpecificError - */ - int32_t getServiceSpecificError() const { return AStatus_getServiceSpecificError(get()); } - - /** - * See AStatus_getStatus - */ - binder_status_t getStatus() const { return AStatus_getStatus(get()); } - - /** - * See AStatus_getMessage - */ - const char* getMessage() const { return AStatus_getMessage(get()); } - - /** - * Convenience methods for creating scoped statuses. + * Convenience method for okay status. */ static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); } - static ScopedAStatus fromExceptionCode(binder_exception_t exception) { - return ScopedAStatus(AStatus_fromExceptionCode(exception)); - } - static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception, - const char* message) { - return ScopedAStatus(AStatus_fromExceptionCodeWithMessage(exception, message)); - } - static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) { - return ScopedAStatus(AStatus_fromServiceSpecificError(serviceSpecific)); - } - static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific, - const char* message) { - return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(serviceSpecific, message)); - } - static ScopedAStatus fromStatus(binder_status_t status) { - return ScopedAStatus(AStatus_fromStatus(status)); - } }; /** diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index 4d5c044232..80d12541be 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -34,7 +34,7 @@ #include <android/binder_status.h> __BEGIN_DECLS -#if __ANDROID_API__ >= 29 +#if __ANDROID_API__ >= __ANDROID_API_Q__ // Also see TF_* in kernel's binder.h typedef uint32_t binder_flags_t; @@ -165,8 +165,6 @@ typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transacti * * None of these parameters can be null. * - * Available since API level 29. - * * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for * sanity checks on transactions. * \param onCreate see AIBinder_Class_onCreate. @@ -201,8 +199,6 @@ typedef binder_status_t (*AIBinder_onDump)(AIBinder* binder, int fd, const char* * If this isn't set, nothing will be dumped when dump is called (for instance with * android.os.Binder#dump). Must be called before any instance of the class is created. * - * Available since API level 29. - * * \param dump function to call when an instance of this binder class is being dumped. */ void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29); @@ -224,8 +220,6 @@ void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __I * these two objects are actually equal using the AIBinder pointer alone (which they should be able * to do). Also see the suggested memory ownership model suggested above. * - * Available since API level 29. - * * \param clazz the type of the object to be created. * \param args the args to pass to AIBinder_onCreate for that class. * @@ -237,8 +231,6 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* /** * If this is hosted in a process other than the current one. * - * Available since API level 29. - * * \param binder the binder being queried. * * \return true if the AIBinder represents an object in another process. @@ -252,8 +244,6 @@ bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29); * updated as the result of a transaction made using AIBinder_transact, but it will also be updated * based on the results of bookkeeping or other transactions made internally. * - * Available since API level 29. - * * \param binder the binder being queried. * * \return true if the binder is alive. @@ -265,8 +255,6 @@ bool AIBinder_isAlive(const AIBinder* binder) __INTRODUCED_IN(29); * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a * sanity check. * - * Available since API level 29. - * * \param binder the binder being queried. * * \return STATUS_OK if the ping succeeds. @@ -276,9 +264,7 @@ binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29); /** * Built-in transaction for all binder objects. This dumps information about a given binder. * - * See also AIBinder_Class_setOnDump, AIBinder_onDump. - * - * Available since API level 29. + * See also AIBinder_Class_setOnDump, AIBinder_onDump * * \param binder the binder to dump information about * \param fd where information should be dumped to @@ -301,8 +287,6 @@ binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint3 * * If binder is local, this will return STATUS_INVALID_OPERATION. * - * Available since API level 29. - * * \param binder the binder object you want to receive death notifications from. * \param recipient the callback that will receive notifications when/if the binder dies. * \param cookie the value that will be passed to the death recipient on death. @@ -322,8 +306,6 @@ binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* * If the binder dies, it will automatically unlink. If the binder is deleted, it will be * automatically unlinked. * - * Available since API level 29. - * * \param binder the binder object to remove a previously linked death recipient from. * \param recipient the callback to remove. * \param cookie the cookie used to link to death. @@ -340,11 +322,9 @@ binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient * This can be used with higher-level system services to determine the caller's identity and check * permissions. * - * Available since API level 29. - * * \return calling uid or the current process's UID if this thread isn't processing a transaction. */ -uid_t AIBinder_getCallingUid() __INTRODUCED_IN(29); +uid_t AIBinder_getCallingUid(); /** * This returns the calling PID assuming that this thread is called from a thread that is processing @@ -355,18 +335,14 @@ uid_t AIBinder_getCallingUid() __INTRODUCED_IN(29); * calling process dies and is replaced with another process with elevated permissions and the same * PID. * - * Available since API level 29. - * * \return calling pid or the current process's PID if this thread isn't processing a transaction. * If the transaction being processed is a oneway transaction, then this method will return 0. */ -pid_t AIBinder_getCallingPid() __INTRODUCED_IN(29); +pid_t AIBinder_getCallingPid(); /** * This can only be called if a strong reference to this object already exists in process. * - * Available since API level 29. - * * \param binder the binder object to add a refcount to. */ void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29); @@ -374,8 +350,6 @@ void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29); /** * This will delete the object and call onDestroy once the refcount reaches zero. * - * Available since API level 29. - * * \param binder the binder object to remove a refcount from. */ void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29); @@ -383,8 +357,6 @@ void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29); /** * For debugging only! * - * Available since API level 29. - * * \param binder the binder object to retrieve the refcount of. * * \return the number of strong-refs on this binder in this process. If binder is null, this will be @@ -401,8 +373,6 @@ int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29); * This returns true if the class association succeeds. If it fails, no change is made to the * binder object. * - * Available since API level 29. - * * \param binder the object to attach the class to. * \param clazz the clazz to attach to binder. * @@ -413,8 +383,6 @@ bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) __IN /** * Returns the class that this binder was constructed with or associated with. * - * Available since API level 29. - * * \param binder the object that is being queried. * * \return the class that this binder is associated with. If this binder wasn't created with @@ -426,8 +394,6 @@ const AIBinder_Class* AIBinder_getClass(AIBinder* binder) __INTRODUCED_IN(29); * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns * null), this also returns null. For a remote binder, this will always return null. * - * Available since API level 29. - * * \param binder the object that is being queried. * * \return the userdata returned from AIBinder_onCreate when this object was created. This may be @@ -456,8 +422,6 @@ void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29); * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be * deleted with AParcel_delete. * - * Available since API level 29. - * * \param binder the binder object to start a transaction on. * \param in out parameter for input data to the transaction. * @@ -478,8 +442,6 @@ binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __IN * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller * and must be released with AParcel_delete when finished reading. * - * Available since API level 29. - * * \param binder the binder object to transact on. * \param code the implementation-specific code representing which transaction should be taken. * \param in the implementation-specific input data to this transaction. @@ -497,8 +459,6 @@ binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, APa * This does not take any ownership of the input binder, but it can be used to retrieve it if * something else in some process still holds a reference to it. * - * Available since API level 29. - * * \param binder object to create a weak pointer to. * * \return object representing a weak pointer to binder (or null if binder is null). @@ -509,8 +469,6 @@ __attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* b /** * Deletes the weak reference. This will have no impact on the lifetime of the binder. * - * Available since API level 29. - * * \param weakBinder object created with AIBinder_Weak_new. */ void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29); @@ -519,8 +477,6 @@ void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29); * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns * null. * - * Available since API level 29. - * * \param weakBinder weak pointer to attempt retrieving the original object from. * * \return an AIBinder object with one refcount given to the caller or null. @@ -531,8 +487,6 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Wea /** * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath. * - * Available since API level 29. - * * \param cookie the cookie passed to AIBinder_linkToDeath. */ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29); @@ -540,8 +494,6 @@ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_ /** * Creates a new binder death recipient. This can be attached to multiple different binder objects. * - * Available since API level 29. - * * \param onBinderDied the callback to call when this death recipient is invoked. * * \return the newly constructed object (or null if onBinderDied is null). @@ -553,87 +505,11 @@ __attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecip * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before * calling this as these will all be automatically unlinked. * - * Available since API level 29. - * * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new). */ void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29); -#endif //__ANDROID_API__ >= 29 - -#if __ANDROID_API__ >= 30 - -/** - * Gets the extension registered with AIBinder_setExtension. - * - * See AIBinder_setExtension. - * - * Available since API level 30. - * - * \param binder the object to get the extension of. - * \param outExt the returned extension object. Will be null if there is no extension set or - * non-null with one strong ref count. - * - * \return error of getting the interface (may be a transaction error if this is - * remote binder). STATUS_UNEXPECTED_NULL if binder is null. - */ -binder_status_t AIBinder_getExtension(AIBinder* binder, AIBinder** outExt) __INTRODUCED_IN(30); - -/** - * Gets the extension of a binder interface. This allows a downstream developer to add - * an extension to an interface without modifying its interface file. This should be - * called immediately when the object is created before it is passed to another thread. - * No thread safety is required. - * - * For instance, imagine if we have this interface: - * interface IFoo { void doFoo(); } - * - * A). Historical option that has proven to be BAD! Only the original - * author of an interface should change an interface. If someone - * downstream wants additional functionality, they should not ever - * change the interface or use this method. - * - * BAD TO DO: interface IFoo { BAD TO DO - * BAD TO DO: void doFoo(); BAD TO DO - * BAD TO DO: + void doBar(); // adding a method BAD TO DO - * BAD TO DO: } BAD TO DO - * - * B). Option that this method enables. - * Leave the original interface unchanged (do not change IFoo!). - * Instead, create a new interface in a downstream package: - * - * package com.<name>; // new functionality in a new package - * interface IBar { void doBar(); } - * - * When registering the interface, add: - * std::shared_ptr<MyFoo> foo = new MyFoo; // class in AOSP codebase - * std::shared_ptr<MyBar> bar = new MyBar; // custom extension class - * ... = AIBinder_setExtension(foo->asBinder().get(), bar->asBinder().get()); - * // handle error - * - * Then, clients of IFoo can get this extension: - * SpAIBinder binder = ...; - * std::shared_ptr<IFoo> foo = IFoo::fromBinder(binder); // handle if null - * SpAIBinder barBinder; - * ... = AIBinder_getExtension(barBinder.get()); - * // handle error - * std::shared_ptr<IBar> bar = IBar::fromBinder(barBinder); - * // type is checked with AIBinder_associateClass - * // if bar is null, then there is no extension or a different - * // type of extension - * - * Available since API level 30. - * - * \param binder the object to get the extension on. Must be local. - * \param ext the extension to set (binder will hold a strong reference to this) - * - * \return OK on success, STATUS_INVALID_OPERATION if binder is not local, STATUS_UNEXPECTED_NULL - * if either binder is null. - */ -binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) __INTRODUCED_IN(30); - -#endif //__ANDROID_API__ >= 30 - +#endif //__ANDROID_API__ >= __ANDROID_API_Q__ __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h index be3029c3ff..124f36c55b 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h @@ -31,7 +31,7 @@ #include <jni.h> __BEGIN_DECLS -#if __ANDROID_API__ >= 29 +#if __ANDROID_API__ >= __ANDROID_API_Q__ /** * Converts an android.os.IBinder object into an AIBinder* object. @@ -40,8 +40,6 @@ __BEGIN_DECLS * AIBinder object, the original object is returned. The returned object has one refcount * associated with it, and so this should be accompanied with an AIBinder_decStrong call. * - * Available since API level 29. - * * \param env Java environment. * \param binder android.os.IBinder java object. * @@ -57,8 +55,6 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* en * If either env or the binder is null, null is returned. If this binder object was originally an * IBinder object, the original java object will be returned. * - * Available since API level 29. - * * \param env Java environment. * \param binder the object to convert. * @@ -67,7 +63,7 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* en __attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder) __INTRODUCED_IN(29); -#endif //__ANDROID_API__ >= 29 +#endif //__ANDROID_API__ >= __ANDROID_API_Q__ __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h index 86b75b8c61..2258210f2e 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -26,7 +26,6 @@ #pragma once -#include <stddef.h> #include <sys/cdefs.h> #include <android/binder_status.h> @@ -35,7 +34,7 @@ struct AIBinder; typedef struct AIBinder AIBinder; __BEGIN_DECLS -#if __ANDROID_API__ >= 29 +#if __ANDROID_API__ >= __ANDROID_API_Q__ /** * This object represents a package of data that can be sent between processes. When transacting, an @@ -49,8 +48,6 @@ typedef struct AParcel AParcel; /** * Cleans up a parcel. * - * Available since API level 29. - * * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a * transaction is being aborted. */ @@ -59,8 +56,6 @@ void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29); /** * Sets the position within the parcel. * - * Available since API level 29. - * * \param parcel The parcel of which to set the position. * \param position Position of the parcel to set. This must be a value returned by * AParcel_getDataPosition. Positions are constant for a given parcel between processes. @@ -73,8 +68,6 @@ binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position) /** * Gets the current position within the parcel. * - * Available since API level 29. - * * \param parcel The parcel of which to get the position. * * \return The size of the parcel. This will always be greater than 0. The values returned by this @@ -395,8 +388,6 @@ typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length, int8 * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any * refcounts of ownership of the binder from the client. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param binder the value to write to the parcel. * @@ -408,8 +399,6 @@ binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __I * Reads an AIBinder from the next location in a non-null parcel. One strong ref-count of ownership * is passed to the caller of this function. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param binder the out parameter for what is read from the parcel. This may be null. * @@ -424,14 +413,12 @@ binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binde * * This corresponds to the SDK's android.os.ParcelFileDescriptor. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param fd the value to write to the parcel (-1 to represent a null ParcelFileDescriptor). * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) __INTRODUCED_IN(29); +binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd); /** * Reads an int from the next location in a non-null parcel. @@ -440,16 +427,13 @@ binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) __INT * * This corresponds to the SDK's android.os.ParcelFileDescriptor. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param fd the out parameter for what is read from the parcel (or -1 to represent a null * ParcelFileDescriptor) * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) - __INTRODUCED_IN(29); +binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd); /** * Writes an AStatus object to the next location in a non-null parcel. @@ -460,8 +444,6 @@ binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) * this happens or if writing the status object itself fails, the return value from this function * should be propagated to the client, and AParcel_readStatusHeader shouldn't be called. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param status the value to write to the parcel. * @@ -474,8 +456,6 @@ binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller * of this function. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param status the out parameter for what is read from the parcel. * @@ -489,8 +469,6 @@ binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status * * If length is -1, and string is nullptr, this will write a 'null' string to the parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param string the null-terminated string to write to the parcel, at least of size 'length'. * \param length the length of the string to be written. @@ -508,8 +486,6 @@ binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator * will be called with length -1. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param stringData some external representation of a string. * \param allocator allocator that will be called once the size of the string is known. @@ -527,8 +503,6 @@ binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, * returned from this function will be used to fill out the data from the parcel. If length is -1, * this will write a 'null' string array to the binder buffer. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData some external representation of an array. * \param length the length of the array to be written. @@ -551,8 +525,6 @@ binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, * the contents of the string that is read. If the string array being read is 'null', this will * instead just pass -1 to AParcel_stringArrayAllocator. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called with arrayData once the size of the output @@ -570,8 +542,6 @@ binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData, /** * Writes an array of parcelables (user-defined types) to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -591,8 +561,6 @@ binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayD * length is greater than zero, elementReader will be called for every index to read the * corresponding parcelable. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -609,8 +577,6 @@ binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayDa /** * Writes int32_t value to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -621,8 +587,6 @@ binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) __INTRODUCED_ /** * Writes uint32_t value to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -633,8 +597,6 @@ binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) __INTRODUCE /** * Writes int64_t value to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -645,8 +607,6 @@ binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) __INTRODUCED_ /** * Writes uint64_t value to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -657,8 +617,6 @@ binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) __INTRODUCE /** * Writes float value to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -669,8 +627,6 @@ binder_status_t AParcel_writeFloat(AParcel* parcel, float value) __INTRODUCED_IN /** * Writes double value to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -681,8 +637,6 @@ binder_status_t AParcel_writeDouble(AParcel* parcel, double value) __INTRODUCED_ /** * Writes bool value to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -693,8 +647,6 @@ binder_status_t AParcel_writeBool(AParcel* parcel, bool value) __INTRODUCED_IN(2 /** * Writes char16_t value to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -705,8 +657,6 @@ binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) __INTRODUCED_ /** * Writes int8_t value to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -717,8 +667,6 @@ binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) __INTRODUCED_IN /** * Reads into int32_t value from the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -729,8 +677,6 @@ binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) __INTRO /** * Reads into uint32_t value from the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -741,8 +687,6 @@ binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) __INT /** * Reads into int64_t value from the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -753,8 +697,6 @@ binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) __INTRO /** * Reads into uint64_t value from the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -765,8 +707,6 @@ binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) __INT /** * Reads into float value from the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -777,8 +717,6 @@ binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) __INTRODU /** * Reads into double value from the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -789,8 +727,6 @@ binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) __INTRO /** * Reads into bool value from the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -801,8 +737,6 @@ binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) __INTRODUCE /** * Reads into char16_t value from the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -813,8 +747,6 @@ binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRO /** * Reads into int8_t value from the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -825,8 +757,6 @@ binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODU /** * Writes an array of int32_t to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -839,8 +769,6 @@ binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayDat /** * Writes an array of uint32_t to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -853,8 +781,6 @@ binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayD /** * Writes an array of int64_t to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -867,8 +793,6 @@ binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayDat /** * Writes an array of uint64_t to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -881,8 +805,6 @@ binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayD /** * Writes an array of float to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -895,8 +817,6 @@ binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, /** * Writes an array of double to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -912,8 +832,6 @@ binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayDat * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying * values to write to the parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData some external representation of an array. * \param length the length of arrayData (or -1 if this represents a null array). @@ -927,8 +845,6 @@ binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, i /** * Writes an array of char16_t to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -941,8 +857,6 @@ binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayDat /** * Writes an array of int8_t to the next location in a non-null parcel. * - * Available since API level 29. - * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -959,8 +873,6 @@ binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -977,8 +889,6 @@ binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -995,8 +905,6 @@ binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -1013,8 +921,6 @@ binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -1031,8 +937,6 @@ binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -1049,8 +953,6 @@ binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -1066,8 +968,6 @@ binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData, * First, allocator will be called with the length of the array. Then, for every i in [0, length), * setter(arrayData, i, x) will be called where x is the value at the associated index. * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -1087,8 +987,6 @@ binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -1105,8 +1003,6 @@ binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * - * Available since API level 29. - * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -1118,7 +1014,7 @@ binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData, // @END-PRIMITIVE-READ-WRITE -#endif //__ANDROID_API__ >= 29 +#endif //__ANDROID_API__ >= __ANDROID_API_Q__ __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h index 78d70f87ba..2671b9b6fc 100644 --- a/libs/binder/ndk/include_ndk/android/binder_status.h +++ b/libs/binder/ndk/include_ndk/android/binder_status.h @@ -30,7 +30,7 @@ #include <sys/cdefs.h> __BEGIN_DECLS -#if __ANDROID_API__ >= 29 +#if __ANDROID_API__ >= __ANDROID_API_Q__ enum { STATUS_OK = 0, @@ -105,8 +105,6 @@ typedef struct AStatus AStatus; /** * New status which is considered a success. * - * Available since API level 29. - * * \return a newly constructed status object that the caller owns. */ __attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29); @@ -114,8 +112,6 @@ __attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29) /** * New status with exception code. * - * Available since API level 29. - * * \param exception the code that this status should represent. If this is EX_NONE, then this * constructs an non-error status object. * @@ -127,8 +123,6 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(binder_ex /** * New status with exception code and message. * - * Available since API level 29. - * * \param exception the code that this status should represent. If this is EX_NONE, then this * constructs an non-error status object. * \param message the error message to associate with this status object. @@ -143,8 +137,6 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessag * * This is considered to be EX_TRANSACTION_FAILED with extra information. * - * Available since API level 29. - * * \param serviceSpecific an implementation defined error code. * * \return a newly constructed status object that the caller owns. @@ -157,8 +149,6 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError( * * This is considered to be EX_TRANSACTION_FAILED with extra information. * - * Available since API level 29. - * * \param serviceSpecific an implementation defined error code. * \param message the error message to associate with this status object. * @@ -172,8 +162,6 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWit * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning * an AStatus instance. * - * Available since API level 29. - * * \param a low-level error to associate with this status object. * * \return a newly constructed status object that the caller owns. @@ -185,8 +173,6 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t * Whether this object represents a successful transaction. If this function returns true, then * AStatus_getExceptionCode will return EX_NONE. * - * Available since API level 29. - * * \param status the status being queried. * * \return whether the status represents a successful transaction. For more details, see below. @@ -196,8 +182,6 @@ bool AStatus_isOk(const AStatus* status) __INTRODUCED_IN(29); /** * The exception that this status object represents. * - * Available since API level 29. - * * \param status the status being queried. * * \return the exception code that this object represents. @@ -210,8 +194,6 @@ binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_ * 0, the status object may still represent a different exception or status. To find out if this * transaction as a whole is okay, use AStatus_isOk instead. * - * Available since API level 29. - * * \param status the status being queried. * * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0. @@ -224,8 +206,6 @@ int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(2 * object may represent a different exception or a service specific error. To find out if this * transaction as a whole is okay, use AStatus_isOk instead. * - * Available since API level 29. - * * \param status the status being queried. * * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0. @@ -238,8 +218,6 @@ binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29); * * The returned string has the lifetime of the status object passed into this function. * - * Available since API level 29. - * * \param status the status being queried. * * \return the message associated with this error. @@ -249,13 +227,11 @@ const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29); /** * Deletes memory associated with the status instance. * - * Available since API level 29. - * * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs. */ void AStatus_delete(AStatus* status) __INTRODUCED_IN(29); -#endif //__ANDROID_API__ >= 29 +#endif //__ANDROID_API__ >= __ANDROID_API_Q__ __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h deleted file mode 100644 index 2a4ded8691..0000000000 --- a/libs/binder/ndk/include_platform/android/binder_stability.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2019 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 <android/binder_ibinder.h> - -__BEGIN_DECLS - -/** - * Private addition to binder_flag_t. - */ -enum { - /** - * Indicates that this transaction is coupled w/ vendor.img - */ - FLAG_PRIVATE_VENDOR = 0x10000000, -}; - -#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || \ - (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)) - -enum { - FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR, -}; - -/** - * This interface has the stability of the vendor image. - */ -void AIBinder_markVendorStability(AIBinder* binder); - -static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) { - AIBinder_markVendorStability(binder); -} - -#else // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && - // !defined(__ANDROID_APEX__)) - -enum { - FLAG_PRIVATE_LOCAL = 0, -}; - -/** - * This interface has the stability of the system image. - */ -void AIBinder_markSystemStability(AIBinder* binder); - -static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) { - AIBinder_markSystemStability(binder); -} - -#endif // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && - // !defined(__ANDROID_APEX__)) - -/** - * This interface has system<->vendor stability - */ -void AIBinder_markVintfStability(AIBinder* binder); - -__END_DECLS diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index d4d5387f33..7e6581736f 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -89,24 +89,12 @@ LIBBINDER_NDK { # introduced=29 AStatus_getStatus; AStatus_isOk; AStatus_newOk; - ABinderProcess_joinThreadPool; # apex vndk - ABinderProcess_setThreadPoolMaxThreadCount; # apex vndk - ABinderProcess_startThreadPool; # apex vndk - AServiceManager_addService; # apex vndk - AServiceManager_checkService; # apex vndk - AServiceManager_getService; # apex vndk - local: - *; -}; - -LIBBINDER_NDK30 { # introduced=30 - global: - AIBinder_getExtension; - AIBinder_setExtension; - - AIBinder_markSystemStability; # apex - AIBinder_markVendorStability; # vndk - AIBinder_markVintfStability; # apex vndk + ABinderProcess_joinThreadPool; # apex + ABinderProcess_setThreadPoolMaxThreadCount; # apex + ABinderProcess_startThreadPool; # apex + AServiceManager_addService; # apex + AServiceManager_checkService; # apex + AServiceManager_getService; # apex local: *; }; diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index f18e118bc9..ae2276e794 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -50,7 +50,7 @@ binder_status_t WriteAndValidateArraySize(AParcel* parcel, bool isNullArray, int if (length < -1) return STATUS_BAD_VALUE; if (!isNullArray && length < 0) { - LOG(ERROR) << __func__ << ": non-null array but length is " << length; + LOG(ERROR) << __func__ << ": null array must be used with length == -1."; return STATUS_BAD_VALUE; } if (isNullArray && length > 0) { diff --git a/libs/binder/ndk/scripts/format.sh b/libs/binder/ndk/scripts/format.sh new file mode 100755 index 0000000000..698d291cb1 --- /dev/null +++ b/libs/binder/ndk/scripts/format.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +echo "Formatting code" + +bpfmt -w $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -name "Android.bp") +clang-format -i $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -\( -name "*.cpp" -o -name "*.h" -\)) diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh new file mode 100755 index 0000000000..3529b725ce --- /dev/null +++ b/libs/binder/ndk/scripts/init_map.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +# Simple helper for ease of development until this API is frozen. + +echo "LIBBINDER_NDK { # introduced=29" +echo " global:" +{ + grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder.h; + grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder_jni.h; + grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h; + grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h; +} | sort | uniq | awk '{ print " " $0 ";"; }' +{ + grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h; + grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h; +} | sort | uniq | awk '{ print " " $0 "; # apex"; }' +echo " local:" +echo " *;" +echo "};" diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp deleted file mode 100644 index a5b3ecea4a..0000000000 --- a/libs/binder/ndk/stability.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <android/binder_stability.h> - -#include <binder/Stability.h> -#include "ibinder_internal.h" - -#include <log/log.h> - -using ::android::internal::Stability; - -#ifdef __ANDROID_VNDK__ -#error libbinder_ndk should only be built in a system context -#endif - -#ifdef __ANDROID_NDK__ -#error libbinder_ndk should only be built in a system context -#endif - -// explicit extern because symbol is only declared in header when __ANDROID_VNDK__ -extern "C" void AIBinder_markVendorStability(AIBinder* binder) { - Stability::markVndk(binder->getBinder().get()); -} - -void AIBinder_markSystemStability(AIBinder* binder) { - Stability::markCompilationUnit(binder->getBinder().get()); -} - -void AIBinder_markVintfStability(AIBinder* binder) { - Stability::markVintf(binder->getBinder().get()); -} diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp index ebd08b2f71..8cd4e033df 100644 --- a/libs/binder/ndk/test/Android.bp +++ b/libs/binder/ndk/test/Android.bp @@ -44,10 +44,10 @@ cc_defaults { "libandroid_runtime_lazy", "libbase", "libbinder", - "libbinder_ndk", "libutils", ], static_libs: [ + "libbinder_ndk", "test_libbinder_ndk_library", ], } @@ -67,32 +67,3 @@ cc_test { srcs: ["main_server.cpp"], gtest: false, } - -cc_test { - name: "binderVendorDoubleLoadTest", - vendor: true, - srcs: [ - "binderVendorDoubleLoadTest.cpp", - ], - static_libs: [ - "IBinderVendorDoubleLoadTest-cpp", - "IBinderVendorDoubleLoadTest-ndk_platform", - "libbinder_aidl_test_stub-ndk_platform", - ], - shared_libs: [ - "libbase", - "libbinder", - "libbinder_ndk", - "libutils", - ], - test_suites: ["device-tests"], -} - -aidl_interface { - name: "IBinderVendorDoubleLoadTest", - // TODO(b/119771576): only vendor is needed - vendor_available: true, - srcs: [ - "IBinderVendorDoubleLoadTest.aidl", - ], -} diff --git a/libs/binder/ndk/test/AndroidTest.xml b/libs/binder/ndk/test/AndroidTest.xml deleted file mode 100644 index 89646f7776..0000000000 --- a/libs/binder/ndk/test/AndroidTest.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 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="Runs binderVendorDoubleLoadTest."> - <option name="test-suite-tag" value="apct" /> - <option name="test-suite-tag" value="apct-native" /> - - <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> - - <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> - <option name="cleanup" value="true" /> - <option name="push" value="binderVendorDoubleLoadTest->/data/nativetest/vendor/binderVendorDoubleLoadTest" /> - </target_preparer> - - <test class="com.android.tradefed.testtype.GTest" > - <option name="native-test-device-path" value="/data/nativetest/vendor" /> - <option name="module-name" value="binderVendorDoubleLoadTest" /> - </test> -</configuration> - diff --git a/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl b/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl deleted file mode 100644 index 3a5bd9cc56..0000000000 --- a/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -interface IBinderVendorDoubleLoadTest { - @utf8InCpp String RepeatString(@utf8InCpp String toRepeat); -} diff --git a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp deleted file mode 100644 index d3ccdc2878..0000000000 --- a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2019 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 <BnBinderVendorDoubleLoadTest.h> -#include <aidl/BnBinderVendorDoubleLoadTest.h> -#include <aidl/android/os/IServiceManager.h> -#include <android-base/logging.h> -#include <android-base/properties.h> -#include <android-base/strings.h> -#include <android/binder_ibinder.h> -#include <android/binder_manager.h> -#include <android/binder_process.h> -#include <android/binder_stability.h> -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/ProcessState.h> -#include <binder/Stability.h> -#include <binder/Status.h> -#include <gtest/gtest.h> - -#include <sys/prctl.h> - -using namespace android; -using ::android::base::EndsWith; -using ::android::base::GetProperty; -using ::android::base::Split; -using ::android::binder::Status; -using ::android::internal::Stability; -using ::ndk::ScopedAStatus; -using ::ndk::SharedRefBase; -using ::ndk::SpAIBinder; - -static const std::string kLocalNdkServerName = "NdkServer-local-IBinderVendorDoubleLoadTest"; -static const std::string kRemoteNdkServerName = "NdkServer-remote-IBinderVendorDoubleLoadTest"; - -class NdkServer : public aidl::BnBinderVendorDoubleLoadTest { - ScopedAStatus RepeatString(const std::string& in, std::string* out) override { - *out = in; - return ScopedAStatus::ok(); - } -}; -class CppServer : public BnBinderVendorDoubleLoadTest { - Status RepeatString(const std::string& in, std::string* out) override { - *out = in; - return Status::ok(); - } -}; - -TEST(DoubleBinder, VendorCppCantCallIntoSystem) { - Vector<String16> services = defaultServiceManager()->listServices(); - EXPECT_TRUE(services.empty()); -} - -TEST(DoubleBinder, VendorCppCantRegisterService) { - sp<CppServer> cppServer = new CppServer; - status_t status = defaultServiceManager()->addService(String16("anything"), cppServer); - EXPECT_EQ(EX_TRANSACTION_FAILED, status); -} - -TEST(DoubleBinder, CppVendorCantManuallyMarkVintfStability) { - // this test also implies that stability logic is turned on in vendor - ASSERT_DEATH( - { - sp<IBinder> binder = new CppServer(); - Stability::markVintf(binder.get()); - }, - "Should only mark known object."); -} - -TEST(DoubleBinder, NdkVendorCantManuallyMarkVintfStability) { - // this test also implies that stability logic is turned on in vendor - ASSERT_DEATH( - { - std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>(); - AIBinder_markVintfStability(ndkServer->asBinder().get()); - }, - "Should only mark known object."); -} - -TEST(DoubleBinder, CallIntoNdk) { - for (const std::string& serviceName : {kLocalNdkServerName, kRemoteNdkServerName}) { - SpAIBinder binder = SpAIBinder(AServiceManager_checkService(serviceName.c_str())); - ASSERT_NE(nullptr, binder.get()) << serviceName; - EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())) << serviceName; - - std::shared_ptr<aidl::IBinderVendorDoubleLoadTest> server = - aidl::IBinderVendorDoubleLoadTest::fromBinder(binder); - - ASSERT_NE(nullptr, server.get()) << serviceName; - - EXPECT_EQ(STATUS_OK, AIBinder_ping(server->asBinder().get())); - - std::string outString; - ScopedAStatus status = server->RepeatString("foo", &outString); - EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get())) << serviceName; - EXPECT_EQ("foo", outString) << serviceName; - } -} - -TEST(DoubleBinder, CallIntoSystemStabilityNdk) { - // picking an arbitrary system service - SpAIBinder binder = SpAIBinder(AServiceManager_checkService("manager")); - ASSERT_NE(nullptr, binder.get()); - - // can make stable transaction to system server - EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())); - - using aidl::android::os::IServiceManager; - std::shared_ptr<IServiceManager> manager = IServiceManager::fromBinder(binder); - ASSERT_NE(nullptr, manager.get()); - - std::vector<std::string> services; - ASSERT_EQ( - STATUS_BAD_TYPE, - manager->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &services).getStatus()); -} - -void initDrivers() { - // Explicitly instantiated with the same driver that system would use. - // __ANDROID_VNDK__ right now uses /dev/vndbinder by default. - ProcessState::initWithDriver("/dev/binder"); - ProcessState::self()->startThreadPool(); - ABinderProcess_startThreadPool(); -} - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - - if (fork() == 0) { - // child process - - prctl(PR_SET_PDEATHSIG, SIGHUP); - - initDrivers(); - - // REMOTE SERVERS - std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>(); - CHECK(STATUS_OK == AServiceManager_addService(ndkServer->asBinder().get(), - kRemoteNdkServerName.c_str())); - - // OR sleep forever or whatever, it doesn't matter - IPCThreadState::self()->joinThreadPool(true); - exit(1); // should not reach - } - - sleep(1); - - initDrivers(); - - // LOCAL SERVERS - std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>(); - AServiceManager_addService(ndkServer->asBinder().get(), kLocalNdkServerName.c_str()); - - return RUN_ALL_TESTS(); -} diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh new file mode 100755 index 0000000000..9a4577ffff --- /dev/null +++ b/libs/binder/ndk/update.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +set -ex + +# This script makes sure that the source code is in sync with the various scripts +./scripts/gen_parcel_helper.py +./scripts/format.sh +./scripts/init_map.sh > libbinder_ndk.map.txt diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 5a7f9a97fa..c451780dd7 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -19,34 +19,45 @@ cc_defaults { cflags: [ "-Wall", "-Werror", + "-Wno-unused-private-field", + "-Wno-unused-variable", ], } cc_test { name: "binderDriverInterfaceTest_IPC_32", - defaults: ["binder_test_defaults"], srcs: ["binderDriverInterfaceTest.cpp"], + defaults: ["binder_test_defaults"], compile_multilib: "32", cflags: ["-DBINDER_IPC_32BIT=1"], } cc_test { - name: "binderDriverInterfaceTest", - defaults: ["binder_test_defaults"], product_variables: { binder32bit: { cflags: ["-DBINDER_IPC_32BIT=1"], }, }, + name: "binderDriverInterfaceTest", srcs: ["binderDriverInterfaceTest.cpp"], - test_suites: ["device-tests"], + defaults: ["binder_test_defaults"], } cc_test { - name: "binderLibTest_IPC_32", + name: "binderValueTypeTest", + srcs: ["binderValueTypeTest.cpp"], defaults: ["binder_test_defaults"], + shared_libs: [ + "libbinder", + "libutils", + ], +} + +cc_test { + name: "binderLibTest_IPC_32", srcs: ["binderLibTest.cpp"], + defaults: ["binder_test_defaults"], shared_libs: [ "libbinder", "libutils", @@ -56,27 +67,25 @@ cc_test { } cc_test { - name: "binderLibTest", - defaults: ["binder_test_defaults"], product_variables: { binder32bit: { cflags: ["-DBINDER_IPC_32BIT=1"], }, }, + defaults: ["binder_test_defaults"], + name: "binderLibTest", srcs: ["binderLibTest.cpp"], shared_libs: [ "libbinder", "libutils", ], - test_suites: ["device-tests"], - require_root: true, } cc_test { name: "binderThroughputTest", - defaults: ["binder_test_defaults"], srcs: ["binderThroughputTest.cpp"], + defaults: ["binder_test_defaults"], shared_libs: [ "libbinder", "libutils", @@ -92,20 +101,19 @@ cc_test { cc_test { name: "binderTextOutputTest", - defaults: ["binder_test_defaults"], srcs: ["binderTextOutputTest.cpp"], + defaults: ["binder_test_defaults"], shared_libs: [ "libbinder", "libutils", "libbase", ], - test_suites: ["device-tests"], } cc_test { name: "schd-dbg", - defaults: ["binder_test_defaults"], srcs: ["schd-dbg.cpp"], + defaults: ["binder_test_defaults"], shared_libs: [ "libbinder", "libutils", @@ -115,11 +123,16 @@ cc_test { cc_test { name: "binderSafeInterfaceTest", - defaults: ["binder_test_defaults"], srcs: ["binderSafeInterfaceTest.cpp"], + defaults: ["binder_test_defaults"], cppflags: [ - "-Wextra", + "-Weverything", + "-Wno-c++98-compat", + "-Wno-c++98-compat-pedantic", + "-Wno-global-constructors", + "-Wno-padded", + "-Wno-weak-vtables", ], cpp_std: "experimental", @@ -131,35 +144,4 @@ cc_test { "liblog", "libutils", ], - test_suites: ["device-tests"], - require_root: true, -} - -aidl_interface { - name: "binderStabilityTestIface", - srcs: [ - "IBinderStabilityTest.aidl", - ], -} - -cc_test { - name: "binderStabilityTest", - defaults: ["binder_test_defaults"], - srcs: [ - "binderStabilityTest.cpp", - ], - - shared_libs: [ - "libbinder_ndk", - "libbinder", - "liblog", - "libutils", - ], - static_libs: [ - "binderStabilityTestIface-cpp", - "binderStabilityTestIface-ndk_platform", - ], - - test_suites: ["device-tests"], - require_root: true, } diff --git a/libs/binder/tests/IBinderStabilityTest.aidl b/libs/binder/tests/IBinderStabilityTest.aidl deleted file mode 100644 index 36e1c2cbc4..0000000000 --- a/libs/binder/tests/IBinderStabilityTest.aidl +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! -// THIS IS ONLY FOR TESTING! -interface IBinderStabilityTest { - // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! - // THIS IS ONLY FOR TESTING! - void sendBinder(IBinder binder); - - // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! - // THIS IS ONLY FOR TESTING! - void sendAndCallBinder(IBinder binder); - - // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! - // THIS IS ONLY FOR TESTING! - IBinder returnNoStabilityBinder(); - - // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! - // THIS IS ONLY FOR TESTING! - IBinder returnLocalStabilityBinder(); - - // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! - // THIS IS ONLY FOR TESTING! - IBinder returnVintfStabilityBinder(); - - // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! - // THIS IS ONLY FOR TESTING! - IBinder returnVendorStabilityBinder(); -} -// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS! -// THIS IS ONLY FOR TESTING! -// Construct and return a binder with a specific stability diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp index f3ed6a613c..77ebac8f5a 100644 --- a/libs/binder/tests/binderDriverInterfaceTest.cpp +++ b/libs/binder/tests/binderDriverInterfaceTest.cpp @@ -230,6 +230,7 @@ TEST_F(BinderDriverInterfaceTest, IncRefsAcquireReleaseDecRefs) { } TEST_F(BinderDriverInterfaceTest, Transaction) { + binder_uintptr_t cookie = 1234; struct { uint32_t cmd1; struct binder_transaction_data arg1; diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 5e0574ad8a..78f11594b9 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -28,7 +28,6 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> -#include <private/binder/binder_module.h> #include <sys/epoll.h> #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) @@ -67,6 +66,7 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION, + BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, BINDER_LIB_TEST_EXIT_TRANSACTION, BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION, BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, @@ -553,6 +553,50 @@ TEST_F(BinderLibTest, AddServer) ASSERT_TRUE(server != nullptr); } +TEST_F(BinderLibTest, DeathNotificationNoRefs) +{ + status_t ret; + + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + + { + sp<IBinder> binder = addServer(); + ASSERT_TRUE(binder != nullptr); + ret = binder->linkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); + } + IPCThreadState::self()->flushCommands(); + ret = testDeathRecipient->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); +#if 0 /* Is there an unlink api that does not require a strong reference? */ + ret = binder->unlinkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); +#endif +} + +TEST_F(BinderLibTest, DeathNotificationWeakRef) +{ + status_t ret; + wp<IBinder> wbinder; + + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + + { + sp<IBinder> binder = addServer(); + ASSERT_TRUE(binder != nullptr); + ret = binder->linkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); + wbinder = binder; + } + IPCThreadState::self()->flushCommands(); + ret = testDeathRecipient->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); +#if 0 /* Is there an unlink api that does not require a strong reference? */ + ret = binder->unlinkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); +#endif +} + TEST_F(BinderLibTest, DeathNotificationStrongRef) { status_t ret; @@ -770,22 +814,20 @@ TEST_F(BinderLibTest, PromoteLocal) { EXPECT_TRUE(strong_from_weak == nullptr); } -TEST_F(BinderLibTest, LocalGetExtension) { - sp<BBinder> binder = new BBinder(); - sp<IBinder> ext = new BBinder(); - binder->setExtension(ext); - EXPECT_EQ(ext, binder->getExtension()); -} - -TEST_F(BinderLibTest, RemoteGetExtension) { +TEST_F(BinderLibTest, PromoteRemote) { + int ret; + Parcel data, reply; + sp<IBinder> strong = new BBinder(); sp<IBinder> server = addServer(); + ASSERT_TRUE(server != nullptr); + ASSERT_TRUE(strong != nullptr); - sp<IBinder> extension; - EXPECT_EQ(NO_ERROR, server->getExtension(&extension)); - ASSERT_NE(nullptr, extension.get()); + ret = data.writeWeakBinder(strong); + EXPECT_EQ(NO_ERROR, ret); - EXPECT_EQ(NO_ERROR, extension->pingBinder()); + ret = server->transact(BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, data, &reply); + EXPECT_GE(ret, 0); } TEST_F(BinderLibTest, CheckHandleZeroBinderHighBitsZeroCookie) { @@ -813,6 +855,7 @@ TEST_F(BinderLibTest, FreedBinder) { wp<IBinder> keepFreedBinder; { Parcel data, reply; + data.writeBool(false); /* request weak reference */ ret = server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply); ASSERT_EQ(NO_ERROR, ret); struct flat_binder_object *freed = (struct flat_binder_object *)(reply.data()); @@ -821,9 +864,8 @@ TEST_F(BinderLibTest, FreedBinder) { * delete its reference to it - otherwise the transaction * fails regardless of whether the driver is fixed. */ - keepFreedBinder = reply.readStrongBinder(); + keepFreedBinder = reply.readWeakBinder(); } - IPCThreadState::self()->flushCommands(); { Parcel data, reply; data.writeStrongBinder(server); @@ -973,6 +1015,9 @@ TEST_F(BinderLibTest, WorkSourceRestored) TEST_F(BinderLibTest, PropagateFlagSet) { + status_t ret; + Parcel data, reply; + IPCThreadState::self()->clearPropagateWorkSource(); IPCThreadState::self()->setCallingWorkSourceUid(100); EXPECT_EQ(true, IPCThreadState::self()->shouldPropagateWorkSource()); @@ -980,6 +1025,9 @@ TEST_F(BinderLibTest, PropagateFlagSet) TEST_F(BinderLibTest, PropagateFlagCleared) { + status_t ret; + Parcel data, reply; + IPCThreadState::self()->setCallingWorkSourceUid(100); IPCThreadState::self()->clearPropagateWorkSource(); EXPECT_EQ(false, IPCThreadState::self()->shouldPropagateWorkSource()); @@ -987,6 +1035,9 @@ TEST_F(BinderLibTest, PropagateFlagCleared) TEST_F(BinderLibTest, PropagateFlagRestored) { + status_t ret; + Parcel data, reply; + int token = IPCThreadState::self()->setCallingWorkSourceUid(100); IPCThreadState::self()->restoreCallingWorkSource(token); @@ -1085,6 +1136,7 @@ class BinderLibTestService : public BBinder case BINDER_LIB_TEST_ADD_POLL_SERVER: case BINDER_LIB_TEST_ADD_SERVER: { int ret; + uint8_t buf[1] = { 0 }; int serverid; if (m_id != 0) { @@ -1282,6 +1334,29 @@ class BinderLibTestService : public BBinder if (ret != size) return UNKNOWN_ERROR; return NO_ERROR; } + case BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION: { + int ret; + wp<IBinder> weak; + sp<IBinder> strong; + Parcel data2, reply2; + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> server = sm->getService(binderLibTestServiceName); + + weak = data.readWeakBinder(); + if (weak == nullptr) { + return BAD_VALUE; + } + strong = weak.promote(); + + ret = server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data2, &reply2); + if (ret != NO_ERROR) + exit(EXIT_FAILURE); + + if (strong == nullptr) { + reply->setError(1); + } + return NO_ERROR; + } case BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION: alarm(10); return NO_ERROR; @@ -1290,8 +1365,13 @@ class BinderLibTestService : public BBinder ; exit(EXIT_SUCCESS); case BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION: { + bool strongRef = data.readBool(); sp<IBinder> binder = new BBinder(); - reply->writeStrongBinder(binder); + if (strongRef) { + reply->writeStrongBinder(binder); + } else { + reply->writeWeakBinder(binder); + } return NO_ERROR; } case BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION: { @@ -1319,6 +1399,7 @@ class BinderLibTestService : public BBinder bool m_serverStartRequested; sp<IBinder> m_serverStarted; sp<IBinder> m_strongRef; + bool m_callbackPending; sp<IBinder> m_callback; }; @@ -1331,13 +1412,6 @@ int run_server(int index, int readypipefd, bool usePoll) BinderLibTestService* testServicePtr; { sp<BinderLibTestService> testService = new BinderLibTestService(index); - - /* - * Normally would also contain functionality as well, but we are only - * testing the extension mechanism. - */ - testService->setExtension(new BBinder()); - /* * We need this below, but can't hold a sp<> because it prevents the * node from being cleaned up automatically. It's safe in this case @@ -1387,7 +1461,7 @@ int run_server(int index, int readypipefd, bool usePoll) * We simulate a single-threaded process using the binder poll * interface; besides handling binder commands, it can also * issue outgoing transactions, by storing a callback in - * m_callback. + * m_callback and setting m_callbackPending. * * processPendingCall() will then issue that transaction. */ @@ -1414,6 +1488,8 @@ int run_server(int index, int readypipefd, bool usePoll) } int main(int argc, char **argv) { + int ret; + if (argc == 4 && !strcmp(argv[1], "--servername")) { binderservername = argv[2]; } else { diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index 09f58cc833..3b1db27749 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -75,7 +75,7 @@ public: private: int32_t mValue = 0; - __attribute__((unused)) uint8_t mPadding[4] = {}; // Avoids a warning from -Wpadded + uint8_t mPadding[4] = {}; // Avoids a warning from -Wpadded }; struct TestFlattenable : Flattenable<TestFlattenable> { @@ -743,7 +743,6 @@ TEST_F(SafeInterfaceTest, TestIncremementParcelableVector) { const std::vector<TestParcelable> a{TestParcelable{1}, TestParcelable{2}}; std::vector<TestParcelable> aPlusOne; status_t result = mSafeInterfaceTest->increment(a, &aPlusOne); - ASSERT_EQ(NO_ERROR, result); ASSERT_EQ(a.size(), aPlusOne.size()); for (size_t i = 0; i < a.size(); ++i) { ASSERT_EQ(a[i].getValue() + 1, aPlusOne[i].getValue()); diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp deleted file mode 100644 index 1f2779abf0..0000000000 --- a/libs/binder/tests/binderStabilityTest.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <android/binder_manager.h> -#include <android/binder_stability.h> -#include <binder/Binder.h> -#include <binder/IBinder.h> -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/Parcel.h> -#include <binder/Stability.h> -#include <gtest/gtest.h> - -#include <sys/prctl.h> - -#include "aidl/BnBinderStabilityTest.h" -#include "BnBinderStabilityTest.h" - -using namespace android; -using namespace ndk; -using android::binder::Status; -using android::internal::Stability; // for testing only! - -const String16 kSystemStabilityServer = String16("binder_stability_test_service_system"); - -// This is handwritten so that we can test different stability levels w/o having the AIDL -// compiler assign them. Hand-writing binder interfaces is considered a bad practice -// sanity reasons. YOU SHOULD DEFINE AN AIDL INTERFACE INSTEAD! -class BadStableBinder : public BBinder { -public: - static constexpr uint32_t USER_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION; - static String16 kDescriptor; - - bool gotUserTransaction = false; - - static status_t doUserTransaction(const sp<IBinder>& binder) { - Parcel data, reply; - data.writeInterfaceToken(kDescriptor); - return binder->transact(USER_TRANSACTION, data, &reply, 0/*flags*/); - } - - status_t onTransact(uint32_t code, - const Parcel& data, Parcel* reply, uint32_t flags) override { - if (code == USER_TRANSACTION) { - // not interested in this kind of stability. Make sure - // we have a test failure - LOG_ALWAYS_FATAL_IF(!data.enforceInterface(kDescriptor)); - - gotUserTransaction = true; - - ALOGE("binder stability: Got user transaction"); - return OK; - } - return BBinder::onTransact(code, data, reply, flags); - } - - static sp<BadStableBinder> undef() { - sp<BadStableBinder> iface = new BadStableBinder(); - return iface; - } - - static sp<BadStableBinder> system() { - sp<BadStableBinder> iface = new BadStableBinder(); - Stability::markCompilationUnit(iface.get()); // <- for test only - return iface; - } - - static sp<BadStableBinder> vintf() { - sp<BadStableBinder> iface = new BadStableBinder(); - Stability::markVintf(iface.get()); // <- for test only - return iface; - } - - static sp<BadStableBinder> vendor() { - sp<BadStableBinder> iface = new BadStableBinder(); - Stability::markVndk(iface.get()); // <- for test only - return iface; - } -}; -String16 BadStableBinder::kDescriptor = String16("BadStableBinder.test"); - -// NO! NO! NO! Do not even think of doing something like this! -// This is for testing! If a class like this was actually used in production, -// it would ruin everything! -class MyBinderStabilityTest : public BnBinderStabilityTest { -public: - Status sendBinder(const sp<IBinder>& /*binder*/) override { - return Status::ok(); - } - Status sendAndCallBinder(const sp<IBinder>& binder) override { - Stability::debugLogStability("sendAndCallBinder got binder", binder); - return Status::fromExceptionCode(BadStableBinder::doUserTransaction(binder)); - } - Status returnNoStabilityBinder(sp<IBinder>* _aidl_return) override { - *_aidl_return = BadStableBinder::undef(); - return Status::ok(); - } - Status returnLocalStabilityBinder(sp<IBinder>* _aidl_return) override { - *_aidl_return = BadStableBinder::system(); - return Status::ok(); - } - Status returnVintfStabilityBinder(sp<IBinder>* _aidl_return) override { - *_aidl_return = BadStableBinder::vintf(); - return Status::ok(); - } - Status returnVendorStabilityBinder(sp<IBinder>* _aidl_return) override { - *_aidl_return = BadStableBinder::vendor(); - return Status::ok(); - } -}; - -TEST(BinderStability, OnlyVintfStabilityBinderNeedsVintfDeclaration) { - EXPECT_FALSE(Stability::requiresVintfDeclaration(nullptr)); - EXPECT_FALSE(Stability::requiresVintfDeclaration(BadStableBinder::undef())); - EXPECT_FALSE(Stability::requiresVintfDeclaration(BadStableBinder::system())); - EXPECT_FALSE(Stability::requiresVintfDeclaration(BadStableBinder::vendor())); - - EXPECT_TRUE(Stability::requiresVintfDeclaration(BadStableBinder::vintf())); -} - -TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) { - sp<IBinder> vintfServer = BadStableBinder::vintf(); - - for (const char* instance8 : { - ".", "/", "/.", "a.d.IFoo", "foo", "a.d.IFoo/foo" - }) { - String16 instance (instance8); - - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8; - EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8; - } -} - -TEST(BinderStability, CantCallVendorBinderInSystemContext) { - sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer); - auto server = interface_cast<IBinderStabilityTest>(serverBinder); - - ASSERT_NE(nullptr, server.get()); - ASSERT_NE(nullptr, IInterface::asBinder(server)->remoteBinder()); - - EXPECT_TRUE(server->sendBinder(BadStableBinder::undef()).isOk()); - EXPECT_TRUE(server->sendBinder(BadStableBinder::system()).isOk()); - EXPECT_TRUE(server->sendBinder(BadStableBinder::vintf()).isOk()); - EXPECT_TRUE(server->sendBinder(BadStableBinder::vendor()).isOk()); - - { - sp<BadStableBinder> binder = BadStableBinder::undef(); - EXPECT_TRUE(server->sendAndCallBinder(binder).isOk()); - EXPECT_TRUE(binder->gotUserTransaction); - } - { - sp<BadStableBinder> binder = BadStableBinder::system(); - EXPECT_TRUE(server->sendAndCallBinder(binder).isOk()); - EXPECT_TRUE(binder->gotUserTransaction); - } - { - sp<BadStableBinder> binder = BadStableBinder::vintf(); - EXPECT_TRUE(server->sendAndCallBinder(binder).isOk()); - EXPECT_TRUE(binder->gotUserTransaction); - } - { - // !!! user-defined transaction may not be stable for remote server !!! - // !!! so, it does not work !!! - sp<BadStableBinder> binder = BadStableBinder::vendor(); - EXPECT_EQ(BAD_TYPE, server->sendAndCallBinder(binder).exceptionCode()); - EXPECT_FALSE(binder->gotUserTransaction); - } - - sp<IBinder> out; - EXPECT_TRUE(server->returnNoStabilityBinder(&out).isOk()); - ASSERT_NE(nullptr, out.get()); - EXPECT_EQ(OK, out->pingBinder()); - EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out)); - - EXPECT_TRUE(server->returnLocalStabilityBinder(&out).isOk()); - ASSERT_NE(nullptr, out.get()); - EXPECT_EQ(OK, out->pingBinder()); - EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out)); - - EXPECT_TRUE(server->returnVintfStabilityBinder(&out).isOk()); - ASSERT_NE(nullptr, out.get()); - EXPECT_EQ(OK, out->pingBinder()); - EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out)); - - EXPECT_TRUE(server->returnVendorStabilityBinder(&out).isOk()); - ASSERT_NE(nullptr, out.get()); - - // !!! libbinder-defined transaction works !!! - EXPECT_EQ(OK, out->pingBinder()); - - // !!! user-defined transaction may not be stable !!! - // !!! so, it does not work !!! - EXPECT_EQ(BAD_TYPE, BadStableBinder::doUserTransaction(out)); -} - -// This is handwritten so that we can test different stability levels w/o having the AIDL -// compiler assign them. Hand-writing binder interfaces is considered a bad practice -// sanity reasons. YOU SHOULD DEFINE AN AIDL INTERFACE INSTEAD! - -struct NdkBinderStable_DataClass { - bool gotUserTransaction = false; -}; -void* NdkBadStableBinder_Class_onCreate(void* args) { - LOG_ALWAYS_FATAL_IF(args != nullptr, "Takes no args"); - return static_cast<void*>(new NdkBinderStable_DataClass); -} -void NdkBadStableBinder_Class_onDestroy(void* userData) { - delete static_cast<NdkBinderStable_DataClass*>(userData); -} -NdkBinderStable_DataClass* NdkBadStableBinder_getUserData(AIBinder* binder) { - LOG_ALWAYS_FATAL_IF(binder == nullptr); - void* userData = AIBinder_getUserData(binder); - LOG_ALWAYS_FATAL_IF(userData == nullptr, "null data - binder is remote?"); - - return static_cast<NdkBinderStable_DataClass*>(userData); -} -binder_status_t NdkBadStableBinder_Class_onTransact( - AIBinder* binder, transaction_code_t code, const AParcel* /*in*/, AParcel* /*out*/) { - - if (code == BadStableBinder::USER_TRANSACTION) { - ALOGE("ndk binder stability: Got user transaction"); - NdkBadStableBinder_getUserData(binder)->gotUserTransaction = true; - return STATUS_OK; - } - - return STATUS_UNKNOWN_TRANSACTION; -} - -static AIBinder_Class* kNdkBadStableBinder = - AIBinder_Class_define(String8(BadStableBinder::kDescriptor).c_str(), - NdkBadStableBinder_Class_onCreate, - NdkBadStableBinder_Class_onDestroy, - NdkBadStableBinder_Class_onTransact); - -// for testing only to get around __ANDROID_VNDK__ guard. -extern "C" void AIBinder_markVendorStability(AIBinder* binder); // <- BAD DO NOT COPY - -TEST(BinderStability, NdkCantCallVendorBinderInSystemContext) { - SpAIBinder binder = SpAIBinder(AServiceManager_getService( - String8(kSystemStabilityServer).c_str())); - - std::shared_ptr<aidl::IBinderStabilityTest> remoteServer = - aidl::IBinderStabilityTest::fromBinder(binder); - - ASSERT_NE(nullptr, remoteServer.get()); - - SpAIBinder comp = SpAIBinder(AIBinder_new(kNdkBadStableBinder, nullptr /*args*/)); - EXPECT_TRUE(remoteServer->sendBinder(comp).isOk()); - EXPECT_TRUE(remoteServer->sendAndCallBinder(comp).isOk()); - EXPECT_TRUE(NdkBadStableBinder_getUserData(comp.get())->gotUserTransaction); - - SpAIBinder vendor = SpAIBinder(AIBinder_new(kNdkBadStableBinder, nullptr /*args*/)); - AIBinder_markVendorStability(vendor.get()); - EXPECT_TRUE(remoteServer->sendBinder(vendor).isOk()); - EXPECT_FALSE(remoteServer->sendAndCallBinder(vendor).isOk()); - EXPECT_FALSE(NdkBadStableBinder_getUserData(vendor.get())->gotUserTransaction); -} - -class MarksStabilityInConstructor : public BBinder { -public: - static bool gDestructed; - - MarksStabilityInConstructor() { - Stability::markCompilationUnit(this); - } - ~MarksStabilityInConstructor() { - gDestructed = true; - } -}; -bool MarksStabilityInConstructor::gDestructed = false; - -TEST(BinderStability, MarkingObjectNoDestructTest) { - ASSERT_FALSE(MarksStabilityInConstructor::gDestructed); - - // best practice is to put this directly in an sp, but for this test, we - // want to explicitly check what happens before that happens - MarksStabilityInConstructor* binder = new MarksStabilityInConstructor(); - ASSERT_FALSE(MarksStabilityInConstructor::gDestructed); - - sp<MarksStabilityInConstructor> binderSp = binder; - ASSERT_FALSE(MarksStabilityInConstructor::gDestructed); - - binderSp = nullptr; - ASSERT_TRUE(MarksStabilityInConstructor::gDestructed); -} - -TEST(BinderStability, RemarkDies) { - ASSERT_DEATH({ - sp<IBinder> binder = new BBinder(); - Stability::markCompilationUnit(binder.get()); // <-- only called for tests - Stability::markVndk(binder.get()); // <-- only called for tests - }, "Should only mark known object."); -} - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - - if (fork() == 0) { - // child process - prctl(PR_SET_PDEATHSIG, SIGHUP); - - sp<IBinder> server = new MyBinderStabilityTest; - android::defaultServiceManager()->addService(kSystemStabilityServer, server); - - IPCThreadState::self()->joinThreadPool(true); - exit(1); // should not reach - } - - // This is not racey. Just giving these services some time to register before we call - // getService which sleeps for much longer... - usleep(10000); - - return RUN_ALL_TESTS(); -} diff --git a/libs/binder/tests/binderValueTypeTest.cpp b/libs/binder/tests/binderValueTypeTest.cpp new file mode 100644 index 0000000000..f8922b0784 --- /dev/null +++ b/libs/binder/tests/binderValueTypeTest.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits> +#include <cstddef> +#include <vector> + +#include "android-base/file.h" +#include <gtest/gtest.h> + +#include <binder/Parcel.h> +#include <binder/Value.h> +#include <binder/Debug.h> + +using ::android::binder::Value; +using ::android::os::PersistableBundle; +using ::android::String16; +using ::std::vector; + +#define VALUE_TYPE_TEST(T, TYPENAME, VAL) \ + TEST(ValueType, Handles ## TYPENAME) { \ + T x = VAL; \ + T y = T(); \ + Value value = VAL; \ + ASSERT_FALSE(value.empty()); \ + ASSERT_TRUE(value.is ## TYPENAME ()); \ + ASSERT_TRUE(value.get ## TYPENAME (&y)); \ + ASSERT_EQ(x, y); \ + ASSERT_EQ(value, Value(y)); \ + value.put ## TYPENAME (x); \ + ASSERT_EQ(value, Value(y)); \ + value = Value(); \ + ASSERT_TRUE(value.empty()); \ + ASSERT_NE(value, Value(y)); \ + value = y; \ + ASSERT_EQ(value, Value(x)); \ + } + +#define VALUE_TYPE_VECTOR_TEST(T, TYPENAME, VAL) \ + TEST(ValueType, Handles ## TYPENAME ## Vector) { \ + vector<T> x; \ + vector<T> y; \ + x.push_back(VAL); \ + x.push_back(T()); \ + Value value(x); \ + ASSERT_FALSE(value.empty()); \ + ASSERT_TRUE(value.is ## TYPENAME ## Vector()); \ + ASSERT_TRUE(value.get ## TYPENAME ## Vector(&y)); \ + ASSERT_EQ(x, y); \ + ASSERT_EQ(value, Value(y)); \ + value.put ## TYPENAME ## Vector(x); \ + ASSERT_EQ(value, Value(y)); \ + value = Value(); \ + ASSERT_TRUE(value.empty()); \ + ASSERT_NE(value, Value(y)); \ + value = y; \ + ASSERT_EQ(value, Value(x)); \ + } + +VALUE_TYPE_TEST(bool, Boolean, true) +VALUE_TYPE_TEST(int32_t, Int, 31337) +VALUE_TYPE_TEST(int64_t, Long, 13370133701337L) +VALUE_TYPE_TEST(double, Double, 3.14159265358979323846) +VALUE_TYPE_TEST(String16, String, String16("Lovely")) + +VALUE_TYPE_VECTOR_TEST(bool, Boolean, true) +VALUE_TYPE_VECTOR_TEST(int32_t, Int, 31337) +VALUE_TYPE_VECTOR_TEST(int64_t, Long, 13370133701337L) +VALUE_TYPE_VECTOR_TEST(double, Double, 3.14159265358979323846) +VALUE_TYPE_VECTOR_TEST(String16, String, String16("Lovely")) + +VALUE_TYPE_TEST(PersistableBundle, PersistableBundle, PersistableBundle()) + +TEST(ValueType, HandlesClear) { + Value value; + ASSERT_TRUE(value.empty()); + value.putInt(31337); + ASSERT_FALSE(value.empty()); + value.clear(); + ASSERT_TRUE(value.empty()); +} + +TEST(ValueType, HandlesSwap) { + Value value_a, value_b; + int32_t int_x; + value_a.putInt(31337); + ASSERT_FALSE(value_a.empty()); + ASSERT_TRUE(value_b.empty()); + value_a.swap(value_b); + ASSERT_FALSE(value_b.empty()); + ASSERT_TRUE(value_a.empty()); + ASSERT_TRUE(value_b.getInt(&int_x)); + ASSERT_EQ(31337, int_x); +} diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp index ab4c56a6af..ec9534abac 100644 --- a/libs/binder/tests/schd-dbg.cpp +++ b/libs/binder/tests/schd-dbg.cpp @@ -290,7 +290,6 @@ static void* thread_start(void* p) { sta = tickNow(); status_t ret = workers[target]->transact(BINDER_NOP, data, &reply); - ASSERT(ret == NO_ERROR); end = tickNow(); results_fifo->add_time(tickNano(sta, end)); diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp index ee1a6a4860..512b0698d3 100644 --- a/libs/binderthreadstate/Android.bp +++ b/libs/binderthreadstate/Android.bp @@ -20,8 +20,6 @@ cc_library { enabled: true, support_system_process: true, }, - host_supported: true, - srcs: [ "IPCThreadStateBase.cpp", ], diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp index e403d36da1..3412e14f17 100644 --- a/libs/dumputils/Android.bp +++ b/libs/dumputils/Android.bp @@ -17,7 +17,9 @@ cc_library { shared_libs: [ "libbase", + "libbinder", "libhidlbase", + "libhidltransport", "liblog", "libutils", ], diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 250f902f9d..047780171e 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -16,7 +16,9 @@ #include <set> #include <android-base/file.h> +#include <android-base/properties.h> #include <android-base/stringprintf.h> +#include <android-base/strings.h> #include <android/hidl/manager/1.0/IServiceManager.h> #include <dumputils/dump_utils.h> #include <log/log.h> @@ -62,16 +64,40 @@ static const char* hal_interfaces_to_dump[] { "android.hardware.sensors@1.0::ISensors", "android.hardware.thermal@2.0::IThermal", "android.hardware.vr@1.0::IVr", + "android.hardware.automotive.audiocontrol@1.0::IAudioControl", + "android.hardware.automotive.vehicle@2.0::IVehicle", + "android.hardware.automotive.evs@1.0::IEvsCamera", NULL, }; -bool should_dump_hal_interface(const char* interface) { +/* list of extra hal interfaces to dump containing process during native dumps */ +// This is filled when dumpstate is called. +static std::set<const std::string> extra_hal_interfaces_to_dump; + +static void read_extra_hals_to_dump_from_property() { + // extra hals to dump are already filled + if (extra_hal_interfaces_to_dump.size() > 0) { + return; + } + std::string value = android::base::GetProperty("ro.dump.hals.extra", ""); + std::vector<std::string> tokens = android::base::Split(value, ","); + for (const auto &token : tokens) { + std::string trimmed_token = android::base::Trim(token); + if (trimmed_token.length() == 0) { + continue; + } + extra_hal_interfaces_to_dump.insert(trimmed_token); + } +} + +// check if interface is included in either default hal list or extra hal list +bool should_dump_hal_interface(const std::string& interface) { for (const char** i = hal_interfaces_to_dump; *i; i++) { - if (!strcmp(*i, interface)) { + if (interface == *i) { return true; } } - return false; + return extra_hal_interfaces_to_dump.find(interface) != extra_hal_interfaces_to_dump.end(); } bool should_dump_native_traces(const char* path) { @@ -91,13 +117,15 @@ std::set<int> get_interesting_hal_pids() { sp<IServiceManager> manager = IServiceManager::getService(); std::set<int> pids; + read_extra_hals_to_dump_from_property(); + Return<void> ret = manager->debugDump([&](auto& hals) { for (const auto &info : hals) { if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) { continue; } - if (!should_dump_hal_interface(info.interfaceName.c_str())) { + if (!should_dump_hal_interface(info.interfaceName)) { continue; } diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index bb9e263ac4..6e59cc5040 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -139,12 +139,8 @@ static const std::string getSystemNativeLibraries(NativeLibrary type) { return env; } -int GraphicsEnv::getCanLoadSystemLibraries() { - if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { - // Return an integer value since this crosses library boundaries - return 1; - } - return 0; +bool GraphicsEnv::isDebuggable() { + return prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) > 0; } void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path, diff --git a/libs/graphicsenv/OWNERS b/libs/graphicsenv/OWNERS deleted file mode 100644 index c0bb75f982..0000000000 --- a/libs/graphicsenv/OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -chrisforbes@google.com -cnorthrop@google.com -courtneygo@google.com -lpy@google.com -timvp@google.com -zzyiwei@google.com diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 937bcd9ac6..227b4587cc 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -84,7 +84,16 @@ private: public: static GraphicsEnv& getInstance(); - int getCanLoadSystemLibraries(); + // Check if the process is debuggable. It returns false except in any of the + // following circumstances: + // 1. ro.debuggable=1 (global debuggable enabled). + // 2. android:debuggable="true" in the manifest for an individual app. + // 3. An app which explicitly calls prctl(PR_SET_DUMPABLE, 1). + // 4. GraphicsEnv calls prctl(PR_SET_DUMPABLE, 1) in the presence of + // <meta-data android:name="com.android.graphics.injectLayers.enable" + // android:value="true"/> + // in the application manifest. + bool isDebuggable(); // Set a search path for loading graphics drivers. The path is a list of // directories separated by ':'. A directory can be contained in a zip file diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 166775b89a..e3e63ee54e 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -15,18 +15,6 @@ cc_library_headers { name: "libgui_headers", vendor_available: true, export_include_dirs: ["include"], - - // we must build this module to get the required header as that is generated - export_shared_lib_headers: [ - "android.hidl.token@1.0-utils", - "android.hardware.graphics.bufferqueue@1.0", - "android.hardware.graphics.bufferqueue@2.0", - ], - shared_libs: [ - "android.hidl.token@1.0-utils", - "android.hardware.graphics.bufferqueue@1.0", - "android.hardware.graphics.bufferqueue@2.0", - ], } cc_library_shared { @@ -178,6 +166,8 @@ cc_defaults { "libEGL", "libGLESv2", "libhidlbase", + "libhidltransport", + "libhwbinder", "liblog", "libnativewindow", "libsync", diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 528bfb194e..3a7cb44450 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -166,7 +166,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, mCore->mFreeBuffers.push_back(front->mSlot); } - listener = mCore->mConnectedProducerListener; + if (mCore->mBufferReleasedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } ++numDroppedBuffers; } @@ -457,7 +459,9 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, mCore->mFreeBuffers.push_back(slot); } - listener = mCore->mConnectedProducerListener; + if (mCore->mBufferReleasedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } BQ_LOGV("releaseBuffer: releasing slot %d", slot); mCore->mDequeueCondition.notify_all(); @@ -668,7 +672,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; VALIDATE_CONSISTENCY(); - if (delta < 0) { + if (delta < 0 && mCore->mBufferReleasedCbEnabled) { listener = mCore->mConsumerListener; } } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index e0e3431ca5..0264bd24a6 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -65,6 +65,7 @@ BufferQueueCore::BufferQueueCore() : mConnectedApi(NO_CONNECTED_API), mLinkedToDeath(), mConnectedProducerListener(), + mBufferReleasedCbEnabled(false), mSlots(), mQueue(), mFreeSlots(), @@ -260,6 +261,12 @@ void BufferQueueCore::freeAllBuffersLocked() { } void BufferQueueCore::discardFreeBuffersLocked() { + // Notify producer about the discarded buffers. + if (mConnectedProducerListener != nullptr && mFreeBuffers.size() > 0) { + std::vector<int32_t> freeBuffers(mFreeBuffers.begin(), mFreeBuffers.end()); + mConnectedProducerListener->onBuffersDiscarded(freeBuffers); + } + for (int s : mFreeBuffers) { mFreeSlots.insert(s); clearBufferSlotLocked(s); diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 92ab41019e..a317aaf2f2 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1221,9 +1221,8 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, } mCore->mLinkedToDeath = listener; } - if (listener->needsReleaseNotify()) { - mCore->mConnectedProducerListener = listener; - } + mCore->mConnectedProducerListener = listener; + mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify(); } break; default: diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 936063a5bd..808e3369f1 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -24,6 +24,7 @@ namespace android { enum { ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION, NEEDS_RELEASE_NOTIFY, + ON_BUFFERS_DISCARDED, }; class BpProducerListener : public BpInterface<IProducerListener> @@ -56,6 +57,13 @@ public: } return result; } + + virtual void onBuffersDiscarded(const std::vector<int>& discardedSlots) { + Parcel data, reply; + data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); + data.writeInt32Vector(discardedSlots); + remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -76,6 +84,10 @@ public: virtual bool needsReleaseNotify() override { return mBase->needsReleaseNotify(); } + + virtual void onBuffersDiscarded(const std::vector<int32_t>& discardedSlots) override { + return mBase->onBuffersDiscarded(discardedSlots); + } }; IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener, @@ -92,6 +104,17 @@ status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, CHECK_INTERFACE(IProducerListener, data, reply); reply->writeBool(needsReleaseNotify()); return NO_ERROR; + case ON_BUFFERS_DISCARDED: { + CHECK_INTERFACE(IProducerListener, data, reply); + std::vector<int32_t> discardedSlots; + status_t result = data.readInt32Vector(&discardedSlots); + if (result != NO_ERROR) { + ALOGE("ON_BUFFERS_DISCARDED failed to read discardedSlots: %d", result); + return result; + } + onBuffersDiscarded(discardedSlots); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } @@ -104,4 +127,7 @@ bool BnProducerListener::needsReleaseNotify() { return true; } +void BnProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*discardedSlots*/) { +} + } // namespace android diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 12deaf0bd6..e487792c87 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -88,7 +88,7 @@ public: data.writeStrongBinder(applyToken); commands.write(data); data.writeInt64(desiredPresentTime); - data.writeStrongBinder(uncacheBuffer.token.promote()); + data.writeWeakBinder(uncacheBuffer.token); data.writeUint64(uncacheBuffer.id); if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) { @@ -1036,7 +1036,7 @@ status_t BnSurfaceComposer::onTransact( int64_t desiredPresentTime = data.readInt64(); client_cache_t uncachedBuffer; - uncachedBuffer.token = data.readStrongBinder(); + uncachedBuffer.token = data.readWeakBinder(); uncachedBuffer.id = data.readUint64(); std::vector<ListenerCallbacks> listenerCallbacks; diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 42eb9213d6..6066421faf 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -87,7 +87,7 @@ status_t layer_state_t::write(Parcel& output) const colorTransform.asArray(), 16 * sizeof(float)); output.writeFloat(cornerRadius); output.writeBool(hasListenerCallbacks); - output.writeStrongBinder(cachedBuffer.token.promote()); + output.writeWeakBinder(cachedBuffer.token); output.writeUint64(cachedBuffer.id); output.writeParcelable(metadata); @@ -157,7 +157,7 @@ status_t layer_state_t::read(const Parcel& input) colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float)))); cornerRadius = input.readFloat(); hasListenerCallbacks = input.readBool(); - cachedBuffer.token = input.readStrongBinder(); + cachedBuffer.token = input.readWeakBinder(); cachedBuffer.id = input.readUint64(); input.readParcelable(&metadata); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 9fe5de82d1..b822319d22 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -35,6 +35,7 @@ #include <ui/DisplayStatInfo.h> #include <ui/Fence.h> +#include <ui/GraphicBuffer.h> #include <ui/HdrCapabilities.h> #include <ui/Region.h> @@ -1287,6 +1288,14 @@ int Surface::connect(int api, const sp<IProducerListener>& listener) { } int Surface::connect( + int api, bool reportBufferRemoval, const sp<SurfaceListener>& sListener) { + if (sListener != nullptr) { + mListenerProxy = new ProducerListenerProxy(this, sListener); + } + return connect(api, mListenerProxy, reportBufferRemoval); +} + +int Surface::connect( int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) { ATRACE_CALL(); ALOGV("Surface::connect"); @@ -1684,6 +1693,28 @@ void Surface::freeAllBuffers() { } } +status_t Surface::getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots, + std::vector<sp<GraphicBuffer>>* outBuffers) { + ALOGV("Surface::getAndFlushBuffersFromSlots"); + for (int32_t i : slots) { + if (i < 0 || i >= NUM_BUFFER_SLOTS) { + ALOGE("%s: Invalid slotIndex: %d", __FUNCTION__, i); + return BAD_VALUE; + } + } + + Mutex::Autolock lock(mMutex); + for (int32_t i : slots) { + if (mSlots[i].buffer == nullptr) { + ALOGW("%s: Discarded slot %d doesn't contain buffer!", __FUNCTION__, i); + continue; + } + outBuffers->push_back(mSlots[i].buffer); + mSlots[i].buffer = nullptr; + } + return OK; +} + void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) { ATRACE_CALL(); ALOGV("Surface::setSurfaceDamage"); @@ -1951,4 +1982,22 @@ status_t Surface::attachAndQueueBufferWithDataspace(Surface* surface, sp<Graphic return err; } +void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_t>& slots) { + ATRACE_CALL(); + sp<Surface> parent = mParent.promote(); + if (parent == nullptr) { + return; + } + + std::vector<sp<GraphicBuffer>> discardedBufs; + status_t res = parent->getAndFlushBuffersFromSlots(slots, &discardedBufs); + if (res != OK) { + ALOGE("%s: Failed to get buffers from slots: %s(%d)", __FUNCTION__, + strerror(-res), res); + return; + } + + mSurfaceListener->onBuffersDiscarded(discardedBufs); +} + }; // namespace android diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 690a85f395..17617bce13 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -189,8 +189,12 @@ private: sp<IProducerListener> mLinkedToDeath; // mConnectedProducerListener is used to handle the onBufferReleased - // notification. + // and onBuffersDiscarded notification. sp<IProducerListener> mConnectedProducerListener; + // mBufferReleasedCbEnabled is used to indicate whether onBufferReleased() + // callback is registered by the listener. When set to false, + // mConnectedProducerListener will not trigger onBufferReleased() callback. + bool mBufferReleasedCbEnabled; // mSlots is an array of buffer slots that must be mirrored on the producer // side. This allows buffer ownership to be transferred between the producer diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index a13d8e4945..32a3690ff2 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GUI_IPRODUCERLISTENER_H #define ANDROID_GUI_IPRODUCERLISTENER_H +#include <vector> + #include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h> #include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h> #include <binder/IInterface.h> @@ -44,6 +46,9 @@ public: // multiple threads. virtual void onBufferReleased() = 0; // Asynchronous virtual bool needsReleaseNotify() = 0; + // onBuffersFreed is called from IGraphicBufferConsumer::discardFreeBuffers + // to notify the producer that certain free buffers are discarded by the consumer. + virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) = 0; // Asynchronous }; class IProducerListener : public ProducerListener, public IInterface @@ -65,6 +70,7 @@ public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual bool needsReleaseNotify(); + virtual void onBuffersDiscarded(const std::vector<int32_t>& slots); }; class DummyProducerListener : public BnProducerListener diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 5c6a1ee383..a5641b07e5 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -20,6 +20,7 @@ #include <gui/BufferQueueDefs.h> #include <gui/HdrMetadata.h> #include <gui/IGraphicBufferProducer.h> +#include <gui/IProducerListener.h> #include <ui/ANativeObjectBase.h> #include <ui/GraphicTypes.h> @@ -35,6 +36,21 @@ namespace android { class ISurfaceComposer; +/* This is the same as ProducerListener except that onBuffersDiscarded is + * called with a vector of graphic buffers instead of buffer slots. + */ +class SurfaceListener : public virtual RefBase +{ +public: + SurfaceListener() = default; + virtual ~SurfaceListener() = default; + + virtual void onBufferReleased() = 0; + virtual bool needsReleaseNotify() = 0; + + virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) = 0; +}; + /* * An implementation of ANativeWindow that feeds graphics buffers into a * BufferQueue. @@ -283,6 +299,10 @@ public: sp<Fence>* outFence); virtual int attachBuffer(ANativeWindowBuffer*); + virtual int connect( + int api, bool reportBufferRemoval, + const sp<SurfaceListener>& sListener); + // When client connects to Surface with reportBufferRemoval set to true, any buffers removed // from this Surface will be collected and returned here. Once this method returns, these // buffers will no longer be referenced by this Surface unless they are attached to this @@ -299,6 +319,26 @@ protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; + class ProducerListenerProxy : public BnProducerListener { + public: + ProducerListenerProxy(wp<Surface> parent, sp<SurfaceListener> listener) + : mParent(parent), mSurfaceListener(listener) {} + virtual ~ProducerListenerProxy() {} + + virtual void onBufferReleased() { + mSurfaceListener->onBufferReleased(); + } + + virtual bool needsReleaseNotify() { + return mSurfaceListener->needsReleaseNotify(); + } + + virtual void onBuffersDiscarded(const std::vector<int32_t>& slots); + private: + wp<Surface> mParent; + sp<SurfaceListener> mSurfaceListener; + }; + void querySupportedTimestampsLocked() const; void freeAllBuffers(); @@ -466,6 +506,10 @@ protected: bool mReportRemovedBuffers = false; std::vector<sp<GraphicBuffer>> mRemovedBuffers; + + sp<IProducerListener> mListenerProxy; + status_t getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots, + std::vector<sp<GraphicBuffer>>* outBuffers); }; } // namespace android diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index cbda6b23ff..ab6dcaa3f6 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -47,6 +47,7 @@ cc_test { "libcutils", "libgui", "libhidlbase", + "libhidltransport", "libinput", "libui", "libutils", diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 119e888edb..406f21faf6 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -998,12 +998,31 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { ASSERT_EQ(true, thirdSegment.usedThirdBuffer); } +struct BufferDiscardedListener : public BnProducerListener { +public: + BufferDiscardedListener() = default; + virtual ~BufferDiscardedListener() = default; + + virtual void onBufferReleased() {} + virtual bool needsReleaseNotify() { return false; } + virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) { + mDiscardedSlots.insert(mDiscardedSlots.end(), slots.begin(), slots.end()); + } + + const std::vector<int32_t>& getDiscardedSlots() const { return mDiscardedSlots; } +private: + // No need to use lock given the test triggers the listener in the same + // thread context. + std::vector<int32_t> mDiscardedSlots; +}; + TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { createBufferQueue(); sp<DummyConsumer> dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + sp<BufferDiscardedListener> pl(new BufferDiscardedListener); + ASSERT_EQ(OK, mProducer->connect(pl, NATIVE_WINDOW_API_CPU, false, &output)); int slot = BufferQueue::INVALID_BUFFER_SLOT; @@ -1044,12 +1063,19 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); + int releasedSlot = item.mSlot; + // Acquire 1 buffer, leaving 1 filled buffer in queue ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); // Now discard the free buffers ASSERT_EQ(OK, mConsumer->discardFreeBuffers()); + // Check onBuffersDiscarded is called with correct slots + auto buffersDiscarded = pl->getDiscardedSlots(); + ASSERT_EQ(buffersDiscarded.size(), 1); + ASSERT_EQ(buffersDiscarded[0], releasedSlot); + // Check no free buffers in dump String8 dumpString; mConsumer->dumpState(String8{}, &dumpString); diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 0babd23573..66a8a04c82 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -133,27 +133,6 @@ public: EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction()); } - void expectMotionEvent(int motionEventType, int x, int y) { - InputEvent *ev = consumeEvent(); - ASSERT_NE(ev, nullptr); - ASSERT_EQ(ev->getType(), AINPUT_EVENT_TYPE_MOTION); - MotionEvent *mev = static_cast<MotionEvent *>(ev); - EXPECT_EQ(motionEventType, mev->getAction()); - EXPECT_EQ(x, mev->getX(0)); - EXPECT_EQ(y, mev->getY(0)); - } - - void expectNoMotionEvent(int motionEventType) { - InputEvent *ev = consumeEvent(); - if (ev == nullptr || ev->getType() != AINPUT_EVENT_TYPE_MOTION) { - // Didn't find an event or a motion event so assume action didn't occur. - return; - } - - MotionEvent *mev = static_cast<MotionEvent *>(ev); - EXPECT_NE(motionEventType, mev->getAction()); - } - ~InputSurface() { mInputFlinger->unregisterInputChannel(mServerChannel); } @@ -278,15 +257,6 @@ void injectTap(int x, int y) { } } -void injectMotionEvent(std::string event, int x, int y) { - char *buf1, *buf2; - asprintf(&buf1, "%d", x); - asprintf(&buf2, "%d", y); - if (fork() == 0) { - execlp("input", "input", "motionevent", event.c_str(), buf1, buf2, NULL); - } -} - TEST_F(InputSurfacesTest, can_receive_input) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(100, 100); @@ -410,19 +380,6 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets) { bgSurface->expectTap(1, 1); } -TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) { - std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100); - // In case we pass the very big inset without any checking. - fgSurface->mInputInfo.surfaceInset = INT32_MAX; - fgSurface->showAt(100, 100); - - fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); }); - - // expect no crash for overflow, and inset size to be clamped to surface size - injectTap(202, 202); - fgSurface->expectTap(1, 1); -} - // Ensure we ignore transparent region when getting screen bounds when positioning input frame. TEST_F(InputSurfacesTest, input_ignores_transparent_region) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); @@ -506,26 +463,6 @@ TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) { bgSurface->expectTap(1, 1); } -TEST_F(InputSurfacesTest, transfer_touch_focus) { - std::unique_ptr<InputSurface> fromSurface = makeSurface(100, 100); - - fromSurface->showAt(10, 10); - injectMotionEvent("DOWN", 11, 11); - fromSurface->expectMotionEvent(AMOTION_EVENT_ACTION_DOWN, 1, 1); - - std::unique_ptr<InputSurface> toSurface = makeSurface(100, 100); - toSurface->showAt(10, 10); - - sp<IBinder> fromToken = fromSurface->mServerChannel->getToken(); - sp<IBinder> toToken = toSurface->mServerChannel->getToken(); - SurfaceComposerClient::Transaction t; - t.transferTouchFocus(fromToken, toToken).apply(true); - - injectMotionEvent("UP", 11, 11); - toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1); - fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP); -} - TEST_F(InputSurfacesTest, input_respects_outscreen) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(-1, -1); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index d3708586f5..a8516872fd 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -57,6 +57,37 @@ class FakeProducerFrameEventHistory; static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max(); +class DummySurfaceListener : public SurfaceListener { +public: + DummySurfaceListener(bool enableReleasedCb = false) : + mEnableReleaseCb(enableReleasedCb), + mBuffersReleased(0) {} + virtual ~DummySurfaceListener() = default; + + virtual void onBufferReleased() { + mBuffersReleased++; + } + virtual bool needsReleaseNotify() { + return mEnableReleaseCb; + } + virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) { + mDiscardedBuffers.insert(mDiscardedBuffers.end(), buffers.begin(), buffers.end()); + } + + int getReleaseNotifyCount() const { + return mBuffersReleased; + } + const std::vector<sp<GraphicBuffer>>& getDiscardedBuffers() const { + return mDiscardedBuffers; + } +private: + // No need to use lock given the test triggers the listener in the same + // thread context. + bool mEnableReleaseCb; + int32_t mBuffersReleased; + std::vector<sp<GraphicBuffer>> mDiscardedBuffers; +}; + class SurfaceTest : public ::testing::Test { protected: SurfaceTest() { @@ -88,6 +119,86 @@ protected: mComposerClient->dispose(); } + void testSurfaceListener(bool hasSurfaceListener, bool enableReleasedCb, + int32_t extraDiscardedBuffers) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<DummyConsumer> dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + sp<DummySurfaceListener> listener; + if (hasSurfaceListener) { + listener = new DummySurfaceListener(enableReleasedCb); + } + ASSERT_EQ(OK, surface->connect( + NATIVE_WINDOW_API_CPU, + /*reportBufferRemoval*/true, + /*listener*/listener)); + const int BUFFER_COUNT = 4 + extraDiscardedBuffers; + ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT)); + + ANativeWindowBuffer* buffers[BUFFER_COUNT]; + // Dequeue first to allocate a number of buffers + for (int i = 0; i < BUFFER_COUNT; i++) { + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffers[i])); + } + for (int i = 0; i < BUFFER_COUNT; i++) { + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], -1)); + } + + ANativeWindowBuffer* buffer; + // Fill BUFFER_COUNT-1 buffers + for (int i = 0; i < BUFFER_COUNT-1; i++) { + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer)); + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, -1)); + } + + // Dequeue 1 buffer + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer)); + + // Acquire and free 1+extraDiscardedBuffers buffer, check onBufferReleased is called. + std::vector<BufferItem> releasedItems; + releasedItems.resize(1+extraDiscardedBuffers); + for (int i = 0; i < releasedItems.size(); i++) { + ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&releasedItems[i], 0)); + ASSERT_EQ(NO_ERROR, consumer->releaseBuffer(releasedItems[i].mSlot, + releasedItems[i].mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE)); + } + int32_t expectedReleaseCb = (enableReleasedCb ? releasedItems.size() : 0); + if (hasSurfaceListener) { + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + } + + // Acquire 1 buffer, leaving 1+extraDiscardedBuffers filled buffer in queue + BufferItem item; + ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&item, 0)); + + // Discard free buffers + ASSERT_EQ(NO_ERROR, consumer->discardFreeBuffers()); + + if (hasSurfaceListener) { + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + + // Check onBufferDiscarded is called with correct buffer + auto discardedBuffers = listener->getDiscardedBuffers(); + ASSERT_EQ(discardedBuffers.size(), releasedItems.size()); + for (int i = 0; i < releasedItems.size(); i++) { + ASSERT_EQ(discardedBuffers[i], releasedItems[i].mGraphicBuffer); + } + + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + } + + // Disconnect the surface + ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU)); + } + sp<Surface> mSurface; sp<SurfaceComposerClient> mComposerClient; sp<SurfaceControl> mSurfaceControl; @@ -480,6 +591,21 @@ TEST_F(SurfaceTest, GetAndFlushRemovedBuffers) { ASSERT_LE(removedBuffers.size(), 1u); } +TEST_F(SurfaceTest, SurfaceListenerTest) { + // Test discarding 1 free buffers with no listener + testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/0); + // Test discarding 2 free buffers with no listener + testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/1); + // Test discarding 1 free buffers with a listener, disabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/0); + // Test discarding 2 free buffers with a listener, disabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/1); + // Test discarding 1 free buffers with a listener, enabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/0); + // Test discarding 3 free buffers with a listener, enabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/2); +} + TEST_F(SurfaceTest, TestGetLastDequeueStartTime) { sp<ANativeWindow> anw(mSurface); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU)); diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp index d6a73bfd27..de3a23d76e 100644 --- a/libs/input/IInputFlinger.cpp +++ b/libs/input/IInputFlinger.cpp @@ -45,16 +45,6 @@ public: IBinder::FLAG_ONEWAY); } - virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) { - Parcel data, reply; - data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); - - data.writeStrongBinder(fromToken); - data.writeStrongBinder(toToken); - remote()->transact(BnInputFlinger::TRANSFER_TOUCH_FOCUS, data, &reply, - IBinder::FLAG_ONEWAY); - } - virtual void registerInputChannel(const sp<InputChannel>& channel) { Parcel data, reply; data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); @@ -104,13 +94,6 @@ status_t BnInputFlinger::onTransact( unregisterInputChannel(channel); break; } - case TRANSFER_TOUCH_FOCUS: { - CHECK_INTERFACE(IInputFlinger, data, reply); - sp<IBinder> fromToken = data.readStrongBinder(); - sp<IBinder> toToken = data.readStrongBinder(); - transferTouchFocus(fromToken, toToken); - break; - } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index ec28757933..5a60347ed3 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -99,7 +99,7 @@ status_t InputWindowInfo::write(Parcel& output) const { applicationInfo.write(output); output.write(touchableRegion); output.writeBool(replaceTouchableRegionWithCrop); - output.writeStrongBinder(touchableRegionCropHandle.promote()); + output.writeWeakBinder(touchableRegionCropHandle); return OK; } @@ -142,7 +142,7 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { ret.applicationInfo = InputApplicationInfo::read(from); from.read(ret.touchableRegion); ret.replaceTouchableRegionWithCrop = from.readBool(); - ret.touchableRegionCropHandle = from.readStrongBinder(); + ret.touchableRegionCropHandle = from.readWeakBinder(); return ret; } diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp index 8a4298a36f..ce76e3fa6d 100644 --- a/libs/input/TouchVideoFrame.cpp +++ b/libs/input/TouchVideoFrame.cpp @@ -42,13 +42,13 @@ const struct timeval& TouchVideoFrame::getTimestamp() const { return mTimestamp; void TouchVideoFrame::rotate(int32_t orientation) { switch (orientation) { case DISPLAY_ORIENTATION_90: - rotateQuarterTurn(true /*clockwise*/); + rotateQuarterTurn(false /*clockwise*/); break; case DISPLAY_ORIENTATION_180: rotate180(); break; case DISPLAY_ORIENTATION_270: - rotateQuarterTurn(false /*clockwise*/); + rotateQuarterTurn(true /*clockwise*/); break; } } diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp index 815424ee31..fe06cad72c 100644 --- a/libs/input/tests/TouchVideoFrame_test.cpp +++ b/libs/input/tests/TouchVideoFrame_test.cpp @@ -85,14 +85,14 @@ TEST(TouchVideoFrame, Rotate90_1x1) { TEST(TouchVideoFrame, Rotate90_2x2) { TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_90); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate90_3x2) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_90); ASSERT_EQ(frame, frameRotated); } @@ -170,14 +170,14 @@ TEST(TouchVideoFrame, Rotate270_1x1) { TEST(TouchVideoFrame, Rotate270_2x2) { TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_270); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate270_3x2) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_270); ASSERT_EQ(frame, frameRotated); } diff --git a/libs/math/include/math/quat.h b/libs/math/include/math/quat.h index 07573c5ecf..1936a2baec 100644 --- a/libs/math/include/math/quat.h +++ b/libs/math/include/math/quat.h @@ -109,7 +109,7 @@ public: // initialize from 4 values to w + xi + yj + zk template<typename A, typename B, typename C, typename D> - constexpr TQuaternion(A w, B x, C y, D z) : x(static_cast<T>(x)), y(static_cast<T>(y)), z(static_cast<T>(z)), w(static_cast<T>(w)) { } + constexpr TQuaternion(A w, B x, C y, D z) : x(x), y(y), z(z), w(w) { } // initialize from a vec3 + a value to : v.xi + v.yj + v.zk + w template<typename A, typename B> diff --git a/libs/math/include/math/vec2.h b/libs/math/include/math/vec2.h index e0adb7f6cc..a34763347c 100644 --- a/libs/math/include/math/vec2.h +++ b/libs/math/include/math/vec2.h @@ -89,7 +89,7 @@ public: constexpr TVec2(A v) : x(v), y(v) { } template<typename A, typename B> - constexpr TVec2(A x, B y) : x(static_cast<T>(x)), y(static_cast<T>(y)) { } + constexpr TVec2(A x, B y) : x(x), y(y) { } template<typename A> explicit diff --git a/libs/math/include/math/vec3.h b/libs/math/include/math/vec3.h index 21fb684efc..009fd84e3b 100644 --- a/libs/math/include/math/vec3.h +++ b/libs/math/include/math/vec3.h @@ -86,13 +86,13 @@ public: // handles implicit conversion to a tvec4. must not be explicit. template<typename A, typename = typename std::enable_if<std::is_arithmetic<A>::value >::type> - constexpr TVec3(A v) : x(static_cast<T>(v)), y(static_cast<T>(v)), z(static_cast<T>(v)) { } + constexpr TVec3(A v) : x(v), y(v), z(v) { } template<typename A, typename B, typename C> - constexpr TVec3(A x, B y, C z) : x(static_cast<T>(x)), y(static_cast<T>(y)), z(static_cast<T>(z)) { } + constexpr TVec3(A x, B y, C z) : x(x), y(y), z(z) { } template<typename A, typename B> - constexpr TVec3(const TVec2<A>& v, B z) : x(v.x), y(v.y), z(static_cast<T>(z)) { } + constexpr TVec3(const TVec2<A>& v, B z) : x(v.x), y(v.y), z(z) { } template<typename A> explicit diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 1ec73ce961..9bd30955f3 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -266,10 +266,10 @@ int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int so char buf[CMSG_SPACE(kFdBufferSize)]; struct msghdr msg = { - .msg_iov = &iov[0], - .msg_iovlen = 1, .msg_control = buf, .msg_controllen = sizeof(buf), + .msg_iov = &iov[0], + .msg_iovlen = 1, }; struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); @@ -306,10 +306,10 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out iov[0].iov_len = kMessageBufferSize; struct msghdr msg = { - .msg_iov = &iov[0], - .msg_iovlen = 1, .msg_control = fdBuf, .msg_controllen = sizeof(fdBuf), + .msg_iov = &iov[0], + .msg_iovlen = 1, }; int result; diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index ae5e47ba97..da959e36d2 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -342,8 +342,6 @@ typedef struct AHardwareBuffer AHardwareBuffer; * not compatible with its usage flags, the results are undefined and * may include program termination. * - * Available since API level 26. - * * \return 0 on success, or an error number of the allocation fails for * any reason. The returned buffer has a reference count of 1. */ @@ -354,24 +352,18 @@ int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, * * This prevents the object from being deleted until the last reference * is removed. - * - * Available since API level 26. */ void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26); /** * Remove a reference that was previously acquired with * AHardwareBuffer_acquire() or AHardwareBuffer_allocate(). - * - * Available since API level 26. */ void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26); /** * Return a description of the AHardwareBuffer in the passed * AHardwareBuffer_Desc struct. - * - * Available since API level 26. */ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26); @@ -421,8 +413,6 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, * simultaneously, and the contents of the buffer behave like shared * memory. * - * Available since API level 26. - * * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer * has more than one layer. Error number if the lock fails for any other @@ -451,8 +441,6 @@ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, * * See the AHardwareBuffer_lock documentation for all other locking semantics. * - * Available since API level 29. - * * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer * has more than one layer. Error number if the lock fails for any other @@ -474,8 +462,6 @@ int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, * completed before the function returned and no further operations are * necessary. * - * Available since API level 26. - * * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if * the unlock fails for any reason. */ @@ -484,8 +470,6 @@ int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED /** * Send the AHardwareBuffer to an AF_UNIX socket. * - * Available since API level 26. - * * \return 0 on success, -EINVAL if \a buffer is NULL, or an error * number if the operation fails for any reason. */ @@ -494,8 +478,6 @@ int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int so /** * Receive an AHardwareBuffer from an AF_UNIX socket. * - * Available since API level 26. - * * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error * number if the operation fails for any reason. */ @@ -519,8 +501,6 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out * some implementations have implementation-defined limits on texture * size and layer count. * - * Available since API level 29. - * * \return 1 if the format and usage flag combination is allocatable, * 0 otherwise. */ @@ -534,8 +514,6 @@ int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_I * of the locked buffer. If the bytes per pixel or bytes per stride are unknown * or variable, or if the underlying mapper implementation does not support returning * additional information, then this call will fail with INVALID_OPERATION - * - * Available since API level 29. */ int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage, int32_t fence, const ARect* rect, void** outVirtualAddress, diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 3e436e3b07..6730596ec7 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -189,8 +189,6 @@ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); /** * Set a transform that will be applied to future buffers posted to the window. * - * Available since API level 26. - * * \param transform combination of {@link ANativeWindowTransform} flags * \return 0 for success, or -EINVAL if \p transform is invalid */ @@ -210,8 +208,6 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo * measurement data instead of color images. The default dataSpace is 0, * ADATASPACE_UNKNOWN, unless it has been overridden by the producer. * - * Available since API level 28. - * * \param dataSpace data space of all buffers queued after this call. * \return 0 for success, -EINVAL if window is invalid or the dataspace is not * supported. @@ -220,9 +216,6 @@ int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpa /** * Get the dataspace of the buffers in window. - * - * Available since API level 28. - * * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if * dataspace is unknown, or -EINVAL if window is invalid. */ diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp index e8154a6931..940ff5afbc 100644 --- a/libs/sensor/Android.bp +++ b/libs/sensor/Android.bp @@ -21,7 +21,22 @@ cc_library_shared { "-Werror", ], cppflags: [ - "-Wextra", + "-Weverything", + + // The static constructors and destructors in this library have not been noted to + // introduce significant overheads + "-Wno-exit-time-destructors", + "-Wno-global-constructors", + + // We only care about compiling as C++14 + "-Wno-c++98-compat-pedantic", + + // android/sensors.h uses nested anonymous unions and anonymous structs + "-Wno-nested-anon-types", + "-Wno-gnu-anonymous-struct", + + // Don't warn about struct padding + "-Wno-padded", ], srcs: [ diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS index 90c233030e..81099e895c 100644 --- a/libs/sensor/OWNERS +++ b/libs/sensor/OWNERS @@ -1,3 +1,3 @@ arthuri@google.com bduddie@google.com -stange@google.com +bstack@google.com diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index bf8b9f73fe..96d5eb9d1f 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -150,7 +150,7 @@ status_t SensorManager::assertStateLocked() { class DeathObserver : public IBinder::DeathRecipient { SensorManager& mSensorManager; virtual void binderDied(const wp<IBinder>& who) { - ALOGW("sensorservice died [%p]", static_cast<void*>(who.unsafe_get())); + ALOGW("sensorservice died [%p]", who.unsafe_get()); mSensorManager.sensorManagerDied(); } public: diff --git a/libs/sensorprivacy/Android.bp b/libs/sensorprivacy/Android.bp index 4a606ffec2..e0e3469fbb 100644 --- a/libs/sensorprivacy/Android.bp +++ b/libs/sensorprivacy/Android.bp @@ -28,7 +28,8 @@ cc_library_shared { ], srcs: [ - ":libsensorprivacy_aidl", + "aidl/android/hardware/ISensorPrivacyListener.aidl", + "aidl/android/hardware/ISensorPrivacyManager.aidl", "SensorPrivacyManager.cpp", ], @@ -44,12 +45,3 @@ cc_library_shared { export_shared_lib_headers: ["libbinder"], } - -filegroup { - name: "libsensorprivacy_aidl", - srcs: [ - "aidl/android/hardware/ISensorPrivacyListener.aidl", - "aidl/android/hardware/ISensorPrivacyManager.aidl", - ], - path: "aidl", -} diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index db15e17524..0407d8802c 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -26,7 +26,27 @@ cc_library_shared { "-Werror", ], cppflags: [ - "-Wextra", + "-Weverything", + + // The static constructors and destructors in this library have not been noted to + // introduce significant overheads + "-Wno-exit-time-destructors", + "-Wno-global-constructors", + + // We only care about compiling as C++14 + "-Wno-c++98-compat-pedantic", + + // We are aware of the risks inherent in comparing floats for equality + "-Wno-float-equal", + + // We use four-character constants for the GraphicBuffer header, and don't care + // that they're non-portable as long as they're consistent within one execution + "-Wno-four-char-constants", + + // Don't warn about struct padding + "-Wno-padded", + + "-Wno-switch-enum", ], sanitize: { @@ -75,7 +95,10 @@ cc_library_shared { "android.hardware.graphics.mapper@3.0", "libbase", "libcutils", + "libhardware", "libhidlbase", + "libhidltransport", + "libhwbinder", "libsync", "libutils", "liblog", diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp index df390e2588..7a14af1c9d 100644 --- a/libs/ui/ColorSpace.cpp +++ b/libs/ui/ColorSpace.cpp @@ -364,11 +364,7 @@ std::unique_ptr<float3[]> ColorSpace::createLUT(uint32_t size, const ColorSpace& for (uint32_t z = 0; z < size; z++) { for (int32_t y = int32_t(size - 1); y >= 0; y--) { for (uint32_t x = 0; x < size; x++) { - *data++ = connector.transform({ - static_cast<float>(x) * m, - static_cast<float>(y) * m, - static_cast<float>(z) * m, - }); + *data++ = connector.transform({x * m, y * m, z * m}); } } } diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index d02bb94a05..d588346dfb 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -81,7 +81,7 @@ void GraphicBufferAllocator::dump(std::string& result) const { if (rec.size) { StringAppendF(&result, "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64 " | %s\n", - list.keyAt(i), static_cast<double>(rec.size) / 1024.0, rec.width, rec.stride, rec.height, + list.keyAt(i), rec.size / 1024.0, rec.width, rec.stride, rec.height, rec.layerCount, rec.format, rec.usage, rec.requestorName.c_str()); } else { StringAppendF(&result, @@ -91,7 +91,7 @@ void GraphicBufferAllocator::dump(std::string& result) const { } total += rec.size; } - StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", static_cast<double>(total) / 1024.0); + StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", total / 1024.0); result.append(mAllocator->dumpDebugInfo()); } diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index 1222cd6fad..55e3b99aa1 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -339,10 +339,10 @@ Region& Region::scaleSelf(float sx, float sy) { size_t count = mStorage.size(); Rect* rects = mStorage.editArray(); while (count) { - rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f); - rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f); - rects->top = static_cast<int32_t>(static_cast<float>(rects->top) * sy + 0.5f); - rects->bottom = static_cast<int32_t>(static_cast<float>(rects->bottom) * sy + 0.5f); + rects->left = static_cast<int32_t>(rects->left * sx + 0.5f); + rects->right = static_cast<int32_t>(rects->right * sx + 0.5f); + rects->top = static_cast<int32_t>(rects->top * sy + 0.5f); + rects->bottom = static_cast<int32_t>(rects->bottom * sy + 0.5f); rects++; count--; } diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h index d9b713df4c..c39d8af1d6 100644 --- a/libs/ui/include/ui/Size.h +++ b/libs/ui/include/ui/Size.h @@ -132,7 +132,7 @@ struct Size { // Otherwise we leverage implicit conversion to safely compare values of // different types, to ensure we return a value clamped to the range of // ToType. - return v < toLowest ? toLowest : (static_cast<ToType>(v) > toHighest ? toHighest : static_cast<ToType>(v)); + return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v)); } }; diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 0a07a48bd1..15f4b6407c 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -58,6 +58,7 @@ cc_test { "android.frameworks.bufferhub@1.0", "libcutils", "libhidlbase", + "libhwbinder", "libui", "libutils", ], @@ -78,6 +79,7 @@ cc_test { "android.frameworks.bufferhub@1.0", "libcutils", "libhidlbase", + "libhwbinder", "liblog", "libui", "libutils" diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp index 2fcee7bee6..6d202aec05 100644 --- a/libs/vr/libbufferhub/Android.bp +++ b/libs/vr/libbufferhub/Android.bp @@ -29,9 +29,11 @@ sourceFiles = [ sharedLibraries = [ "libbase", "libcutils", + "libhardware", "liblog", "libui", "libutils", + "libnativewindow", "libpdx_default_transport", ] diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp index 77c79112de..9f72c05f0c 100644 --- a/libs/vr/libbufferhubqueue/Android.bp +++ b/libs/vr/libbufferhubqueue/Android.bp @@ -26,8 +26,10 @@ staticLibraries = [ ] sharedLibraries = [ + "libbase", "libbinder", "libcutils", + "libhardware", "liblog", "libui", "libutils", diff --git a/libs/vr/libdisplay/vsync_service.cpp b/libs/vr/libdisplay/vsync_service.cpp index 04d4f30140..4668b9836c 100644 --- a/libs/vr/libdisplay/vsync_service.cpp +++ b/libs/vr/libdisplay/vsync_service.cpp @@ -45,8 +45,8 @@ public: ALOGE("onVsync failed to writeInt64: %d", result); return result; } - result = remote()->transact(BnVsyncCallback::ON_VSYNC, data, &reply, - IBinder::FLAG_ONEWAY); + result = remote()->transact( + BnVsyncCallback::ON_VSYNC, data, &reply, TF_ONE_WAY); if (result != OK) { ALOGE("onVsync failed to transact: %d", result); return result; diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp index 12ce74b1ea..282935307c 100644 --- a/libs/vr/libvrflinger/Android.bp +++ b/libs/vr/libvrflinger/Android.bp @@ -57,6 +57,7 @@ sharedLibraries = [ "libgui", "libsync", "libhidlbase", + "libhidltransport", "libfmq", "libpdx_default_transport", ] diff --git a/opengl/OWNERS b/opengl/OWNERS index b505712eb5..881f1b8f35 100644 --- a/opengl/OWNERS +++ b/opengl/OWNERS @@ -1,7 +1,16 @@ +# alanward@google.com +chiur@google.com chrisforbes@google.com cnorthrop@google.com courtneygo@google.com +hliatis@google.com ianelliott@google.com jessehall@google.com lpy@google.com +marissaw@google.com +nduca@google.com +pmuetschard@google.com +timvp@google.com +tobine@google.com +vhau@google.com zzyiwei@google.com diff --git a/opengl/libagl/Android.bp b/opengl/libagl/Android.bp index f5bf015bad..6ec24b3712 100644 --- a/opengl/libagl/Android.bp +++ b/opengl/libagl/Android.bp @@ -25,9 +25,8 @@ cc_defaults { "libnativewindow", ], - header_libs: [ - "bionic_libc_platform_headers", - ], + // we need to access the private Bionic header <bionic_tls.h> + include_dirs: ["bionic/libc/private"], arch: { arm: { diff --git a/opengl/libagl/context.h b/opengl/libagl/context.h index 6e77a2366f..18ef7d5716 100644 --- a/opengl/libagl/context.h +++ b/opengl/libagl/context.h @@ -22,7 +22,7 @@ #include <sys/types.h> #include <pthread.h> #ifdef __ANDROID__ -#include <bionic/tls.h> +#include <bionic_tls.h> #endif #include <private/pixelflinger/ggl_context.h> diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index eb90c8b45b..abc7a72716 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -72,13 +72,15 @@ cc_defaults { "libarect", ], header_libs: [ - "bionic_libc_platform_headers", "gl_headers", "libsystem_headers", "libhardware_headers", "libnativebase_headers", ], export_header_lib_headers: ["gl_headers"], + + // we need to access the private Bionic header <bionic_tls.h> + include_dirs: ["bionic/libc/private"], } //############################################################################## @@ -151,6 +153,7 @@ cc_library_shared { "android.hardware.configstore-utils", "libbase", "libhidlbase", + "libhidltransport", "libnativebridge_lazy", "libnativeloader_lazy", "libutils", diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index c51a1295e7..29a966d348 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -40,6 +40,7 @@ static inline void clearError() { EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { ATRACE_CALL(); + clearError(); if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); @@ -47,7 +48,6 @@ EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { // Call down the chain, which usually points directly to the impl // but may also be routed through layers - clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetDisplay(display); } @@ -55,6 +55,7 @@ EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { EGLDisplay eglGetPlatformDisplay(EGLenum platform, EGLNativeDisplayType display, const EGLAttrib* attrib_list) { ATRACE_CALL(); + clearError(); if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); @@ -62,7 +63,6 @@ EGLDisplay eglGetPlatformDisplay(EGLenum platform, EGLNativeDisplayType display, // Call down the chain, which usually points directly to the impl // but may also be routed through layers - clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetPlatformDisplay(platform, display, attrib_list); } @@ -239,12 +239,13 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char* procname) // in which case we must make sure we've initialized ourselves, this // happens the first time egl_get_display() is called. + clearError(); + if (egl_init_drivers() == EGL_FALSE) { setError(EGL_BAD_PARAMETER, NULL); return nullptr; } - clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetProcAddress(procname); } @@ -323,21 +324,23 @@ EGLBoolean eglWaitClient(void) { } EGLBoolean eglBindAPI(EGLenum api) { + clearError(); + if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); } - clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglBindAPI(api); } EGLenum eglQueryAPI(void) { + clearError(); + if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); } - clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglQueryAPI(); } @@ -592,21 +595,23 @@ EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer* buffer) { } EGLuint64NV eglGetSystemTimeFrequencyNV() { + clearError(); + if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); } - clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetSystemTimeFrequencyNV(); } EGLuint64NV eglGetSystemTimeNV() { + clearError(); + if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); } - clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetSystemTimeNV(); } diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp index ac01dc8f96..ba7cacdbf2 100644 --- a/opengl/libs/EGL/egl_layers.cpp +++ b/opengl/libs/EGL/egl_layers.cpp @@ -337,7 +337,7 @@ void LayerLoader::LoadLayers() { // Only enable the system search path for non-user builds std::string system_path; - if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { + if (android::GraphicsEnv::getInstance().isDebuggable()) { system_path = kSystemLayerLibraryDir; } diff --git a/opengl/libs/ETC1/etc1.cpp b/opengl/libs/ETC1/etc1.cpp index 19d428a394..97d10851de 100644 --- a/opengl/libs/ETC1/etc1.cpp +++ b/opengl/libs/ETC1/etc1.cpp @@ -378,30 +378,34 @@ static void etc_encodeBaseColors(etc1_byte* pBaseColors, const etc1_byte* pColors, etc_compressed* pCompressed) { int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks bool differential; - int r51 = convert8To5(pColors[0]); - int g51 = convert8To5(pColors[1]); - int b51 = convert8To5(pColors[2]); - int r52 = convert8To5(pColors[3]); - int g52 = convert8To5(pColors[4]); - int b52 = convert8To5(pColors[5]); - - r1 = convert5To8(r51); - g1 = convert5To8(g51); - b1 = convert5To8(b51); - - int dr = r52 - r51; - int dg = g52 - g51; - int db = b52 - b51; - - differential = inRange4bitSigned(dr) && inRange4bitSigned(dg) - && inRange4bitSigned(db); - if (differential) { - r2 = convert5To8(r51 + dr); - g2 = convert5To8(g51 + dg); - b2 = convert5To8(b51 + db); - pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19) - | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2; - } else { + { + int r51 = convert8To5(pColors[0]); + int g51 = convert8To5(pColors[1]); + int b51 = convert8To5(pColors[2]); + int r52 = convert8To5(pColors[3]); + int g52 = convert8To5(pColors[4]); + int b52 = convert8To5(pColors[5]); + + r1 = convert5To8(r51); + g1 = convert5To8(g51); + b1 = convert5To8(b51); + + int dr = r52 - r51; + int dg = g52 - g51; + int db = b52 - b51; + + differential = inRange4bitSigned(dr) && inRange4bitSigned(dg) + && inRange4bitSigned(db); + if (differential) { + r2 = convert5To8(r51 + dr); + g2 = convert5To8(g51 + dg); + b2 = convert5To8(b51 + db); + pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19) + | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2; + } + } + + if (!differential) { int r41 = convert8To4(pColors[0]); int g41 = convert8To4(pColors[1]); int b41 = convert8To4(pColors[2]); diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h index 86fec21bae..63a0e140cc 100644 --- a/opengl/libs/hooks.h +++ b/opengl/libs/hooks.h @@ -46,7 +46,7 @@ #define MAX_NUMBER_OF_GL_EXTENSIONS 256 -#include <bionic/tls.h> /* special private C library header */ +#include <bionic_tls.h> /* special private C library header */ // ---------------------------------------------------------------------------- namespace android { diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp index 8bfe517812..a9e873ac43 100644 --- a/opengl/tests/EGLTest/Android.bp +++ b/opengl/tests/EGLTest/Android.bp @@ -22,17 +22,16 @@ cc_test { "libbinder", "libgui", "libhidlbase", + "libhidltransport", "liblog", "libutils", "libnativewindow", ], include_dirs: [ + "bionic/libc/private", "frameworks/native/opengl/libs", "frameworks/native/opengl/libs/EGL", ], - header_libs: [ - "bionic_libc_platform_headers", - ], } diff --git a/opengl/tests/gl_perf/fill_common.cpp b/opengl/tests/gl_perf/fill_common.cpp index 613f1c6aa1..fefedc0939 100644 --- a/opengl/tests/gl_perf/fill_common.cpp +++ b/opengl/tests/gl_perf/fill_common.cpp @@ -191,10 +191,10 @@ static void setupVA() { static void randUniform(int pgm, const char *var) { GLint loc = glGetUniformLocation(pgm, var); if (loc >= 0) { - float x = ((float)rand()) / (float)RAND_MAX; - float y = ((float)rand()) / (float)RAND_MAX; - float z = ((float)rand()) / (float)RAND_MAX; - float w = ((float)rand()) / (float)RAND_MAX; + float x = ((float)rand()) / RAND_MAX; + float y = ((float)rand()) / RAND_MAX; + float z = ((float)rand()) / RAND_MAX; + float w = ((float)rand()) / RAND_MAX; glUniform4f(loc, x, y, z, w); } } diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp index 2bb6aef3a5..cd03bc2be7 100644 --- a/services/bufferhub/Android.bp +++ b/services/bufferhub/Android.bp @@ -37,6 +37,8 @@ cc_library_shared { "libcrypto", "libcutils", "libhidlbase", + "libhidltransport", + "libhwbinder", "liblog", "libui", "libutils", @@ -62,6 +64,8 @@ cc_binary { "libcrypto", "libcutils", "libhidlbase", + "libhidltransport", + "libhwbinder", "liblog", "libui", "libutils", diff --git a/services/displayservice/Android.bp b/services/displayservice/Android.bp index 4d2d87352b..3442cb2ff7 100644 --- a/services/displayservice/Android.bp +++ b/services/displayservice/Android.bp @@ -27,6 +27,7 @@ cc_library_shared { "liblog", "libgui", "libhidlbase", + "libhidltransport", "libutils", "android.frameworks.displayservice@1.0", ], diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index 7b8e0f835c..dbb6ba6719 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -59,6 +59,9 @@ cc_defaults { cc_defaults { name: "gpuservice_binary", defaults: ["gpuservice_defaults"], + whole_static_libs: [ + "libsigchain", + ], shared_libs: [ "libbinder", "libcutils", diff --git a/services/gpuservice/OWNERS b/services/gpuservice/OWNERS deleted file mode 100644 index 5d028393f6..0000000000 --- a/services/gpuservice/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -chrisforbes@google.com -lpy@google.com -zzyiwei@google.com diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 11578c393e..576c8d8bb5 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -30,6 +30,7 @@ cc_library_shared { srcs: [ "InputClassifier.cpp", "InputClassifierConverter.cpp", + "InputDispatcher.cpp", "InputManager.cpp", ], @@ -46,11 +47,6 @@ cc_library_shared { "liblog", "libutils", "libui", - "server_configurable_flags", - ], - - static_libs: [ - "libinputdispatcher", ], cflags: [ @@ -63,16 +59,44 @@ cc_library_shared { "include", ], - export_static_lib_headers: [ - "libinputdispatcher", - ], } cc_library_headers { name: "libinputflinger_headers", - header_libs: ["libinputreporter_headers"], export_include_dirs: ["include"], - export_header_lib_headers: ["libinputreporter_headers"], +} + +cc_library_shared { + name: "libinputreader", + defaults: ["inputflinger_defaults"], + + srcs: [ + "EventHub.cpp", + "InputReader.cpp", + "InputReaderFactory.cpp", + "TouchVideoDevice.cpp", + ], + + shared_libs: [ + "libbase", + "libinputflinger_base", + "libcrypto", + "libcutils", + "libinput", + "liblog", + "libui", + "libutils", + "libhardware_legacy", + "libstatslog", + ], + + header_libs: [ + "libinputflinger_headers", + ], + + export_header_lib_headers: [ + "libinputflinger_headers", + ], } cc_library_shared { @@ -100,6 +124,28 @@ cc_library_shared { ], } +cc_library_shared { + name: "libinputreporter", + defaults: ["inputflinger_defaults"], + + srcs: [ + "InputReporter.cpp", + ], + + shared_libs: [ + "liblog", + "libutils", + ], + + header_libs: [ + "libinputflinger_headers", + ], + + export_header_lib_headers: [ + "libinputflinger_headers", + ], +} + subdirs = [ "host", "tests", diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/EventHub.cpp index a5e5415dd7..ce5627271a 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -25,9 +25,9 @@ #include <stdlib.h> #include <string.h> #include <sys/epoll.h> +#include <sys/limits.h> #include <sys/inotify.h> #include <sys/ioctl.h> -#include <sys/limits.h> #include <sys/utsname.h> #include <unistd.h> @@ -42,13 +42,13 @@ #include <android-base/stringprintf.h> #include <cutils/properties.h> #include <openssl/sha.h> -#include <utils/Errors.h> #include <utils/Log.h> #include <utils/Timers.h> #include <utils/threads.h> +#include <utils/Errors.h> -#include <input/KeyCharacterMap.h> #include <input/KeyLayoutMap.h> +#include <input/KeyCharacterMap.h> #include <input/VirtualKeyMap.h> /* this macro is used to tell if "bit" is set in "array" @@ -56,10 +56,10 @@ * operation with a byte that only has the relevant bit set. * eg. to check for the 12th bit, we do (array[1] & 1<<4) */ -#define test_bit(bit, array) ((array)[(bit) / 8] & (1 << ((bit) % 8))) +#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)%8))) /* this macro computes the number of bytes needed to represent a bit array of the specified size */ -#define sizeof_bit_array(bits) (((bits) + 7) / 8) +#define sizeof_bit_array(bits) (((bits) + 7) / 8) #define INDENT " " #define INDENT2 " " @@ -71,10 +71,10 @@ namespace android { static constexpr bool DEBUG = false; -static const char* WAKE_LOCK_ID = "KeyEvents"; -static const char* DEVICE_PATH = "/dev/input"; +static const char *WAKE_LOCK_ID = "KeyEvents"; +static const char *DEVICE_PATH = "/dev/input"; // v4l2 devices go directly into /dev -static const char* VIDEO_DEVICE_PATH = "/dev"; +static const char *VIDEO_DEVICE_PATH = "/dev"; static inline const char* toString(bool value) { return value ? "true" : "false"; @@ -126,7 +126,7 @@ static bool isV4lTouchNode(const char* name) { * directly from /dev. */ static bool isV4lScanningEnabled() { - return property_get_bool("ro.input.video_enabled", true /* default_value */); + return property_get_bool("ro.input.video_enabled", true /* default_value */); } static nsecs_t processEventTimestamp(const struct input_event& event) { @@ -153,27 +153,27 @@ uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { // Touch devices get dibs on touch-related axes. if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) { switch (axis) { - case ABS_X: - case ABS_Y: - case ABS_PRESSURE: - case ABS_TOOL_WIDTH: - case ABS_DISTANCE: - case ABS_TILT_X: - case ABS_TILT_Y: - case ABS_MT_SLOT: - case ABS_MT_TOUCH_MAJOR: - case ABS_MT_TOUCH_MINOR: - case ABS_MT_WIDTH_MAJOR: - case ABS_MT_WIDTH_MINOR: - case ABS_MT_ORIENTATION: - case ABS_MT_POSITION_X: - case ABS_MT_POSITION_Y: - case ABS_MT_TOOL_TYPE: - case ABS_MT_BLOB_ID: - case ABS_MT_TRACKING_ID: - case ABS_MT_PRESSURE: - case ABS_MT_DISTANCE: - return INPUT_DEVICE_CLASS_TOUCH; + case ABS_X: + case ABS_Y: + case ABS_PRESSURE: + case ABS_TOOL_WIDTH: + case ABS_DISTANCE: + case ABS_TILT_X: + case ABS_TILT_Y: + case ABS_MT_SLOT: + case ABS_MT_TOUCH_MAJOR: + case ABS_MT_TOUCH_MINOR: + case ABS_MT_WIDTH_MAJOR: + case ABS_MT_WIDTH_MINOR: + case ABS_MT_ORIENTATION: + case ABS_MT_POSITION_X: + case ABS_MT_POSITION_Y: + case ABS_MT_TOOL_TYPE: + case ABS_MT_BLOB_ID: + case ABS_MT_TRACKING_ID: + case ABS_MT_PRESSURE: + case ABS_MT_DISTANCE: + return INPUT_DEVICE_CLASS_TOUCH; } } @@ -191,20 +191,12 @@ uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { // --- EventHub::Device --- EventHub::Device::Device(int fd, int32_t id, const std::string& path, - const InputDeviceIdentifier& identifier) - : next(nullptr), - fd(fd), - id(id), - path(path), - identifier(identifier), - classes(0), - configuration(nullptr), - virtualKeyMap(nullptr), - ffEffectPlaying(false), - ffEffectId(-1), - controllerNumber(0), - enabled(true), - isVirtual(fd < 0) { + const InputDeviceIdentifier& identifier) : + next(nullptr), + fd(fd), id(id), path(path), identifier(identifier), + classes(0), configuration(nullptr), virtualKeyMap(nullptr), + ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0), + enabled(true), isVirtual(fd < 0) { memset(keyBitmask, 0, sizeof(keyBitmask)); memset(absBitmask, 0, sizeof(absBitmask)); memset(relBitmask, 0, sizeof(relBitmask)); @@ -228,7 +220,7 @@ void EventHub::Device::close() { status_t EventHub::Device::enable() { fd = open(path.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK); - if (fd < 0) { + if(fd < 0) { ALOGE("could not open %s, %s\n", path.c_str(), strerror(errno)); return -errno; } @@ -250,18 +242,12 @@ bool EventHub::Device::hasValidFd() { const int EventHub::EPOLL_MAX_EVENTS; -EventHub::EventHub(void) - : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), - mNextDeviceId(1), - mControllerNumbers(), - mOpeningDevices(nullptr), - mClosingDevices(nullptr), +EventHub::EventHub(void) : + mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(), + mOpeningDevices(nullptr), mClosingDevices(nullptr), mNeedToSendFinishedDeviceScan(false), - mNeedToReopenDevices(false), - mNeedToScanDevices(true), - mPendingEventCount(0), - mPendingEventIndex(0), - mPendingINotify(false) { + mNeedToReopenDevices(false), mNeedToScanDevices(true), + mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mEpollFd = epoll_create1(EPOLL_CLOEXEC); @@ -269,12 +255,12 @@ EventHub::EventHub(void) mINotifyFd = inotify_init(); mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); - LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH, - strerror(errno)); + LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", + DEVICE_PATH, strerror(errno)); if (isV4lScanningEnabled()) { mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE); LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s", - VIDEO_DEVICE_PATH, strerror(errno)); + VIDEO_DEVICE_PATH, strerror(errno)); } else { mVideoWd = -1; ALOGI("Video device scanning disabled"); @@ -296,16 +282,16 @@ EventHub::EventHub(void) result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", - errno); + errno); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", - errno); + errno); eventItem.data.fd = mWakeReadPipeFd; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", - errno); + errno); int major, minor; getLinuxRelease(&major, &minor); @@ -362,7 +348,7 @@ void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) } status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const { + RawAbsoluteAxisInfo* outAxisInfo) const { outAxisInfo->clear(); if (axis >= 0 && axis <= ABS_MAX) { @@ -371,9 +357,9 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, Device* device = getDeviceLocked(deviceId); if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; - if (ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, - device->identifier.name.c_str(), device->fd, errno); + if(ioctl(device->fd, EVIOCGABS(axis), &info)) { + ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", + axis, device->identifier.name.c_str(), device->fd, errno); return -errno; } @@ -480,9 +466,9 @@ status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* Device* device = getDeviceLocked(deviceId); if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; - if (ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, - device->identifier.name.c_str(), device->fd, errno); + if(ioctl(device->fd, EVIOCGABS(axis), &info)) { + ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", + axis, device->identifier.name.c_str(), device->fd, errno); return -errno; } @@ -493,8 +479,8 @@ status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* return -1; } -bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) const { +bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); @@ -503,9 +489,9 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const in for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { scanCodes.clear(); - status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex], - &scanCodes); - if (!err) { + status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey( + keyCodes[codeIndex], &scanCodes); + if (! err) { // check the possible scan codes identified by the layout map against the // map of codes actually emitted by the driver for (size_t sc = 0; sc < scanCodes.size(); sc++) { @@ -521,8 +507,9 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const in return false; } -status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, - int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const { +status_t EventHub::mapKey(int32_t deviceId, + int32_t scanCode, int32_t usageCode, int32_t metaState, + int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); status_t status = NAME_NOT_FOUND; @@ -629,7 +616,7 @@ void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) { } void EventHub::getVirtualKeyDefinitions(int32_t deviceId, - std::vector<VirtualKeyDefinition>& outVirtualKeys) const { + std::vector<VirtualKeyDefinition>& outVirtualKeys) const { outVirtualKeys.clear(); AutoMutex _l(mLock); @@ -650,13 +637,15 @@ sp<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const { return nullptr; } -bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) { +bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, + const sp<KeyCharacterMap>& map) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { if (map != device->overlayKeyMap) { device->overlayKeyMap = map; - device->combinedKeyMap = KeyCharacterMap::combine(device->keyMap.keyCharacterMap, map); + device->combinedKeyMap = KeyCharacterMap::combine( + device->keyMap.keyCharacterMap, map); return true; } } @@ -665,7 +654,8 @@ bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterM static std::string generateDescriptor(InputDeviceIdentifier& identifier) { std::string rawDescriptor; - rawDescriptor += StringPrintf(":%04x:%04x:", identifier.vendor, identifier.product); + rawDescriptor += StringPrintf(":%04x:%04x:", identifier.vendor, + identifier.product); // TODO add handling for USB devices to not uniqueify kbs that show up twice if (!identifier.uniqueId.empty()) { rawDescriptor += "uniqueId:"; @@ -704,13 +694,13 @@ void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) { if (identifier.uniqueId.empty()) { // If it didn't have a unique id check for conflicts and enforce // uniqueness if necessary. - while (getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) { + while(getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) { identifier.nonce++; rawDescriptor = generateDescriptor(identifier); } } ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.c_str(), - identifier.descriptor.c_str()); + identifier.descriptor.c_str()); } void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { @@ -727,7 +717,7 @@ void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { effect.replay.delay = 0; if (ioctl(device->fd, EVIOCSFF, &effect)) { ALOGW("Could not upload force feedback effect to device %s due to error %d.", - device->identifier.name.c_str(), errno); + device->identifier.name.c_str(), errno); return; } device->ffEffectId = effect.id; @@ -740,7 +730,7 @@ void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { ev.value = 1; if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { ALOGW("Could not start force feedback effect on device %s due to error %d.", - device->identifier.name.c_str(), errno); + device->identifier.name.c_str(), errno); return; } device->ffEffectPlaying = true; @@ -762,7 +752,7 @@ void EventHub::cancelVibrate(int32_t deviceId) { ev.value = 0; if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { ALOGW("Could not stop force feedback effect on device %s due to error %d.", - device->identifier.name.c_str(), errno); + device->identifier.name.c_str(), errno); return; } } @@ -849,12 +839,12 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz // Report any devices that had last been added/removed. while (mClosingDevices) { Device* device = mClosingDevices; - ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str()); + ALOGV("Reporting device closed: id=%d, name=%s\n", + device->id, device->path.c_str()); mClosingDevices = device->next; event->when = now; - event->deviceId = (device->id == mBuiltInKeyboardId) - ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID - : device->id; + event->deviceId = (device->id == mBuiltInKeyboardId) ? + ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID : device->id; event->type = DEVICE_REMOVED; event += 1; delete device; @@ -872,7 +862,8 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz while (mOpeningDevices != nullptr) { Device* device = mOpeningDevices; - ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str()); + ALOGV("Reporting device opened: id=%d, name=%s\n", + device->id, device->path.c_str()); mOpeningDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; @@ -918,15 +909,15 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); } else { ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.", - eventItem.events); + eventItem.events); } continue; } Device* device = getDeviceByFdLocked(eventItem.data.fd); if (!device) { - ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events, - eventItem.data.fd); + ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", + eventItem.events, eventItem.data.fd); ALOG_ASSERT(!DEBUG); continue; } @@ -935,30 +926,30 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz size_t numFrames = device->videoDevice->readAndQueueFrames(); if (numFrames == 0) { ALOGE("Received epoll event for video device %s, but could not read frame", - device->videoDevice->getName().c_str()); + device->videoDevice->getName().c_str()); } } else if (eventItem.events & EPOLLHUP) { // TODO(b/121395353) - consider adding EPOLLRDHUP ALOGI("Removing video device %s due to epoll hang-up event.", - device->videoDevice->getName().c_str()); + device->videoDevice->getName().c_str()); unregisterVideoDeviceFromEpollLocked(*device->videoDevice); device->videoDevice = nullptr; } else { - ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events, - device->videoDevice->getName().c_str()); + ALOGW("Received unexpected epoll event 0x%08x for device %s.", + eventItem.events, device->videoDevice->getName().c_str()); ALOG_ASSERT(!DEBUG); } continue; } // This must be an input event if (eventItem.events & EPOLLIN) { - int32_t readSize = - read(device->fd, readBuffer, sizeof(struct input_event) * capacity); + int32_t readSize = read(device->fd, readBuffer, + sizeof(struct input_event) * capacity); if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { // Device was removed before INotify noticed. ALOGW("could not get event, removed? (fd: %d size: %" PRId32 - " bufferSize: %zu capacity: %zu errno: %d)\n", - device->fd, readSize, bufferSize, capacity, errno); + " bufferSize: %zu capacity: %zu errno: %d)\n", + device->fd, readSize, bufferSize, capacity, errno); deviceChanged = true; closeDeviceLocked(device); } else if (readSize < 0) { @@ -990,12 +981,12 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz } } else if (eventItem.events & EPOLLHUP) { ALOGI("Removing device %s due to epoll hang-up event.", - device->identifier.name.c_str()); + device->identifier.name.c_str()); deviceChanged = true; closeDeviceLocked(device); } else { - ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events, - device->identifier.name.c_str()); + ALOGW("Received unexpected epoll event 0x%08x for device %s.", + eventItem.events, device->identifier.name.c_str()); } } @@ -1090,7 +1081,7 @@ void EventHub::wake() { void EventHub::scanDevicesLocked() { status_t result = scanDirLocked(DEVICE_PATH); - if (result < 0) { + if(result < 0) { ALOGE("scan dir failed for %s", DEVICE_PATH); } if (isV4lScanningEnabled()) { @@ -1118,12 +1109,12 @@ static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint3 } static const int32_t GAMEPAD_KEYCODES[] = { - AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, // - AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, // - AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, // - AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, // - AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, // - AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, // + AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, + AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, + AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, + AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, + AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, + AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, }; status_t EventHub::registerFdForEpoll(int fd) { @@ -1190,7 +1181,7 @@ void EventHub::unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& vide status_t result = unregisterFdFromEpoll(videoDevice.getFd()); if (result != OK) { ALOGW("Could not remove video device fd from epoll for device: %s", - videoDevice.getName().c_str()); + videoDevice.getName().c_str()); } } } @@ -1201,7 +1192,7 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { ALOGV("Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK); - if (fd < 0) { + if(fd < 0) { ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } @@ -1209,7 +1200,7 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { InputDeviceIdentifier identifier; // Get device name. - if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { + if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { ALOGE("Could not get device name for %s: %s", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; @@ -1228,7 +1219,7 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // Get device driver version. int driverVersion; - if (ioctl(fd, EVIOCGVERSION, &driverVersion)) { + if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; @@ -1236,7 +1227,7 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // Get device identifier. struct input_id inputId; - if (ioctl(fd, EVIOCGID, &inputId)) { + if(ioctl(fd, EVIOCGID, &inputId)) { ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; @@ -1247,16 +1238,16 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { identifier.version = inputId.version; // Get device physical location. - if (ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { - // fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); + if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { + //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.location = buffer; } // Get device unique id. - if (ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { - // fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); + if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { + //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.uniqueId = buffer; @@ -1271,16 +1262,16 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { ALOGV("add device %d: %s\n", deviceId, devicePath); ALOGV(" bus: %04x\n" - " vendor %04x\n" - " product %04x\n" - " version %04x\n", - identifier.bus, identifier.vendor, identifier.product, identifier.version); + " vendor %04x\n" + " product %04x\n" + " version %04x\n", + identifier.bus, identifier.vendor, identifier.product, identifier.version); ALOGV(" name: \"%s\"\n", identifier.name.c_str()); ALOGV(" location: \"%s\"\n", identifier.location.c_str()); ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.c_str()); ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.c_str()); - ALOGV(" driver: v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff, - driverVersion & 0xff); + ALOGV(" driver: v%d.%d.%d\n", + driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); // Load the configuration file for the device. loadConfigurationLocked(device); @@ -1296,21 +1287,21 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // See if this is a keyboard. Ignore everything in the button range except for // joystick and gamepad buttons which are handled like keyboards for the most part. - bool haveKeyboardKeys = - containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) || - containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), - sizeof_bit_array(KEY_MAX + 1)); + bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) + || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), + sizeof_bit_array(KEY_MAX + 1)); bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), - sizeof_bit_array(BTN_MOUSE)) || - containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), - sizeof_bit_array(BTN_DIGI)); + sizeof_bit_array(BTN_MOUSE)) + || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), + sizeof_bit_array(BTN_DIGI)); if (haveKeyboardKeys || haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } // See if this is a cursor device such as a trackball or mouse. - if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) && - test_bit(REL_Y, device->relBitmask)) { + if (test_bit(BTN_MOUSE, device->keyBitmask) + && test_bit(REL_X, device->relBitmask) + && test_bit(REL_Y, device->relBitmask)) { device->classes |= INPUT_DEVICE_CLASS_CURSOR; } @@ -1318,29 +1309,31 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { String8 deviceType = String8(); if (device->configuration && device->configuration->tryGetProperty(String8("device.type"), deviceType)) { - if (!deviceType.compare(String8("rotaryEncoder"))) { - device->classes |= INPUT_DEVICE_CLASS_ROTARY_ENCODER; - } + if (!deviceType.compare(String8("rotaryEncoder"))) { + device->classes |= INPUT_DEVICE_CLASS_ROTARY_ENCODER; + } } // See if this is a touch pad. // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_POSITION_X, device->absBitmask) && - test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { + if (test_bit(ABS_MT_POSITION_X, device->absBitmask) + && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { // Some joysticks such as the PS3 controller report axes that conflict // with the ABS_MT range. Try to confirm that the device really is // a touch screen. if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; } - // Is this an old style single-touch driver? - } else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) && - test_bit(ABS_Y, device->absBitmask)) { + // Is this an old style single-touch driver? + } else if (test_bit(BTN_TOUCH, device->keyBitmask) + && test_bit(ABS_X, device->absBitmask) + && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; - // Is this a BT stylus? + // Is this a BT stylus? } else if ((test_bit(ABS_PRESSURE, device->absBitmask) || - test_bit(BTN_TOUCH, device->keyBitmask)) && - !test_bit(ABS_X, device->absBitmask) && !test_bit(ABS_Y, device->absBitmask)) { + test_bit(BTN_TOUCH, device->keyBitmask)) + && !test_bit(ABS_X, device->absBitmask) + && !test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; // Keyboard will try to claim some of the buttons but we really want to reserve those so we // can fuse it with the touch screen data, so just take them back. Note this means an @@ -1354,8 +1347,8 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { if (haveGamepadButtons) { uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; for (int i = 0; i <= ABS_MAX; i++) { - if (test_bit(i, device->absBitmask) && - (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { + if (test_bit(i, device->absBitmask) + && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { device->classes = assumedClasses; break; } @@ -1396,8 +1389,10 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // Configure the keyboard, gamepad or virtual keyboard. if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { // Register the keyboard as a built-in keyboard if it is eligible. - if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD && - isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) { + if (!keyMapStatus + && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD + && isEligibleBuiltInKeyboard(device->identifier, + device->configuration, &device->keyMap)) { mBuiltInKeyboardId = device->id; } @@ -1408,15 +1403,15 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // See if this device has a DPAD. if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && - hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && - hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { + hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && + hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && + hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && + hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. - for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES) / sizeof(GAMEPAD_KEYCODES[0]); i++) { + for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; @@ -1426,8 +1421,8 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { - ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath, - device->identifier.name.c_str()); + ALOGV("Dropping device: id=%d, path='%s', name='%s'", + deviceId, devicePath, device->identifier.name.c_str()); delete device; return -1; } @@ -1442,8 +1437,8 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; } - if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD) && - device->classes & INPUT_DEVICE_CLASS_GAMEPAD) { + if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD) + && device->classes & INPUT_DEVICE_CLASS_GAMEPAD) { device->controllerNumber = getNextControllerNumberLocked(device); setLedForControllerLocked(device); } @@ -1456,12 +1451,10 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { break; } } - mUnattachedVideoDevices - .erase(std::remove_if(mUnattachedVideoDevices.begin(), mUnattachedVideoDevices.end(), - [](const std::unique_ptr<TouchVideoDevice>& videoDevice) { - return videoDevice == nullptr; - }), - mUnattachedVideoDevices.end()); + mUnattachedVideoDevices.erase(std::remove_if(mUnattachedVideoDevices.begin(), + mUnattachedVideoDevices.end(), + [](const std::unique_ptr<TouchVideoDevice>& videoDevice){ + return videoDevice == nullptr; }), mUnattachedVideoDevices.end()); if (registerDeviceForEpollLocked(device) != OK) { delete device; @@ -1471,10 +1464,13 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { configureFd(device); ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " - "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ", - deviceId, fd, devicePath, device->identifier.name.c_str(), device->classes, - device->configurationFile.c_str(), device->keyMap.keyLayoutFile.c_str(), - device->keyMap.keyCharacterMapFile.c_str(), toString(mBuiltInKeyboardId == deviceId)); + "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ", + deviceId, fd, devicePath, device->identifier.name.c_str(), + device->classes, + device->configurationFile.c_str(), + device->keyMap.keyLayoutFile.c_str(), + device->keyMap.keyCharacterMapFile.c_str(), + toString(mBuiltInKeyboardId == deviceId)); addDeviceLocked(device); return OK; @@ -1486,8 +1482,8 @@ void EventHub::configureFd(Device* device) { // Disable kernel key repeat since we handle it ourselves unsigned int repeatRate[] = {0, 0}; if (ioctl(device->fd, EVIOCSREP, repeatRate)) { - ALOGW("Unable to disable kernel key repeat for %s: %s", device->path.c_str(), - strerror(errno)); + ALOGW("Unable to disable kernel key repeat for %s: %s", + device->path.c_str(), strerror(errno)); } } @@ -1511,7 +1507,8 @@ void EventHub::configureFd(Device* device) { // clock. int clockId = CLOCK_MONOTONIC; bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId); - ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(), toString(usingClockIoctl)); + ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(), + toString(usingClockIoctl)); } void EventHub::openVideoDeviceLocked(const std::string& devicePath) { @@ -1535,7 +1532,7 @@ void EventHub::openVideoDeviceLocked(const std::string& devicePath) { // Couldn't find a matching input device, so just add it to a temporary holding queue. // A matching input device may appear later. ALOGI("Adding video device %s to list of unattached video devices", - videoDevice->getName().c_str()); + videoDevice->getName().c_str()); mUnattachedVideoDevices.push_back(std::move(videoDevice)); } @@ -1592,10 +1589,12 @@ void EventHub::createVirtualKeyboardLocked() { identifier.uniqueId = "<virtual>"; assignDescriptorLocked(identifier); - Device* device = - new Device(-1, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, "<virtual>", identifier); - device->classes = INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY | - INPUT_DEVICE_CLASS_DPAD | INPUT_DEVICE_CLASS_VIRTUAL; + Device* device = new Device(-1, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, "<virtual>", + identifier); + device->classes = INPUT_DEVICE_CLASS_KEYBOARD + | INPUT_DEVICE_CLASS_ALPHAKEY + | INPUT_DEVICE_CLASS_DPAD + | INPUT_DEVICE_CLASS_VIRTUAL; loadKeyMapLocked(device); addDeviceLocked(device); } @@ -1611,14 +1610,14 @@ void EventHub::loadConfigurationLocked(Device* device) { device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); if (device->configurationFile.empty()) { ALOGD("No input device configuration file found for device '%s'.", - device->identifier.name.c_str()); + device->identifier.name.c_str()); } else { status_t status = PropertyMap::load(String8(device->configurationFile.c_str()), - &device->configuration); + &device->configuration); if (status) { ALOGE("Error loading input device configuration file for device '%s'. " - "Using default configuration.", - device->identifier.name.c_str()); + "Using default configuration.", + device->identifier.name.c_str()); } } } @@ -1662,7 +1661,7 @@ bool EventHub::deviceHasMicLocked(Device* device) { int32_t EventHub::getNextControllerNumberLocked(Device* device) { if (mControllerNumbers.isFull()) { ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s", - device->identifier.name.c_str()); + device->identifier.name.c_str()); return 0; } // Since the controller number 0 is reserved for non-controllers, translate all numbers up by @@ -1672,7 +1671,7 @@ int32_t EventHub::getNextControllerNumberLocked(Device* device) { void EventHub::releaseControllerNumberLocked(Device* device) { int32_t num = device->controllerNumber; - device->controllerNumber = 0; + device->controllerNumber= 0; if (num == 0) { return; } @@ -1693,7 +1692,7 @@ bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { std::vector<int32_t> scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); const size_t N = scanCodes.size(); - for (size_t i = 0; i < N && i <= KEY_MAX; i++) { + for (size_t i=0; i<N && i<=KEY_MAX; i++) { int32_t sc = scanCodes[i]; if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) { return true; @@ -1709,8 +1708,8 @@ status_t EventHub::mapLed(Device* device, int32_t led, int32_t* outScanCode) con } int32_t scanCode; - if (device->keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) { - if (scanCode >= 0 && scanCode <= LED_MAX && test_bit(scanCode, device->ledBitmask)) { + if(device->keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) { + if(scanCode >= 0 && scanCode <= LED_MAX && test_bit(scanCode, device->ledBitmask)) { *outScanCode = scanCode; return NO_ERROR; } @@ -1718,7 +1717,7 @@ status_t EventHub::mapLed(Device* device, int32_t led, int32_t* outScanCode) con return NAME_NOT_FOUND; } -void EventHub::closeDeviceByPathLocked(const char* devicePath) { +void EventHub::closeDeviceByPathLocked(const char *devicePath) { Device* device = getDeviceByPathLocked(devicePath); if (device) { closeDeviceLocked(device); @@ -1743,13 +1742,10 @@ void EventHub::closeVideoDeviceByPathLocked(const std::string& devicePath) { return; } } - mUnattachedVideoDevices - .erase(std::remove_if(mUnattachedVideoDevices.begin(), mUnattachedVideoDevices.end(), - [&devicePath]( - const std::unique_ptr<TouchVideoDevice>& videoDevice) { - return videoDevice->getPath() == devicePath; - }), - mUnattachedVideoDevices.end()); + mUnattachedVideoDevices.erase(std::remove_if(mUnattachedVideoDevices.begin(), + mUnattachedVideoDevices.end(), [&devicePath]( + const std::unique_ptr<TouchVideoDevice>& videoDevice) { + return videoDevice->getPath() == devicePath; }), mUnattachedVideoDevices.end()); } void EventHub::closeAllDevicesLocked() { @@ -1760,12 +1756,13 @@ void EventHub::closeAllDevicesLocked() { } void EventHub::closeDeviceLocked(Device* device) { - ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x", device->path.c_str(), - device->identifier.name.c_str(), device->id, device->fd, device->classes); + ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x", + device->path.c_str(), device->identifier.name.c_str(), device->id, + device->fd, device->classes); if (device->id == mBuiltInKeyboardId) { ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", - device->path.c_str(), mBuiltInKeyboardId); + device->path.c_str(), mBuiltInKeyboardId); mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD; } @@ -1783,7 +1780,7 @@ void EventHub::closeDeviceLocked(Device* device) { // Unlink for opening devices list if it is present. Device* pred = nullptr; bool found = false; - for (Device* entry = mOpeningDevices; entry != nullptr;) { + for (Device* entry = mOpeningDevices; entry != nullptr; ) { if (entry == device) { found = true; break; @@ -1815,28 +1812,30 @@ status_t EventHub::readNotifyLocked() { char event_buf[512]; int event_size; int event_pos = 0; - struct inotify_event* event; + struct inotify_event *event; ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd); res = read(mINotifyFd, event_buf, sizeof(event_buf)); - if (res < (int)sizeof(*event)) { - if (errno == EINTR) return 0; + if(res < (int)sizeof(*event)) { + if(errno == EINTR) + return 0; ALOGW("could not get event, %s\n", strerror(errno)); return -1; } - while (res >= (int)sizeof(*event)) { - event = (struct inotify_event*)(event_buf + event_pos); - if (event->len) { + while(res >= (int)sizeof(*event)) { + event = (struct inotify_event *)(event_buf + event_pos); + if(event->len) { if (event->wd == mInputWd) { std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name); - if (event->mask & IN_CREATE) { + if(event->mask & IN_CREATE) { openDeviceLocked(filename.c_str()); } else { ALOGI("Removing device '%s' due to inotify event\n", filename.c_str()); closeDeviceByPathLocked(filename.c_str()); } - } else if (event->wd == mVideoWd) { + } + else if (event->wd == mVideoWd) { if (isV4lTouchNode(event->name)) { std::string filename = StringPrintf("%s/%s", VIDEO_DEVICE_PATH, event->name); if (event->mask & IN_CREATE) { @@ -1846,7 +1845,8 @@ status_t EventHub::readNotifyLocked() { closeVideoDeviceByPathLocked(filename); } } - } else { + } + else { LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd); } } @@ -1857,19 +1857,22 @@ status_t EventHub::readNotifyLocked() { return 0; } -status_t EventHub::scanDirLocked(const char* dirname) { +status_t EventHub::scanDirLocked(const char *dirname) +{ char devname[PATH_MAX]; - char* filename; - DIR* dir; - struct dirent* de; + char *filename; + DIR *dir; + struct dirent *de; dir = opendir(dirname); - if (dir == nullptr) return -1; + if(dir == nullptr) + return -1; strcpy(devname, dirname); filename = devname + strlen(devname); *filename++ = '/'; - while ((de = readdir(dir))) { - if (de->d_name[0] == '.' && - (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) + while((de = readdir(dir))) { + if(de->d_name[0] == '.' && + (de->d_name[1] == '\0' || + (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); openDeviceLocked(devname); @@ -1881,16 +1884,17 @@ status_t EventHub::scanDirLocked(const char* dirname) { /** * Look for all dirname/v4l-touch* devices, and open them. */ -status_t EventHub::scanVideoDirLocked(const std::string& dirname) { +status_t EventHub::scanVideoDirLocked(const std::string& dirname) +{ DIR* dir; struct dirent* de; dir = opendir(dirname.c_str()); - if (!dir) { + if(!dir) { ALOGE("Could not open video directory %s", dirname.c_str()); return BAD_VALUE; } - while ((de = readdir(dir))) { + while((de = readdir(dir))) { const char* name = de->d_name; if (isV4lTouchNode(name)) { ALOGI("Found touch video device %s", name); @@ -1922,10 +1926,10 @@ void EventHub::dump(std::string& dump) { const Device* device = mDevices.valueAt(i); if (mBuiltInKeyboardId == device->id) { dump += StringPrintf(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", - device->id, device->identifier.name.c_str()); + device->id, device->identifier.name.c_str()); } else { dump += StringPrintf(INDENT2 "%d: %s\n", device->id, - device->identifier.name.c_str()); + device->identifier.name.c_str()); } dump += StringPrintf(INDENT3 "Classes: 0x%08x\n", device->classes); dump += StringPrintf(INDENT3 "Path: %s\n", device->path.c_str()); @@ -1935,17 +1939,17 @@ void EventHub::dump(std::string& dump) { dump += StringPrintf(INDENT3 "ControllerNumber: %d\n", device->controllerNumber); dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.c_str()); dump += StringPrintf(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " - "product=0x%04x, version=0x%04x\n", - device->identifier.bus, device->identifier.vendor, - device->identifier.product, device->identifier.version); + "product=0x%04x, version=0x%04x\n", + device->identifier.bus, device->identifier.vendor, + device->identifier.product, device->identifier.version); dump += StringPrintf(INDENT3 "KeyLayoutFile: %s\n", - device->keyMap.keyLayoutFile.c_str()); + device->keyMap.keyLayoutFile.c_str()); dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n", - device->keyMap.keyCharacterMapFile.c_str()); + device->keyMap.keyCharacterMapFile.c_str()); dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n", - device->configurationFile.c_str()); + device->configurationFile.c_str()); dump += StringPrintf(INDENT3 "HaveKeyboardLayoutOverlay: %s\n", - toString(device->overlayKeyMap != nullptr)); + toString(device->overlayKeyMap != nullptr)); dump += INDENT3 "VideoDevice: "; if (device->videoDevice) { dump += device->videoDevice->dump() + "\n"; @@ -1970,4 +1974,5 @@ void EventHub::monitor() { mLock.unlock(); } + }; // namespace android diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/EventHub.h index 794396acca..63a20ef3e2 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -14,6 +14,7 @@ * limitations under the License. */ +// #ifndef _RUNTIME_EVENT_HUB_H #define _RUNTIME_EVENT_HUB_H @@ -21,17 +22,17 @@ #include <input/Input.h> #include <input/InputDevice.h> -#include <input/KeyCharacterMap.h> -#include <input/KeyLayoutMap.h> #include <input/Keyboard.h> +#include <input/KeyLayoutMap.h> +#include <input/KeyCharacterMap.h> #include <input/VirtualKeyMap.h> -#include <utils/BitSet.h> -#include <utils/Errors.h> -#include <utils/KeyedVector.h> -#include <utils/List.h> -#include <utils/Log.h> #include <utils/Mutex.h> +#include <utils/Log.h> +#include <utils/List.h> +#include <utils/Errors.h> #include <utils/PropertyMap.h> +#include <utils/KeyedVector.h> +#include <utils/BitSet.h> #include <linux/input.h> #include <sys/epoll.h> @@ -40,8 +41,8 @@ /* Convenience constants. */ -#define BTN_FIRST 0x100 // first button code -#define BTN_LAST 0x15f // last button code +#define BTN_FIRST 0x100 // first button code +#define BTN_LAST 0x15f // last button code namespace android { @@ -60,10 +61,10 @@ struct RawEvent { struct RawAbsoluteAxisInfo { bool valid; // true if the information is valid, false otherwise - int32_t minValue; // minimum value - int32_t maxValue; // maximum value - int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 - int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise + int32_t minValue; // minimum value + int32_t maxValue; // maximum value + int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 + int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise int32_t resolution; // resolution in units per mm or radians per mm inline void clear() { @@ -81,37 +82,37 @@ struct RawAbsoluteAxisInfo { */ enum { /* The input device is a keyboard or has buttons. */ - INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, + INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, /* The input device is an alpha-numeric keyboard (not just a dial pad). */ - INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, + INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */ - INPUT_DEVICE_CLASS_TOUCH = 0x00000004, + INPUT_DEVICE_CLASS_TOUCH = 0x00000004, /* The input device is a cursor device such as a trackball or mouse. */ - INPUT_DEVICE_CLASS_CURSOR = 0x00000008, + INPUT_DEVICE_CLASS_CURSOR = 0x00000008, /* The input device is a multi-touch touchscreen. */ - INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, + INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, /* The input device is a directional pad (implies keyboard, has DPAD keys). */ - INPUT_DEVICE_CLASS_DPAD = 0x00000020, + INPUT_DEVICE_CLASS_DPAD = 0x00000020, /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ - INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, + INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, /* The input device has switches. */ - INPUT_DEVICE_CLASS_SWITCH = 0x00000080, + INPUT_DEVICE_CLASS_SWITCH = 0x00000080, /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ - INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, + INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, /* The input device has a vibrator (supports FF_RUMBLE). */ - INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, + INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, /* The input device has a microphone. */ - INPUT_DEVICE_CLASS_MIC = 0x00000400, + INPUT_DEVICE_CLASS_MIC = 0x00000400, /* The input device is an external stylus (has data we want to fuse with touch data). */ INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800, @@ -120,10 +121,10 @@ enum { INPUT_DEVICE_CLASS_ROTARY_ENCODER = 0x00001000, /* The input device is virtual (not a real device, not part of UI configuration). */ - INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, + INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, /* The input device is external (not built-in). */ - INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, + INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, }; /* @@ -147,8 +148,8 @@ extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses); */ class EventHubInterface : public virtual RefBase { protected: - EventHubInterface() {} - virtual ~EventHubInterface() {} + EventHubInterface() { } + virtual ~EventHubInterface() { } public: // Synthetic raw event type codes produced when devices are added or removed. @@ -173,17 +174,18 @@ public: virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0; virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const = 0; + RawAbsoluteAxisInfo* outAxisInfo) const = 0; virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0; virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; - virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, - uint32_t* outFlags) const = 0; + virtual status_t mapKey(int32_t deviceId, + int32_t scanCode, int32_t usageCode, int32_t metaState, + int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const = 0; - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const = 0; + virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, + AxisInfo* outAxisInfo) const = 0; // Sets devices that are excluded from opening. // This can be used to ignore input devices for sensors. @@ -211,13 +213,13 @@ public: virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, - int32_t* outValue) const = 0; + int32_t* outValue) const = 0; /* * Examine key input devices for specific framework keycode support */ virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) const = 0; + uint8_t* outFlags) const = 0; virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; @@ -225,8 +227,8 @@ public: virtual bool hasLed(int32_t deviceId, int32_t led) const = 0; virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0; - virtual void getVirtualKeyDefinitions( - int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const = 0; + virtual void getVirtualKeyDefinitions(int32_t deviceId, + std::vector<VirtualKeyDefinition>& outVirtualKeys) const = 0; virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0; virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0; @@ -257,7 +259,8 @@ public: virtual status_t disableDevice(int32_t deviceId) = 0; }; -class EventHub : public EventHubInterface { +class EventHub : public EventHubInterface +{ public: EventHub(); @@ -270,17 +273,18 @@ public: virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const; virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const; + RawAbsoluteAxisInfo* outAxisInfo) const; virtual bool hasRelativeAxis(int32_t deviceId, int axis) const; virtual bool hasInputProperty(int32_t deviceId, int property) const; - virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, - uint32_t* outFlags) const; + virtual status_t mapKey(int32_t deviceId, + int32_t scanCode, int32_t usageCode, int32_t metaState, + int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const; - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const; + virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, + AxisInfo* outAxisInfo) const; virtual void setExcludedDevices(const std::vector<std::string>& devices); @@ -289,8 +293,8 @@ public: virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const; - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) const; + virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) const; virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId); @@ -300,7 +304,7 @@ public: virtual void setLedState(int32_t deviceId, int32_t led, bool on); virtual void getVirtualKeyDefinitions(int32_t deviceId, - std::vector<VirtualKeyDefinition>& outVirtualKeys) const; + std::vector<VirtualKeyDefinition>& outVirtualKeys) const; virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const; virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map); @@ -353,7 +357,7 @@ private: int32_t controllerNumber; Device(int fd, int32_t id, const std::string& path, - const InputDeviceIdentifier& identifier); + const InputDeviceIdentifier& identifier); ~Device(); void close(); @@ -378,7 +382,7 @@ private: void addDeviceLocked(Device* device); void assignDescriptorLocked(InputDeviceIdentifier& identifier); - void closeDeviceByPathLocked(const char* devicePath); + void closeDeviceByPathLocked(const char *devicePath); void closeVideoDeviceByPathLocked(const std::string& devicePath); void closeDeviceLocked(Device* device); void closeAllDevicesLocked(); @@ -395,7 +399,7 @@ private: status_t unregisterDeviceFromEpollLocked(Device* device); void unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& videoDevice); - status_t scanDirLocked(const char* dirname); + status_t scanDirLocked(const char *dirname); status_t scanVideoDirLocked(const std::string& dirname); void scanDevicesLocked(); status_t readNotifyLocked(); @@ -451,8 +455,8 @@ private: */ std::vector<std::unique_ptr<TouchVideoDevice>> mUnattachedVideoDevices; - Device* mOpeningDevices; - Device* mClosingDevices; + Device *mOpeningDevices; + Device *mClosingDevices; bool mNeedToSendFinishedDeviceScan; bool mNeedToReopenDevices; diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 6a7f2797f4..cda0e0cdcb 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -27,7 +27,6 @@ #if defined(__linux__) #include <pthread.h> #endif -#include <server_configurable_flags/get_flags.h> #include <unordered_set> #include <android/hardware/input/classifier/1.0/IInputClassifier.h> @@ -46,13 +45,6 @@ using namespace android::hardware::input; namespace android { -static constexpr bool DEBUG = false; - -// Category (=namespace) name for the input settings that are applied at boot time -static const char* INPUT_NATIVE_BOOT = "input_native_boot"; -// Feature flag name for the deep press feature -static const char* DEEP_PRESS_ENABLED = "deep_press_enabled"; - //Max number of elements to store in mEvents. static constexpr size_t MAX_EVENTS = 5; @@ -79,20 +71,6 @@ static bool isTouchEvent(const NotifyMotionArgs& args) { return args.source == AINPUT_SOURCE_TOUCHPAD || args.source == AINPUT_SOURCE_TOUCHSCREEN; } -// Check if the "deep touch" feature is on. -static bool deepPressEnabled() { - std::string flag_value = server_configurable_flags::GetServerConfigurableFlag( - INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "false"); - std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower); - if (flag_value == "1" || flag_value == "true") { - ALOGI("Deep press feature enabled."); - return true; - } - ALOGI("Deep press feature is not enabled."); - return false; -} - - // --- ClassifierEvent --- ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) : @@ -141,53 +119,40 @@ std::optional<int32_t> ClassifierEvent::getDeviceId() const { // --- MotionClassifier --- -MotionClassifier::MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient) : - mDeathRecipient(deathRecipient), mEvents(MAX_EVENTS) { - mHalThread = std::thread(&MotionClassifier::callInputClassifierHal, this); +MotionClassifier::MotionClassifier( + sp<android::hardware::input::classifier::V1_0::IInputClassifier> service) + : mEvents(MAX_EVENTS), mService(service) { + // Under normal operation, we do not need to reset the HAL here. But in the case where system + // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already + // have received events in the past. That means, that HAL could be in an inconsistent state + // once it receives events from the newly created MotionClassifier. + mEvents.push(ClassifierEvent::createHalResetEvent()); + + mHalThread = std::thread(&MotionClassifier::processEvents, this); #if defined(__linux__) // Set the thread name for debugging pthread_setname_np(mHalThread.native_handle(), "InputClassifier"); #endif } -/** - * This function may block for some time to initialize the HAL, so it should only be called - * from the "InputClassifier HAL" thread. - */ -bool MotionClassifier::init() { - ensureHalThread(__func__); +std::unique_ptr<MotionClassifierInterface> MotionClassifier::create( + sp<android::hardware::hidl_death_recipient> deathRecipient) { sp<android::hardware::input::classifier::V1_0::IInputClassifier> service = classifier::V1_0::IInputClassifier::getService(); if (!service) { // Not really an error, maybe the device does not have this HAL, // but somehow the feature flag is flipped ALOGI("Could not obtain InputClassifier HAL"); - return false; + return nullptr; } - sp<android::hardware::hidl_death_recipient> recipient = mDeathRecipient.promote(); - if (recipient != nullptr) { - const bool linked = service->linkToDeath(recipient, 0 /* cookie */).withDefault(false); - if (!linked) { - ALOGE("Could not link MotionClassifier to the HAL death"); - return false; - } + const bool linked = service->linkToDeath(deathRecipient, 0 /* cookie */).withDefault(false); + if (!linked) { + ALOGE("Could not link death recipient to the HAL death"); + return nullptr; } - - // Under normal operation, we do not need to reset the HAL here. But in the case where system - // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already - // have received events in the past. That means, that HAL could be in an inconsistent state - // once it receives events from the newly created MotionClassifier. - mEvents.push(ClassifierEvent::createHalResetEvent()); - - { - std::scoped_lock lock(mLock); - if (mService) { - ALOGE("MotionClassifier::%s should only be called once", __func__); - } - mService = service; - } - return true; + // Using 'new' to access a non-public constructor + return std::unique_ptr<MotionClassifier>(new MotionClassifier(service)); } MotionClassifier::~MotionClassifier() { @@ -195,14 +160,6 @@ MotionClassifier::~MotionClassifier() { mHalThread.join(); } -void MotionClassifier::ensureHalThread(const char* function) { - if (DEBUG) { - if (std::this_thread::get_id() != mHalThread.get_id()) { - LOG_FATAL("Function %s should only be called from InputClassifier thread", function); - } - } -} - /** * Obtain the classification from the HAL for a given MotionEvent. * Should only be called from the InputClassifier thread (mHalThread). @@ -213,23 +170,7 @@ void MotionClassifier::ensureHalThread(const char* function) { * To remove any possibility of negatively affecting the touch latency, the HAL * is called from a dedicated thread. */ -void MotionClassifier::callInputClassifierHal() { - ensureHalThread(__func__); - const bool initialized = init(); - if (!initialized) { - // MotionClassifier no longer useful. - // Deliver death notification from a separate thread - // because ~MotionClassifier may be invoked, which calls mHalThread.join() - std::thread([deathRecipient = mDeathRecipient](){ - sp<android::hardware::hidl_death_recipient> recipient = deathRecipient.promote(); - if (recipient != nullptr) { - recipient->serviceDied(0 /*cookie*/, nullptr); - } - }).detach(); - return; - } - // From this point on, mService is guaranteed to be non-null. - +void MotionClassifier::processEvents() { while (true) { ClassifierEvent event = mEvents.pop(); bool halResponseOk = true; @@ -383,24 +324,41 @@ void MotionClassifier::dump(std::string& dump) { } } +// --- HalDeathRecipient -// --- InputClassifier --- +InputClassifier::HalDeathRecipient::HalDeathRecipient(InputClassifier& parent) : mParent(parent) {} -InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) : - mListener(listener) { - // The rest of the initialization is done in onFirstRef, because we need to obtain - // an sp to 'this' in order to register for HAL death notifications +void InputClassifier::HalDeathRecipient::serviceDied( + uint64_t cookie, const wp<android::hidl::base::V1_0::IBase>& who) { + sp<android::hidl::base::V1_0::IBase> service = who.promote(); + if (service) { + service->unlinkToDeath(this); + } + mParent.setMotionClassifier(nullptr); } -void InputClassifier::onFirstRef() { - if (!deepPressEnabled()) { - // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work. - // When MotionClassifier is null, InputClassifier will forward all events - // to the next InputListener, unmodified. - return; +// --- InputClassifier --- + +InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) + : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {} + +void InputClassifier::setMotionClassifierEnabled(bool enabled) { + if (enabled) { + ALOGI("Enabling motion classifier"); + if (mInitializeMotionClassifierThread.joinable()) { + mInitializeMotionClassifierThread.join(); + } + mInitializeMotionClassifierThread = std::thread( + [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); }); +#if defined(__linux__) + // Set the thread name for debugging + pthread_setname_np(mInitializeMotionClassifierThread.native_handle(), + "Create MotionClassifier"); +#endif + } else { + ALOGI("Disabling motion classifier"); + setMotionClassifier(nullptr); } - std::scoped_lock lock(mLock); - mMotionClassifier = std::make_unique<MotionClassifier>(this); } void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { @@ -441,15 +399,10 @@ void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) { mListener->notifyDeviceReset(args); } -void InputClassifier::serviceDied(uint64_t /*cookie*/, - const wp<android::hidl::base::V1_0::IBase>& who) { +void InputClassifier::setMotionClassifier( + std::unique_ptr<MotionClassifierInterface> motionClassifier) { std::scoped_lock lock(mLock); - ALOGE("InputClassifier HAL has died. Setting mMotionClassifier to null"); - mMotionClassifier = nullptr; - sp<android::hidl::base::V1_0::IBase> service = who.promote(); - if (service) { - service->unlinkToDeath(this); - } + mMotionClassifier = std::move(motionClassifier); } void InputClassifier::dump(std::string& dump) { @@ -465,4 +418,10 @@ void InputClassifier::dump(std::string& dump) { dump += "\n"; } +InputClassifier::~InputClassifier() { + if (mInitializeMotionClassifierThread.joinable()) { + mInitializeMotionClassifierThread.join(); + } +} + } // namespace android diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h index 47e20dbf75..9ac8e2db2b 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputClassifier.h @@ -19,8 +19,8 @@ #include <android-base/thread_annotations.h> #include <utils/RefBase.h> -#include <unordered_map> #include <thread> +#include <unordered_map> #include "BlockingQueue.h" #include "InputListener.h" @@ -90,6 +90,7 @@ public: */ class InputClassifierInterface : public virtual RefBase, public InputListenerInterface { public: + virtual void setMotionClassifierEnabled(bool enabled) = 0; /** * Dump the state of the input classifier. * This method may be called on any thread (usually by the input manager). @@ -113,23 +114,23 @@ protected: */ class MotionClassifier final : public MotionClassifierInterface { public: - /** - * The deathRecipient will be subscribed to the HAL death. If the death recipient - * owns MotionClassifier and receives HAL death, it should delete its copy of it. - * The callback serviceDied will also be sent if the MotionClassifier itself fails - * to initialize. If the MotionClassifier fails to initialize, it is not useful, and - * should be deleted. - * If no death recipient is supplied, then the registration step will be skipped, so there will - * be no listeners registered for the HAL death. This is useful for testing - * MotionClassifier in isolation. + /* + * Create an instance of MotionClassifier. + * The death recipient, if provided, will be subscribed to the HAL death. + * The death recipient could be used to destroy MotionClassifier. + * + * This function should be called asynchronously, because getService takes a long time. */ - explicit MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient = nullptr); + static std::unique_ptr<MotionClassifierInterface> create( + sp<android::hardware::hidl_death_recipient> deathRecipient); + ~MotionClassifier(); /** * Classifies events asynchronously; that is, it doesn't block events on a classification, - * but instead sends them over to the classifier HAL and after a classification is - * determined, it then marks the next event it sees in the stream with it. + * but instead sends them over to the classifier HAL. After a classification of a specific + * event is determined, MotionClassifier then marks the next event in the stream with this + * classification. * * Therefore, it is acceptable to have the classifications be delayed by 1-2 events * in a particular gesture. @@ -141,15 +142,9 @@ public: virtual void dump(std::string& dump) override; private: - /** - * Initialize MotionClassifier. - * Return true if initializaion is successful. - */ - bool init(); - /** - * Entity that will be notified of the HAL death (most likely InputClassifier). - */ - wp<android::hardware::hidl_death_recipient> mDeathRecipient; + friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation + explicit MotionClassifier( + sp<android::hardware::input::classifier::V1_0::IInputClassifier> service); // The events that need to be sent to the HAL. BlockingQueue<ClassifierEvent> mEvents; @@ -164,14 +159,9 @@ private: */ std::thread mHalThread; /** - * Print an error message if the caller is not on the InputClassifier thread. - * Caller must supply the name of the calling function as __func__ + * Process events and call the InputClassifier HAL */ - void ensureHalThread(const char* function); - /** - * Call the InputClassifier HAL - */ - void callInputClassifierHal(); + void processEvents(); /** * Access to the InputClassifier HAL. May be null if init() hasn't completed yet. * When init() successfully completes, mService is guaranteed to remain non-null and to not @@ -223,19 +213,15 @@ private: const char* getServiceStatus() REQUIRES(mLock); }; - /** * Implementation of the InputClassifierInterface. * Represents a separate stage of input processing. All of the input events go through this stage. * Acts as a passthrough for all input events except for motion events. * The events of motion type are sent to MotionClassifier. */ -class InputClassifier : public InputClassifierInterface, - public android::hardware::hidl_death_recipient { +class InputClassifier : public InputClassifierInterface { public: explicit InputClassifier(const sp<InputListenerInterface>& listener); - // Some of the constructor logic is finished in onFirstRef - virtual void onFirstRef() override; virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; virtual void notifyKey(const NotifyKeyArgs* args) override; @@ -243,17 +229,47 @@ public: virtual void notifySwitch(const NotifySwitchArgs* args) override; virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - virtual void serviceDied(uint64_t cookie, - const wp<android::hidl::base::V1_0::IBase>& who) override; - virtual void dump(std::string& dump) override; + ~InputClassifier(); + + // Called from InputManager + virtual void setMotionClassifierEnabled(bool enabled) override; + private: // Protect access to mMotionClassifier, since it may become null via a hidl callback std::mutex mLock; - std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock); // The next stage to pass input events to sp<InputListenerInterface> mListener; + + std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock); + std::thread mInitializeMotionClassifierThread; + /** + * Set the value of mMotionClassifier. + * This is called from 2 different threads: + * 1) mInitializeMotionClassifierThread, when we have constructed a MotionClassifier + * 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause + * mMotionClassifier to become nullptr. + */ + void setMotionClassifier(std::unique_ptr<MotionClassifierInterface> motionClassifier); + + /** + * The deathRecipient will call setMotionClassifier(null) when the HAL dies. + */ + class HalDeathRecipient : public android::hardware::hidl_death_recipient { + public: + explicit HalDeathRecipient(InputClassifier& parent); + virtual void serviceDied(uint64_t cookie, + const wp<android::hidl::base::V1_0::IBase>& who) override; + + private: + InputClassifier& mParent; + }; + // We retain a reference to death recipient, because the death recipient will be calling + // ~MotionClassifier if the HAL dies. + // If we don't retain a reference, and MotionClassifier is the only owner of the death + // recipient, the serviceDied call will cause death recipient to call its own destructor. + sp<HalDeathRecipient> mHalDeathRecipient; }; } // namespace android diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 44100086c4..b921d954dc 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -45,22 +45,20 @@ #include "InputDispatcher.h" -#include "Connection.h" - #include <errno.h> #include <inttypes.h> #include <limits.h> +#include <sstream> #include <stddef.h> #include <time.h> #include <unistd.h> -#include <sstream> #include <android-base/chrono_utils.h> #include <android-base/stringprintf.h> -#include <binder/Binder.h> #include <log/log.h> -#include <powermanager/PowerManager.h> #include <utils/Trace.h> +#include <powermanager/PowerManager.h> +#include <binder/Binder.h> #define INDENT " " #define INDENT2 " " @@ -69,7 +67,7 @@ using android::base::StringPrintf; -namespace android::inputdispatcher { +namespace android { // Default input dispatching timeout if there is no focused application or paused window // from which to determine an appropriate dispatching timeout. @@ -99,6 +97,10 @@ constexpr std::chrono::milliseconds SLOW_INTERCEPTION_THRESHOLD = 50ms; // Number of recent events to keep for debugging purposes. constexpr size_t RECENT_QUEUE_MAX_SIZE = 10; +// Sequence number for synthesized or injected events. +constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0; + + static inline nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); } @@ -107,23 +109,41 @@ static inline const char* toString(bool value) { return value ? "true" : "false"; } +static std::string dispatchModeToString(int32_t dispatchMode) { + switch (dispatchMode) { + case InputTarget::FLAG_DISPATCH_AS_IS: + return "DISPATCH_AS_IS"; + case InputTarget::FLAG_DISPATCH_AS_OUTSIDE: + return "DISPATCH_AS_OUTSIDE"; + case InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER: + return "DISPATCH_AS_HOVER_ENTER"; + case InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT: + return "DISPATCH_AS_HOVER_EXIT"; + case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT: + return "DISPATCH_AS_SLIPPERY_EXIT"; + case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER: + return "DISPATCH_AS_SLIPPERY_ENTER"; + } + return StringPrintf("%" PRId32, dispatchMode); +} + static inline int32_t getMotionEventActionPointerIndex(int32_t action) { - return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> - AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) + >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } static bool isValidKeyAction(int32_t action) { switch (action) { - case AKEY_EVENT_ACTION_DOWN: - case AKEY_EVENT_ACTION_UP: - return true; - default: - return false; + case AKEY_EVENT_ACTION_DOWN: + case AKEY_EVENT_ACTION_UP: + return true; + default: + return false; } } static bool validateKeyEvent(int32_t action) { - if (!isValidKeyAction(action)) { + if (! isValidKeyAction(action)) { ALOGE("Key event has invalid action code 0x%x", action); return false; } @@ -132,46 +152,46 @@ static bool validateKeyEvent(int32_t action) { static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) { switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_OUTSIDE: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - case AMOTION_EVENT_ACTION_HOVER_EXIT: - case AMOTION_EVENT_ACTION_SCROLL: - return true; - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: { - int32_t index = getMotionEventActionPointerIndex(action); - return index >= 0 && index < pointerCount; - } - case AMOTION_EVENT_ACTION_BUTTON_PRESS: - case AMOTION_EVENT_ACTION_BUTTON_RELEASE: - return actionButton != 0; - default: - return false; + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_MOVE: + case AMOTION_EVENT_ACTION_OUTSIDE: + case AMOTION_EVENT_ACTION_HOVER_ENTER: + case AMOTION_EVENT_ACTION_HOVER_MOVE: + case AMOTION_EVENT_ACTION_HOVER_EXIT: + case AMOTION_EVENT_ACTION_SCROLL: + return true; + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_POINTER_UP: { + int32_t index = getMotionEventActionPointerIndex(action); + return index >= 0 && index < pointerCount; + } + case AMOTION_EVENT_ACTION_BUTTON_PRESS: + case AMOTION_EVENT_ACTION_BUTTON_RELEASE: + return actionButton != 0; + default: + return false; } } static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount, - const PointerProperties* pointerProperties) { - if (!isValidMotionAction(action, actionButton, pointerCount)) { + const PointerProperties* pointerProperties) { + if (! isValidMotionAction(action, actionButton, pointerCount)) { ALOGE("Motion event has invalid action code 0x%x", action); return false; } if (pointerCount < 1 || pointerCount > MAX_POINTERS) { ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %d.", - pointerCount, MAX_POINTERS); + pointerCount, MAX_POINTERS); return false; } BitSet32 pointerIdBits; for (size_t i = 0; i < pointerCount; i++) { int32_t id = pointerProperties[i].id; if (id < 0 || id > MAX_POINTER_ID) { - ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id, - MAX_POINTER_ID); + ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", + id, MAX_POINTER_ID); return false; } if (pointerIdBits.hasBit(id)) { @@ -203,26 +223,23 @@ static void dumpRegion(std::string& dump, const Region& region) { } } -template <typename T, typename U> +template<typename T, typename U> static T getValueByKey(std::unordered_map<U, T>& map, U key) { typename std::unordered_map<U, T>::const_iterator it = map.find(key); return it != map.end() ? it->second : T{}; } + // --- InputDispatcher --- -InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) - : mPolicy(policy), - mPendingEvent(nullptr), - mLastDropReason(DROP_REASON_NOT_DROPPED), - mAppSwitchSawKeyDown(false), - mAppSwitchDueTime(LONG_LONG_MAX), - mNextUnblockedEvent(nullptr), - mDispatchEnabled(false), - mDispatchFrozen(false), - mInputFilterEnabled(false), - mFocusedDisplayId(ADISPLAY_ID_DEFAULT), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { +InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : + mPolicy(policy), + mPendingEvent(nullptr), mLastDropReason(DROP_REASON_NOT_DROPPED), + mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), + mNextUnblockedEvent(nullptr), + mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), + mFocusedDisplayId(ADISPLAY_ID_DEFAULT), + mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); mReporter = createInputReporter(); @@ -298,7 +315,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { // Ready to start a new event. // If we don't already have a pending event, go grab one. - if (!mPendingEvent) { + if (! mPendingEvent) { if (mInboundQueue.isEmpty()) { if (isAppSwitchDue) { // The inbound queue is empty so the app switch key we were waiting @@ -353,59 +370,63 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { } switch (mPendingEvent->type) { - case EventEntry::TYPE_CONFIGURATION_CHANGED: { - ConfigurationChangedEntry* typedEntry = - static_cast<ConfigurationChangedEntry*>(mPendingEvent); - done = dispatchConfigurationChangedLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped - break; + case EventEntry::TYPE_CONFIGURATION_CHANGED: { + ConfigurationChangedEntry* typedEntry = + static_cast<ConfigurationChangedEntry*>(mPendingEvent); + done = dispatchConfigurationChangedLocked(currentTime, typedEntry); + dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped + break; + } + + case EventEntry::TYPE_DEVICE_RESET: { + DeviceResetEntry* typedEntry = + static_cast<DeviceResetEntry*>(mPendingEvent); + done = dispatchDeviceResetLocked(currentTime, typedEntry); + dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped + break; + } + + case EventEntry::TYPE_KEY: { + KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); + if (isAppSwitchDue) { + if (isAppSwitchKeyEvent(typedEntry)) { + resetPendingAppSwitchLocked(true); + isAppSwitchDue = false; + } else if (dropReason == DROP_REASON_NOT_DROPPED) { + dropReason = DROP_REASON_APP_SWITCH; + } } - - case EventEntry::TYPE_DEVICE_RESET: { - DeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent); - done = dispatchDeviceResetLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped - break; + if (dropReason == DROP_REASON_NOT_DROPPED + && isStaleEvent(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; } - - case EventEntry::TYPE_KEY: { - KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); - if (isAppSwitchDue) { - if (isAppSwitchKeyEvent(typedEntry)) { - resetPendingAppSwitchLocked(true); - isAppSwitchDue = false; - } else if (dropReason == DROP_REASON_NOT_DROPPED) { - dropReason = DROP_REASON_APP_SWITCH; - } - } - if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; - } - done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); - break; + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; } + done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); + break; + } - case EventEntry::TYPE_MOTION: { - MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); - if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { - dropReason = DROP_REASON_APP_SWITCH; - } - if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; - } - done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); - break; + case EventEntry::TYPE_MOTION: { + MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); + if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { + dropReason = DROP_REASON_APP_SWITCH; + } + if (dropReason == DROP_REASON_NOT_DROPPED + && isStaleEvent(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; + } + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; } + done = dispatchMotionLocked(currentTime, typedEntry, + &dropReason, nextWakeupTime); + break; + } - default: - ALOG_ASSERT(false); - break; + default: + ALOG_ASSERT(false); + break; } if (done) { @@ -415,7 +436,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { mLastDropReason = dropReason; releasePendingEventLocked(); - *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately + *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } } @@ -425,56 +446,55 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { traceInboundQueueLengthLocked(); switch (entry->type) { - case EventEntry::TYPE_KEY: { - // Optimize app switch latency. - // If the application takes too long to catch up then we drop all events preceding - // the app switch key. - KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); - if (isAppSwitchKeyEvent(keyEntry)) { - if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { - mAppSwitchSawKeyDown = true; - } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - if (mAppSwitchSawKeyDown) { + case EventEntry::TYPE_KEY: { + // Optimize app switch latency. + // If the application takes too long to catch up then we drop all events preceding + // the app switch key. + KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); + if (isAppSwitchKeyEvent(keyEntry)) { + if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { + mAppSwitchSawKeyDown = true; + } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { + if (mAppSwitchSawKeyDown) { #if DEBUG_APP_SWITCH - ALOGD("App switch is pending!"); + ALOGD("App switch is pending!"); #endif - mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; - mAppSwitchSawKeyDown = false; - needWake = true; - } + mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; + mAppSwitchSawKeyDown = false; + needWake = true; } } - break; } - - case EventEntry::TYPE_MOTION: { - // Optimize case where the current application is unresponsive and the user - // decides to touch a window in a different application. - // If the application takes too long to catch up then we drop all events preceding - // the touch into the other window. - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && - (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && - mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY && - mInputTargetWaitApplicationToken != nullptr) { - int32_t displayId = motionEntry->displayId; - int32_t x = - int32_t(motionEntry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = - int32_t(motionEntry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp<InputWindowHandle> touchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y); - if (touchedWindowHandle != nullptr && - touchedWindowHandle->getApplicationToken() != - mInputTargetWaitApplicationToken) { - // User touched a different application than the one we are waiting on. - // Flag the event, and start pruning the input queue. - mNextUnblockedEvent = motionEntry; - needWake = true; - } + break; + } + + case EventEntry::TYPE_MOTION: { + // Optimize case where the current application is unresponsive and the user + // decides to touch a window in a different application. + // If the application takes too long to catch up then we drop all events preceding + // the touch into the other window. + MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); + if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN + && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) + && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY + && mInputTargetWaitApplicationToken != nullptr) { + int32_t displayId = motionEntry->displayId; + int32_t x = int32_t(motionEntry->pointerCoords[0]. + getAxisValue(AMOTION_EVENT_AXIS_X)); + int32_t y = int32_t(motionEntry->pointerCoords[0]. + getAxisValue(AMOTION_EVENT_AXIS_Y)); + sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); + if (touchedWindowHandle != nullptr + && touchedWindowHandle->getApplicationToken() + != mInputTargetWaitApplicationToken) { + // User touched a different application than the one we are waiting on. + // Flag the event, and start pruning the input queue. + mNextUnblockedEvent = motionEntry; + needWake = true; } - break; } + break; + } } return needWake; @@ -488,9 +508,8 @@ void InputDispatcher::addRecentEventLocked(EventEntry* entry) { } } -sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, - int32_t y, bool addOutsideTargets, - bool addPortalWindows) { +sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, + int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) { // Traverse windows from front to back to find touched window. const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId); for (const sp<InputWindowHandle>& windowHandle : windowHandles) { @@ -500,19 +519,18 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display if (windowInfo->visible) { if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - bool isTouchModal = (flags & - (InputWindowInfo::FLAG_NOT_FOCUSABLE | - InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; + bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE + | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { int32_t portalToDisplayId = windowInfo->portalToDisplayId; - if (portalToDisplayId != ADISPLAY_ID_NONE && - portalToDisplayId != displayId) { + if (portalToDisplayId != ADISPLAY_ID_NONE + && portalToDisplayId != displayId) { if (addPortalWindows) { // For the monitoring channels of the display. mTempTouchState.addPortalWindow(windowHandle); } - return findTouchedWindowAtLocked(portalToDisplayId, x, y, - addOutsideTargets, addPortalWindows); + return findTouchedWindowAtLocked( + portalToDisplayId, x, y, addOutsideTargets, addPortalWindows); } // Found window. return windowHandle; @@ -520,9 +538,8 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display } if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { - mTempTouchState.addOrUpdateWindow(windowHandle, - InputTarget::FLAG_DISPATCH_AS_OUTSIDE, - BitSet32(0)); + mTempTouchState.addOrUpdateWindow( + windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0)); } } } @@ -530,7 +547,7 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display return nullptr; } -std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked( +std::vector<InputDispatcher::TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked( int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) { std::vector<TouchedMonitor> touchedMonitors; @@ -539,15 +556,14 @@ std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked( for (const sp<InputWindowHandle>& portalWindow : portalWindows) { const InputWindowInfo* windowInfo = portalWindow->getInfo(); monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId); - addGestureMonitors(monitors, touchedMonitors, -windowInfo->frameLeft, - -windowInfo->frameTop); + addGestureMonitors(monitors, touchedMonitors, + -windowInfo->frameLeft, -windowInfo->frameTop); } return touchedMonitors; } void InputDispatcher::addGestureMonitors(const std::vector<Monitor>& monitors, - std::vector<TouchedMonitor>& outTouchedMonitors, - float xOffset, float yOffset) { + std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset, float yOffset) { if (monitors.empty()) { return; } @@ -560,66 +576,68 @@ void InputDispatcher::addGestureMonitors(const std::vector<Monitor>& monitors, void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { const char* reason; switch (dropReason) { - case DROP_REASON_POLICY: + case DROP_REASON_POLICY: #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("Dropped event because policy consumed it."); + ALOGD("Dropped event because policy consumed it."); #endif - reason = "inbound event was dropped because the policy consumed it"; - break; - case DROP_REASON_DISABLED: - if (mLastDropReason != DROP_REASON_DISABLED) { - ALOGI("Dropped event because input dispatch is disabled."); - } - reason = "inbound event was dropped because input dispatch is disabled"; - break; - case DROP_REASON_APP_SWITCH: - ALOGI("Dropped event because of pending overdue app switch."); - reason = "inbound event was dropped because of pending overdue app switch"; - break; - case DROP_REASON_BLOCKED: - ALOGI("Dropped event because the current application is not responding and the user " - "has started interacting with a different application."); - reason = "inbound event was dropped because the current application is not responding " - "and the user has started interacting with a different application"; - break; - case DROP_REASON_STALE: - ALOGI("Dropped event because it is stale."); - reason = "inbound event was dropped because it is stale"; - break; - default: - ALOG_ASSERT(false); - return; + reason = "inbound event was dropped because the policy consumed it"; + break; + case DROP_REASON_DISABLED: + if (mLastDropReason != DROP_REASON_DISABLED) { + ALOGI("Dropped event because input dispatch is disabled."); + } + reason = "inbound event was dropped because input dispatch is disabled"; + break; + case DROP_REASON_APP_SWITCH: + ALOGI("Dropped event because of pending overdue app switch."); + reason = "inbound event was dropped because of pending overdue app switch"; + break; + case DROP_REASON_BLOCKED: + ALOGI("Dropped event because the current application is not responding and the user " + "has started interacting with a different application."); + reason = "inbound event was dropped because the current application is not responding " + "and the user has started interacting with a different application"; + break; + case DROP_REASON_STALE: + ALOGI("Dropped event because it is stale."); + reason = "inbound event was dropped because it is stale"; + break; + default: + ALOG_ASSERT(false); + return; } switch (entry->type) { - case EventEntry::TYPE_KEY: { + case EventEntry::TYPE_KEY: { + CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); + synthesizeCancelationEventsForAllConnectionsLocked(options); + break; + } + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); + if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { + CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); + synthesizeCancelationEventsForAllConnectionsLocked(options); + } else { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); - break; - } - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } else { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } - break; } + break; + } } } static bool isAppSwitchKeyCode(int32_t keyCode) { - return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL || - keyCode == AKEYCODE_APP_SWITCH; + return keyCode == AKEYCODE_HOME + || keyCode == AKEYCODE_ENDCALL + || keyCode == AKEYCODE_APP_SWITCH; } bool InputDispatcher::isAppSwitchKeyEvent(KeyEntry* keyEntry) { - return !(keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) && isAppSwitchKeyCode(keyEntry->keyCode) && - (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) && - (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); + return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) + && isAppSwitchKeyCode(keyEntry->keyCode) + && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) + && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); } bool InputDispatcher::isAppSwitchPendingLocked() { @@ -659,18 +677,18 @@ bool InputDispatcher::runCommandsLockedInterruptible() { commandEntry->connection.clear(); delete commandEntry; - } while (!mCommandQueue.isEmpty()); + } while (! mCommandQueue.isEmpty()); return true; } -CommandEntry* InputDispatcher::postCommandLocked(Command command) { +InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { CommandEntry* commandEntry = new CommandEntry(command); mCommandQueue.enqueueAtTail(commandEntry); return commandEntry; } void InputDispatcher::drainInboundQueueLocked() { - while (!mInboundQueue.isEmpty()) { + while (! mInboundQueue.isEmpty()) { EventEntry* entry = mInboundQueue.dequeueAtHead(); releaseInboundEventLocked(entry); } @@ -707,7 +725,7 @@ void InputDispatcher::resetKeyRepeatLocked() { } } -KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { +InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { KeyEntry* entry = mKeyRepeatState.lastKeyEntry; // Reuse the repeated key entry if it is otherwise unreferenced. @@ -719,11 +737,10 @@ KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { entry->policyFlags = policyFlags; entry->repeatCount += 1; } else { - KeyEntry* newEntry = - new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, entry->deviceId, - entry->source, entry->displayId, policyFlags, entry->action, - entry->flags, entry->keyCode, entry->scanCode, entry->metaState, - entry->repeatCount + 1, entry->downTime); + KeyEntry* newEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, + entry->deviceId, entry->source, entry->displayId, policyFlags, + entry->action, entry->flags, entry->keyCode, entry->scanCode, + entry->metaState, entry->repeatCount + 1, entry->downTime); mKeyRepeatState.lastKeyEntry = newEntry; entry->release(); @@ -740,8 +757,8 @@ KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { return entry; } -bool InputDispatcher::dispatchConfigurationChangedLocked(nsecs_t currentTime, - ConfigurationChangedEntry* entry) { +bool InputDispatcher::dispatchConfigurationChangedLocked( + nsecs_t currentTime, ConfigurationChangedEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry->eventTime); #endif @@ -750,33 +767,36 @@ bool InputDispatcher::dispatchConfigurationChangedLocked(nsecs_t currentTime, resetKeyRepeatLocked(); // Enqueue a command to run outside the lock to tell the policy that the configuration changed. - CommandEntry* commandEntry = - postCommandLocked(&InputDispatcher::doNotifyConfigurationChangedLockedInterruptible); + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doNotifyConfigurationChangedLockedInterruptible); commandEntry->eventTime = entry->eventTime; return true; } -bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime, DeviceResetEntry* entry) { +bool InputDispatcher::dispatchDeviceResetLocked( + nsecs_t currentTime, DeviceResetEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry->eventTime, - entry->deviceId); + entry->deviceId); #endif - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "device was reset"); + CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, + "device was reset"); options.deviceId = entry->deviceId; synthesizeCancelationEventsForAllConnectionsLocked(options); return true; } bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime) { + DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. - if (!entry->dispatchInProgress) { - if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN && - (entry->policyFlags & POLICY_FLAG_TRUSTED) && - (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { - if (mKeyRepeatState.lastKeyEntry && - mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { + if (! entry->dispatchInProgress) { + if (entry->repeatCount == 0 + && entry->action == AKEY_EVENT_ACTION_DOWN + && (entry->policyFlags & POLICY_FLAG_TRUSTED) + && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { + if (mKeyRepeatState.lastKeyEntry + && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { // We have seen two identical key downs in a row which indicates that the device // driver is automatically generating key repeats itself. We take note of the // repeat here, but we disable our own next key repeat timer since it is clear that @@ -791,7 +811,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, } mKeyRepeatState.lastKeyEntry = entry; entry->refCount += 1; - } else if (!entry->syntheticRepeat) { + } else if (! entry->syntheticRepeat) { resetKeyRepeatLocked(); } @@ -822,11 +842,12 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( - &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); + & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); sp<InputWindowHandle> focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry)); if (focusedWindowHandle != nullptr) { - commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken()); + commandEntry->inputChannel = + getInputChannelLocked(focusedWindowHandle->getToken()); } commandEntry->keyEntry = entry; entry->refCount += 1; @@ -842,17 +863,16 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResult(entry, - *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED - : INPUT_EVENT_INJECTION_FAILED); + setInjectionResult(entry, *dropReason == DROP_REASON_POLICY + ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); mReporter->reportDroppedKey(entry->sequenceNum); return true; } // Identify targets. std::vector<InputTarget> inputTargets; - int32_t injectionResult = - findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); + int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, + entry, inputTargets, nextWakeupTime); if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } @@ -873,19 +893,20 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", " - "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, " - "metaState=0x%x, repeatCount=%d, downTime=%" PRId64, - prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId, - entry->policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, - entry->metaState, entry->repeatCount, entry->downTime); + "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, " + "metaState=0x%x, repeatCount=%d, downTime=%" PRId64, + prefix, + entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags, + entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, + entry->repeatCount, entry->downTime); #endif } -bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime) { +bool InputDispatcher::dispatchMotionLocked( + nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { ATRACE_CALL(); // Preprocessing. - if (!entry->dispatchInProgress) { + if (! entry->dispatchInProgress) { entry->dispatchInProgress = true; logOutboundMotionDetails("dispatchMotion - ", entry); @@ -893,9 +914,8 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* ent // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResult(entry, - *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED - : INPUT_EVENT_INJECTION_FAILED); + setInjectionResult(entry, *dropReason == DROP_REASON_POLICY + ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); return true; } @@ -908,13 +928,12 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* ent int32_t injectionResult; if (isPointerEvent) { // Pointer event. (eg. touchscreen) - injectionResult = - findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, - &conflictingPointerActions); + injectionResult = findTouchedWindowTargetsLocked(currentTime, + entry, inputTargets, nextWakeupTime, &conflictingPointerActions); } else { // Non touch event. (eg. trackball) - injectionResult = - findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); + injectionResult = findFocusedWindowTargetsLocked(currentTime, + entry, inputTargets, nextWakeupTime); } if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; @@ -923,9 +942,9 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* ent setInjectionResult(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) { - CancelationOptions::Mode mode(isPointerEvent - ? CancelationOptions::CANCEL_POINTER_EVENTS - : CancelationOptions::CANCEL_NON_POINTER_EVENTS); + CancelationOptions::Mode mode(isPointerEvent ? + CancelationOptions::CANCEL_POINTER_EVENTS : + CancelationOptions::CANCEL_NON_POINTER_EVENTS); CancelationOptions options(mode, "input event injection failed"); synthesizeCancelationEventsForMonitorsLocked(options); } @@ -945,7 +964,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* ent for (size_t i = 0; i < state.portalWindows.size(); i++) { const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo(); addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, - -windowInfo->frameLeft, -windowInfo->frameTop); + -windowInfo->frameLeft, -windowInfo->frameTop); } } } @@ -954,46 +973,50 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* ent // Dispatch the motion. if (conflictingPointerActions) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "conflicting pointer actions"); + "conflicting pointer actions"); synthesizeCancelationEventsForAllConnectionsLocked(options); } dispatchEventLocked(currentTime, entry, inputTargets); return true; } + void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 - ", policyFlags=0x%x, " - "action=0x%x, actionButton=0x%x, flags=0x%x, " - "metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, - prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId, - entry->policyFlags, entry->action, entry->actionButton, entry->flags, entry->metaState, - entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, - entry->downTime); + ", policyFlags=0x%x, " + "action=0x%x, actionButton=0x%x, flags=0x%x, " + "metaState=0x%x, buttonState=0x%x," + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, + prefix, + entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags, + entry->action, entry->actionButton, entry->flags, + entry->metaState, entry->buttonState, + entry->edgeFlags, entry->xPrecision, entry->yPrecision, + entry->downTime); for (uint32_t i = 0; i < entry->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, entry->pointerProperties[i].id, entry->pointerProperties[i].toolType, - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + "x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " + "orientation=%f", + i, entry->pointerProperties[i].id, + entry->pointerProperties[i].toolType, + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif } -void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, - const std::vector<InputTarget>& inputTargets) { +void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, + EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) { ATRACE_CALL(); #if DEBUG_DISPATCH_CYCLE ALOGD("dispatchEventToCurrentInputTargets"); @@ -1011,17 +1034,18 @@ void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* event } else { #if DEBUG_FOCUS ALOGD("Dropping event delivery to target with channel '%s' because it " - "is no longer registered with the input dispatcher.", - inputTarget.inputChannel->getName().c_str()); + "is no longer registered with the input dispatcher.", + inputTarget.inputChannel->getName().c_str()); #endif } } } -int32_t InputDispatcher::handleTargetsNotReadyLocked( - nsecs_t currentTime, const EventEntry* entry, +int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, + const EventEntry* entry, const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, nsecs_t* nextWakeupTime, const char* reason) { + const sp<InputWindowHandle>& windowHandle, + nsecs_t* nextWakeupTime, const char* reason) { if (applicationHandle == nullptr && windowHandle == nullptr) { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { #if DEBUG_FOCUS @@ -1037,14 +1061,15 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked( if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { #if DEBUG_FOCUS ALOGD("Waiting for application to become ready for input: %s. Reason: %s", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason); + getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), + reason); #endif nsecs_t timeout; if (windowHandle != nullptr) { timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else if (applicationHandle != nullptr) { - timeout = - applicationHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); + timeout = applicationHandle->getDispatchingTimeout( + DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else { timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; } @@ -1069,8 +1094,8 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked( } if (currentTime >= mInputTargetWaitTimeoutTime) { - onANRLocked(currentTime, applicationHandle, windowHandle, entry->eventTime, - mInputTargetWaitStartTime, reason); + onANRLocked(currentTime, applicationHandle, windowHandle, + entry->eventTime, mInputTargetWaitStartTime, reason); // Force poll loop to wake up immediately on next iteration once we get the // ANR response back from the policy. @@ -1092,8 +1117,8 @@ void InputDispatcher::removeWindowByTokenLocked(const sp<IBinder>& token) { } } -void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked( - nsecs_t newTimeout, const sp<InputChannel>& inputChannel) { +void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, + const sp<InputChannel>& inputChannel) { if (newTimeout > 0) { // Extend the timeout. mInputTargetWaitTimeoutTime = now() + newTimeout; @@ -1114,7 +1139,7 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked( if (connection->status == Connection::STATUS_NORMAL) { CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "application not responding"); + "application not responding"); synthesizeCancelationEventsForConnectionLocked(connection, options); } } @@ -1122,7 +1147,8 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked( } } -nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) { +nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( + nsecs_t currentTime) { if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { return currentTime - mInputTargetWaitStartTime; } @@ -1131,7 +1157,7 @@ nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked(nsecs_t current void InputDispatcher::resetANRTimeoutsLocked() { #if DEBUG_FOCUS - ALOGD("Resetting ANR timeouts."); + ALOGD("Resetting ANR timeouts."); #endif // Reset input target wait timeout. @@ -1147,28 +1173,26 @@ void InputDispatcher::resetANRTimeoutsLocked() { int32_t InputDispatcher::getTargetDisplayId(const EventEntry* entry) { int32_t displayId; switch (entry->type) { - case EventEntry::TYPE_KEY: { - const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry); - displayId = typedEntry->displayId; - break; - } - case EventEntry::TYPE_MOTION: { - const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry); - displayId = typedEntry->displayId; - break; - } - default: { - ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type); - return ADISPLAY_ID_NONE; - } + case EventEntry::TYPE_KEY: { + const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry); + displayId = typedEntry->displayId; + break; + } + case EventEntry::TYPE_MOTION: { + const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry); + displayId = typedEntry->displayId; + break; + } + default: { + ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type); + return ADISPLAY_ID_NONE; + } } return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId; } int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, - const EventEntry* entry, - std::vector<InputTarget>& inputTargets, - nsecs_t* nextWakeupTime) { + const EventEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { int32_t injectionResult; std::string reason; @@ -1182,20 +1206,16 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, // then drop the event. if (focusedWindowHandle == nullptr) { if (focusedApplicationHandle != nullptr) { - injectionResult = - handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle, - nullptr, nextWakeupTime, - "Waiting because no window has focus but there is " - "a " - "focused application that may eventually add a " - "window " - "when it finishes starting up."); + injectionResult = handleTargetsNotReadyLocked(currentTime, entry, + focusedApplicationHandle, nullptr, nextWakeupTime, + "Waiting because no window has focus but there is a " + "focused application that may eventually add a window " + "when it finishes starting up."); goto Unresponsive; } ALOGI("Dropping event because there is no focused window or focused application in display " - "%" PRId32 ".", - displayId); + "%" PRId32 ".", displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } @@ -1207,19 +1227,19 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, } // Check whether the window is ready for more input. - reason = checkWindowReadyForMoreInputLocked(currentTime, focusedWindowHandle, entry, "focused"); + reason = checkWindowReadyForMoreInputLocked(currentTime, + focusedWindowHandle, entry, "focused"); if (!reason.empty()) { - injectionResult = - handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle, - focusedWindowHandle, nextWakeupTime, reason.c_str()); + injectionResult = handleTargetsNotReadyLocked(currentTime, entry, + focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str()); goto Unresponsive; } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; addWindowTargetLocked(focusedWindowHandle, - InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0), inputTargets); + InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), + inputTargets); // Done. Failed: @@ -1228,17 +1248,15 @@ Unresponsive: updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findFocusedWindow finished: injectionResult=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, timeSpentWaitingForApplication / 1000000.0); + "timeSpentWaitingForApplication=%0.1fms", + injectionResult, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, - const MotionEntry* entry, - std::vector<InputTarget>& inputTargets, - nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions) { + const MotionEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, + bool* outConflictingPointerActions) { ATRACE_CALL(); enum InjectionPermission { INJECTION_PERMISSION_UNKNOWN, @@ -1268,22 +1286,23 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } bool isSplit = mTempTouchState.split; - bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 && - (mTempTouchState.deviceId != entry->deviceId || - mTempTouchState.source != entry->source || mTempTouchState.displayId != displayId); - bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || - maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || - maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); - bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN || - maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction); + bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 + && (mTempTouchState.deviceId != entry->deviceId + || mTempTouchState.source != entry->source + || mTempTouchState.displayId != displayId); + bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE + || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER + || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); + bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN + || maskedAction == AMOTION_EVENT_ACTION_SCROLL + || isHoverAction); bool wrongDevice = false; if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; if (switchedDevice && mTempTouchState.down && !down && !isHoverAction) { #if DEBUG_FOCUS ALOGD("Dropping event because a pointer for a different device is already down " - "in display %" PRId32, - displayId); + "in display %" PRId32, displayId); #endif // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_FAILED; @@ -1300,8 +1319,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) { #if DEBUG_FOCUS ALOGI("Dropping move event because a pointer for a different device is already active " - "in display %" PRId32, - displayId); + "in display %" PRId32, displayId); #endif // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; @@ -1314,20 +1332,21 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ int32_t pointerIndex = getMotionEventActionPointerIndex(action); - int32_t x = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)); + int32_t x = int32_t(entry->pointerCoords[pointerIndex]. + getAxisValue(AMOTION_EVENT_AXIS_X)); + int32_t y = int32_t(entry->pointerCoords[pointerIndex]. + getAxisValue(AMOTION_EVENT_AXIS_Y)); bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; - sp<InputWindowHandle> newTouchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y, isDown /*addOutsideTargets*/, - true /*addPortalWindows*/); + sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked( + displayId, x, y, isDown /*addOutsideTargets*/, true /*addPortalWindows*/); std::vector<TouchedMonitor> newGestureMonitors = isDown ? findTouchedGestureMonitorsLocked(displayId, mTempTouchState.portalWindows) : std::vector<TouchedMonitor>{}; // Figure out whether splitting will be allowed for this window. - if (newTouchedWindowHandle != nullptr && - newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { + if (newTouchedWindowHandle != nullptr + && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { // New window supports splitting. isSplit = true; } else if (isSplit) { @@ -1344,8 +1363,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) { ALOGI("Dropping event because there is no touchable window or gesture monitor at " - "(%d, %d) in display %" PRId32 ".", - x, y, displayId); + "(%d, %d) in display %" PRId32 ".", x, y, displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } @@ -1383,19 +1401,19 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ // If the pointer is not currently down, then ignore the event. - if (!mTempTouchState.down) { + if (! mTempTouchState.down) { #if DEBUG_FOCUS ALOGD("Dropping event because the pointer is not down or we previously " - "dropped the pointer down event in display %" PRId32, - displayId); + "dropped the pointer down event in display %" PRId32, displayId); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } // Check whether touches should slip outside of the current foreground window. - if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry->pointerCount == 1 && - mTempTouchState.isSlippery()) { + if (maskedAction == AMOTION_EVENT_ACTION_MOVE + && entry->pointerCount == 1 + && mTempTouchState.isSlippery()) { int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); @@ -1403,25 +1421,26 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, mTempTouchState.getFirstForegroundWindowHandle(); sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); - if (oldTouchedWindowHandle != newTouchedWindowHandle && - oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) { + if (oldTouchedWindowHandle != newTouchedWindowHandle + && oldTouchedWindowHandle != nullptr + && newTouchedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32, - oldTouchedWindowHandle->getName().c_str(), - newTouchedWindowHandle->getName().c_str(), displayId); + oldTouchedWindowHandle->getName().c_str(), + newTouchedWindowHandle->getName().c_str(), + displayId); #endif // Make a slippery exit from the old window. mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, - BitSet32(0)); + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0)); // Make a slippery entrance into the new window. if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { isSplit = true; } - int32_t targetFlags = - InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; + int32_t targetFlags = InputTarget::FLAG_FOREGROUND + | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } @@ -1443,22 +1462,20 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (mLastHoverWindowHandle != nullptr) { #if DEBUG_HOVER ALOGD("Sending hover exit event to window %s.", - mLastHoverWindowHandle->getName().c_str()); + mLastHoverWindowHandle->getName().c_str()); #endif mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, - BitSet32(0)); + InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); } // Let the new window know that the hover sequence is starting. if (newHoverWindowHandle != nullptr) { #if DEBUG_HOVER ALOGD("Sending hover enter event to window %s.", - newHoverWindowHandle->getName().c_str()); + newHoverWindowHandle->getName().c_str()); #endif mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, - BitSet32(0)); + InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); } } @@ -1469,7 +1486,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { haveForegroundWindow = true; - if (!checkInjectionPermission(touchedWindow.windowHandle, entry->injectionState)) { + if (! checkInjectionPermission(touchedWindow.windowHandle, + entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; goto Failed; @@ -1479,9 +1497,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, bool hasGestureMonitor = !mTempTouchState.gestureMonitors.empty(); if (!haveForegroundWindow && !hasGestureMonitor) { #if DEBUG_FOCUS - ALOGD("Dropping event because there is no touched foreground window in display %" PRId32 - " or gesture monitor to receive it.", - displayId); + ALOGD("Dropping event because there is no touched foreground window in display %" + PRId32 " or gesture monitor to receive it.", displayId); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; @@ -1503,8 +1520,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle; if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { mTempTouchState.addOrUpdateWindow(inputWindowHandle, - InputTarget::FLAG_ZERO_COORDS, - BitSet32(0)); + InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); } } } @@ -1515,13 +1531,11 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { // Check whether the window is ready for more input. - std::string reason = - checkWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, - entry, "touched"); + std::string reason = checkWindowReadyForMoreInputLocked(currentTime, + touchedWindow.windowHandle, entry, "touched"); if (!reason.empty()) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, nullptr, - touchedWindow.windowHandle, - nextWakeupTime, reason.c_str()); + injectionResult = handleTargetsNotReadyLocked(currentTime, entry, + nullptr, touchedWindow.windowHandle, nextWakeupTime, reason.c_str()); goto Unresponsive; } } @@ -1541,15 +1555,14 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, getWindowHandlesLocked(displayId); for (const sp<InputWindowHandle>& windowHandle : windowHandles) { const InputWindowInfo* info = windowHandle->getInfo(); - if (info->displayId == displayId && - windowHandle->getInfo()->layoutParamsType == InputWindowInfo::TYPE_WALLPAPER) { - mTempTouchState - .addOrUpdateWindow(windowHandle, - InputTarget::FLAG_WINDOW_IS_OBSCURED | - InputTarget:: - FLAG_WINDOW_IS_PARTIALLY_OBSCURED | - InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0)); + if (info->displayId == displayId + && windowHandle->getInfo()->layoutParamsType + == InputWindowInfo::TYPE_WALLPAPER) { + mTempTouchState.addOrUpdateWindow(windowHandle, + InputTarget::FLAG_WINDOW_IS_OBSCURED + | InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED + | InputTarget::FLAG_DISPATCH_AS_IS, + BitSet32(0)); } } } @@ -1560,12 +1573,12 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.pointerIds, inputTargets); + touchedWindow.pointerIds, inputTargets); } for (const TouchedMonitor& touchedMonitor : mTempTouchState.gestureMonitors) { addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset, - touchedMonitor.yOffset, inputTargets); + touchedMonitor.yOffset, inputTargets); } // Drop the outside or hover touch windows since we will not care about them @@ -1601,14 +1614,14 @@ Failed: *outConflictingPointerActions = true; } mTempTouchState.reset(); - if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || - maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { + if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER + || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { mTempTouchState.deviceId = entry->deviceId; mTempTouchState.source = entry->source; mTempTouchState.displayId = displayId; } - } else if (maskedAction == AMOTION_EVENT_ACTION_UP || - maskedAction == AMOTION_EVENT_ACTION_CANCEL) { + } else if (maskedAction == AMOTION_EVENT_ACTION_UP + || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. mTempTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { @@ -1625,7 +1638,7 @@ Failed: int32_t pointerIndex = getMotionEventActionPointerIndex(action); uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - for (size_t i = 0; i < mTempTouchState.windows.size();) { + for (size_t i = 0; i < mTempTouchState.windows.size(); ) { TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { touchedWindow.pointerIds.clearBit(pointerId); @@ -1670,15 +1683,14 @@ Unresponsive: updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); + "timeSpentWaitingForApplication=%0.1fms", + injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, - std::vector<InputTarget>& inputTargets) { + int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) { sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken()); if (inputChannel == nullptr) { ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str()); @@ -1689,8 +1701,8 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH InputTarget target; target.inputChannel = inputChannel; target.flags = targetFlags; - target.xOffset = -windowInfo->frameLeft; - target.yOffset = -windowInfo->frameTop; + target.xOffset = - windowInfo->frameLeft; + target.yOffset = - windowInfo->frameTop; target.globalScaleFactor = windowInfo->globalScaleFactor; target.windowXScale = windowInfo->windowXScale; target.windowYScale = windowInfo->windowYScale; @@ -1699,8 +1711,8 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH } void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, - int32_t displayId, float xOffset, - float yOffset) { + int32_t displayId, float xOffset, float yOffset) { + std::unordered_map<int32_t, std::vector<Monitor>>::const_iterator it = mGlobalMonitorsByDisplay.find(displayId); @@ -1712,9 +1724,8 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& } } -void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xOffset, - float yOffset, - std::vector<InputTarget>& inputTargets) { +void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, + float xOffset, float yOffset, std::vector<InputTarget>& inputTargets) { InputTarget target; target.inputChannel = monitor.inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; @@ -1726,27 +1737,28 @@ void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xO } bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, - const InjectionState* injectionState) { - if (injectionState && - (windowHandle == nullptr || - windowHandle->getInfo()->ownerUid != injectionState->injectorUid) && - !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { + const InjectionState* injectionState) { + if (injectionState + && (windowHandle == nullptr + || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) + && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { if (windowHandle != nullptr) { ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " - "owned by uid %d", - injectionState->injectorPid, injectionState->injectorUid, - windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid); + "owned by uid %d", + injectionState->injectorPid, injectionState->injectorUid, + windowHandle->getName().c_str(), + windowHandle->getInfo()->ownerUid); } else { ALOGW("Permission denied: injecting event from pid %d uid %d", - injectionState->injectorPid, injectionState->injectorUid); + injectionState->injectorPid, injectionState->injectorUid); } return false; } return true; } -bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, - int32_t x, int32_t y) const { +bool InputDispatcher::isWindowObscuredAtPointLocked( + const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const { int32_t displayId = windowHandle->getInfo()->displayId; const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId); for (const sp<InputWindowHandle>& otherHandle : windowHandles) { @@ -1755,14 +1767,16 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& } const InputWindowInfo* otherInfo = otherHandle->getInfo(); - if (otherInfo->displayId == displayId && otherInfo->visible && - !otherInfo->isTrustedOverlay() && otherInfo->frameContainsPoint(x, y)) { + if (otherInfo->displayId == displayId + && otherInfo->visible && !otherInfo->isTrustedOverlay() + && otherInfo->frameContainsPoint(x, y)) { return true; } } return false; } + bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const { int32_t displayId = windowHandle->getInfo()->displayId; const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId); @@ -1773,47 +1787,45 @@ bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& window } const InputWindowInfo* otherInfo = otherHandle->getInfo(); - if (otherInfo->displayId == displayId && otherInfo->visible && - !otherInfo->isTrustedOverlay() && otherInfo->overlaps(windowInfo)) { + if (otherInfo->displayId == displayId + && otherInfo->visible && !otherInfo->isTrustedOverlay() + && otherInfo->overlaps(windowInfo)) { return true; } } return false; } -std::string InputDispatcher::checkWindowReadyForMoreInputLocked( - nsecs_t currentTime, const sp<InputWindowHandle>& windowHandle, - const EventEntry* eventEntry, const char* targetType) { +std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, + const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, + const char* targetType) { // If the window is paused then keep waiting. if (windowHandle->getInfo()->paused) { return StringPrintf("Waiting because the %s window is paused.", targetType); } // If the window's connection is not registered then keep waiting. - ssize_t connectionIndex = - getConnectionIndexLocked(getInputChannelLocked(windowHandle->getToken())); + ssize_t connectionIndex = getConnectionIndexLocked( + getInputChannelLocked(windowHandle->getToken())); if (connectionIndex < 0) { return StringPrintf("Waiting because the %s window's input channel is not " - "registered with the input dispatcher. The window may be in the " - "process " - "of being removed.", - targetType); + "registered with the input dispatcher. The window may be in the process " + "of being removed.", targetType); } // If the connection is dead then keep waiting. sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->status != Connection::STATUS_NORMAL) { return StringPrintf("Waiting because the %s window's input connection is %s." - "The window may be in the process of being removed.", - targetType, connection->getStatusLabel()); + "The window may be in the process of being removed.", targetType, + connection->getStatusLabel()); } // If the connection is backed up then keep waiting. if (connection->inputPublisherBlocked) { return StringPrintf("Waiting because the %s window's input channel is full. " - "Outbound queue length: %d. Wait queue length: %d.", - targetType, connection->outboundQueue.count(), - connection->waitQueue.count()); + "Outbound queue length: %d. Wait queue length: %d.", + targetType, connection->outboundQueue.count(), connection->waitQueue.count()); } // Ensure that the dispatch queues aren't too far backed up for this event. @@ -1831,11 +1843,9 @@ std::string InputDispatcher::checkWindowReadyForMoreInputLocked( // prior input events. if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) { return StringPrintf("Waiting to send key event because the %s window has not " - "finished processing all of the input events that were previously " - "delivered to it. Outbound queue length: %d. Wait queue length: " - "%d.", - targetType, connection->outboundQueue.count(), - connection->waitQueue.count()); + "finished processing all of the input events that were previously " + "delivered to it. Outbound queue length: %d. Wait queue length: %d.", + targetType, connection->outboundQueue.count(), connection->waitQueue.count()); } } else { // Touch events can always be sent to a window immediately because the user intended @@ -1853,17 +1863,15 @@ std::string InputDispatcher::checkWindowReadyForMoreInputLocked( // The one case where we pause input event delivery is when the wait queue is piling // up with lots of events because the application is not responding. // This condition ensures that ANRs are detected reliably. - if (!connection->waitQueue.isEmpty() && - currentTime >= connection->waitQueue.head->deliveryTime + STREAM_AHEAD_EVENT_TIMEOUT) { + if (!connection->waitQueue.isEmpty() + && currentTime >= connection->waitQueue.head->deliveryTime + + STREAM_AHEAD_EVENT_TIMEOUT) { return StringPrintf("Waiting to send non-key event because the %s window has not " - "finished processing certain input events that were delivered to " - "it over " - "%0.1fms ago. Wait queue length: %d. Wait queue head age: " - "%0.1fms.", - targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f, - connection->waitQueue.count(), - (currentTime - connection->waitQueue.head->deliveryTime) * - 0.000001f); + "finished processing certain input events that were delivered to it over " + "%0.1fms ago. Wait queue length: %d. Wait queue head age: %0.1fms.", + targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f, + connection->waitQueue.count(), + (currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f); } } return ""; @@ -1904,50 +1912,50 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { int32_t eventType = USER_ACTIVITY_EVENT_OTHER; switch (eventEntry->type) { - case EventEntry::TYPE_MOTION: { - const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry); - if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { - return; - } + case EventEntry::TYPE_MOTION: { + const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry); + if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { + return; + } - if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { - eventType = USER_ACTIVITY_EVENT_TOUCH; - } - break; + if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { + eventType = USER_ACTIVITY_EVENT_TOUCH; } - case EventEntry::TYPE_KEY: { - const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry); - if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { - return; - } - eventType = USER_ACTIVITY_EVENT_BUTTON; - break; + break; + } + case EventEntry::TYPE_KEY: { + const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry); + if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { + return; } + eventType = USER_ACTIVITY_EVENT_BUTTON; + break; + } } - CommandEntry* commandEntry = - postCommandLocked(&InputDispatcher::doPokeUserActivityLockedInterruptible); + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doPokeUserActivityLockedInterruptible); commandEntry->eventTime = eventEntry->eventTime; commandEntry->userActivityEventType = eventType; } void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, - EventEntry* eventEntry, - const InputTarget* inputTarget) { + const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { if (ATRACE_ENABLED()) { - std::string message = - StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", - connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + std::string message = StringPrintf( + "prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", + connection->getInputChannelName().c_str(), eventEntry->sequenceNum); ATRACE_NAME(message.c_str()); } #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " - "xOffset=%f, yOffset=%f, globalScaleFactor=%f, " - "windowScaleFactor=(%f, %f), pointerIds=0x%x", - connection->getInputChannelName().c_str(), inputTarget->flags, inputTarget->xOffset, - inputTarget->yOffset, inputTarget->globalScaleFactor, inputTarget->windowXScale, - inputTarget->windowYScale, inputTarget->pointerIds.value); + "xOffset=%f, yOffset=%f, globalScaleFactor=%f, " + "windowScaleFactor=(%f, %f), pointerIds=0x%x", + connection->getInputChannelName().c_str(), inputTarget->flags, + inputTarget->xOffset, inputTarget->yOffset, + inputTarget->globalScaleFactor, + inputTarget->windowXScale, inputTarget->windowYScale, + inputTarget->pointerIds.value); #endif // Skip this event if the connection status is not normal. @@ -1955,7 +1963,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, if (connection->status != Connection::STATUS_NORMAL) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Dropping event because the channel status is %s", - connection->getInputChannelName().c_str(), connection->getStatusLabel()); + connection->getInputChannelName().c_str(), connection->getStatusLabel()); #endif return; } @@ -1966,16 +1974,18 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry); if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { - MotionEntry* splitMotionEntry = - splitMotionEvent(originalMotionEntry, inputTarget->pointerIds); + MotionEntry* splitMotionEntry = splitMotionEvent( + originalMotionEntry, inputTarget->pointerIds); if (!splitMotionEntry) { return; // split event was dropped } #if DEBUG_FOCUS - ALOGD("channel '%s' ~ Split motion event.", connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ Split motion event.", + connection->getInputChannelName().c_str()); logOutboundMotionDetails(" ", splitMotionEntry); #endif - enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget); + enqueueDispatchEntriesLocked(currentTime, connection, + splitMotionEntry, inputTarget); splitMotionEntry->release(); return; } @@ -1986,14 +1996,11 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, } void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, - const sp<Connection>& connection, - EventEntry* eventEntry, - const InputTarget* inputTarget) { + const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { if (ATRACE_ENABLED()) { - std::string message = - StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 - ")", - connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + std::string message = StringPrintf( + "enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", + connection->getInputChannelName().c_str(), eventEntry->sequenceNum); ATRACE_NAME(message.c_str()); } @@ -2001,17 +2008,17 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, // Enqueue dispatch entries for the requested modes. enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); + InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_OUTSIDE); + InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); + InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_IS); + InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); // If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty && !connection->outboundQueue.isEmpty()) { @@ -2019,14 +2026,14 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, } } -void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection, - EventEntry* eventEntry, - const InputTarget* inputTarget, - int32_t dispatchMode) { +void InputDispatcher::enqueueDispatchEntryLocked( + const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, + int32_t dispatchMode) { if (ATRACE_ENABLED()) { - std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)", - connection->getInputChannelName().c_str(), - dispatchModeToString(dispatchMode).c_str()); + std::string message = StringPrintf( + "enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)", + connection->getInputChannelName().c_str(), + dispatchModeToString(dispatchMode).c_str()); ATRACE_NAME(message.c_str()); } int32_t inputTargetFlags = inputTarget->flags; @@ -2037,81 +2044,78 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio // This is a new event. // Enqueue a new dispatch entry onto the outbound queue for this connection. - DispatchEntry* dispatchEntry = - new DispatchEntry(eventEntry, // increments ref - inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, - inputTarget->globalScaleFactor, inputTarget->windowXScale, - inputTarget->windowYScale); + DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref + inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, + inputTarget->globalScaleFactor, inputTarget->windowXScale, + inputTarget->windowYScale); // Apply target flags and update the connection's input state. switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - dispatchEntry->resolvedAction = keyEntry->action; - dispatchEntry->resolvedFlags = keyEntry->flags; + case EventEntry::TYPE_KEY: { + KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); + dispatchEntry->resolvedAction = keyEntry->action; + dispatchEntry->resolvedFlags = keyEntry->flags; - if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction, - dispatchEntry->resolvedFlags)) { + if (!connection->inputState.trackKey(keyEntry, + dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", + connection->getInputChannelName().c_str()); #endif - delete dispatchEntry; - return; // skip the inconsistent event - } - break; + delete dispatchEntry; + return; // skip the inconsistent event + } + break; + } + + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); + if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; + } else { + dispatchEntry->resolvedAction = motionEntry->action; } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); - if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; - } else { - dispatchEntry->resolvedAction = motionEntry->action; - } - if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE && - !connection->inputState.isHovering(motionEntry->deviceId, motionEntry->source, - motionEntry->displayId)) { + if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE + && !connection->inputState.isHovering( + motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) { #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter " - "event", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event", + connection->getInputChannelName().c_str()); #endif - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; + } - dispatchEntry->resolvedFlags = motionEntry->flags; - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { - dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; - } - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) { - dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; - } + dispatchEntry->resolvedFlags = motionEntry->flags; + if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { + dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; + } + if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) { + dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + } - if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction, - dispatchEntry->resolvedFlags)) { + if (!connection->inputState.trackMotion(motionEntry, + dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion " - "event", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event", + connection->getInputChannelName().c_str()); #endif - delete dispatchEntry; - return; // skip the inconsistent event - } + delete dispatchEntry; + return; // skip the inconsistent event + } - dispatchPointerDownOutsideFocus(motionEntry->source, dispatchEntry->resolvedAction, - inputTarget->inputChannel->getToken()); + dispatchPointerDownOutsideFocus(motionEntry->source, + dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken()); - break; - } + break; + } } // Remember that we are waiting for this dispatch to complete. @@ -2122,10 +2126,11 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio // Enqueue the dispatch entry. connection->outboundQueue.enqueueAtTail(dispatchEntry); traceOutboundQueueLength(connection); + } void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, - const sp<IBinder>& newToken) { + const sp<IBinder>& newToken) { int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; uint32_t maskedSource = source & AINPUT_SOURCE_CLASS_MASK; if (maskedSource != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) { @@ -2146,24 +2151,25 @@ void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t a return; } - CommandEntry* commandEntry = - postCommandLocked(&InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible); + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible); commandEntry->newToken = newToken; } void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection) { + const sp<Connection>& connection) { if (ATRACE_ENABLED()) { std::string message = StringPrintf("startDispatchCycleLocked(inputChannel=%s)", - connection->getInputChannelName().c_str()); + connection->getInputChannelName().c_str()); ATRACE_NAME(message.c_str()); } #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ startDispatchCycle", + connection->getInputChannelName().c_str()); #endif - while (connection->status == Connection::STATUS_NORMAL && - !connection->outboundQueue.isEmpty()) { + while (connection->status == Connection::STATUS_NORMAL + && !connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.head; dispatchEntry->deliveryTime = currentTime; @@ -2171,77 +2177,70 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - - // Publish the key event. - status = connection->inputPublisher - .publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, - keyEntry->source, keyEntry->displayId, - dispatchEntry->resolvedAction, - dispatchEntry->resolvedFlags, keyEntry->keyCode, - keyEntry->scanCode, keyEntry->metaState, - keyEntry->repeatCount, keyEntry->downTime, - keyEntry->eventTime); - break; - } + case EventEntry::TYPE_KEY: { + KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); - - PointerCoords scaledCoords[MAX_POINTERS]; - const PointerCoords* usingCoords = motionEntry->pointerCoords; - - // Set the X and Y offset depending on the input source. - float xOffset, yOffset; - if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && - !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { - float globalScaleFactor = dispatchEntry->globalScaleFactor; - float wxs = dispatchEntry->windowXScale; - float wys = dispatchEntry->windowYScale; - xOffset = dispatchEntry->xOffset * wxs; - yOffset = dispatchEntry->yOffset * wys; - if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) { - for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i] = motionEntry->pointerCoords[i]; - scaledCoords[i].scale(globalScaleFactor, wxs, wys); - } - usingCoords = scaledCoords; - } - } else { - xOffset = 0.0f; - yOffset = 0.0f; + // Publish the key event. + status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, + keyEntry->deviceId, keyEntry->source, keyEntry->displayId, + dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, + keyEntry->keyCode, keyEntry->scanCode, + keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, + keyEntry->eventTime); + break; + } - // We don't want the dispatch target to know. - if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { - for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i].clear(); - } - usingCoords = scaledCoords; + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); + + PointerCoords scaledCoords[MAX_POINTERS]; + const PointerCoords* usingCoords = motionEntry->pointerCoords; + + // Set the X and Y offset depending on the input source. + float xOffset, yOffset; + if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) + && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { + float globalScaleFactor = dispatchEntry->globalScaleFactor; + float wxs = dispatchEntry->windowXScale; + float wys = dispatchEntry->windowYScale; + xOffset = dispatchEntry->xOffset * wxs; + yOffset = dispatchEntry->yOffset * wys; + if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) { + for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { + scaledCoords[i] = motionEntry->pointerCoords[i]; + scaledCoords[i].scale(globalScaleFactor, wxs, wys); } + usingCoords = scaledCoords; } + } else { + xOffset = 0.0f; + yOffset = 0.0f; - // Publish the motion event. - status = connection->inputPublisher - .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, - motionEntry->source, motionEntry->displayId, - dispatchEntry->resolvedAction, - motionEntry->actionButton, - dispatchEntry->resolvedFlags, - motionEntry->edgeFlags, motionEntry->metaState, - motionEntry->buttonState, - motionEntry->classification, xOffset, yOffset, - motionEntry->xPrecision, - motionEntry->yPrecision, motionEntry->downTime, - motionEntry->eventTime, - motionEntry->pointerCount, - motionEntry->pointerProperties, usingCoords); - break; + // We don't want the dispatch target to know. + if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { + for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { + scaledCoords[i].clear(); + } + usingCoords = scaledCoords; + } } - default: - ALOG_ASSERT(false); - return; + // Publish the motion event. + status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, + motionEntry->deviceId, motionEntry->source, motionEntry->displayId, + dispatchEntry->resolvedAction, motionEntry->actionButton, + dispatchEntry->resolvedFlags, motionEntry->edgeFlags, + motionEntry->metaState, motionEntry->buttonState, motionEntry->classification, + xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, + motionEntry->downTime, motionEntry->eventTime, + motionEntry->pointerCount, motionEntry->pointerProperties, + usingCoords); + break; + } + + default: + ALOG_ASSERT(false); + return; } // Check the result. @@ -2249,25 +2248,24 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, if (status == WOULD_BLOCK) { if (connection->waitQueue.isEmpty()) { ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " - "This is unexpected because the wait queue is empty, so the pipe " - "should be empty and we shouldn't have any problems writing an " - "event to it, status=%d", - connection->getInputChannelName().c_str(), status); + "This is unexpected because the wait queue is empty, so the pipe " + "should be empty and we shouldn't have any problems writing an " + "event to it, status=%d", connection->getInputChannelName().c_str(), + status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } else { // Pipe is full and we are waiting for the app to finish process some events // before sending more events to it. #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Could not publish event because the pipe is full, " - "waiting for the application to catch up", - connection->getInputChannelName().c_str()); + "waiting for the application to catch up", + connection->getInputChannelName().c_str()); #endif connection->inputPublisherBlocked = true; } } else { ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " - "status=%d", - connection->getInputChannelName().c_str(), status); + "status=%d", connection->getInputChannelName().c_str(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } return; @@ -2282,17 +2280,16 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, uint32_t seq, - bool handled) { + const sp<Connection>& connection, uint32_t seq, bool handled) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s", - connection->getInputChannelName().c_str(), seq, toString(handled)); + connection->getInputChannelName().c_str(), seq, toString(handled)); #endif connection->inputPublisherBlocked = false; - if (connection->status == Connection::STATUS_BROKEN || - connection->status == Connection::STATUS_ZOMBIE) { + if (connection->status == Connection::STATUS_BROKEN + || connection->status == Connection::STATUS_ZOMBIE) { return; } @@ -2301,11 +2298,10 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, } void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, - bool notify) { + const sp<Connection>& connection, bool notify) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s", - connection->getInputChannelName().c_str(), toString(notify)); + connection->getInputChannelName().c_str(), toString(notify)); #endif // Clear the dispatch queues. @@ -2349,8 +2345,7 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); if (connectionIndex < 0) { ALOGE("Received spurious receive callback for unknown input channel. " - "fd=%d, events=0x%x", - fd, events); + "fd=%d, events=0x%x", fd, events); return 0; // remove the callback } @@ -2359,8 +2354,7 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { if (!(events & ALOOPER_EVENT_INPUT)) { ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " - "events=0x%x", - connection->getInputChannelName().c_str(), events); + "events=0x%x", connection->getInputChannelName().c_str(), events); return 1; } @@ -2387,7 +2381,7 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { notify = status != DEAD_OBJECT || !connection->monitor; if (notify) { ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d", - connection->getInputChannelName().c_str(), status); + connection->getInputChannelName().c_str(), status); } } else { // Monitor channels are never explicitly unregistered. @@ -2396,25 +2390,25 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { notify = !connection->monitor; if (notify) { ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. " - "events=0x%x", - connection->getInputChannelName().c_str(), events); + "events=0x%x", connection->getInputChannelName().c_str(), events); } } // Unregister the channel. d->unregisterInputChannelLocked(connection->inputChannel, notify); return 0; // remove the callback - } // release lock + } // release lock } -void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( +void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked ( const CancelationOptions& options) { for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - synthesizeCancelationEventsForConnectionLocked(mConnectionsByFd.valueAt(i), options); + synthesizeCancelationEventsForConnectionLocked( + mConnectionsByFd.valueAt(i), options); } } -void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked( +void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked ( const CancelationOptions& options) { synthesizeCancelationEventsForMonitorsLocked(options, mGlobalMonitorsByDisplay); synthesizeCancelationEventsForMonitorsLocked(options, mGestureMonitorsByDisplay); @@ -2435,7 +2429,8 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( const sp<InputChannel>& channel, const CancelationOptions& options) { ssize_t index = getConnectionIndexLocked(channel); if (index >= 0) { - synthesizeCancelationEventsForConnectionLocked(mConnectionsByFd.valueAt(index), options); + synthesizeCancelationEventsForConnectionLocked( + mConnectionsByFd.valueAt(index), options); } } @@ -2448,31 +2443,32 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( nsecs_t currentTime = now(); std::vector<EventEntry*> cancelationEvents; - connection->inputState.synthesizeCancelationEvents(currentTime, cancelationEvents, options); + connection->inputState.synthesizeCancelationEvents(currentTime, + cancelationEvents, options); if (!cancelationEvents.empty()) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync " - "with reality: %s, mode=%d.", - connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason, - options.mode); + "with reality: %s, mode=%d.", + connection->getInputChannelName().c_str(), cancelationEvents.size(), + options.reason, options.mode); #endif for (size_t i = 0; i < cancelationEvents.size(); i++) { EventEntry* cancelationEventEntry = cancelationEvents[i]; switch (cancelationEventEntry->type) { - case EventEntry::TYPE_KEY: - logOutboundKeyDetails("cancel - ", - static_cast<KeyEntry*>(cancelationEventEntry)); - break; - case EventEntry::TYPE_MOTION: - logOutboundMotionDetails("cancel - ", - static_cast<MotionEntry*>(cancelationEventEntry)); - break; + case EventEntry::TYPE_KEY: + logOutboundKeyDetails("cancel - ", + static_cast<KeyEntry*>(cancelationEventEntry)); + break; + case EventEntry::TYPE_MOTION: + logOutboundMotionDetails("cancel - ", + static_cast<MotionEntry*>(cancelationEventEntry)); + break; } InputTarget target; - sp<InputWindowHandle> windowHandle = - getWindowHandleLocked(connection->inputChannel->getToken()); + sp<InputWindowHandle> windowHandle = getWindowHandleLocked( + connection->inputChannel->getToken()); if (windowHandle != nullptr) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); target.xOffset = -windowInfo->frameLeft; @@ -2489,7 +2485,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( target.flags = InputTarget::FLAG_DISPATCH_AS_IS; enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref - &target, InputTarget::FLAG_DISPATCH_AS_IS); + &target, InputTarget::FLAG_DISPATCH_AS_IS); cancelationEventEntry->release(); } @@ -2498,8 +2494,8 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } } -MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, - BitSet32 pointerIds) { +InputDispatcher::MotionEntry* +InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { ALOG_ASSERT(pointerIds.value != 0); uint32_t splitPointerIndexMap[MAX_POINTERS]; @@ -2510,7 +2506,7 @@ MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotion uint32_t splitPointerCount = 0; for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; - originalPointerIndex++) { + originalPointerIndex++) { const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); @@ -2530,16 +2526,16 @@ MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotion // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers // in this way. ALOGW("Dropping split motion event because the pointer count is %d but " - "we expected there to be %d pointers. This probably means we received " - "a broken sequence of pointer ids from the input device.", - splitPointerCount, pointerIds.count()); + "we expected there to be %d pointers. This probably means we received " + "a broken sequence of pointer ids from the input device.", + splitPointerCount, pointerIds.count()); return nullptr; } int32_t action = originalMotionEntry->action; int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN || - maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { + if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN + || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; @@ -2548,16 +2544,15 @@ MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotion if (pointerIds.count() == 1) { // The first/last pointer went down/up. action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - ? AMOTION_EVENT_ACTION_DOWN - : AMOTION_EVENT_ACTION_UP; + ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; } else { // A secondary pointer went down/up. uint32_t splitPointerIndex = 0; while (pointerId != uint32_t(splitPointerProperties[splitPointerIndex].id)) { splitPointerIndex += 1; } - action = maskedAction | - (splitPointerIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + action = maskedAction | (splitPointerIndex + << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } } else { // An unrelated pointer changed. @@ -2565,16 +2560,24 @@ MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotion } } - MotionEntry* splitMotionEntry = - new MotionEntry(originalMotionEntry->sequenceNum, originalMotionEntry->eventTime, - originalMotionEntry->deviceId, originalMotionEntry->source, - originalMotionEntry->displayId, originalMotionEntry->policyFlags, - action, originalMotionEntry->actionButton, originalMotionEntry->flags, - originalMotionEntry->metaState, originalMotionEntry->buttonState, - originalMotionEntry->classification, originalMotionEntry->edgeFlags, - originalMotionEntry->xPrecision, originalMotionEntry->yPrecision, - originalMotionEntry->downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords, 0, 0); + MotionEntry* splitMotionEntry = new MotionEntry( + originalMotionEntry->sequenceNum, + originalMotionEntry->eventTime, + originalMotionEntry->deviceId, + originalMotionEntry->source, + originalMotionEntry->displayId, + originalMotionEntry->policyFlags, + action, + originalMotionEntry->actionButton, + originalMotionEntry->flags, + originalMotionEntry->metaState, + originalMotionEntry->buttonState, + originalMotionEntry->classification, + originalMotionEntry->edgeFlags, + originalMotionEntry->xPrecision, + originalMotionEntry->yPrecision, + originalMotionEntry->downTime, + splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0); if (originalMotionEntry->injectionState) { splitMotionEntry->injectionState = originalMotionEntry->injectionState; @@ -2610,7 +2613,7 @@ void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChange * This will potentially overwrite keyCode and metaState. */ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int32_t action, - int32_t& keyCode, int32_t& metaState) { + int32_t& keyCode, int32_t& metaState) { if (metaState & AMETA_META_ON && action == AKEY_EVENT_ACTION_DOWN) { int32_t newKeyCode = AKEYCODE_UNKNOWN; if (keyCode == AKEYCODE_DEL) { @@ -2642,12 +2645,12 @@ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int3 void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyKey - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 - "policyFlags=0x%x, action=0x%x, " - "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64, - args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, - args->action, args->flags, args->keyCode, args->scanCode, args->metaState, - args->downTime); + ALOGD("notifyKey - eventTime=%" PRId64 + ", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, " + "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64, + args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, + args->action, args->flags, args->keyCode, args->scanCode, + args->metaState, args->downTime); #endif if (!validateKeyEvent(args->action)) { return; @@ -2673,14 +2676,15 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState); KeyEvent event; - event.initialize(args->deviceId, args->source, args->displayId, args->action, flags, keyCode, - args->scanCode, metaState, repeatCount, args->downTime, args->eventTime); + event.initialize(args->deviceId, args->source, args->displayId, args->action, + flags, keyCode, args->scanCode, metaState, repeatCount, + args->downTime, args->eventTime); android::base::Timer t; mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + std::to_string(t.duration().count()).c_str()); } bool needWake; @@ -2698,10 +2702,10 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { mLock.lock(); } - KeyEntry* newEntry = - new KeyEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, - args->displayId, policyFlags, args->action, flags, keyCode, - args->scanCode, metaState, repeatCount, args->downTime); + KeyEntry* newEntry = new KeyEntry(args->sequenceNum, args->eventTime, + args->deviceId, args->source, args->displayId, policyFlags, + args->action, flags, keyCode, args->scanCode, + metaState, repeatCount, args->downTime); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); @@ -2719,31 +2723,32 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 - ", policyFlags=0x%x, " - "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, - args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, - args->action, args->actionButton, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); + ", policyFlags=0x%x, " + "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, + args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, + args->action, args->actionButton, args->flags, args->metaState, args->buttonState, + args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, args->pointerProperties[i].id, args->pointerProperties[i].toolType, - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + "x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " + "orientation=%f", + i, args->pointerProperties[i].id, + args->pointerProperties[i].toolType, + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif - if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount, - args->pointerProperties)) { + if (!validateMotionEvent(args->action, args->actionButton, + args->pointerCount, args->pointerProperties)) { return; } @@ -2754,7 +2759,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + std::to_string(t.duration().count()).c_str()); } bool needWake; @@ -2765,11 +2770,12 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - event.initialize(args->deviceId, args->source, args->displayId, args->action, - args->actionButton, args->flags, args->edgeFlags, args->metaState, - args->buttonState, args->classification, 0, 0, args->xPrecision, - args->yPrecision, args->downTime, args->eventTime, args->pointerCount, - args->pointerProperties, args->pointerCoords); + event.initialize(args->deviceId, args->source, args->displayId, + args->action, args->actionButton, + args->flags, args->edgeFlags, args->metaState, args->buttonState, + args->classification, 0, 0, args->xPrecision, args->yPrecision, + args->downTime, args->eventTime, + args->pointerCount, args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { @@ -2780,13 +2786,12 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { } // Just enqueue a new motion event. - MotionEntry* newEntry = - new MotionEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, - args->displayId, policyFlags, args->action, args->actionButton, - args->flags, args->metaState, args->buttonState, - args->classification, args->edgeFlags, args->xPrecision, - args->yPrecision, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords, 0, 0); + MotionEntry* newEntry = new MotionEntry(args->sequenceNum, args->eventTime, + args->deviceId, args->source, args->displayId, policyFlags, + args->action, args->actionButton, args->flags, + args->metaState, args->buttonState, args->classification, + args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, + args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); @@ -2804,19 +2809,20 @@ bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, " - "switchMask=0x%08x", - args->eventTime, args->policyFlags, args->switchValues, args->switchMask); + "switchMask=0x%08x", + args->eventTime, args->policyFlags, args->switchValues, args->switchMask); #endif uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->notifySwitch(args->eventTime, args->switchValues, args->switchMask, policyFlags); + mPolicy->notifySwitch(args->eventTime, + args->switchValues, args->switchMask, policyFlags); } void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args->eventTime, - args->deviceId); + ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", + args->eventTime, args->deviceId); #endif bool needWake; @@ -2833,13 +2839,13 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { } } -int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid, - int32_t injectorUid, int32_t syncMode, - int32_t timeoutMillis, uint32_t policyFlags) { +int32_t InputDispatcher::injectInputEvent(const InputEvent* event, + int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, + uint32_t policyFlags) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " - "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", - event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); + "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", + event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); #endif nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); @@ -2852,107 +2858,104 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec EventEntry* firstInjectedEntry; EventEntry* lastInjectedEntry; switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: { - KeyEvent keyEvent; - keyEvent.initialize(*static_cast<const KeyEvent*>(event)); - int32_t action = keyEvent.getAction(); - if (!validateKeyEvent(action)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - int32_t flags = keyEvent.getFlags(); - int32_t keyCode = keyEvent.getKeyCode(); - int32_t metaState = keyEvent.getMetaState(); - accelerateMetaShortcuts(keyEvent.getDeviceId(), action, - /*byref*/ keyCode, /*byref*/ metaState); - keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), - keyEvent.getDisplayId(), action, flags, keyCode, - keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(), - keyEvent.getDownTime(), keyEvent.getEventTime()); - - if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { - policyFlags |= POLICY_FLAG_VIRTUAL; - } + case AINPUT_EVENT_TYPE_KEY: { + KeyEvent keyEvent; + keyEvent.initialize(*static_cast<const KeyEvent*>(event)); + int32_t action = keyEvent.getAction(); + if (! validateKeyEvent(action)) { + return INPUT_EVENT_INJECTION_FAILED; + } - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - android::base::Timer t; - mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags); - if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { - ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); - } - } + int32_t flags = keyEvent.getFlags(); + int32_t keyCode = keyEvent.getKeyCode(); + int32_t metaState = keyEvent.getMetaState(); + accelerateMetaShortcuts(keyEvent.getDeviceId(), action, + /*byref*/ keyCode, /*byref*/ metaState); + keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(), + action, flags, keyCode, keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(), + keyEvent.getDownTime(), keyEvent.getEventTime()); - mLock.lock(); - firstInjectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, - keyEvent.getEventTime(), keyEvent.getDeviceId(), - keyEvent.getSource(), keyEvent.getDisplayId(), - policyFlags, action, flags, keyEvent.getKeyCode(), - keyEvent.getScanCode(), keyEvent.getMetaState(), - keyEvent.getRepeatCount(), keyEvent.getDownTime()); - lastInjectedEntry = firstInjectedEntry; - break; + if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { + policyFlags |= POLICY_FLAG_VIRTUAL; } - case AINPUT_EVENT_TYPE_MOTION: { - const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); - int32_t action = motionEvent->getAction(); - size_t pointerCount = motionEvent->getPointerCount(); - const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); - int32_t actionButton = motionEvent->getActionButton(); - int32_t displayId = motionEvent->getDisplayId(); - if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { - return INPUT_EVENT_INJECTION_FAILED; + if (!(policyFlags & POLICY_FLAG_FILTERED)) { + android::base::Timer t; + mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags); + if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { + ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms", + std::to_string(t.duration().count()).c_str()); } + } - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - nsecs_t eventTime = motionEvent->getEventTime(); - android::base::Timer t; - mPolicy->interceptMotionBeforeQueueing(displayId, eventTime, /*byref*/ policyFlags); - if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { - ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); - } - } + mLock.lock(); + firstInjectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(), + keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(), + policyFlags, action, flags, + keyEvent.getKeyCode(), keyEvent.getScanCode(), keyEvent.getMetaState(), + keyEvent.getRepeatCount(), keyEvent.getDownTime()); + lastInjectedEntry = firstInjectedEntry; + break; + } + + case AINPUT_EVENT_TYPE_MOTION: { + const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); + int32_t action = motionEvent->getAction(); + size_t pointerCount = motionEvent->getPointerCount(); + const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); + int32_t actionButton = motionEvent->getActionButton(); + int32_t displayId = motionEvent->getDisplayId(); + if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { + return INPUT_EVENT_INJECTION_FAILED; + } - mLock.lock(); - const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); - const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - firstInjectedEntry = - new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), - motionEvent->getDisplayId(), policyFlags, action, actionButton, - motionEvent->getFlags(), motionEvent->getMetaState(), - motionEvent->getButtonState(), motionEvent->getClassification(), - motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), - motionEvent->getYPrecision(), motionEvent->getDownTime(), - uint32_t(pointerCount), pointerProperties, samplePointerCoords, - motionEvent->getXOffset(), motionEvent->getYOffset()); - lastInjectedEntry = firstInjectedEntry; - for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { - sampleEventTimes += 1; - samplePointerCoords += pointerCount; - MotionEntry* nextInjectedEntry = - new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), - motionEvent->getDisplayId(), policyFlags, action, - actionButton, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getClassification(), - motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), - motionEvent->getYPrecision(), motionEvent->getDownTime(), - uint32_t(pointerCount), pointerProperties, - samplePointerCoords, motionEvent->getXOffset(), - motionEvent->getYOffset()); - lastInjectedEntry->next = nextInjectedEntry; - lastInjectedEntry = nextInjectedEntry; + if (!(policyFlags & POLICY_FLAG_FILTERED)) { + nsecs_t eventTime = motionEvent->getEventTime(); + android::base::Timer t; + mPolicy->interceptMotionBeforeQueueing(displayId, eventTime, /*byref*/ policyFlags); + if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { + ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", + std::to_string(t.duration().count()).c_str()); } - break; } - default: - ALOGW("Cannot inject event of type %d", event->getType()); - return INPUT_EVENT_INJECTION_FAILED; + mLock.lock(); + const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); + const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); + firstInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), motionEvent->getDisplayId(), + policyFlags, + action, actionButton, motionEvent->getFlags(), + motionEvent->getMetaState(), motionEvent->getButtonState(), + motionEvent->getClassification(), motionEvent->getEdgeFlags(), + motionEvent->getXPrecision(), motionEvent->getYPrecision(), + motionEvent->getDownTime(), + uint32_t(pointerCount), pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); + lastInjectedEntry = firstInjectedEntry; + for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { + sampleEventTimes += 1; + samplePointerCoords += pointerCount; + MotionEntry* nextInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, + *sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), + motionEvent->getDisplayId(), policyFlags, + action, actionButton, motionEvent->getFlags(), + motionEvent->getMetaState(), motionEvent->getButtonState(), + motionEvent->getClassification(), motionEvent->getEdgeFlags(), + motionEvent->getXPrecision(), motionEvent->getYPrecision(), + motionEvent->getDownTime(), + uint32_t(pointerCount), pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); + lastInjectedEntry->next = nextInjectedEntry; + lastInjectedEntry = nextInjectedEntry; + } + break; + } + + default: + ALOGW("Cannot inject event of type %d", event->getType()); + return INPUT_EVENT_INJECTION_FAILED; } InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); @@ -2964,7 +2967,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec lastInjectedEntry->injectionState = injectionState; bool needWake = false; - for (EventEntry* entry = firstInjectedEntry; entry != nullptr;) { + for (EventEntry* entry = firstInjectedEntry; entry != nullptr; ) { EventEntry* nextEntry = entry->next; needWake |= enqueueInboundEventLocked(entry); entry = nextEntry; @@ -2993,7 +2996,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec if (remainingTimeout <= 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Timed out waiting for injection result " - "to become available."); + "to become available."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; @@ -3002,18 +3005,18 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec mInjectionResultAvailable.wait_for(_l, std::chrono::nanoseconds(remainingTimeout)); } - if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED && - syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { + if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED + && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { while (injectionState->pendingForegroundDispatches != 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.", - injectionState->pendingForegroundDispatches); + injectionState->pendingForegroundDispatches); #endif nsecs_t remainingTimeout = endTime - now(); if (remainingTimeout <= 0) { #if DEBUG_INJECTION - ALOGD("injectInputEvent - Timed out waiting for pending foreground " - "dispatches to finish."); + ALOGD("injectInputEvent - Timed out waiting for pending foreground " + "dispatches to finish."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; @@ -3029,16 +3032,16 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec #if DEBUG_INJECTION ALOGD("injectInputEvent - Finished with result %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectorPid, injectorUid); + "injectorPid=%d, injectorUid=%d", + injectionResult, injectorPid, injectorUid); #endif return injectionResult; } bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { - return injectorUid == 0 || - mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); + return injectorUid == 0 + || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); } void InputDispatcher::setInjectionResult(EventEntry* entry, int32_t injectionResult) { @@ -3046,25 +3049,26 @@ void InputDispatcher::setInjectionResult(EventEntry* entry, int32_t injectionRes if (injectionState) { #if DEBUG_INJECTION ALOGD("Setting input event injection result to %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectionState->injectorPid, injectionState->injectorUid); + "injectorPid=%d, injectorUid=%d", + injectionResult, injectionState->injectorPid, injectionState->injectorUid); #endif - if (injectionState->injectionIsAsync && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { + if (injectionState->injectionIsAsync + && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { // Log the outcome since the injector did not wait for the injection result. switch (injectionResult) { - case INPUT_EVENT_INJECTION_SUCCEEDED: - ALOGV("Asynchronous input event injection succeeded."); - break; - case INPUT_EVENT_INJECTION_FAILED: - ALOGW("Asynchronous input event injection failed."); - break; - case INPUT_EVENT_INJECTION_PERMISSION_DENIED: - ALOGW("Asynchronous input event injection permission denied."); - break; - case INPUT_EVENT_INJECTION_TIMED_OUT: - ALOGW("Asynchronous input event injection timed out."); - break; + case INPUT_EVENT_INJECTION_SUCCEEDED: + ALOGV("Asynchronous input event injection succeeded."); + break; + case INPUT_EVENT_INJECTION_FAILED: + ALOGW("Asynchronous input event injection failed."); + break; + case INPUT_EVENT_INJECTION_PERMISSION_DENIED: + ALOGW("Asynchronous input event injection permission denied."); + break; + case INPUT_EVENT_INJECTION_TIMED_OUT: + ALOGW("Asynchronous input event injection timed out."); + break; } } @@ -3095,7 +3099,7 @@ std::vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked( int32_t displayId) const { std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>::const_iterator it = mWindowHandlesByDisplay.find(displayId); - if (it != mWindowHandlesByDisplay.end()) { + if(it != mWindowHandlesByDisplay.end()) { return it->second; } @@ -3123,9 +3127,9 @@ bool InputDispatcher::hasWindowHandleLocked(const sp<InputWindowHandle>& windowH if (handle->getToken() == windowHandle->getToken()) { if (windowHandle->getInfo()->displayId != it.first) { ALOGE("Found window %s in display %" PRId32 - ", but it should belong to display %" PRId32, - windowHandle->getName().c_str(), it.first, - windowHandle->getInfo()->displayId); + ", but it should belong to display %" PRId32, + windowHandle->getName().c_str(), it.first, + windowHandle->getInfo()->displayId); } return true; } @@ -3150,8 +3154,7 @@ sp<InputChannel> InputDispatcher::getInputChannelLocked(const sp<IBinder>& token * For removed handle, check if need to send a cancel event if already in touch. */ void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& inputWindowHandles, - int32_t displayId, - const sp<ISetInputWindowsListener>& setInputWindowsListener) { + int32_t displayId, const sp<ISetInputWindowsListener>& setInputWindowsListener) { #if DEBUG_FOCUS ALOGD("setInputWindows displayId=%" PRId32, displayId); #endif @@ -3218,8 +3221,8 @@ void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& for (const sp<InputWindowHandle>& windowHandle : newHandles) { // Set newFocusedWindowHandle to the top most focused window instead of the last one - if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus && - windowHandle->getInfo()->visible) { + if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus + && windowHandle->getInfo()->visible) { newFocusedWindowHandle = windowHandle; } if (windowHandle == mLastHoverWindowHandle) { @@ -3242,21 +3245,22 @@ void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& if (oldFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus left window: %s in display %" PRId32, - oldFocusedWindowHandle->getName().c_str(), displayId); + oldFocusedWindowHandle->getName().c_str(), displayId); #endif - sp<InputChannel> focusedInputChannel = - getInputChannelLocked(oldFocusedWindowHandle->getToken()); + sp<InputChannel> focusedInputChannel = getInputChannelLocked( + oldFocusedWindowHandle->getToken()); if (focusedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "focus left window"); - synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options); + "focus left window"); + synthesizeCancelationEventsForInputChannelLocked( + focusedInputChannel, options); } mFocusedWindowHandlesByDisplay.erase(displayId); } if (newFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus entered window: %s in display %" PRId32, - newFocusedWindowHandle->getName().c_str(), displayId); + newFocusedWindowHandle->getName().c_str(), displayId); #endif mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle; } @@ -3264,29 +3268,30 @@ void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& if (mFocusedDisplayId == displayId) { onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle); } + } ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); if (stateIndex >= 0) { TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex); - for (size_t i = 0; i < state.windows.size();) { + for (size_t i = 0; i < state.windows.size(); ) { TouchedWindow& touchedWindow = state.windows[i]; if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS ALOGD("Touched window was removed: %s in display %" PRId32, - touchedWindow.windowHandle->getName().c_str(), displayId); + touchedWindow.windowHandle->getName().c_str(), displayId); #endif sp<InputChannel> touchedInputChannel = getInputChannelLocked(touchedWindow.windowHandle->getToken()); if (touchedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "touched window was removed"); - synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, - options); + "touched window was removed"); + synthesizeCancelationEventsForInputChannelLocked( + touchedInputChannel, options); } state.windows.erase(state.windows.begin() + i); } else { - ++i; + ++i; } } } @@ -3337,7 +3342,7 @@ void InputDispatcher::setFocusedApplication( } #if DEBUG_FOCUS - // logDispatchStateLocked(); + //logDispatchStateLocked(); #endif } // release lock @@ -3366,11 +3371,11 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) { getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId); if (oldFocusedWindowHandle != nullptr) { sp<InputChannel> inputChannel = - getInputChannelLocked(oldFocusedWindowHandle->getToken()); + getInputChannelLocked(oldFocusedWindowHandle->getToken()); if (inputChannel != nullptr) { - CancelationOptions - options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "The display which contains this window no longer has focus."); + CancelationOptions options( + CancelationOptions::CANCEL_NON_POINTER_EVENTS, + "The display which contains this window no longer has focus."); options.displayId = ADISPLAY_ID_NONE; synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); } @@ -3389,8 +3394,8 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) { for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputWindowHandle>& windowHandle = it.second; - ALOGE("Display #%" PRId32 " has focused window: '%s'\n", displayId, - windowHandle->getName().c_str()); + ALOGE("Display #%" PRId32 " has focused window: '%s'\n", + displayId, windowHandle->getName().c_str()); } } } @@ -3480,7 +3485,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< } #if DEBUG_FOCUS ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s", - fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str()); + fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str()); #endif if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) { #if DEBUG_FOCUS @@ -3500,9 +3505,9 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< state.windows.erase(state.windows.begin() + i); - int32_t newTargetFlags = oldTargetFlags & - (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT | - InputTarget::FLAG_DISPATCH_AS_IS); + int32_t newTargetFlags = oldTargetFlags + & (InputTarget::FLAG_FOREGROUND + | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); state.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); found = true; @@ -3510,15 +3515,16 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< } } } - Found: +Found: - if (!found) { + if (! found) { #if DEBUG_FOCUS ALOGD("Focus transfer failed because from window did not have focus."); #endif return false; } + sp<InputChannel> fromChannel = getInputChannelLocked(fromToken); sp<InputChannel> toChannel = getInputChannelLocked(toToken); ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); @@ -3528,9 +3534,8 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex); fromConnection->inputState.copyPointerStateTo(toConnection->inputState); - CancelationOptions - options(CancelationOptions::CANCEL_POINTER_EVENTS, - "transferring touch focus from this window to another window"); + CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, + "transferring touch focus from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); } @@ -3585,12 +3590,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (auto& it : mFocusedApplicationHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputApplicationHandle>& applicationHandle = it.second; - dump += StringPrintf(INDENT2 "displayId=%" PRId32 - ", name='%s', dispatchingTimeout=%0.3fms\n", - displayId, applicationHandle->getName().c_str(), - applicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT) / - 1000000.0); + dump += StringPrintf( + INDENT2 "displayId=%" PRId32 ", name='%s', dispatchingTimeout=%0.3fms\n", + displayId, + applicationHandle->getName().c_str(), + applicationHandle->getDispatchingTimeout( + DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); } } else { dump += StringPrintf(INDENT "FocusedApplications: <none>\n"); @@ -3601,8 +3606,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputWindowHandle>& windowHandle = it.second; - dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId, - windowHandle->getName().c_str()); + dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", + displayId, windowHandle->getName().c_str()); } } else { dump += StringPrintf(INDENT "FocusedWindows: <none>\n"); @@ -3613,16 +3618,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) { const TouchState& state = mTouchStatesByDisplay.valueAt(i); dump += StringPrintf(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n", - state.displayId, toString(state.down), toString(state.split), - state.deviceId, state.source); + state.displayId, toString(state.down), toString(state.split), + state.deviceId, state.source); if (!state.windows.empty()) { dump += INDENT3 "Windows:\n"; for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; - dump += StringPrintf(INDENT4 - "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.windowHandle->getName().c_str(), - touchedWindow.pointerIds.value, touchedWindow.targetFlags); + dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", + i, touchedWindow.windowHandle->getName().c_str(), + touchedWindow.pointerIds.value, + touchedWindow.targetFlags); } } else { dump += INDENT3 "Windows: <none>\n"; @@ -3631,8 +3636,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT3 "Portal windows:\n"; for (size_t i = 0; i < state.portalWindows.size(); i++) { const sp<InputWindowHandle> portalWindowHandle = state.portalWindows[i]; - dump += StringPrintf(INDENT4 "%zu: name='%s'\n", i, - portalWindowHandle->getName().c_str()); + dump += StringPrintf(INDENT4 "%zu: name='%s'\n", + i, portalWindowHandle->getName().c_str()); } } } @@ -3641,7 +3646,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mWindowHandlesByDisplay.empty()) { - for (auto& it : mWindowHandlesByDisplay) { + for (auto& it : mWindowHandlesByDisplay) { const std::vector<sp<InputWindowHandle>> windowHandles = it.second; dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first); if (!windowHandles.empty()) { @@ -3651,31 +3656,28 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, " - "portalToDisplayId=%d, paused=%s, hasFocus=%s, " - "hasWallpaper=%s, " - "visible=%s, canReceiveKeys=%s, flags=0x%08x, " - "type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], globalScale=%f, " - "windowScale=(%f,%f), " - "touchableRegion=", - i, windowInfo->name.c_str(), windowInfo->displayId, - windowInfo->portalToDisplayId, - toString(windowInfo->paused), - toString(windowInfo->hasFocus), - toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), - toString(windowInfo->canReceiveKeys), - windowInfo->layoutParamsFlags, - windowInfo->layoutParamsType, windowInfo->layer, - windowInfo->frameLeft, windowInfo->frameTop, - windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->globalScaleFactor, windowInfo->windowXScale, - windowInfo->windowYScale); + "portalToDisplayId=%d, paused=%s, hasFocus=%s, hasWallpaper=%s, " + "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " + "frame=[%d,%d][%d,%d], globalScale=%f, windowScale=(%f,%f), " + "touchableRegion=", + i, windowInfo->name.c_str(), windowInfo->displayId, + windowInfo->portalToDisplayId, + toString(windowInfo->paused), + toString(windowInfo->hasFocus), + toString(windowInfo->hasWallpaper), + toString(windowInfo->visible), + toString(windowInfo->canReceiveKeys), + windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, + windowInfo->layer, + windowInfo->frameLeft, windowInfo->frameTop, + windowInfo->frameRight, windowInfo->frameBottom, + windowInfo->globalScaleFactor, + windowInfo->windowXScale, windowInfo->windowYScale); dumpRegion(dump, windowInfo->touchableRegion); dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - windowInfo->ownerPid, windowInfo->ownerUid, - windowInfo->dispatchingTimeout / 1000000.0); + windowInfo->ownerPid, windowInfo->ownerUid, + windowInfo->dispatchingTimeout / 1000000.0); } } else { dump += INDENT2 "Windows: <none>\n"; @@ -3686,16 +3688,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mGlobalMonitorsByDisplay.empty() || !mGestureMonitorsByDisplay.empty()) { - for (auto& it : mGlobalMonitorsByDisplay) { + for (auto& it : mGlobalMonitorsByDisplay) { const std::vector<Monitor>& monitors = it.second; dump += StringPrintf(INDENT "Global monitors in display %" PRId32 ":\n", it.first); dumpMonitors(dump, monitors); - } - for (auto& it : mGestureMonitorsByDisplay) { + } + for (auto& it : mGestureMonitorsByDisplay) { const std::vector<Monitor>& monitors = it.second; dump += StringPrintf(INDENT "Gesture monitors in display %" PRId32 ":\n", it.first); dumpMonitors(dump, monitors); - } + } } else { dump += INDENT "Monitors: <none>\n"; } @@ -3708,7 +3710,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) { dump += INDENT2; entry->appendDescription(dump); - dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); + dump += StringPrintf(", age=%0.1fms\n", + (currentTime - entry->eventTime) * 0.000001f); } } else { dump += INDENT "RecentQueue: <empty>\n"; @@ -3720,7 +3723,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT2; mPendingEvent->appendDescription(dump); dump += StringPrintf(", age=%0.1fms\n", - (currentTime - mPendingEvent->eventTime) * 0.000001f); + (currentTime - mPendingEvent->eventTime) * 0.000001f); } else { dump += INDENT "PendingEvent: <none>\n"; } @@ -3731,7 +3734,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) { dump += INDENT2; entry->appendDescription(dump); - dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); + dump += StringPrintf(", age=%0.1fms\n", + (currentTime - entry->eventTime) * 0.000001f); } } else { dump += INDENT "InboundQueue: <empty>\n"; @@ -3742,8 +3746,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (size_t i = 0; i < mReplacedKeys.size(); i++) { const KeyReplacement& replacement = mReplacedKeys.keyAt(i); int32_t newKeyCode = mReplacedKeys.valueAt(i); - dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", i, - replacement.keyCode, replacement.deviceId, newKeyCode); + dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", + i, replacement.keyCode, replacement.deviceId, newKeyCode); } } else { dump += INDENT "ReplacedKeys: <empty>\n"; @@ -3754,22 +3758,22 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (size_t i = 0; i < mConnectionsByFd.size(); i++) { const sp<Connection>& connection = mConnectionsByFd.valueAt(i); dump += StringPrintf(INDENT2 "%zu: channelName='%s', windowName='%s', " - "status=%s, monitor=%s, inputPublisherBlocked=%s\n", - i, connection->getInputChannelName().c_str(), - connection->getWindowName().c_str(), connection->getStatusLabel(), - toString(connection->monitor), - toString(connection->inputPublisherBlocked)); + "status=%s, monitor=%s, inputPublisherBlocked=%s\n", + i, connection->getInputChannelName().c_str(), + connection->getWindowName().c_str(), + connection->getStatusLabel(), toString(connection->monitor), + toString(connection->inputPublisherBlocked)); if (!connection->outboundQueue.isEmpty()) { dump += StringPrintf(INDENT3 "OutboundQueue: length=%u\n", - connection->outboundQueue.count()); + connection->outboundQueue.count()); for (DispatchEntry* entry = connection->outboundQueue.head; entry; - entry = entry->next) { + entry = entry->next) { dump.append(INDENT4); entry->eventEntry->appendDescription(dump); dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f); + entry->targetFlags, entry->resolvedAction, + (currentTime - entry->eventEntry->eventTime) * 0.000001f); } } else { dump += INDENT3 "OutboundQueue: <empty>\n"; @@ -3777,16 +3781,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { if (!connection->waitQueue.isEmpty()) { dump += StringPrintf(INDENT3 "WaitQueue: length=%u\n", - connection->waitQueue.count()); + connection->waitQueue.count()); for (DispatchEntry* entry = connection->waitQueue.head; entry; - entry = entry->next) { + entry = entry->next) { dump += INDENT4; entry->eventEntry->appendDescription(dump); dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, " - "age=%0.1fms, wait=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f, - (currentTime - entry->deliveryTime) * 0.000001f); + "age=%0.1fms, wait=%0.1fms\n", + entry->targetFlags, entry->resolvedAction, + (currentTime - entry->eventEntry->eventTime) * 0.000001f, + (currentTime - entry->deliveryTime) * 0.000001f); } } else { dump += INDENT3 "WaitQueue: <empty>\n"; @@ -3798,15 +3802,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { if (isAppSwitchPendingLocked()) { dump += StringPrintf(INDENT "AppSwitch: pending, due in %0.1fms\n", - (mAppSwitchDueTime - now()) / 1000000.0); + (mAppSwitchDueTime - now()) / 1000000.0); } else { dump += INDENT "AppSwitch: not pending\n"; } dump += INDENT "Configuration:\n"; - dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f); + dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n", + mConfig.keyRepeatDelay * 0.000001f); dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %0.1fms\n", - mConfig.keyRepeatTimeout * 0.000001f); + mConfig.keyRepeatTimeout * 0.000001f); } void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) { @@ -3820,10 +3825,10 @@ void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor> } status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, - int32_t displayId) { + int32_t displayId) { #if DEBUG_REGISTRATION ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32, - inputChannel->getName().c_str(), displayId); + inputChannel->getName().c_str(), displayId); #endif { // acquire lock @@ -3831,7 +3836,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan if (getConnectionIndexLocked(inputChannel) >= 0) { ALOGW("Attempted to register already registered input channel '%s'", - inputChannel->getName().c_str()); + inputChannel->getName().c_str()); return BAD_VALUE; } @@ -3850,7 +3855,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan } status_t InputDispatcher::registerInputMonitor(const sp<InputChannel>& inputChannel, - int32_t displayId, bool isGestureMonitor) { + int32_t displayId, bool isGestureMonitor) { { // acquire lock std::scoped_lock _l(mLock); @@ -3870,11 +3875,13 @@ status_t InputDispatcher::registerInputMonitor(const sp<InputChannel>& inputChan mConnectionsByFd.add(fd, connection); mInputChannelsByToken[inputChannel->getToken()] = inputChannel; - auto& monitorsByDisplay = - isGestureMonitor ? mGestureMonitorsByDisplay : mGlobalMonitorsByDisplay; + auto& monitorsByDisplay = isGestureMonitor + ? mGestureMonitorsByDisplay + : mGlobalMonitorsByDisplay; monitorsByDisplay[displayId].emplace_back(inputChannel); mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); + } // Wake the looper because some connections have changed. mLooper->wake(); @@ -3902,11 +3909,11 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh } status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, - bool notify) { + bool notify) { ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex < 0) { ALOGW("Attempted to unregister already unregistered input channel '%s'", - inputChannel->getName().c_str()); + inputChannel->getName().c_str()); return BAD_VALUE; } @@ -3933,17 +3940,16 @@ void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputCh removeMonitorChannelLocked(inputChannel, mGestureMonitorsByDisplay); } -void InputDispatcher::removeMonitorChannelLocked( - const sp<InputChannel>& inputChannel, +void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel, std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) { - for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end();) { + for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end(); ) { std::vector<Monitor>& monitors = it->second; const size_t numMonitors = monitors.size(); for (size_t i = 0; i < numMonitors; i++) { - if (monitors[i].inputChannel == inputChannel) { - monitors.erase(monitors.begin() + i); - break; - } + if (monitors[i].inputChannel == inputChannel) { + monitors.erase(monitors.begin() + i); + break; + } } if (monitors.empty()) { it = monitorsByDisplay.erase(it); @@ -3979,14 +3985,14 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { } if (!foundDeviceId || !state.down) { ALOGW("Attempted to pilfer points from a monitor without any on-going pointer streams." - " Ignoring."); + " Ignoring."); return BAD_VALUE; } int32_t deviceId = foundDeviceId.value(); // Send cancel events to all the input channels we're stealing from. CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "gesture monitor stole pointer stream"); + "gesture monitor stole pointer stream"); options.deviceId = deviceId; options.displayId = displayId; for (const TouchedWindow& window : state.windows) { @@ -3999,6 +4005,7 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { return OK; } + std::optional<int32_t> InputDispatcher::findGestureMonitorDisplayByTokenLocked( const sp<IBinder>& token) { for (const auto& it : mGestureMonitorsByDisplay) { @@ -4027,47 +4034,46 @@ ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputC return -1; } -void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime, - const sp<Connection>& connection, uint32_t seq, - bool handled) { - CommandEntry* commandEntry = - postCommandLocked(&InputDispatcher::doDispatchCycleFinishedLockedInterruptible); +void InputDispatcher::onDispatchCycleFinishedLocked( + nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); commandEntry->connection = connection; commandEntry->eventTime = currentTime; commandEntry->seq = seq; commandEntry->handled = handled; } -void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime, - const sp<Connection>& connection) { +void InputDispatcher::onDispatchCycleBrokenLocked( + nsecs_t currentTime, const sp<Connection>& connection) { ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", - connection->getInputChannelName().c_str()); + connection->getInputChannelName().c_str()); - CommandEntry* commandEntry = - postCommandLocked(&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); commandEntry->connection = connection; } void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus, - const sp<InputWindowHandle>& newFocus) { + const sp<InputWindowHandle>& newFocus) { sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr; sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr; - CommandEntry* commandEntry = - postCommandLocked(&InputDispatcher::doNotifyFocusChangedLockedInterruptible); + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doNotifyFocusChangedLockedInterruptible); commandEntry->oldToken = oldToken; commandEntry->newToken = newToken; } -void InputDispatcher::onANRLocked(nsecs_t currentTime, - const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, nsecs_t eventTime, - nsecs_t waitStartTime, const char* reason) { +void InputDispatcher::onANRLocked( + nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, + nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) { float dispatchLatency = (currentTime - eventTime) * 0.000001f; float waitDuration = (currentTime - waitStartTime) * 0.000001f; ALOGI("Application is not responding: %s. " - "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), dispatchLatency, - waitDuration, reason); + "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", + getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), + dispatchLatency, waitDuration, reason); // Capture a record of the InputDispatcher state at the time of the ANR. time_t t = time(nullptr); @@ -4078,23 +4084,23 @@ void InputDispatcher::onANRLocked(nsecs_t currentTime, mLastANRState.clear(); mLastANRState += INDENT "ANR:\n"; mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr); - mLastANRState += - StringPrintf(INDENT2 "Window: %s\n", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str()); + mLastANRState += StringPrintf(INDENT2 "Window: %s\n", + getApplicationWindowLabel(applicationHandle, windowHandle).c_str()); mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason); dumpDispatchStateLocked(mLastANRState); - CommandEntry* commandEntry = - postCommandLocked(&InputDispatcher::doNotifyANRLockedInterruptible); + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doNotifyANRLockedInterruptible); commandEntry->inputApplicationHandle = applicationHandle; - commandEntry->inputChannel = - windowHandle != nullptr ? getInputChannelLocked(windowHandle->getToken()) : nullptr; + commandEntry->inputChannel = windowHandle != nullptr ? + getInputChannelLocked(windowHandle->getToken()) : nullptr; commandEntry->reason = reason; } -void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) { +void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible ( + CommandEntry* commandEntry) { mLock.unlock(); mPolicy->notifyConfigurationChanged(commandEntry->eventTime); @@ -4102,7 +4108,8 @@ void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible(CommandEnt mLock.lock(); } -void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) { +void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( + CommandEntry* commandEntry) { sp<Connection> connection = commandEntry->connection; if (connection->status != Connection::STATUS_ZOMBIE) { @@ -4114,7 +4121,8 @@ void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(CommandEntry } } -void InputDispatcher::doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) { +void InputDispatcher::doNotifyFocusChangedLockedInterruptible( + CommandEntry* commandEntry) { sp<IBinder> oldToken = commandEntry->oldToken; sp<IBinder> newToken = commandEntry->newToken; mLock.unlock(); @@ -4122,18 +4130,19 @@ void InputDispatcher::doNotifyFocusChangedLockedInterruptible(CommandEntry* comm mLock.lock(); } -void InputDispatcher::doNotifyANRLockedInterruptible(CommandEntry* commandEntry) { +void InputDispatcher::doNotifyANRLockedInterruptible( + CommandEntry* commandEntry) { mLock.unlock(); - nsecs_t newTimeout = - mPolicy->notifyANR(commandEntry->inputApplicationHandle, - commandEntry->inputChannel ? commandEntry->inputChannel->getToken() - : nullptr, - commandEntry->reason); + nsecs_t newTimeout = mPolicy->notifyANR( + commandEntry->inputApplicationHandle, + commandEntry->inputChannel ? commandEntry->inputChannel->getToken() : nullptr, + commandEntry->reason); mLock.lock(); - resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputChannel); + resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, + commandEntry->inputChannel); } void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( @@ -4146,13 +4155,13 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( mLock.unlock(); android::base::Timer t; - sp<IBinder> token = commandEntry->inputChannel != nullptr - ? commandEntry->inputChannel->getToken() - : nullptr; - nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry->policyFlags); + sp<IBinder> token = commandEntry->inputChannel != nullptr ? + commandEntry->inputChannel->getToken() : nullptr; + nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, + &event, entry->policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms", - std::to_string(t.duration().count()).c_str()); + std::to_string(t.duration().count()).c_str()); } mLock.lock(); @@ -4174,7 +4183,8 @@ void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntr mLock.lock(); } -void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) { +void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( + CommandEntry* commandEntry) { sp<Connection> connection = commandEntry->connection; nsecs_t finishTime = commandEntry->eventTime; uint32_t seq = commandEntry->seq; @@ -4187,7 +4197,7 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* c if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { std::string msg = StringPrintf("Window '%s' spent %0.1fms processing the last input event: ", - connection->getWindowName().c_str(), eventDuration * 0.000001f); + connection->getWindowName().c_str(), eventDuration * 0.000001f); dispatchEntry->eventEntry->appendDescription(msg); ALOGI("%s", msg.c_str()); } @@ -4195,12 +4205,12 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* c bool restartEvent; if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); - restartEvent = - afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled); + restartEvent = afterKeyEventLockedInterruptible(connection, + dispatchEntry, keyEntry, handled); } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry); - restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, - motionEntry, handled); + restartEvent = afterMotionEventLockedInterruptible(connection, + dispatchEntry, motionEntry, handled); } else { restartEvent = false; } @@ -4226,8 +4236,7 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* c } bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, - KeyEntry* keyEntry, bool handled) { + DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) { if (keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK) { if (!handled) { // Report the key as unhandled, since the fallback was not handled. @@ -4252,9 +4261,9 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // Dispatch the unhandled key to the policy with the cancel flag. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to cancel fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, + keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); @@ -4262,8 +4271,8 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con mLock.unlock(); - mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), &event, - keyEntry->policyFlags, &event); + mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), + &event, keyEntry->policyFlags, &event); mLock.lock(); @@ -4282,13 +4291,15 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // If the application did not handle a non-fallback key, first check // that we are in a good state to perform unhandled key event processing // Then ask the policy what to do with it. - bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN && keyEntry->repeatCount == 0; + bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN + && keyEntry->repeatCount == 0; if (fallbackKeyCode == -1 && !initialDown) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Skipping unhandled key event processing " - "since this is not an initial down. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - originalKeyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); + "since this is not an initial down. " + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + originalKeyCode, keyEntry->action, keyEntry->repeatCount, + keyEntry->policyFlags); #endif return false; } @@ -4296,16 +4307,17 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // Dispatch the unhandled key to the policy. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to perform fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, + keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); mLock.unlock(); - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), &event, - keyEntry->policyFlags, &event); + bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), + &event, keyEntry->policyFlags, &event); mLock.lock(); @@ -4330,19 +4342,19 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // Cancel the fallback key if the policy decides not to send it anymore. // We will continue to dispatch the key to the policy but we will no // longer dispatch a fallback key to the application. - if (fallbackKeyCode != AKEYCODE_UNKNOWN && - (!fallback || fallbackKeyCode != event.getKeyCode())) { + if (fallbackKeyCode != AKEYCODE_UNKNOWN + && (!fallback || fallbackKeyCode != event.getKeyCode())) { #if DEBUG_OUTBOUND_EVENT_DETAILS if (fallback) { ALOGD("Unhandled key event: Policy requested to send key %d" - "as a fallback for %d, but on the DOWN it had requested " - "to send %d instead. Fallback canceled.", - event.getKeyCode(), originalKeyCode, fallbackKeyCode); + "as a fallback for %d, but on the DOWN it had requested " + "to send %d instead. Fallback canceled.", + event.getKeyCode(), originalKeyCode, fallbackKeyCode); } else { ALOGD("Unhandled key event: Policy did not request fallback for %d, " - "but on the DOWN it had requested to send %d. " - "Fallback canceled.", - originalKeyCode, fallbackKeyCode); + "but on the DOWN it had requested to send %d. " + "Fallback canceled.", + originalKeyCode, fallbackKeyCode); } #endif @@ -4354,7 +4366,8 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con fallback = false; fallbackKeyCode = AKEYCODE_UNKNOWN; if (keyEntry->action != AKEY_EVENT_ACTION_UP) { - connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); + connection->inputState.setFallbackKey(originalKeyCode, + fallbackKeyCode); } } @@ -4364,10 +4377,11 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con const KeyedVector<int32_t, int32_t>& fallbackKeys = connection->inputState.getFallbackKeys(); for (size_t i = 0; i < fallbackKeys.size(); i++) { - msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i)); + msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), + fallbackKeys.valueAt(i)); } ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.", - fallbackKeys.size(), msg.c_str()); + fallbackKeys.size(), msg.c_str()); } #endif @@ -4387,8 +4401,8 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Dispatching fallback key. " - "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", - originalKeyCode, fallbackKeyCode, keyEntry->metaState); + "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", + originalKeyCode, fallbackKeyCode, keyEntry->metaState); #endif return true; // restart the event } else { @@ -4404,8 +4418,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con } bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, - MotionEntry* motionEntry, bool handled) { + DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) { return false; } @@ -4419,13 +4432,12 @@ void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* comman void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) { event->initialize(entry->deviceId, entry->source, entry->displayId, entry->action, entry->flags, - entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, - entry->downTime, entry->eventTime); + entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, + entry->downTime, entry->eventTime); } void InputDispatcher::updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, - nsecs_t timeSpentWaitingForApplication) { + int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) { // TODO Write some statistics about how long we spend waiting. } @@ -4470,4 +4482,762 @@ void InputDispatcher::monitor() { mDispatcherIsAlive.wait(_l); } -} // namespace android::inputdispatcher + +// --- InputDispatcher::InjectionState --- + +InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : + refCount(1), + injectorPid(injectorPid), injectorUid(injectorUid), + injectionResult(INPUT_EVENT_INJECTION_PENDING), injectionIsAsync(false), + pendingForegroundDispatches(0) { +} + +InputDispatcher::InjectionState::~InjectionState() { +} + +void InputDispatcher::InjectionState::release() { + refCount -= 1; + if (refCount == 0) { + delete this; + } else { + ALOG_ASSERT(refCount > 0); + } +} + + +// --- InputDispatcher::EventEntry --- + +InputDispatcher::EventEntry::EventEntry(uint32_t sequenceNum, int32_t type, + nsecs_t eventTime, uint32_t policyFlags) : + sequenceNum(sequenceNum), refCount(1), type(type), eventTime(eventTime), + policyFlags(policyFlags), injectionState(nullptr), dispatchInProgress(false) { +} + +InputDispatcher::EventEntry::~EventEntry() { + releaseInjectionState(); +} + +void InputDispatcher::EventEntry::release() { + refCount -= 1; + if (refCount == 0) { + delete this; + } else { + ALOG_ASSERT(refCount > 0); + } +} + +void InputDispatcher::EventEntry::releaseInjectionState() { + if (injectionState) { + injectionState->release(); + injectionState = nullptr; + } +} + + +// --- InputDispatcher::ConfigurationChangedEntry --- + +InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry( + uint32_t sequenceNum, nsecs_t eventTime) : + EventEntry(sequenceNum, TYPE_CONFIGURATION_CHANGED, eventTime, 0) { +} + +InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { +} + +void InputDispatcher::ConfigurationChangedEntry::appendDescription(std::string& msg) const { + msg += StringPrintf("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags); +} + + +// --- InputDispatcher::DeviceResetEntry --- + +InputDispatcher::DeviceResetEntry::DeviceResetEntry( + uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId) : + EventEntry(sequenceNum, TYPE_DEVICE_RESET, eventTime, 0), + deviceId(deviceId) { +} + +InputDispatcher::DeviceResetEntry::~DeviceResetEntry() { +} + +void InputDispatcher::DeviceResetEntry::appendDescription(std::string& msg) const { + msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", + deviceId, policyFlags); +} + + +// --- InputDispatcher::KeyEntry --- + +InputDispatcher::KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, + int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, + int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, + int32_t repeatCount, nsecs_t downTime) : + EventEntry(sequenceNum, TYPE_KEY, eventTime, policyFlags), + deviceId(deviceId), source(source), displayId(displayId), action(action), flags(flags), + keyCode(keyCode), scanCode(scanCode), metaState(metaState), + repeatCount(repeatCount), downTime(downTime), + syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), + interceptKeyWakeupTime(0) { +} + +InputDispatcher::KeyEntry::~KeyEntry() { +} + +void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const { + msg += StringPrintf("KeyEvent"); +} + +void InputDispatcher::KeyEntry::recycle() { + releaseInjectionState(); + + dispatchInProgress = false; + syntheticRepeat = false; + interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; + interceptKeyWakeupTime = 0; +} + + +// --- InputDispatcher::MotionEntry --- + +InputDispatcher::MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, + uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, + int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, + int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, + uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset) : + EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags), + eventTime(eventTime), + deviceId(deviceId), source(source), displayId(displayId), action(action), + actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState), + classification(classification), edgeFlags(edgeFlags), + xPrecision(xPrecision), yPrecision(yPrecision), + downTime(downTime), pointerCount(pointerCount) { + for (uint32_t i = 0; i < pointerCount; i++) { + this->pointerProperties[i].copyFrom(pointerProperties[i]); + this->pointerCoords[i].copyFrom(pointerCoords[i]); + if (xOffset || yOffset) { + this->pointerCoords[i].applyOffset(xOffset, yOffset); + } + } +} + +InputDispatcher::MotionEntry::~MotionEntry() { +} + +void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const { + msg += StringPrintf("MotionEvent"); +} + + +// --- InputDispatcher::DispatchEntry --- + +volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic; + +InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, + int32_t targetFlags, float xOffset, float yOffset, float globalScaleFactor, + float windowXScale, float windowYScale) : + seq(nextSeq()), + eventEntry(eventEntry), targetFlags(targetFlags), + xOffset(xOffset), yOffset(yOffset), globalScaleFactor(globalScaleFactor), + windowXScale(windowXScale), windowYScale(windowYScale), + deliveryTime(0), resolvedAction(0), resolvedFlags(0) { + eventEntry->refCount += 1; +} + +InputDispatcher::DispatchEntry::~DispatchEntry() { + eventEntry->release(); +} + +uint32_t InputDispatcher::DispatchEntry::nextSeq() { + // Sequence number 0 is reserved and will never be returned. + uint32_t seq; + do { + seq = android_atomic_inc(&sNextSeqAtomic); + } while (!seq); + return seq; +} + + +// --- InputDispatcher::InputState --- + +InputDispatcher::InputState::InputState() { +} + +InputDispatcher::InputState::~InputState() { +} + +bool InputDispatcher::InputState::isNeutral() const { + return mKeyMementos.empty() && mMotionMementos.empty(); +} + +bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source, + int32_t displayId) const { + for (const MotionMemento& memento : mMotionMementos) { + if (memento.deviceId == deviceId + && memento.source == source + && memento.displayId == displayId + && memento.hovering) { + return true; + } + } + return false; +} + +bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, + int32_t action, int32_t flags) { + switch (action) { + case AKEY_EVENT_ACTION_UP: { + if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) { + for (size_t i = 0; i < mFallbackKeys.size(); ) { + if (mFallbackKeys.valueAt(i) == entry->keyCode) { + mFallbackKeys.removeItemsAt(i); + } else { + i += 1; + } + } + } + ssize_t index = findKeyMemento(entry); + if (index >= 0) { + mKeyMementos.erase(mKeyMementos.begin() + index); + return true; + } + /* FIXME: We can't just drop the key up event because that prevents creating + * popup windows that are automatically shown when a key is held and then + * dismissed when the key is released. The problem is that the popup will + * not have received the original key down, so the key up will be considered + * to be inconsistent with its observed state. We could perhaps handle this + * by synthesizing a key down but that will cause other problems. + * + * So for now, allow inconsistent key up events to be dispatched. + * +#if DEBUG_OUTBOUND_EVENT_DETAILS + ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " + "keyCode=%d, scanCode=%d", + entry->deviceId, entry->source, entry->keyCode, entry->scanCode); +#endif + return false; + */ + return true; + } + + case AKEY_EVENT_ACTION_DOWN: { + ssize_t index = findKeyMemento(entry); + if (index >= 0) { + mKeyMementos.erase(mKeyMementos.begin() + index); + } + addKeyMemento(entry, flags); + return true; + } + + default: + return true; + } +} + +bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry, + int32_t action, int32_t flags) { + int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; + switch (actionMasked) { + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_CANCEL: { + ssize_t index = findMotionMemento(entry, false /*hovering*/); + if (index >= 0) { + mMotionMementos.erase(mMotionMementos.begin() + index); + return true; + } +#if DEBUG_OUTBOUND_EVENT_DETAILS + ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, " + "displayId=%" PRId32 ", actionMasked=%d", + entry->deviceId, entry->source, entry->displayId, actionMasked); +#endif + return false; + } + + case AMOTION_EVENT_ACTION_DOWN: { + ssize_t index = findMotionMemento(entry, false /*hovering*/); + if (index >= 0) { + mMotionMementos.erase(mMotionMementos.begin() + index); + } + addMotionMemento(entry, flags, false /*hovering*/); + return true; + } + + case AMOTION_EVENT_ACTION_POINTER_UP: + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_MOVE: { + if (entry->source & AINPUT_SOURCE_CLASS_NAVIGATION) { + // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need to + // generate cancellation events for these since they're based in relative rather than + // absolute units. + return true; + } + + ssize_t index = findMotionMemento(entry, false /*hovering*/); + + if (entry->source & AINPUT_SOURCE_CLASS_JOYSTICK) { + // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all + // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral. Any + // other value and we need to track the motion so we can send cancellation events for + // anything generating fallback events (e.g. DPad keys for joystick movements). + if (index >= 0) { + if (entry->pointerCoords[0].isEmpty()) { + mMotionMementos.erase(mMotionMementos.begin() + index); + } else { + MotionMemento& memento = mMotionMementos[index]; + memento.setPointers(entry); + } + } else if (!entry->pointerCoords[0].isEmpty()) { + addMotionMemento(entry, flags, false /*hovering*/); + } + + // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP. + return true; + } + if (index >= 0) { + MotionMemento& memento = mMotionMementos[index]; + memento.setPointers(entry); + return true; + } +#if DEBUG_OUTBOUND_EVENT_DETAILS + ALOGD("Dropping inconsistent motion pointer up/down or move event: " + "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d", + entry->deviceId, entry->source, entry->displayId, actionMasked); +#endif + return false; + } + + case AMOTION_EVENT_ACTION_HOVER_EXIT: { + ssize_t index = findMotionMemento(entry, true /*hovering*/); + if (index >= 0) { + mMotionMementos.erase(mMotionMementos.begin() + index); + return true; + } +#if DEBUG_OUTBOUND_EVENT_DETAILS + ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, " + "displayId=%" PRId32, + entry->deviceId, entry->source, entry->displayId); +#endif + return false; + } + + case AMOTION_EVENT_ACTION_HOVER_ENTER: + case AMOTION_EVENT_ACTION_HOVER_MOVE: { + ssize_t index = findMotionMemento(entry, true /*hovering*/); + if (index >= 0) { + mMotionMementos.erase(mMotionMementos.begin() + index); + } + addMotionMemento(entry, flags, true /*hovering*/); + return true; + } + + default: + return true; + } +} + +ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const { + for (size_t i = 0; i < mKeyMementos.size(); i++) { + const KeyMemento& memento = mKeyMementos[i]; + if (memento.deviceId == entry->deviceId + && memento.source == entry->source + && memento.displayId == entry->displayId + && memento.keyCode == entry->keyCode + && memento.scanCode == entry->scanCode) { + return i; + } + } + return -1; +} + +ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry, + bool hovering) const { + for (size_t i = 0; i < mMotionMementos.size(); i++) { + const MotionMemento& memento = mMotionMementos[i]; + if (memento.deviceId == entry->deviceId + && memento.source == entry->source + && memento.displayId == entry->displayId + && memento.hovering == hovering) { + return i; + } + } + return -1; +} + +void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) { + KeyMemento memento; + memento.deviceId = entry->deviceId; + memento.source = entry->source; + memento.displayId = entry->displayId; + memento.keyCode = entry->keyCode; + memento.scanCode = entry->scanCode; + memento.metaState = entry->metaState; + memento.flags = flags; + memento.downTime = entry->downTime; + memento.policyFlags = entry->policyFlags; + mKeyMementos.push_back(memento); +} + +void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, + int32_t flags, bool hovering) { + MotionMemento memento; + memento.deviceId = entry->deviceId; + memento.source = entry->source; + memento.displayId = entry->displayId; + memento.flags = flags; + memento.xPrecision = entry->xPrecision; + memento.yPrecision = entry->yPrecision; + memento.downTime = entry->downTime; + memento.setPointers(entry); + memento.hovering = hovering; + memento.policyFlags = entry->policyFlags; + mMotionMementos.push_back(memento); +} + +void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) { + pointerCount = entry->pointerCount; + for (uint32_t i = 0; i < entry->pointerCount; i++) { + pointerProperties[i].copyFrom(entry->pointerProperties[i]); + pointerCoords[i].copyFrom(entry->pointerCoords[i]); + } +} + +void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, + std::vector<EventEntry*>& outEvents, const CancelationOptions& options) { + for (KeyMemento& memento : mKeyMementos) { + if (shouldCancelKey(memento, options)) { + outEvents.push_back(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, + memento.deviceId, memento.source, memento.displayId, memento.policyFlags, + AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, + memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime)); + } + } + + for (const MotionMemento& memento : mMotionMementos) { + if (shouldCancelMotion(memento, options)) { + const int32_t action = memento.hovering ? + AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; + outEvents.push_back(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, + memento.deviceId, memento.source, memento.displayId, memento.policyFlags, + action, 0 /*actionButton*/, memento.flags, AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + memento.xPrecision, memento.yPrecision, memento.downTime, + memento.pointerCount, memento.pointerProperties, memento.pointerCoords, + 0 /*xOffset*/, 0 /*yOffset*/)); + } + } +} + +void InputDispatcher::InputState::clear() { + mKeyMementos.clear(); + mMotionMementos.clear(); + mFallbackKeys.clear(); +} + +void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { + for (size_t i = 0; i < mMotionMementos.size(); i++) { + const MotionMemento& memento = mMotionMementos[i]; + if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { + for (size_t j = 0; j < other.mMotionMementos.size(); ) { + const MotionMemento& otherMemento = other.mMotionMementos[j]; + if (memento.deviceId == otherMemento.deviceId + && memento.source == otherMemento.source + && memento.displayId == otherMemento.displayId) { + other.mMotionMementos.erase(other.mMotionMementos.begin() + j); + } else { + j += 1; + } + } + other.mMotionMementos.push_back(memento); + } + } +} + +int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) { + ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); + return index >= 0 ? mFallbackKeys.valueAt(index) : -1; +} + +void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode, + int32_t fallbackKeyCode) { + ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); + if (index >= 0) { + mFallbackKeys.replaceValueAt(index, fallbackKeyCode); + } else { + mFallbackKeys.add(originalKeyCode, fallbackKeyCode); + } +} + +void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) { + mFallbackKeys.removeItem(originalKeyCode); +} + +bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, + const CancelationOptions& options) { + if (options.keyCode && memento.keyCode != options.keyCode.value()) { + return false; + } + + if (options.deviceId && memento.deviceId != options.deviceId.value()) { + return false; + } + + if (options.displayId && memento.displayId != options.displayId.value()) { + return false; + } + + switch (options.mode) { + case CancelationOptions::CANCEL_ALL_EVENTS: + case CancelationOptions::CANCEL_NON_POINTER_EVENTS: + return true; + case CancelationOptions::CANCEL_FALLBACK_EVENTS: + return memento.flags & AKEY_EVENT_FLAG_FALLBACK; + default: + return false; + } +} + +bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, + const CancelationOptions& options) { + if (options.deviceId && memento.deviceId != options.deviceId.value()) { + return false; + } + + if (options.displayId && memento.displayId != options.displayId.value()) { + return false; + } + + switch (options.mode) { + case CancelationOptions::CANCEL_ALL_EVENTS: + return true; + case CancelationOptions::CANCEL_POINTER_EVENTS: + return memento.source & AINPUT_SOURCE_CLASS_POINTER; + case CancelationOptions::CANCEL_NON_POINTER_EVENTS: + return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); + default: + return false; + } +} + + +// --- InputDispatcher::Connection --- + +InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor) : + status(STATUS_NORMAL), inputChannel(inputChannel), + monitor(monitor), + inputPublisher(inputChannel), inputPublisherBlocked(false) { +} + +InputDispatcher::Connection::~Connection() { +} + +const std::string InputDispatcher::Connection::getWindowName() const { + if (inputChannel != nullptr) { + return inputChannel->getName(); + } + if (monitor) { + return "monitor"; + } + return "?"; +} + +const char* InputDispatcher::Connection::getStatusLabel() const { + switch (status) { + case STATUS_NORMAL: + return "NORMAL"; + + case STATUS_BROKEN: + return "BROKEN"; + + case STATUS_ZOMBIE: + return "ZOMBIE"; + + default: + return "UNKNOWN"; + } +} + +InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) { + for (DispatchEntry* entry = waitQueue.head; entry != nullptr; entry = entry->next) { + if (entry->seq == seq) { + return entry; + } + } + return nullptr; +} + +// --- InputDispatcher::Monitor +InputDispatcher::Monitor::Monitor(const sp<InputChannel>& inputChannel) : + inputChannel(inputChannel) { +} + + +// --- InputDispatcher::CommandEntry --- +// +InputDispatcher::CommandEntry::CommandEntry(Command command) : + command(command), eventTime(0), keyEntry(nullptr), userActivityEventType(0), + seq(0), handled(false) { +} + +InputDispatcher::CommandEntry::~CommandEntry() { +} + +// --- InputDispatcher::TouchedMonitor --- +InputDispatcher::TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset, + float yOffset) : monitor(monitor), xOffset(xOffset), yOffset(yOffset) { +} + +// --- InputDispatcher::TouchState --- + +InputDispatcher::TouchState::TouchState() : + down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) { +} + +InputDispatcher::TouchState::~TouchState() { +} + +void InputDispatcher::TouchState::reset() { + down = false; + split = false; + deviceId = -1; + source = 0; + displayId = ADISPLAY_ID_NONE; + windows.clear(); + portalWindows.clear(); + gestureMonitors.clear(); +} + +void InputDispatcher::TouchState::copyFrom(const TouchState& other) { + down = other.down; + split = other.split; + deviceId = other.deviceId; + source = other.source; + displayId = other.displayId; + windows = other.windows; + portalWindows = other.portalWindows; + gestureMonitors = other.gestureMonitors; +} + +void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, + int32_t targetFlags, BitSet32 pointerIds) { + if (targetFlags & InputTarget::FLAG_SPLIT) { + split = true; + } + + for (size_t i = 0; i < windows.size(); i++) { + TouchedWindow& touchedWindow = windows[i]; + if (touchedWindow.windowHandle == windowHandle) { + touchedWindow.targetFlags |= targetFlags; + if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { + touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; + } + touchedWindow.pointerIds.value |= pointerIds.value; + return; + } + } + + TouchedWindow touchedWindow; + touchedWindow.windowHandle = windowHandle; + touchedWindow.targetFlags = targetFlags; + touchedWindow.pointerIds = pointerIds; + windows.push_back(touchedWindow); +} + +void InputDispatcher::TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) { + size_t numWindows = portalWindows.size(); + for (size_t i = 0; i < numWindows; i++) { + if (portalWindows[i] == windowHandle) { + return; + } + } + portalWindows.push_back(windowHandle); +} + +void InputDispatcher::TouchState::addGestureMonitors( + const std::vector<TouchedMonitor>& newMonitors) { + const size_t newSize = gestureMonitors.size() + newMonitors.size(); + gestureMonitors.reserve(newSize); + gestureMonitors.insert(std::end(gestureMonitors), + std::begin(newMonitors), std::end(newMonitors)); +} + +void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) { + for (size_t i = 0; i < windows.size(); i++) { + if (windows[i].windowHandle == windowHandle) { + windows.erase(windows.begin() + i); + return; + } + } +} + +void InputDispatcher::TouchState::removeWindowByToken(const sp<IBinder>& token) { + for (size_t i = 0; i < windows.size(); i++) { + if (windows[i].windowHandle->getToken() == token) { + windows.erase(windows.begin() + i); + return; + } + } +} + +void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { + for (size_t i = 0 ; i < windows.size(); ) { + TouchedWindow& window = windows[i]; + if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS + | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) { + window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK; + window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS; + i += 1; + } else { + windows.erase(windows.begin() + i); + } + } +} + +void InputDispatcher::TouchState::filterNonMonitors() { + windows.clear(); + portalWindows.clear(); +} + +sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const { + for (size_t i = 0; i < windows.size(); i++) { + const TouchedWindow& window = windows[i]; + if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { + return window.windowHandle; + } + } + return nullptr; +} + +bool InputDispatcher::TouchState::isSlippery() const { + // Must have exactly one foreground window. + bool haveSlipperyForegroundWindow = false; + for (const TouchedWindow& window : windows) { + if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { + if (haveSlipperyForegroundWindow + || !(window.windowHandle->getInfo()->layoutParamsFlags + & InputWindowInfo::FLAG_SLIPPERY)) { + return false; + } + haveSlipperyForegroundWindow = true; + } + } + return haveSlipperyForegroundWindow; +} + + +// --- InputDispatcherThread --- + +InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) : + Thread(/*canCallJava*/ true), mDispatcher(dispatcher) { +} + +InputDispatcherThread::~InputDispatcherThread() { +} + +bool InputDispatcherThread::threadLoop() { + mDispatcher->dispatchOnce(); + return true; +} + +} // namespace android diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h new file mode 100644 index 0000000000..753b748884 --- /dev/null +++ b/services/inputflinger/InputDispatcher.h @@ -0,0 +1,1305 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UI_INPUT_DISPATCHER_H +#define _UI_INPUT_DISPATCHER_H + +#include <condition_variable> +#include <input/Input.h> +#include <input/InputApplication.h> +#include <input/InputTransport.h> +#include <input/InputWindow.h> +#include <input/ISetInputWindowsListener.h> +#include <optional> +#include <ui/Region.h> +#include <utils/threads.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/Looper.h> +#include <utils/BitSet.h> +#include <cutils/atomic.h> +#include <unordered_map> + +#include <stddef.h> +#include <unistd.h> +#include <limits.h> +#include <unordered_map> + +#include "InputListener.h" +#include "InputReporterInterface.h" + +namespace android { + +/* + * Constants used to report the outcome of input event injection. + */ +enum { + /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */ + INPUT_EVENT_INJECTION_PENDING = -1, + + /* Injection succeeded. */ + INPUT_EVENT_INJECTION_SUCCEEDED = 0, + + /* Injection failed because the injector did not have permission to inject + * into the application with input focus. */ + INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1, + + /* Injection failed because there were no available input targets. */ + INPUT_EVENT_INJECTION_FAILED = 2, + + /* Injection failed due to a timeout. */ + INPUT_EVENT_INJECTION_TIMED_OUT = 3 +}; + +/* + * Constants used to determine the input event injection synchronization mode. + */ +enum { + /* Injection is asynchronous and is assumed always to be successful. */ + INPUT_EVENT_INJECTION_SYNC_NONE = 0, + + /* Waits for previous events to be dispatched so that the input dispatcher can determine + * whether input event injection willbe permitted based on the current input focus. + * Does not wait for the input event to finish processing. */ + INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1, + + /* Waits for the input event to be completely processed. */ + INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2, +}; + + +/* + * An input target specifies how an input event is to be dispatched to a particular window + * including the window's input channel, control flags, a timeout, and an X / Y offset to + * be added to input event coordinates to compensate for the absolute position of the + * window area. + */ +struct InputTarget { + enum { + /* This flag indicates that the event is being delivered to a foreground application. */ + FLAG_FOREGROUND = 1 << 0, + + /* This flag indicates that the MotionEvent falls within the area of the target + * obscured by another visible window above it. The motion event should be + * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ + FLAG_WINDOW_IS_OBSCURED = 1 << 1, + + /* This flag indicates that a motion event is being split across multiple windows. */ + FLAG_SPLIT = 1 << 2, + + /* This flag indicates that the pointer coordinates dispatched to the application + * will be zeroed out to avoid revealing information to an application. This is + * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing + * the same UID from watching all touches. */ + FLAG_ZERO_COORDS = 1 << 3, + + /* This flag indicates that the event should be sent as is. + * Should always be set unless the event is to be transmuted. */ + FLAG_DISPATCH_AS_IS = 1 << 8, + + /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside + * of the area of this target and so should instead be delivered as an + * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ + FLAG_DISPATCH_AS_OUTSIDE = 1 << 9, + + /* This flag indicates that a hover sequence is starting in the given window. + * The event is transmuted into ACTION_HOVER_ENTER. */ + FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10, + + /* This flag indicates that a hover event happened outside of a window which handled + * previous hover events, signifying the end of the current hover sequence for that + * window. + * The event is transmuted into ACTION_HOVER_ENTER. */ + FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, + + /* This flag indicates that the event should be canceled. + * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips + * outside of a window. */ + FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12, + + /* This flag indicates that the event should be dispatched as an initial down. + * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips + * into a new window. */ + FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13, + + /* Mask for all dispatch modes. */ + FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS + | FLAG_DISPATCH_AS_OUTSIDE + | FLAG_DISPATCH_AS_HOVER_ENTER + | FLAG_DISPATCH_AS_HOVER_EXIT + | FLAG_DISPATCH_AS_SLIPPERY_EXIT + | FLAG_DISPATCH_AS_SLIPPERY_ENTER, + + /* This flag indicates that the target of a MotionEvent is partly or wholly + * obscured by another visible window above it. The motion event should be + * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */ + FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14, + + }; + + // The input channel to be targeted. + sp<InputChannel> inputChannel; + + // Flags for the input target. + int32_t flags; + + // The x and y offset to add to a MotionEvent as it is delivered. + // (ignored for KeyEvents) + float xOffset, yOffset; + + // Scaling factor to apply to MotionEvent as it is delivered. + // (ignored for KeyEvents) + float globalScaleFactor; + float windowXScale = 1.0f; + float windowYScale = 1.0f; + + // The subset of pointer ids to include in motion events dispatched to this input target + // if FLAG_SPLIT is set. + BitSet32 pointerIds; +}; + + +/* + * Input dispatcher configuration. + * + * Specifies various options that modify the behavior of the input dispatcher. + * The values provided here are merely defaults. The actual values will come from ViewConfiguration + * and are passed into the dispatcher during initialization. + */ +struct InputDispatcherConfiguration { + // The key repeat initial timeout. + nsecs_t keyRepeatTimeout; + + // The key repeat inter-key delay. + nsecs_t keyRepeatDelay; + + InputDispatcherConfiguration() : + keyRepeatTimeout(500 * 1000000LL), + keyRepeatDelay(50 * 1000000LL) { } +}; + + +/* + * Input dispatcher policy interface. + * + * The input reader policy is used by the input reader to interact with the Window Manager + * and other system components. + * + * The actual implementation is partially supported by callbacks into the DVM + * via JNI. This interface is also mocked in the unit tests. + */ +class InputDispatcherPolicyInterface : public virtual RefBase { +protected: + InputDispatcherPolicyInterface() { } + virtual ~InputDispatcherPolicyInterface() { } + +public: + /* Notifies the system that a configuration change has occurred. */ + virtual void notifyConfigurationChanged(nsecs_t when) = 0; + + /* Notifies the system that an application is not responding. + * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ + virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, + const sp<IBinder>& token, + const std::string& reason) = 0; + + /* Notifies the system that an input channel is unrecoverably broken. */ + virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0; + virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0; + + /* Gets the input dispatcher configuration. */ + virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; + + /* Filters an input event. + * Return true to dispatch the event unmodified, false to consume the event. + * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED + * to injectInputEvent. + */ + virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0; + + /* Intercepts a key event immediately before queueing it. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing such as updating policy flags. + * + * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event + * should be dispatched to applications. + */ + virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; + + /* Intercepts a touch, trackball or other motion event before queueing it. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing such as updating policy flags. + * + * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event + * should be dispatched to applications. + */ + virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when, + uint32_t& policyFlags) = 0; + + /* Allows the policy a chance to intercept a key before dispatching. */ + virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token, + const KeyEvent* keyEvent, uint32_t policyFlags) = 0; + + /* Allows the policy a chance to perform default processing for an unhandled key. + * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */ + virtual bool dispatchUnhandledKey(const sp<IBinder>& token, + const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0; + + /* Notifies the policy about switch events. + */ + virtual void notifySwitch(nsecs_t when, + uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) = 0; + + /* Poke user activity for an event dispatched to a window. */ + virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; + + /* Checks whether a given application pid/uid has permission to inject input events + * into other applications. + * + * This method is special in that its implementation promises to be non-reentrant and + * is safe to call while holding other locks. (Most other methods make no such guarantees!) + */ + virtual bool checkInjectEventsPermissionNonReentrant( + int32_t injectorPid, int32_t injectorUid) = 0; + + /* Notifies the policy that a pointer down event has occurred outside the current focused + * window. + * + * The touchedToken passed as an argument is the window that received the input event. + */ + virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0; +}; + + +/* Notifies the system about input events generated by the input reader. + * The dispatcher is expected to be mostly asynchronous. */ +class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface { +protected: + InputDispatcherInterface() { } + virtual ~InputDispatcherInterface() { } + +public: + /* Dumps the state of the input dispatcher. + * + * This method may be called on any thread (usually by the input manager). */ + virtual void dump(std::string& dump) = 0; + + /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ + virtual void monitor() = 0; + + /* Runs a single iteration of the dispatch loop. + * Nominally processes one queued event, a timeout, or a response from an input consumer. + * + * This method should only be called on the input dispatcher thread. + */ + virtual void dispatchOnce() = 0; + + /* Injects an input event and optionally waits for sync. + * The synchronization mode determines whether the method blocks while waiting for + * input injection to proceed. + * Returns one of the INPUT_EVENT_INJECTION_XXX constants. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual int32_t injectInputEvent(const InputEvent* event, + int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, + uint32_t policyFlags) = 0; + + /* Sets the list of input windows. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual void setInputWindows(const std::vector<sp<InputWindowHandle> >& inputWindowHandles, + int32_t displayId, + const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) = 0; + + /* Sets the focused application on the given display. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual void setFocusedApplication( + int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) = 0; + + /* Sets the focused display. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual void setFocusedDisplay(int32_t displayId) = 0; + + /* Sets the input dispatching mode. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual void setInputDispatchMode(bool enabled, bool frozen) = 0; + + /* Sets whether input event filtering is enabled. + * When enabled, incoming input events are sent to the policy's filterInputEvent + * method instead of being dispatched. The filter is expected to use + * injectInputEvent to inject the events it would like to have dispatched. + * It should include POLICY_FLAG_FILTERED in the policy flags during injection. + */ + virtual void setInputFilterEnabled(bool enabled) = 0; + + /* Transfers touch focus from one window to another window. + * + * Returns true on success. False if the window did not actually have touch focus. + */ + virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0; + + /* Registers input channels that may be used as targets for input events. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual status_t registerInputChannel( + const sp<InputChannel>& inputChannel, int32_t displayId) = 0; + + /* Registers input channels to be used to monitor input events. + * + * Each monitor must target a specific display and will only receive input events sent to that + * display. If the monitor is a gesture monitor, it will only receive pointer events on the + * targeted display. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual status_t registerInputMonitor( + const sp<InputChannel>& inputChannel, int32_t displayId, bool gestureMonitor) = 0; + + /* Unregister input channels that will no longer receive input events. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; + + /* Allows an input monitor steal the current pointer stream away from normal input windows. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual status_t pilferPointers(const sp<IBinder>& token) = 0; + +}; + +/* Dispatches events to input targets. Some functions of the input dispatcher, such as + * identifying input targets, are controlled by a separate policy object. + * + * IMPORTANT INVARIANT: + * Because the policy can potentially block or cause re-entrance into the input dispatcher, + * the input dispatcher never calls into the policy while holding its internal locks. + * The implementation is also carefully designed to recover from scenarios such as an + * input channel becoming unregistered while identifying input targets or processing timeouts. + * + * Methods marked 'Locked' must be called with the lock acquired. + * + * Methods marked 'LockedInterruptible' must be called with the lock acquired but + * may during the course of their execution release the lock, call into the policy, and + * then reacquire the lock. The caller is responsible for recovering gracefully. + * + * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. + */ +class InputDispatcher : public InputDispatcherInterface { +protected: + virtual ~InputDispatcher(); + +public: + explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); + + virtual void dump(std::string& dump) override; + virtual void monitor() override; + + virtual void dispatchOnce() override; + + virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; + virtual void notifyKey(const NotifyKeyArgs* args) override; + virtual void notifyMotion(const NotifyMotionArgs* args) override; + virtual void notifySwitch(const NotifySwitchArgs* args) override; + virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; + + virtual int32_t injectInputEvent(const InputEvent* event, + int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, + uint32_t policyFlags) override; + + virtual void setInputWindows(const std::vector<sp<InputWindowHandle> >& inputWindowHandles, + int32_t displayId, + const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override; + virtual void setFocusedApplication(int32_t displayId, + const sp<InputApplicationHandle>& inputApplicationHandle) override; + virtual void setFocusedDisplay(int32_t displayId) override; + virtual void setInputDispatchMode(bool enabled, bool frozen) override; + virtual void setInputFilterEnabled(bool enabled) override; + + virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) + override; + + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, + int32_t displayId) override; + virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, + int32_t displayId, bool isGestureMonitor) override; + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) override; + virtual status_t pilferPointers(const sp<IBinder>& token) override; + +private: + template <typename T> + struct Link { + T* next; + T* prev; + + protected: + inline Link() : next(nullptr), prev(nullptr) { } + }; + + struct InjectionState { + mutable int32_t refCount; + + int32_t injectorPid; + int32_t injectorUid; + int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING + bool injectionIsAsync; // set to true if injection is not waiting for the result + int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress + + InjectionState(int32_t injectorPid, int32_t injectorUid); + void release(); + + private: + ~InjectionState(); + }; + + struct EventEntry : Link<EventEntry> { + enum { + TYPE_CONFIGURATION_CHANGED, + TYPE_DEVICE_RESET, + TYPE_KEY, + TYPE_MOTION + }; + + uint32_t sequenceNum; + mutable int32_t refCount; + int32_t type; + nsecs_t eventTime; + uint32_t policyFlags; + InjectionState* injectionState; + + bool dispatchInProgress; // initially false, set to true while dispatching + + inline bool isInjected() const { return injectionState != nullptr; } + + void release(); + + virtual void appendDescription(std::string& msg) const = 0; + + protected: + EventEntry(uint32_t sequenceNum, int32_t type, nsecs_t eventTime, uint32_t policyFlags); + virtual ~EventEntry(); + void releaseInjectionState(); + }; + + struct ConfigurationChangedEntry : EventEntry { + explicit ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime); + virtual void appendDescription(std::string& msg) const; + + protected: + virtual ~ConfigurationChangedEntry(); + }; + + struct DeviceResetEntry : EventEntry { + int32_t deviceId; + + DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId); + virtual void appendDescription(std::string& msg) const; + + protected: + virtual ~DeviceResetEntry(); + }; + + struct KeyEntry : EventEntry { + int32_t deviceId; + uint32_t source; + int32_t displayId; + int32_t action; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + int32_t repeatCount; + nsecs_t downTime; + + bool syntheticRepeat; // set to true for synthetic key repeats + + enum InterceptKeyResult { + INTERCEPT_KEY_RESULT_UNKNOWN, + INTERCEPT_KEY_RESULT_SKIP, + INTERCEPT_KEY_RESULT_CONTINUE, + INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER, + }; + InterceptKeyResult interceptKeyResult; // set based on the interception result + nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER + + KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, + int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, + int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, + int32_t repeatCount, nsecs_t downTime); + virtual void appendDescription(std::string& msg) const; + void recycle(); + + protected: + virtual ~KeyEntry(); + }; + + struct MotionEntry : EventEntry { + nsecs_t eventTime; + int32_t deviceId; + uint32_t source; + int32_t displayId; + int32_t action; + int32_t actionButton; + int32_t flags; + int32_t metaState; + int32_t buttonState; + MotionClassification classification; + int32_t edgeFlags; + float xPrecision; + float yPrecision; + nsecs_t downTime; + uint32_t pointerCount; + PointerProperties pointerProperties[MAX_POINTERS]; + PointerCoords pointerCoords[MAX_POINTERS]; + + MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, + int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, + int32_t action, int32_t actionButton, int32_t flags, + int32_t metaState, int32_t buttonState, MotionClassification classification, + int32_t edgeFlags, float xPrecision, float yPrecision, + nsecs_t downTime, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset); + virtual void appendDescription(std::string& msg) const; + + protected: + virtual ~MotionEntry(); + }; + + // Tracks the progress of dispatching a particular event to a particular connection. + struct DispatchEntry : Link<DispatchEntry> { + const uint32_t seq; // unique sequence number, never 0 + + EventEntry* eventEntry; // the event to dispatch + int32_t targetFlags; + float xOffset; + float yOffset; + float globalScaleFactor; + float windowXScale = 1.0f; + float windowYScale = 1.0f; + nsecs_t deliveryTime; // time when the event was actually delivered + + // Set to the resolved action and flags when the event is enqueued. + int32_t resolvedAction; + int32_t resolvedFlags; + + DispatchEntry(EventEntry* eventEntry, + int32_t targetFlags, float xOffset, float yOffset, + float globalScaleFactor, float windowXScale, float windowYScale); + ~DispatchEntry(); + + inline bool hasForegroundTarget() const { + return targetFlags & InputTarget::FLAG_FOREGROUND; + } + + inline bool isSplit() const { + return targetFlags & InputTarget::FLAG_SPLIT; + } + + private: + static volatile int32_t sNextSeqAtomic; + + static uint32_t nextSeq(); + }; + + // A command entry captures state and behavior for an action to be performed in the + // dispatch loop after the initial processing has taken place. It is essentially + // a kind of continuation used to postpone sensitive policy interactions to a point + // in the dispatch loop where it is safe to release the lock (generally after finishing + // the critical parts of the dispatch cycle). + // + // The special thing about commands is that they can voluntarily release and reacquire + // the dispatcher lock at will. Initially when the command starts running, the + // dispatcher lock is held. However, if the command needs to call into the policy to + // do some work, it can release the lock, do the work, then reacquire the lock again + // before returning. + // + // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch + // never calls into the policy while holding its lock. + // + // Commands are implicitly 'LockedInterruptible'. + struct CommandEntry; + typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry); + + class Connection; + struct CommandEntry : Link<CommandEntry> { + explicit CommandEntry(Command command); + ~CommandEntry(); + + Command command; + + // parameters for the command (usage varies by command) + sp<Connection> connection; + nsecs_t eventTime; + KeyEntry* keyEntry; + sp<InputApplicationHandle> inputApplicationHandle; + std::string reason; + int32_t userActivityEventType; + uint32_t seq; + bool handled; + sp<InputChannel> inputChannel; + sp<IBinder> oldToken; + sp<IBinder> newToken; + }; + + // Generic queue implementation. + template <typename T> + struct Queue { + T* head; + T* tail; + uint32_t entryCount; + + inline Queue() : head(nullptr), tail(nullptr), entryCount(0) { + } + + inline bool isEmpty() const { + return !head; + } + + inline void enqueueAtTail(T* entry) { + entryCount++; + entry->prev = tail; + if (tail) { + tail->next = entry; + } else { + head = entry; + } + entry->next = nullptr; + tail = entry; + } + + inline void enqueueAtHead(T* entry) { + entryCount++; + entry->next = head; + if (head) { + head->prev = entry; + } else { + tail = entry; + } + entry->prev = nullptr; + head = entry; + } + + inline void dequeue(T* entry) { + entryCount--; + if (entry->prev) { + entry->prev->next = entry->next; + } else { + head = entry->next; + } + if (entry->next) { + entry->next->prev = entry->prev; + } else { + tail = entry->prev; + } + } + + inline T* dequeueAtHead() { + entryCount--; + T* entry = head; + head = entry->next; + if (head) { + head->prev = nullptr; + } else { + tail = nullptr; + } + return entry; + } + + uint32_t count() const { + return entryCount; + } + }; + + /* Specifies which events are to be canceled and why. */ + struct CancelationOptions { + enum Mode { + CANCEL_ALL_EVENTS = 0, + CANCEL_POINTER_EVENTS = 1, + CANCEL_NON_POINTER_EVENTS = 2, + CANCEL_FALLBACK_EVENTS = 3, + }; + + // The criterion to use to determine which events should be canceled. + Mode mode; + + // Descriptive reason for the cancelation. + const char* reason; + + // The specific keycode of the key event to cancel, or nullopt to cancel any key event. + std::optional<int32_t> keyCode = std::nullopt; + + // The specific device id of events to cancel, or nullopt to cancel events from any device. + std::optional<int32_t> deviceId = std::nullopt; + + // The specific display id of events to cancel, or nullopt to cancel events on any display. + std::optional<int32_t> displayId = std::nullopt; + + CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) { } + }; + + /* Tracks dispatched key and motion event state so that cancelation events can be + * synthesized when events are dropped. */ + class InputState { + public: + InputState(); + ~InputState(); + + // Returns true if there is no state to be canceled. + bool isNeutral() const; + + // Returns true if the specified source is known to have received a hover enter + // motion event. + bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const; + + // Records tracking information for a key event that has just been published. + // Returns true if the event should be delivered, false if it is inconsistent + // and should be skipped. + bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags); + + // Records tracking information for a motion event that has just been published. + // Returns true if the event should be delivered, false if it is inconsistent + // and should be skipped. + bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags); + + // Synthesizes cancelation events for the current state and resets the tracked state. + void synthesizeCancelationEvents(nsecs_t currentTime, + std::vector<EventEntry*>& outEvents, const CancelationOptions& options); + + // Clears the current state. + void clear(); + + // Copies pointer-related parts of the input state to another instance. + void copyPointerStateTo(InputState& other) const; + + // Gets the fallback key associated with a keycode. + // Returns -1 if none. + // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy. + int32_t getFallbackKey(int32_t originalKeyCode); + + // Sets the fallback key for a particular keycode. + void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode); + + // Removes the fallback key for a particular keycode. + void removeFallbackKey(int32_t originalKeyCode); + + inline const KeyedVector<int32_t, int32_t>& getFallbackKeys() const { + return mFallbackKeys; + } + + private: + struct KeyMemento { + int32_t deviceId; + uint32_t source; + int32_t displayId; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + int32_t flags; + nsecs_t downTime; + uint32_t policyFlags; + }; + + struct MotionMemento { + int32_t deviceId; + uint32_t source; + int32_t displayId; + int32_t flags; + float xPrecision; + float yPrecision; + nsecs_t downTime; + uint32_t pointerCount; + PointerProperties pointerProperties[MAX_POINTERS]; + PointerCoords pointerCoords[MAX_POINTERS]; + bool hovering; + uint32_t policyFlags; + + void setPointers(const MotionEntry* entry); + }; + + std::vector<KeyMemento> mKeyMementos; + std::vector<MotionMemento> mMotionMementos; + KeyedVector<int32_t, int32_t> mFallbackKeys; + + ssize_t findKeyMemento(const KeyEntry* entry) const; + ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const; + + void addKeyMemento(const KeyEntry* entry, int32_t flags); + void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering); + + static bool shouldCancelKey(const KeyMemento& memento, + const CancelationOptions& options); + static bool shouldCancelMotion(const MotionMemento& memento, + const CancelationOptions& options); + }; + + /* Manages the dispatch state associated with a single input channel. */ + class Connection : public RefBase { + protected: + virtual ~Connection(); + + public: + enum Status { + // Everything is peachy. + STATUS_NORMAL, + // An unrecoverable communication error has occurred. + STATUS_BROKEN, + // The input channel has been unregistered. + STATUS_ZOMBIE + }; + + Status status; + sp<InputChannel> inputChannel; // never null + bool monitor; + InputPublisher inputPublisher; + InputState inputState; + + // True if the socket is full and no further events can be published until + // the application consumes some of the input. + bool inputPublisherBlocked; + + // Queue of events that need to be published to the connection. + Queue<DispatchEntry> outboundQueue; + + // Queue of events that have been published to the connection but that have not + // yet received a "finished" response from the application. + Queue<DispatchEntry> waitQueue; + + explicit Connection(const sp<InputChannel>& inputChannel, bool monitor); + + inline const std::string getInputChannelName() const { return inputChannel->getName(); } + + const std::string getWindowName() const; + const char* getStatusLabel() const; + + DispatchEntry* findWaitQueueEntry(uint32_t seq); + }; + + struct Monitor { + sp<InputChannel> inputChannel; // never null + + explicit Monitor(const sp<InputChannel>& inputChannel); + }; + + enum DropReason { + DROP_REASON_NOT_DROPPED = 0, + DROP_REASON_POLICY = 1, + DROP_REASON_APP_SWITCH = 2, + DROP_REASON_DISABLED = 3, + DROP_REASON_BLOCKED = 4, + DROP_REASON_STALE = 5, + }; + + sp<InputDispatcherPolicyInterface> mPolicy; + InputDispatcherConfiguration mConfig; + + std::mutex mLock; + + std::condition_variable mDispatcherIsAlive; + + sp<Looper> mLooper; + + EventEntry* mPendingEvent GUARDED_BY(mLock); + Queue<EventEntry> mInboundQueue GUARDED_BY(mLock); + Queue<EventEntry> mRecentQueue GUARDED_BY(mLock); + Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock); + + DropReason mLastDropReason GUARDED_BY(mLock); + + void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) REQUIRES(mLock); + + // Enqueues an inbound event. Returns true if mLooper->wake() should be called. + bool enqueueInboundEventLocked(EventEntry* entry) REQUIRES(mLock); + + // Cleans up input state when dropping an inbound event. + void dropInboundEventLocked(EventEntry* entry, DropReason dropReason) REQUIRES(mLock); + + // Adds an event to a queue of recent events for debugging purposes. + void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock); + + // App switch latency optimization. + bool mAppSwitchSawKeyDown GUARDED_BY(mLock); + nsecs_t mAppSwitchDueTime GUARDED_BY(mLock); + + bool isAppSwitchKeyEvent(KeyEntry* keyEntry); + bool isAppSwitchPendingLocked() REQUIRES(mLock); + void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock); + + // Stale event latency optimization. + static bool isStaleEvent(nsecs_t currentTime, EventEntry* entry); + + // Blocked event latency optimization. Drops old events when the user intends + // to transfer focus to a new application. + EventEntry* mNextUnblockedEvent GUARDED_BY(mLock); + + sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, + bool addOutsideTargets = false, bool addPortalWindows = false) REQUIRES(mLock); + + // All registered connections mapped by channel file descriptor. + KeyedVector<int, sp<Connection> > mConnectionsByFd GUARDED_BY(mLock); + + struct IBinderHash { + std::size_t operator()(const sp<IBinder>& b) const { + return std::hash<IBinder *>{}(b.get()); + } + }; + std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken + GUARDED_BY(mLock); + + // Finds the display ID of the gesture monitor identified by the provided token. + std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token) + REQUIRES(mLock); + + ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); + + // Input channels that will receive a copy of all input events sent to the provided display. + std::unordered_map<int32_t, std::vector<Monitor>> mGlobalMonitorsByDisplay + GUARDED_BY(mLock); + + // Input channels that will receive pointer events that start within the corresponding display. + // These are a bit special when compared to global monitors since they'll cause gesture streams + // to continue even when there isn't a touched window,and have the ability to steal the rest of + // the pointer stream in order to claim it for a system gesture. + std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay + GUARDED_BY(mLock); + + + // Event injection and synchronization. + std::condition_variable mInjectionResultAvailable; + bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); + void setInjectionResult(EventEntry* entry, int32_t injectionResult); + + std::condition_variable mInjectionSyncFinished; + void incrementPendingForegroundDispatches(EventEntry* entry); + void decrementPendingForegroundDispatches(EventEntry* entry); + + // Key repeat tracking. + struct KeyRepeatState { + KeyEntry* lastKeyEntry; // or null if no repeat + nsecs_t nextRepeatTime; + } mKeyRepeatState GUARDED_BY(mLock); + + void resetKeyRepeatLocked() REQUIRES(mLock); + KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock); + + // Key replacement tracking + struct KeyReplacement { + int32_t keyCode; + int32_t deviceId; + bool operator==(const KeyReplacement& rhs) const { + return keyCode == rhs.keyCode && deviceId == rhs.deviceId; + } + bool operator<(const KeyReplacement& rhs) const { + return keyCode != rhs.keyCode ? keyCode < rhs.keyCode : deviceId < rhs.deviceId; + } + }; + // Maps the key code replaced, device id tuple to the key code it was replaced with + KeyedVector<KeyReplacement, int32_t> mReplacedKeys GUARDED_BY(mLock); + // Process certain Meta + Key combinations + void accelerateMetaShortcuts(const int32_t deviceId, const int32_t action, + int32_t& keyCode, int32_t& metaState); + + // Deferred command processing. + bool haveCommandsLocked() const REQUIRES(mLock); + bool runCommandsLockedInterruptible() REQUIRES(mLock); + CommandEntry* postCommandLocked(Command command) REQUIRES(mLock); + + // Input filter processing. + bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock); + bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) REQUIRES(mLock); + + // Inbound event processing. + void drainInboundQueueLocked() REQUIRES(mLock); + void releasePendingEventLocked() REQUIRES(mLock); + void releaseInboundEventLocked(EventEntry* entry) REQUIRES(mLock); + + // Dispatch state. + bool mDispatchEnabled GUARDED_BY(mLock); + bool mDispatchFrozen GUARDED_BY(mLock); + bool mInputFilterEnabled GUARDED_BY(mLock); + + std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay + GUARDED_BY(mLock); + // Get window handles by display, return an empty vector if not found. + std::vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const + REQUIRES(mLock); + sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const + REQUIRES(mLock); + sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock); + bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); + + // Focus tracking for keys, trackball, etc. + std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay + GUARDED_BY(mLock); + + // Focus tracking for touch. + struct TouchedWindow { + sp<InputWindowHandle> windowHandle; + int32_t targetFlags; + BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set + }; + + // For tracking the offsets we need to apply when adding gesture monitor targets. + struct TouchedMonitor { + Monitor monitor; + float xOffset = 0.f; + float yOffset = 0.f; + + explicit TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset); + }; + + struct TouchState { + bool down; + bool split; + int32_t deviceId; // id of the device that is currently down, others are rejected + uint32_t source; // source of the device that is current down, others are rejected + int32_t displayId; // id to the display that currently has a touch, others are rejected + std::vector<TouchedWindow> windows; + + // This collects the portal windows that the touch has gone through. Each portal window + // targets a display (embedded display for most cases). With this info, we can add the + // monitoring channels of the displays touched. + std::vector<sp<InputWindowHandle>> portalWindows; + + std::vector<TouchedMonitor> gestureMonitors; + + TouchState(); + ~TouchState(); + void reset(); + void copyFrom(const TouchState& other); + void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, + int32_t targetFlags, BitSet32 pointerIds); + void addPortalWindow(const sp<InputWindowHandle>& windowHandle); + void addGestureMonitors(const std::vector<TouchedMonitor>& monitors); + void removeWindow(const sp<InputWindowHandle>& windowHandle); + void removeWindowByToken(const sp<IBinder>& token); + void filterNonAsIsTouchWindows(); + void filterNonMonitors(); + sp<InputWindowHandle> getFirstForegroundWindowHandle() const; + bool isSlippery() const; + }; + + KeyedVector<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock); + TouchState mTempTouchState GUARDED_BY(mLock); + + // Focused applications. + std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay + GUARDED_BY(mLock); + + // Top focused display. + int32_t mFocusedDisplayId GUARDED_BY(mLock); + + // Dispatcher state at time of last ANR. + std::string mLastANRState GUARDED_BY(mLock); + + // Dispatch inbound events. + bool dispatchConfigurationChangedLocked( + nsecs_t currentTime, ConfigurationChangedEntry* entry) REQUIRES(mLock); + bool dispatchDeviceResetLocked( + nsecs_t currentTime, DeviceResetEntry* entry) REQUIRES(mLock); + bool dispatchKeyLocked( + nsecs_t currentTime, KeyEntry* entry, + DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock); + bool dispatchMotionLocked( + nsecs_t currentTime, MotionEntry* entry, + DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock); + void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry, + const std::vector<InputTarget>& inputTargets) REQUIRES(mLock); + + void logOutboundKeyDetails(const char* prefix, const KeyEntry* entry); + void logOutboundMotionDetails(const char* prefix, const MotionEntry* entry); + + // Keeping track of ANR timeouts. + enum InputTargetWaitCause { + INPUT_TARGET_WAIT_CAUSE_NONE, + INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, + INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, + }; + + InputTargetWaitCause mInputTargetWaitCause GUARDED_BY(mLock); + nsecs_t mInputTargetWaitStartTime GUARDED_BY(mLock); + nsecs_t mInputTargetWaitTimeoutTime GUARDED_BY(mLock); + bool mInputTargetWaitTimeoutExpired GUARDED_BY(mLock); + sp<IBinder> mInputTargetWaitApplicationToken GUARDED_BY(mLock); + + // Contains the last window which received a hover event. + sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock); + + // Finding targets for input events. + int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, + const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, + nsecs_t* nextWakeupTime, const char* reason) REQUIRES(mLock); + + void removeWindowByTokenLocked(const sp<IBinder>& token) REQUIRES(mLock); + + void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, + const sp<InputChannel>& inputChannel) REQUIRES(mLock); + nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock); + void resetANRTimeoutsLocked() REQUIRES(mLock); + + int32_t getTargetDisplayId(const EventEntry* entry); + int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, + std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) REQUIRES(mLock); + int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, + std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, + bool* outConflictingPointerActions) REQUIRES(mLock); + std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked(int32_t displayId, + const std::vector<sp<InputWindowHandle>>& portalWindows) REQUIRES(mLock); + void addGestureMonitors(const std::vector<Monitor>& monitors, + std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0, float yOffset = 0); + + void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, + int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) + REQUIRES(mLock); + void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset, + std::vector<InputTarget>& inputTargets) REQUIRES(mLock); + void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, + int32_t displayId, float xOffset = 0, float yOffset = 0) REQUIRES(mLock); + + void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock); + bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, + const InjectionState* injectionState); + bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, + int32_t x, int32_t y) const REQUIRES(mLock); + bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); + std::string getApplicationWindowLabel(const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle); + + std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime, + const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, + const char* targetType) REQUIRES(mLock); + + // Manage the dispatch cycle for a single connection. + // These methods are deliberately not Interruptible because doing all of the work + // with the mutex held makes it easier to ensure that connection invariants are maintained. + // If needed, the methods post commands to run later once the critical bits are done. + void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, + EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock); + void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, + EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock); + void enqueueDispatchEntryLocked(const sp<Connection>& connection, + EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode) + REQUIRES(mLock); + void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) + REQUIRES(mLock); + void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, + uint32_t seq, bool handled) REQUIRES(mLock); + void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, + bool notify) REQUIRES(mLock); + void drainDispatchQueue(Queue<DispatchEntry>* queue); + void releaseDispatchEntry(DispatchEntry* dispatchEntry); + static int handleReceiveCallback(int fd, int events, void* data); + // The action sent should only be of type AMOTION_EVENT_* + void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, + const sp<IBinder>& newToken) REQUIRES(mLock); + + void synthesizeCancelationEventsForAllConnectionsLocked( + const CancelationOptions& options) REQUIRES(mLock); + void synthesizeCancelationEventsForMonitorsLocked( + const CancelationOptions& options) REQUIRES(mLock); + void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options, + std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock); + void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, + const CancelationOptions& options) REQUIRES(mLock); + void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, + const CancelationOptions& options) REQUIRES(mLock); + + // Splitting motion events across windows. + MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); + + // Reset and drop everything the dispatcher is doing. + void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock); + + // Dump state. + void dumpDispatchStateLocked(std::string& dump) REQUIRES(mLock); + void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors); + void logDispatchStateLocked() REQUIRES(mLock); + + // Registration. + void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); + void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel, + std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) + REQUIRES(mLock); + status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify) + REQUIRES(mLock); + + // Interesting events that we might like to log or tell the framework about. + void onDispatchCycleFinishedLocked( + nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) + REQUIRES(mLock); + void onDispatchCycleBrokenLocked( + nsecs_t currentTime, const sp<Connection>& connection) REQUIRES(mLock); + void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus, + const sp<InputWindowHandle>& newFocus) REQUIRES(mLock); + void onANRLocked( + nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, + nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) REQUIRES(mLock); + + // Outbound policy interactions. + void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) + REQUIRES(mLock); + void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void doNotifyANRLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry) + REQUIRES(mLock); + void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + bool afterKeyEventLockedInterruptible(const sp<Connection>& connection, + DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) REQUIRES(mLock); + bool afterMotionEventLockedInterruptible(const sp<Connection>& connection, + DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) REQUIRES(mLock); + void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); + void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) + REQUIRES(mLock); + + // Statistics gathering. + void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, + int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); + void traceInboundQueueLengthLocked() REQUIRES(mLock); + void traceOutboundQueueLength(const sp<Connection>& connection); + void traceWaitQueueLength(const sp<Connection>& connection); + + sp<InputReporterInterface> mReporter; +}; + +/* Enqueues and dispatches input events, endlessly. */ +class InputDispatcherThread : public Thread { +public: + explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher); + ~InputDispatcherThread(); + +private: + virtual bool threadLoop(); + + sp<InputDispatcherInterface> mDispatcher; +}; + +} // namespace android + +#endif // _UI_INPUT_DISPATCHER_H diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index 359325faed..52e908066e 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -19,8 +19,6 @@ //#define LOG_NDEBUG 0 #include "InputManager.h" -#include "InputDispatcherFactory.h" -#include "InputDispatcherThread.h" #include "InputReaderFactory.h" #include <binder/IPCThreadState.h> @@ -35,7 +33,7 @@ namespace android { InputManager::InputManager( const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { - mDispatcher = createInputDispatcher(dispatcherPolicy); + mDispatcher = new InputDispatcher(dispatcherPolicy); mClassifier = new InputClassifier(mDispatcher); mReader = createInputReader(readerPolicy, mClassifier); initialize(); @@ -119,10 +117,6 @@ void InputManager::setInputWindows(const std::vector<InputWindowInfo>& infos, } } -void InputManager::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) { - mDispatcher->transferTouchFocus(fromToken, toToken); -} - // Used by tests only. void InputManager::registerInputChannel(const sp<InputChannel>& channel) { IPCThreadState* ipc = IPCThreadState::self(); @@ -139,4 +133,8 @@ void InputManager::unregisterInputChannel(const sp<InputChannel>& channel) { mDispatcher->unregisterInputChannel(channel); } +void InputManager::setMotionClassifierEnabled(bool enabled) { + mClassifier->setMotionClassifierEnabled(enabled); +} + } // namespace android diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index f3da324ba4..c75611f083 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -21,14 +21,15 @@ * Native input manager. */ -#include "InputClassifier.h" +#include "EventHub.h" #include "InputReaderBase.h" +#include "InputClassifier.h" +#include "InputDispatcher.h" +#include "InputReader.h" -#include <InputDispatcherInterface.h> -#include <InputDispatcherPolicyInterface.h> -#include <input/ISetInputWindowsListener.h> #include <input/Input.h> #include <input/InputTransport.h> +#include <input/ISetInputWindowsListener.h> #include <input/IInputFlinger.h> #include <utils/Errors.h> @@ -38,7 +39,6 @@ namespace android { class InputChannel; -class InputDispatcherThread; /* * The input manager is the core of the system event processing. @@ -96,11 +96,12 @@ public: virtual void setInputWindows(const std::vector<InputWindowInfo>& handles, const sp<ISetInputWindowsListener>& setInputWindowsListener); - virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken); virtual void registerInputChannel(const sp<InputChannel>& channel); virtual void unregisterInputChannel(const sp<InputChannel>& channel); + void setMotionClassifierEnabled(bool enabled); + private: sp<InputReaderInterface> mReader; sp<InputReaderThread> mReaderThread; diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp new file mode 100644 index 0000000000..a45b8a56ce --- /dev/null +++ b/services/inputflinger/InputReader.cpp @@ -0,0 +1,7534 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "InputReader" + +//#define LOG_NDEBUG 0 + +// Log debug messages for each raw event received from the EventHub. +#define DEBUG_RAW_EVENTS 0 + +// Log debug messages about touch screen filtering hacks. +#define DEBUG_HACKS 0 + +// Log debug messages about virtual key processing. +#define DEBUG_VIRTUAL_KEYS 0 + +// Log debug messages about pointers. +#define DEBUG_POINTERS 0 + +// Log debug messages about pointer assignment calculations. +#define DEBUG_POINTER_ASSIGNMENT 0 + +// Log debug messages about gesture detection. +#define DEBUG_GESTURES 0 + +// Log debug messages about the vibrator. +#define DEBUG_VIBRATOR 0 + +// Log debug messages about fusing stylus data. +#define DEBUG_STYLUS_FUSION 0 + +#include "InputReader.h" + +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <math.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> + +#include <log/log.h> + +#include <android-base/stringprintf.h> +#include <input/Keyboard.h> +#include <input/VirtualKeyMap.h> +#include <statslog.h> + +#define INDENT " " +#define INDENT2 " " +#define INDENT3 " " +#define INDENT4 " " +#define INDENT5 " " + +using android::base::StringPrintf; + +namespace android { + +// --- Constants --- + +// Maximum number of slots supported when using the slot-based Multitouch Protocol B. +static constexpr size_t MAX_SLOTS = 32; + +// Maximum amount of latency to add to touch events while waiting for data from an +// external stylus. +static constexpr nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); + +// Maximum amount of time to wait on touch data before pushing out new pressure data. +static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); + +// Artificial latency on synthetic events created from stylus data without corresponding touch +// data. +static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); + +// How often to report input event statistics +static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60); + +// --- Static Functions --- + +template<typename T> +inline static T abs(const T& value) { + return value < 0 ? - value : value; +} + +template<typename T> +inline static T min(const T& a, const T& b) { + return a < b ? a : b; +} + +template<typename T> +inline static void swap(T& a, T& b) { + T temp = a; + a = b; + b = temp; +} + +inline static float avg(float x, float y) { + return (x + y) / 2; +} + +inline static float distance(float x1, float y1, float x2, float y2) { + return hypotf(x1 - x2, y1 - y2); +} + +inline static int32_t signExtendNybble(int32_t value) { + return value >= 8 ? value - 16 : value; +} + +static inline const char* toString(bool value) { + return value ? "true" : "false"; +} + +static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, + const int32_t map[][4], size_t mapSize) { + if (orientation != DISPLAY_ORIENTATION_0) { + for (size_t i = 0; i < mapSize; i++) { + if (value == map[i][0]) { + return map[i][orientation]; + } + } + } + return value; +} + +static const int32_t keyCodeRotationMap[][4] = { + // key codes enumerated counter-clockwise with the original (unrotated) key first + // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation + { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT }, + { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN }, + { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, + { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, + { AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT, + AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT }, + { AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP, + AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN }, + { AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT, + AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT }, + { AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN, + AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP }, +}; +static const size_t keyCodeRotationMapSize = + sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); + +static int32_t rotateStemKey(int32_t value, int32_t orientation, + const int32_t map[][2], size_t mapSize) { + if (orientation == DISPLAY_ORIENTATION_180) { + for (size_t i = 0; i < mapSize; i++) { + if (value == map[i][0]) { + return map[i][1]; + } + } + } + return value; +} + +// The mapping can be defined using input device configuration properties keyboard.rotated.stem_X +static int32_t stemKeyRotationMap[][2] = { + // key codes enumerated with the original (unrotated) key first + // no rotation, 180 degree rotation + { AKEYCODE_STEM_PRIMARY, AKEYCODE_STEM_PRIMARY }, + { AKEYCODE_STEM_1, AKEYCODE_STEM_1 }, + { AKEYCODE_STEM_2, AKEYCODE_STEM_2 }, + { AKEYCODE_STEM_3, AKEYCODE_STEM_3 }, +}; +static const size_t stemKeyRotationMapSize = + sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]); + +static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { + keyCode = rotateStemKey(keyCode, orientation, + stemKeyRotationMap, stemKeyRotationMapSize); + return rotateValueUsingRotationMap(keyCode, orientation, + keyCodeRotationMap, keyCodeRotationMapSize); +} + +static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { + float temp; + switch (orientation) { + case DISPLAY_ORIENTATION_90: + temp = *deltaX; + *deltaX = *deltaY; + *deltaY = -temp; + break; + + case DISPLAY_ORIENTATION_180: + *deltaX = -*deltaX; + *deltaY = -*deltaY; + break; + + case DISPLAY_ORIENTATION_270: + temp = *deltaX; + *deltaX = -*deltaY; + *deltaY = temp; + break; + } +} + +static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { + return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0; +} + +// Returns true if the pointer should be reported as being down given the specified +// button states. This determines whether the event is reported as a touch event. +static bool isPointerDown(int32_t buttonState) { + return buttonState & + (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY + | AMOTION_EVENT_BUTTON_TERTIARY); +} + +static float calculateCommonVector(float a, float b) { + if (a > 0 && b > 0) { + return a < b ? a : b; + } else if (a < 0 && b < 0) { + return a > b ? a : b; + } else { + return 0; + } +} + +static void synthesizeButtonKey(InputReaderContext* context, int32_t action, + nsecs_t when, int32_t deviceId, uint32_t source, int32_t displayId, + uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState, + int32_t buttonState, int32_t keyCode) { + if ( + (action == AKEY_EVENT_ACTION_DOWN + && !(lastButtonState & buttonState) + && (currentButtonState & buttonState)) + || (action == AKEY_EVENT_ACTION_UP + && (lastButtonState & buttonState) + && !(currentButtonState & buttonState))) { + NotifyKeyArgs args(context->getNextSequenceNum(), when, deviceId, source, displayId, + policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when); + context->getListener()->notifyKey(&args); + } +} + +static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, + nsecs_t when, int32_t deviceId, uint32_t source, int32_t displayId, + uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) { + synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags, + lastButtonState, currentButtonState, + AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK); + synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags, + lastButtonState, currentButtonState, + AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD); +} + + +// --- InputReader --- + +InputReader::InputReader(const sp<EventHubInterface>& eventHub, + const sp<InputReaderPolicyInterface>& policy, + const sp<InputListenerInterface>& listener) : + mContext(this), mEventHub(eventHub), mPolicy(policy), + mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1), + mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), + mConfigurationChangesToRefresh(0) { + mQueuedListener = new QueuedInputListener(listener); + + { // acquire lock + AutoMutex _l(mLock); + + refreshConfigurationLocked(0); + updateGlobalMetaStateLocked(); + } // release lock +} + +InputReader::~InputReader() { + for (size_t i = 0; i < mDevices.size(); i++) { + delete mDevices.valueAt(i); + } +} + +void InputReader::loopOnce() { + int32_t oldGeneration; + int32_t timeoutMillis; + bool inputDevicesChanged = false; + std::vector<InputDeviceInfo> inputDevices; + { // acquire lock + AutoMutex _l(mLock); + + oldGeneration = mGeneration; + timeoutMillis = -1; + + uint32_t changes = mConfigurationChangesToRefresh; + if (changes) { + mConfigurationChangesToRefresh = 0; + timeoutMillis = 0; + refreshConfigurationLocked(changes); + } else if (mNextTimeout != LLONG_MAX) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); + } + } // release lock + + size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); + + { // acquire lock + AutoMutex _l(mLock); + mReaderIsAliveCondition.broadcast(); + + if (count) { + processEventsLocked(mEventBuffer, count); + } + + if (mNextTimeout != LLONG_MAX) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + if (now >= mNextTimeout) { +#if DEBUG_RAW_EVENTS + ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); +#endif + mNextTimeout = LLONG_MAX; + timeoutExpiredLocked(now); + } + } + + if (oldGeneration != mGeneration) { + inputDevicesChanged = true; + getInputDevicesLocked(inputDevices); + } + } // release lock + + // Send out a message that the describes the changed input devices. + if (inputDevicesChanged) { + mPolicy->notifyInputDevicesChanged(inputDevices); + } + + // Flush queued events out to the listener. + // This must happen outside of the lock because the listener could potentially call + // back into the InputReader's methods, such as getScanCodeState, or become blocked + // on another thread similarly waiting to acquire the InputReader lock thereby + // resulting in a deadlock. This situation is actually quite plausible because the + // listener is actually the input dispatcher, which calls into the window manager, + // which occasionally calls into the input reader. + mQueuedListener->flush(); +} + +void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { + for (const RawEvent* rawEvent = rawEvents; count;) { + int32_t type = rawEvent->type; + size_t batchSize = 1; + if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { + int32_t deviceId = rawEvent->deviceId; + while (batchSize < count) { + if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT + || rawEvent[batchSize].deviceId != deviceId) { + break; + } + batchSize += 1; + } +#if DEBUG_RAW_EVENTS + ALOGD("BatchSize: %zu Count: %zu", batchSize, count); +#endif + processEventsForDeviceLocked(deviceId, rawEvent, batchSize); + } else { + switch (rawEvent->type) { + case EventHubInterface::DEVICE_ADDED: + addDeviceLocked(rawEvent->when, rawEvent->deviceId); + break; + case EventHubInterface::DEVICE_REMOVED: + removeDeviceLocked(rawEvent->when, rawEvent->deviceId); + break; + case EventHubInterface::FINISHED_DEVICE_SCAN: + handleConfigurationChangedLocked(rawEvent->when); + break; + default: + ALOG_ASSERT(false); // can't happen + break; + } + } + count -= batchSize; + rawEvent += batchSize; + } +} + +void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); + return; + } + + InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); + uint32_t classes = mEventHub->getDeviceClasses(deviceId); + int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); + + InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); + device->configure(when, &mConfig, 0); + device->reset(when); + + if (device->isIgnored()) { + ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, + identifier.name.c_str()); + } else { + ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, + identifier.name.c_str(), device->getSources()); + } + + mDevices.add(deviceId, device); + bumpGenerationLocked(); + + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } +} + +void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { + InputDevice* device = nullptr; + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex < 0) { + ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); + return; + } + + device = mDevices.valueAt(deviceIndex); + mDevices.removeItemsAt(deviceIndex, 1); + bumpGenerationLocked(); + + if (device->isIgnored()) { + ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", + device->getId(), device->getName().c_str()); + } else { + ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", + device->getId(), device->getName().c_str(), device->getSources()); + } + + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } + + device->reset(when); + delete device; +} + +InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, + const InputDeviceIdentifier& identifier, uint32_t classes) { + InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), + controllerNumber, identifier, classes); + + // External devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { + device->setExternal(true); + } + + // Devices with mics. + if (classes & INPUT_DEVICE_CLASS_MIC) { + device->setMic(true); + } + + // Switch-like devices. + if (classes & INPUT_DEVICE_CLASS_SWITCH) { + device->addMapper(new SwitchInputMapper(device)); + } + + // Scroll wheel-like devices. + if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) { + device->addMapper(new RotaryEncoderInputMapper(device)); + } + + // Vibrator-like devices. + if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { + device->addMapper(new VibratorInputMapper(device)); + } + + // Keyboard-like devices. + uint32_t keyboardSource = 0; + int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; + if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { + keyboardSource |= AINPUT_SOURCE_KEYBOARD; + } + if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { + keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; + } + if (classes & INPUT_DEVICE_CLASS_DPAD) { + keyboardSource |= AINPUT_SOURCE_DPAD; + } + if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { + keyboardSource |= AINPUT_SOURCE_GAMEPAD; + } + + if (keyboardSource != 0) { + device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); + } + + // Cursor-like devices. + if (classes & INPUT_DEVICE_CLASS_CURSOR) { + device->addMapper(new CursorInputMapper(device)); + } + + // Touchscreens and touchpad devices. + if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { + device->addMapper(new MultiTouchInputMapper(device)); + } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { + device->addMapper(new SingleTouchInputMapper(device)); + } + + // Joystick-like devices. + if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { + device->addMapper(new JoystickInputMapper(device)); + } + + // External stylus-like devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + device->addMapper(new ExternalStylusInputMapper(device)); + } + + return device; +} + +void InputReader::processEventsForDeviceLocked(int32_t deviceId, + const RawEvent* rawEvents, size_t count) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex < 0) { + ALOGW("Discarding event for unknown deviceId %d.", deviceId); + return; + } + + InputDevice* device = mDevices.valueAt(deviceIndex); + if (device->isIgnored()) { + //ALOGD("Discarding event for ignored deviceId %d.", deviceId); + return; + } + + device->process(rawEvents, count); +} + +void InputReader::timeoutExpiredLocked(nsecs_t when) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + if (!device->isIgnored()) { + device->timeoutExpired(when); + } + } +} + +void InputReader::handleConfigurationChangedLocked(nsecs_t when) { + // Reset global meta state because it depends on the list of all configured devices. + updateGlobalMetaStateLocked(); + + // Enqueue configuration changed. + NotifyConfigurationChangedArgs args(mContext.getNextSequenceNum(), when); + mQueuedListener->notifyConfigurationChanged(&args); +} + +void InputReader::refreshConfigurationLocked(uint32_t changes) { + mPolicy->getReaderConfiguration(&mConfig); + mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); + + if (changes) { + ALOGI("Reconfiguring input devices. changes=0x%08x", changes); + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + + if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { + mEventHub->requestReopenDevices(); + } else { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->configure(now, &mConfig, changes); + } + } + } +} + +void InputReader::updateGlobalMetaStateLocked() { + mGlobalMetaState = 0; + + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + mGlobalMetaState |= device->getMetaState(); + } +} + +int32_t InputReader::getGlobalMetaStateLocked() { + return mGlobalMetaState; +} + +void InputReader::notifyExternalStylusPresenceChanged() { + refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); +} + +void InputReader::getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { + InputDeviceInfo info; + device->getDeviceInfo(&info); + outDevices.push_back(info); + } + } +} + +void InputReader::dispatchExternalStylusState(const StylusState& state) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->updateExternalStylusState(state); + } +} + +void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { + mDisableVirtualKeysTimeout = time; +} + +bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, + InputDevice* device, int32_t keyCode, int32_t scanCode) { + if (now < mDisableVirtualKeysTimeout) { + ALOGI("Dropping virtual key from device %s because virtual keys are " + "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", + device->getName().c_str(), + (mDisableVirtualKeysTimeout - now) * 0.000001, + keyCode, scanCode); + return true; + } else { + return false; + } +} + +void InputReader::fadePointerLocked() { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->fadePointer(); + } +} + +void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { + if (when < mNextTimeout) { + mNextTimeout = when; + mEventHub->wake(); + } +} + +int32_t InputReader::bumpGenerationLocked() { + return ++mGeneration; +} + +void InputReader::getInputDevices(std::vector<InputDeviceInfo>& outInputDevices) { + AutoMutex _l(mLock); + getInputDevicesLocked(outInputDevices); +} + +void InputReader::getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices) { + outInputDevices.clear(); + + size_t numDevices = mDevices.size(); + for (size_t i = 0; i < numDevices; i++) { + InputDevice* device = mDevices.valueAt(i); + if (!device->isIgnored()) { + InputDeviceInfo info; + device->getDeviceInfo(&info); + outInputDevices.push_back(info); + } + } +} + +int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, + int32_t keyCode) { + AutoMutex _l(mLock); + + return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState); +} + +int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, + int32_t scanCode) { + AutoMutex _l(mLock); + + return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState); +} + +int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { + AutoMutex _l(mLock); + + return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState); +} + +int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, + GetStateFunc getStateFunc) { + int32_t result = AKEY_STATE_UNKNOWN; + if (deviceId >= 0) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + result = (device->*getStateFunc)(sourceMask, code); + } + } + } else { + size_t numDevices = mDevices.size(); + for (size_t i = 0; i < numDevices; i++) { + InputDevice* device = mDevices.valueAt(i); + if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that + // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. + int32_t currentResult = (device->*getStateFunc)(sourceMask, code); + if (currentResult >= AKEY_STATE_DOWN) { + return currentResult; + } else if (currentResult == AKEY_STATE_UP) { + result = currentResult; + } + } + } + } + return result; +} + +void InputReader::toggleCapsLockState(int32_t deviceId) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex < 0) { + ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId); + return; + } + + InputDevice* device = mDevices.valueAt(deviceIndex); + if (device->isIgnored()) { + return; + } + + device->updateMetaState(AKEYCODE_CAPS_LOCK); +} + +bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, + size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { + AutoMutex _l(mLock); + + memset(outFlags, 0, numCodes); + return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); +} + +bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, + size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { + bool result = false; + if (deviceId >= 0) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + result = device->markSupportedKeyCodes(sourceMask, + numCodes, keyCodes, outFlags); + } + } + } else { + size_t numDevices = mDevices.size(); + for (size_t i = 0; i < numDevices; i++) { + InputDevice* device = mDevices.valueAt(i); + if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + result |= device->markSupportedKeyCodes(sourceMask, + numCodes, keyCodes, outFlags); + } + } + } + return result; +} + +void InputReader::requestRefreshConfiguration(uint32_t changes) { + AutoMutex _l(mLock); + + if (changes) { + bool needWake = !mConfigurationChangesToRefresh; + mConfigurationChangesToRefresh |= changes; + + if (needWake) { + mEventHub->wake(); + } + } +} + +void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, + ssize_t repeat, int32_t token) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + device->vibrate(pattern, patternSize, repeat, token); + } +} + +void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + device->cancelVibrate(token); + } +} + +bool InputReader::isInputDeviceEnabled(int32_t deviceId) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + return device->isEnabled(); + } + ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); + return false; +} + +bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex < 0) { + ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); + return false; + } + + InputDevice* device = mDevices.valueAt(deviceIndex); + std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplay(); + // No associated display. By default, can dispatch to all displays. + if (!associatedDisplayId) { + return true; + } + + if (*associatedDisplayId == ADISPLAY_ID_NONE) { + ALOGW("Device has associated, but no associated display id."); + return true; + } + + return *associatedDisplayId == displayId; +} + +void InputReader::dump(std::string& dump) { + AutoMutex _l(mLock); + + mEventHub->dump(dump); + dump += "\n"; + + dump += "Input Reader State:\n"; + + for (size_t i = 0; i < mDevices.size(); i++) { + mDevices.valueAt(i)->dump(dump); + } + + dump += INDENT "Configuration:\n"; + dump += INDENT2 "ExcludedDeviceNames: ["; + for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { + if (i != 0) { + dump += ", "; + } + dump += mConfig.excludedDeviceNames[i]; + } + dump += "]\n"; + dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", + mConfig.virtualKeyQuietTime * 0.000001f); + + dump += StringPrintf(INDENT2 "PointerVelocityControlParameters: " + "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", + mConfig.pointerVelocityControlParameters.scale, + mConfig.pointerVelocityControlParameters.lowThreshold, + mConfig.pointerVelocityControlParameters.highThreshold, + mConfig.pointerVelocityControlParameters.acceleration); + + dump += StringPrintf(INDENT2 "WheelVelocityControlParameters: " + "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", + mConfig.wheelVelocityControlParameters.scale, + mConfig.wheelVelocityControlParameters.lowThreshold, + mConfig.wheelVelocityControlParameters.highThreshold, + mConfig.wheelVelocityControlParameters.acceleration); + + dump += StringPrintf(INDENT2 "PointerGesture:\n"); + dump += StringPrintf(INDENT3 "Enabled: %s\n", + toString(mConfig.pointerGesturesEnabled)); + dump += StringPrintf(INDENT3 "QuietInterval: %0.1fms\n", + mConfig.pointerGestureQuietInterval * 0.000001f); + dump += StringPrintf(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", + mConfig.pointerGestureDragMinSwitchSpeed); + dump += StringPrintf(INDENT3 "TapInterval: %0.1fms\n", + mConfig.pointerGestureTapInterval * 0.000001f); + dump += StringPrintf(INDENT3 "TapDragInterval: %0.1fms\n", + mConfig.pointerGestureTapDragInterval * 0.000001f); + dump += StringPrintf(INDENT3 "TapSlop: %0.1fpx\n", + mConfig.pointerGestureTapSlop); + dump += StringPrintf(INDENT3 "MultitouchSettleInterval: %0.1fms\n", + mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); + dump += StringPrintf(INDENT3 "MultitouchMinDistance: %0.1fpx\n", + mConfig.pointerGestureMultitouchMinDistance); + dump += StringPrintf(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", + mConfig.pointerGestureSwipeTransitionAngleCosine); + dump += StringPrintf(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", + mConfig.pointerGestureSwipeMaxWidthRatio); + dump += StringPrintf(INDENT3 "MovementSpeedRatio: %0.1f\n", + mConfig.pointerGestureMovementSpeedRatio); + dump += StringPrintf(INDENT3 "ZoomSpeedRatio: %0.1f\n", + mConfig.pointerGestureZoomSpeedRatio); + + dump += INDENT3 "Viewports:\n"; + mConfig.dump(dump); +} + +void InputReader::monitor() { + // Acquire and release the lock to ensure that the reader has not deadlocked. + mLock.lock(); + mEventHub->wake(); + mReaderIsAliveCondition.wait(mLock); + mLock.unlock(); + + // Check the EventHub + mEventHub->monitor(); +} + + +// --- InputReader::ContextImpl --- + +InputReader::ContextImpl::ContextImpl(InputReader* reader) : + mReader(reader) { +} + +void InputReader::ContextImpl::updateGlobalMetaState() { + // lock is already held by the input loop + mReader->updateGlobalMetaStateLocked(); +} + +int32_t InputReader::ContextImpl::getGlobalMetaState() { + // lock is already held by the input loop + return mReader->getGlobalMetaStateLocked(); +} + +void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { + // lock is already held by the input loop + mReader->disableVirtualKeysUntilLocked(time); +} + +bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, + InputDevice* device, int32_t keyCode, int32_t scanCode) { + // lock is already held by the input loop + return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); +} + +void InputReader::ContextImpl::fadePointer() { + // lock is already held by the input loop + mReader->fadePointerLocked(); +} + +void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { + // lock is already held by the input loop + mReader->requestTimeoutAtTimeLocked(when); +} + +int32_t InputReader::ContextImpl::bumpGeneration() { + // lock is already held by the input loop + return mReader->bumpGenerationLocked(); +} + +void InputReader::ContextImpl::getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) { + // lock is already held by whatever called refreshConfigurationLocked + mReader->getExternalStylusDevicesLocked(outDevices); +} + +void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) { + mReader->dispatchExternalStylusState(state); +} + +InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { + return mReader->mPolicy.get(); +} + +InputListenerInterface* InputReader::ContextImpl::getListener() { + return mReader->mQueuedListener.get(); +} + +EventHubInterface* InputReader::ContextImpl::getEventHub() { + return mReader->mEventHub.get(); +} + +uint32_t InputReader::ContextImpl::getNextSequenceNum() { + return (mReader->mNextSequenceNum)++; +} + +// --- InputDevice --- + +InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, + int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) : + mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber), + mIdentifier(identifier), mClasses(classes), + mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) { +} + +InputDevice::~InputDevice() { + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + delete mMappers[i]; + } + mMappers.clear(); +} + +bool InputDevice::isEnabled() { + return getEventHub()->isDeviceEnabled(mId); +} + +void InputDevice::setEnabled(bool enabled, nsecs_t when) { + if (isEnabled() == enabled) { + return; + } + + if (enabled) { + getEventHub()->enableDevice(mId); + reset(when); + } else { + reset(when); + getEventHub()->disableDevice(mId); + } + // Must change generation to flag this device as changed + bumpGeneration(); +} + +void InputDevice::dump(std::string& dump) { + InputDeviceInfo deviceInfo; + getDeviceInfo(&deviceInfo); + + dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(), + deviceInfo.getDisplayName().c_str()); + dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration); + dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); + dump += StringPrintf(INDENT2 "AssociatedDisplayPort: "); + if (mAssociatedDisplayPort) { + dump += StringPrintf("%" PRIu8 "\n", *mAssociatedDisplayPort); + } else { + dump += "<none>\n"; + } + dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic)); + dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); + dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); + + const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); + if (!ranges.empty()) { + dump += INDENT2 "Motion Ranges:\n"; + for (size_t i = 0; i < ranges.size(); i++) { + const InputDeviceInfo::MotionRange& range = ranges[i]; + const char* label = getAxisLabel(range.axis); + char name[32]; + if (label) { + strncpy(name, label, sizeof(name)); + name[sizeof(name) - 1] = '\0'; + } else { + snprintf(name, sizeof(name), "%d", range.axis); + } + dump += StringPrintf(INDENT3 "%s: source=0x%08x, " + "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n", + name, range.source, range.min, range.max, range.flat, range.fuzz, + range.resolution); + } + } + + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->dump(dump); + } +} + +void InputDevice::addMapper(InputMapper* mapper) { + mMappers.push_back(mapper); +} + +void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { + mSources = 0; + + if (!isIgnored()) { + if (!changes) { // first time only + mContext->getEventHub()->getConfiguration(mId, &mConfiguration); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { + if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { + sp<KeyCharacterMap> keyboardLayout = + mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier); + if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { + bumpGeneration(); + } + } + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { + if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { + std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); + if (mAlias != alias) { + mAlias = alias; + bumpGeneration(); + } + } + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) { + ssize_t index = config->disabledDevices.indexOf(mId); + bool enabled = index < 0; + setEnabled(enabled, when); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + // In most situations, no port will be specified. + mAssociatedDisplayPort = std::nullopt; + // Find the display port that corresponds to the current input port. + const std::string& inputPort = mIdentifier.location; + if (!inputPort.empty()) { + const std::unordered_map<std::string, uint8_t>& ports = config->portAssociations; + const auto& displayPort = ports.find(inputPort); + if (displayPort != ports.end()) { + mAssociatedDisplayPort = std::make_optional(displayPort->second); + } + } + } + + for (InputMapper* mapper : mMappers) { + mapper->configure(when, config, changes); + mSources |= mapper->getSources(); + } + } +} + +void InputDevice::reset(nsecs_t when) { + for (InputMapper* mapper : mMappers) { + mapper->reset(when); + } + + mContext->updateGlobalMetaState(); + + notifyReset(when); +} + +void InputDevice::process(const RawEvent* rawEvents, size_t count) { + // Process all of the events in order for each mapper. + // We cannot simply ask each mapper to process them in bulk because mappers may + // have side-effects that must be interleaved. For example, joystick movement events and + // gamepad button presses are handled by different mappers but they should be dispatched + // in the order received. + for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { +#if DEBUG_RAW_EVENTS + ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64, + rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, + rawEvent->when); +#endif + + if (mDropUntilNextSync) { + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + mDropUntilNextSync = false; +#if DEBUG_RAW_EVENTS + ALOGD("Recovered from input event buffer overrun."); +#endif + } else { +#if DEBUG_RAW_EVENTS + ALOGD("Dropped input event while waiting for next input sync."); +#endif + } + } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { + ALOGI("Detected input event buffer overrun for device %s.", getName().c_str()); + mDropUntilNextSync = true; + reset(rawEvent->when); + } else { + for (InputMapper* mapper : mMappers) { + mapper->process(rawEvent); + } + } + --count; + } +} + +void InputDevice::timeoutExpired(nsecs_t when) { + for (InputMapper* mapper : mMappers) { + mapper->timeoutExpired(when); + } +} + +void InputDevice::updateExternalStylusState(const StylusState& state) { + for (InputMapper* mapper : mMappers) { + mapper->updateExternalStylusState(state); + } +} + +void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { + outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, + mIsExternal, mHasMic); + for (InputMapper* mapper : mMappers) { + mapper->populateDeviceInfo(outDeviceInfo); + } +} + +int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState); +} + +int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + return getState(sourceMask, scanCode, & InputMapper::getScanCodeState); +} + +int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { + return getState(sourceMask, switchCode, & InputMapper::getSwitchState); +} + +int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { + int32_t result = AKEY_STATE_UNKNOWN; + for (InputMapper* mapper : mMappers) { + if (sourcesMatchMask(mapper->getSources(), sourceMask)) { + // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that + // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. + int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); + if (currentResult >= AKEY_STATE_DOWN) { + return currentResult; + } else if (currentResult == AKEY_STATE_UP) { + result = currentResult; + } + } + } + return result; +} + +bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + bool result = false; + for (InputMapper* mapper : mMappers) { + if (sourcesMatchMask(mapper->getSources(), sourceMask)) { + result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + } + } + return result; +} + +void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, + int32_t token) { + for (InputMapper* mapper : mMappers) { + mapper->vibrate(pattern, patternSize, repeat, token); + } +} + +void InputDevice::cancelVibrate(int32_t token) { + for (InputMapper* mapper : mMappers) { + mapper->cancelVibrate(token); + } +} + +void InputDevice::cancelTouch(nsecs_t when) { + for (InputMapper* mapper : mMappers) { + mapper->cancelTouch(when); + } +} + +int32_t InputDevice::getMetaState() { + int32_t result = 0; + for (InputMapper* mapper : mMappers) { + result |= mapper->getMetaState(); + } + return result; +} + +void InputDevice::updateMetaState(int32_t keyCode) { + for (InputMapper* mapper : mMappers) { + mapper->updateMetaState(keyCode); + } +} + +void InputDevice::fadePointer() { + for (InputMapper* mapper : mMappers) { + mapper->fadePointer(); + } +} + +void InputDevice::bumpGeneration() { + mGeneration = mContext->bumpGeneration(); +} + +void InputDevice::notifyReset(nsecs_t when) { + NotifyDeviceResetArgs args(mContext->getNextSequenceNum(), when, mId); + mContext->getListener()->notifyDeviceReset(&args); +} + +std::optional<int32_t> InputDevice::getAssociatedDisplay() { + for (InputMapper* mapper : mMappers) { + std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay(); + if (associatedDisplayId) { + return associatedDisplayId; + } + } + + return std::nullopt; +} + +// --- CursorButtonAccumulator --- + +CursorButtonAccumulator::CursorButtonAccumulator() { + clearButtons(); +} + +void CursorButtonAccumulator::reset(InputDevice* device) { + mBtnLeft = device->isKeyPressed(BTN_LEFT); + mBtnRight = device->isKeyPressed(BTN_RIGHT); + mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); + mBtnBack = device->isKeyPressed(BTN_BACK); + mBtnSide = device->isKeyPressed(BTN_SIDE); + mBtnForward = device->isKeyPressed(BTN_FORWARD); + mBtnExtra = device->isKeyPressed(BTN_EXTRA); + mBtnTask = device->isKeyPressed(BTN_TASK); +} + +void CursorButtonAccumulator::clearButtons() { + mBtnLeft = 0; + mBtnRight = 0; + mBtnMiddle = 0; + mBtnBack = 0; + mBtnSide = 0; + mBtnForward = 0; + mBtnExtra = 0; + mBtnTask = 0; +} + +void CursorButtonAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_KEY) { + switch (rawEvent->code) { + case BTN_LEFT: + mBtnLeft = rawEvent->value; + break; + case BTN_RIGHT: + mBtnRight = rawEvent->value; + break; + case BTN_MIDDLE: + mBtnMiddle = rawEvent->value; + break; + case BTN_BACK: + mBtnBack = rawEvent->value; + break; + case BTN_SIDE: + mBtnSide = rawEvent->value; + break; + case BTN_FORWARD: + mBtnForward = rawEvent->value; + break; + case BTN_EXTRA: + mBtnExtra = rawEvent->value; + break; + case BTN_TASK: + mBtnTask = rawEvent->value; + break; + } + } +} + +uint32_t CursorButtonAccumulator::getButtonState() const { + uint32_t result = 0; + if (mBtnLeft) { + result |= AMOTION_EVENT_BUTTON_PRIMARY; + } + if (mBtnRight) { + result |= AMOTION_EVENT_BUTTON_SECONDARY; + } + if (mBtnMiddle) { + result |= AMOTION_EVENT_BUTTON_TERTIARY; + } + if (mBtnBack || mBtnSide) { + result |= AMOTION_EVENT_BUTTON_BACK; + } + if (mBtnForward || mBtnExtra) { + result |= AMOTION_EVENT_BUTTON_FORWARD; + } + return result; +} + + +// --- CursorMotionAccumulator --- + +CursorMotionAccumulator::CursorMotionAccumulator() { + clearRelativeAxes(); +} + +void CursorMotionAccumulator::reset(InputDevice* device) { + clearRelativeAxes(); +} + +void CursorMotionAccumulator::clearRelativeAxes() { + mRelX = 0; + mRelY = 0; +} + +void CursorMotionAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_REL) { + switch (rawEvent->code) { + case REL_X: + mRelX = rawEvent->value; + break; + case REL_Y: + mRelY = rawEvent->value; + break; + } + } +} + +void CursorMotionAccumulator::finishSync() { + clearRelativeAxes(); +} + + +// --- CursorScrollAccumulator --- + +CursorScrollAccumulator::CursorScrollAccumulator() : + mHaveRelWheel(false), mHaveRelHWheel(false) { + clearRelativeAxes(); +} + +void CursorScrollAccumulator::configure(InputDevice* device) { + mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); + mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); +} + +void CursorScrollAccumulator::reset(InputDevice* device) { + clearRelativeAxes(); +} + +void CursorScrollAccumulator::clearRelativeAxes() { + mRelWheel = 0; + mRelHWheel = 0; +} + +void CursorScrollAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_REL) { + switch (rawEvent->code) { + case REL_WHEEL: + mRelWheel = rawEvent->value; + break; + case REL_HWHEEL: + mRelHWheel = rawEvent->value; + break; + } + } +} + +void CursorScrollAccumulator::finishSync() { + clearRelativeAxes(); +} + + +// --- TouchButtonAccumulator --- + +TouchButtonAccumulator::TouchButtonAccumulator() : + mHaveBtnTouch(false), mHaveStylus(false) { + clearButtons(); +} + +void TouchButtonAccumulator::configure(InputDevice* device) { + mHaveBtnTouch = device->hasKey(BTN_TOUCH); + mHaveStylus = device->hasKey(BTN_TOOL_PEN) + || device->hasKey(BTN_TOOL_RUBBER) + || device->hasKey(BTN_TOOL_BRUSH) + || device->hasKey(BTN_TOOL_PENCIL) + || device->hasKey(BTN_TOOL_AIRBRUSH); +} + +void TouchButtonAccumulator::reset(InputDevice* device) { + mBtnTouch = device->isKeyPressed(BTN_TOUCH); + mBtnStylus = device->isKeyPressed(BTN_STYLUS); + // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch + mBtnStylus2 = + device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); + mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); + mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); + mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); + mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); + mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); + mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); + mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); + mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); + mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); + mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); + mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); +} + +void TouchButtonAccumulator::clearButtons() { + mBtnTouch = 0; + mBtnStylus = 0; + mBtnStylus2 = 0; + mBtnToolFinger = 0; + mBtnToolPen = 0; + mBtnToolRubber = 0; + mBtnToolBrush = 0; + mBtnToolPencil = 0; + mBtnToolAirbrush = 0; + mBtnToolMouse = 0; + mBtnToolLens = 0; + mBtnToolDoubleTap = 0; + mBtnToolTripleTap = 0; + mBtnToolQuadTap = 0; +} + +void TouchButtonAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_KEY) { + switch (rawEvent->code) { + case BTN_TOUCH: + mBtnTouch = rawEvent->value; + break; + case BTN_STYLUS: + mBtnStylus = rawEvent->value; + break; + case BTN_STYLUS2: + case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch + mBtnStylus2 = rawEvent->value; + break; + case BTN_TOOL_FINGER: + mBtnToolFinger = rawEvent->value; + break; + case BTN_TOOL_PEN: + mBtnToolPen = rawEvent->value; + break; + case BTN_TOOL_RUBBER: + mBtnToolRubber = rawEvent->value; + break; + case BTN_TOOL_BRUSH: + mBtnToolBrush = rawEvent->value; + break; + case BTN_TOOL_PENCIL: + mBtnToolPencil = rawEvent->value; + break; + case BTN_TOOL_AIRBRUSH: + mBtnToolAirbrush = rawEvent->value; + break; + case BTN_TOOL_MOUSE: + mBtnToolMouse = rawEvent->value; + break; + case BTN_TOOL_LENS: + mBtnToolLens = rawEvent->value; + break; + case BTN_TOOL_DOUBLETAP: + mBtnToolDoubleTap = rawEvent->value; + break; + case BTN_TOOL_TRIPLETAP: + mBtnToolTripleTap = rawEvent->value; + break; + case BTN_TOOL_QUADTAP: + mBtnToolQuadTap = rawEvent->value; + break; + } + } +} + +uint32_t TouchButtonAccumulator::getButtonState() const { + uint32_t result = 0; + if (mBtnStylus) { + result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY; + } + if (mBtnStylus2) { + result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY; + } + return result; +} + +int32_t TouchButtonAccumulator::getToolType() const { + if (mBtnToolMouse || mBtnToolLens) { + return AMOTION_EVENT_TOOL_TYPE_MOUSE; + } + if (mBtnToolRubber) { + return AMOTION_EVENT_TOOL_TYPE_ERASER; + } + if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { + return AMOTION_EVENT_TOOL_TYPE_STYLUS; + } + if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { + return AMOTION_EVENT_TOOL_TYPE_FINGER; + } + return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; +} + +bool TouchButtonAccumulator::isToolActive() const { + return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber + || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush + || mBtnToolMouse || mBtnToolLens + || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; +} + +bool TouchButtonAccumulator::isHovering() const { + return mHaveBtnTouch && !mBtnTouch; +} + +bool TouchButtonAccumulator::hasStylus() const { + return mHaveStylus; +} + + +// --- RawPointerAxes --- + +RawPointerAxes::RawPointerAxes() { + clear(); +} + +void RawPointerAxes::clear() { + x.clear(); + y.clear(); + pressure.clear(); + touchMajor.clear(); + touchMinor.clear(); + toolMajor.clear(); + toolMinor.clear(); + orientation.clear(); + distance.clear(); + tiltX.clear(); + tiltY.clear(); + trackingId.clear(); + slot.clear(); +} + + +// --- RawPointerData --- + +RawPointerData::RawPointerData() { + clear(); +} + +void RawPointerData::clear() { + pointerCount = 0; + clearIdBits(); +} + +void RawPointerData::copyFrom(const RawPointerData& other) { + pointerCount = other.pointerCount; + hoveringIdBits = other.hoveringIdBits; + touchingIdBits = other.touchingIdBits; + + for (uint32_t i = 0; i < pointerCount; i++) { + pointers[i] = other.pointers[i]; + + int id = pointers[i].id; + idToIndex[id] = other.idToIndex[id]; + } +} + +void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { + float x = 0, y = 0; + uint32_t count = touchingIdBits.count(); + if (count) { + for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const Pointer& pointer = pointerForId(id); + x += pointer.x; + y += pointer.y; + } + x /= count; + y /= count; + } + *outX = x; + *outY = y; +} + + +// --- CookedPointerData --- + +CookedPointerData::CookedPointerData() { + clear(); +} + +void CookedPointerData::clear() { + pointerCount = 0; + hoveringIdBits.clear(); + touchingIdBits.clear(); +} + +void CookedPointerData::copyFrom(const CookedPointerData& other) { + pointerCount = other.pointerCount; + hoveringIdBits = other.hoveringIdBits; + touchingIdBits = other.touchingIdBits; + + for (uint32_t i = 0; i < pointerCount; i++) { + pointerProperties[i].copyFrom(other.pointerProperties[i]); + pointerCoords[i].copyFrom(other.pointerCoords[i]); + + int id = pointerProperties[i].id; + idToIndex[id] = other.idToIndex[id]; + } +} + + +// --- SingleTouchMotionAccumulator --- + +SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { + clearAbsoluteAxes(); +} + +void SingleTouchMotionAccumulator::reset(InputDevice* device) { + mAbsX = device->getAbsoluteAxisValue(ABS_X); + mAbsY = device->getAbsoluteAxisValue(ABS_Y); + mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); + mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); + mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); + mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); + mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); +} + +void SingleTouchMotionAccumulator::clearAbsoluteAxes() { + mAbsX = 0; + mAbsY = 0; + mAbsPressure = 0; + mAbsToolWidth = 0; + mAbsDistance = 0; + mAbsTiltX = 0; + mAbsTiltY = 0; +} + +void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_ABS) { + switch (rawEvent->code) { + case ABS_X: + mAbsX = rawEvent->value; + break; + case ABS_Y: + mAbsY = rawEvent->value; + break; + case ABS_PRESSURE: + mAbsPressure = rawEvent->value; + break; + case ABS_TOOL_WIDTH: + mAbsToolWidth = rawEvent->value; + break; + case ABS_DISTANCE: + mAbsDistance = rawEvent->value; + break; + case ABS_TILT_X: + mAbsTiltX = rawEvent->value; + break; + case ABS_TILT_Y: + mAbsTiltY = rawEvent->value; + break; + } + } +} + + +// --- MultiTouchMotionAccumulator --- + +MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : + mCurrentSlot(-1), mSlots(nullptr), mSlotCount(0), mUsingSlotsProtocol(false), + mHaveStylus(false), mDeviceTimestamp(0) { +} + +MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { + delete[] mSlots; +} + +void MultiTouchMotionAccumulator::configure(InputDevice* device, + size_t slotCount, bool usingSlotsProtocol) { + mSlotCount = slotCount; + mUsingSlotsProtocol = usingSlotsProtocol; + mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); + + delete[] mSlots; + mSlots = new Slot[slotCount]; +} + +void MultiTouchMotionAccumulator::reset(InputDevice* device) { + // Unfortunately there is no way to read the initial contents of the slots. + // So when we reset the accumulator, we must assume they are all zeroes. + if (mUsingSlotsProtocol) { + // Query the driver for the current slot index and use it as the initial slot + // before we start reading events from the device. It is possible that the + // current slot index will not be the same as it was when the first event was + // written into the evdev buffer, which means the input mapper could start + // out of sync with the initial state of the events in the evdev buffer. + // In the extremely unlikely case that this happens, the data from + // two slots will be confused until the next ABS_MT_SLOT event is received. + // This can cause the touch point to "jump", but at least there will be + // no stuck touches. + int32_t initialSlot; + status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), + ABS_MT_SLOT, &initialSlot); + if (status) { + ALOGD("Could not retrieve current multitouch slot index. status=%d", status); + initialSlot = -1; + } + clearSlots(initialSlot); + } else { + clearSlots(-1); + } + mDeviceTimestamp = 0; +} + +void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { + if (mSlots) { + for (size_t i = 0; i < mSlotCount; i++) { + mSlots[i].clear(); + } + } + mCurrentSlot = initialSlot; +} + +void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_ABS) { + bool newSlot = false; + if (mUsingSlotsProtocol) { + if (rawEvent->code == ABS_MT_SLOT) { + mCurrentSlot = rawEvent->value; + newSlot = true; + } + } else if (mCurrentSlot < 0) { + mCurrentSlot = 0; + } + + if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { +#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); + } +#endif + } else { + Slot* slot = &mSlots[mCurrentSlot]; + + switch (rawEvent->code) { + case ABS_MT_POSITION_X: + slot->mInUse = true; + slot->mAbsMTPositionX = rawEvent->value; + break; + case ABS_MT_POSITION_Y: + slot->mInUse = true; + slot->mAbsMTPositionY = rawEvent->value; + break; + case ABS_MT_TOUCH_MAJOR: + slot->mInUse = true; + slot->mAbsMTTouchMajor = rawEvent->value; + break; + case ABS_MT_TOUCH_MINOR: + slot->mInUse = true; + slot->mAbsMTTouchMinor = rawEvent->value; + slot->mHaveAbsMTTouchMinor = true; + break; + case ABS_MT_WIDTH_MAJOR: + slot->mInUse = true; + slot->mAbsMTWidthMajor = rawEvent->value; + break; + case ABS_MT_WIDTH_MINOR: + slot->mInUse = true; + slot->mAbsMTWidthMinor = rawEvent->value; + slot->mHaveAbsMTWidthMinor = true; + break; + case ABS_MT_ORIENTATION: + slot->mInUse = true; + 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; + } else { + slot->mInUse = true; + slot->mAbsMTTrackingId = rawEvent->value; + } + break; + case ABS_MT_PRESSURE: + slot->mInUse = true; + slot->mAbsMTPressure = rawEvent->value; + break; + case ABS_MT_DISTANCE: + slot->mInUse = true; + slot->mAbsMTDistance = rawEvent->value; + break; + case ABS_MT_TOOL_TYPE: + slot->mInUse = true; + slot->mAbsMTToolType = rawEvent->value; + slot->mHaveAbsMTToolType = true; + break; + } + } + } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { + // MultiTouch Sync: The driver has returned all data for *one* of the pointers. + mCurrentSlot += 1; + } else if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) { + mDeviceTimestamp = rawEvent->value; + } +} + +void MultiTouchMotionAccumulator::finishSync() { + if (!mUsingSlotsProtocol) { + clearSlots(-1); + } +} + +bool MultiTouchMotionAccumulator::hasStylus() const { + return mHaveStylus; +} + + +// --- 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) { + case MT_TOOL_FINGER: + return AMOTION_EVENT_TOOL_TYPE_FINGER; + case MT_TOOL_PEN: + return AMOTION_EVENT_TOOL_TYPE_STYLUS; + } + } + return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; +} + + +// --- InputMapper --- + +InputMapper::InputMapper(InputDevice* device) : + mDevice(device), mContext(device->getContext()) { +} + +InputMapper::~InputMapper() { +} + +void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { + info->addSource(getSources()); +} + +void InputMapper::dump(std::string& dump) { +} + +void InputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { +} + +void InputMapper::reset(nsecs_t when) { +} + +void InputMapper::timeoutExpired(nsecs_t when) { +} + +int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + return AKEY_STATE_UNKNOWN; +} + +int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + return AKEY_STATE_UNKNOWN; +} + +int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { + return AKEY_STATE_UNKNOWN; +} + +bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + return false; +} + +void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, + int32_t token) { +} + +void InputMapper::cancelVibrate(int32_t token) { +} + +void InputMapper::cancelTouch(nsecs_t when) { +} + +int32_t InputMapper::getMetaState() { + return 0; +} + +void InputMapper::updateMetaState(int32_t keyCode) { +} + +void InputMapper::updateExternalStylusState(const StylusState& state) { + +} + +void InputMapper::fadePointer() { +} + +status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { + return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); +} + +void InputMapper::bumpGeneration() { + mDevice->bumpGeneration(); +} + +void InputMapper::dumpRawAbsoluteAxisInfo(std::string& dump, + const RawAbsoluteAxisInfo& axis, const char* name) { + if (axis.valid) { + dump += StringPrintf(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", + name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); + } else { + dump += StringPrintf(INDENT4 "%s: unknown range\n", name); + } +} + +void InputMapper::dumpStylusState(std::string& dump, const StylusState& state) { + dump += StringPrintf(INDENT4 "When: %" PRId64 "\n", state.when); + dump += StringPrintf(INDENT4 "Pressure: %f\n", state.pressure); + dump += StringPrintf(INDENT4 "Button State: 0x%08x\n", state.buttons); + dump += StringPrintf(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); +} + +// --- SwitchInputMapper --- + +SwitchInputMapper::SwitchInputMapper(InputDevice* device) : + InputMapper(device), mSwitchValues(0), mUpdatedSwitchMask(0) { +} + +SwitchInputMapper::~SwitchInputMapper() { +} + +uint32_t SwitchInputMapper::getSources() { + return AINPUT_SOURCE_SWITCH; +} + +void SwitchInputMapper::process(const RawEvent* rawEvent) { + switch (rawEvent->type) { + case EV_SW: + processSwitch(rawEvent->code, rawEvent->value); + break; + + case EV_SYN: + if (rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } + } +} + +void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { + if (switchCode >= 0 && switchCode < 32) { + if (switchValue) { + mSwitchValues |= 1 << switchCode; + } else { + mSwitchValues &= ~(1 << switchCode); + } + mUpdatedSwitchMask |= 1 << switchCode; + } +} + +void SwitchInputMapper::sync(nsecs_t when) { + if (mUpdatedSwitchMask) { + uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask; + NotifySwitchArgs args(mContext->getNextSequenceNum(), when, 0, updatedSwitchValues, + mUpdatedSwitchMask); + getListener()->notifySwitch(&args); + + mUpdatedSwitchMask = 0; + } +} + +int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { + return getEventHub()->getSwitchState(getDeviceId(), switchCode); +} + +void SwitchInputMapper::dump(std::string& dump) { + dump += INDENT2 "Switch Input Mapper:\n"; + dump += StringPrintf(INDENT3 "SwitchValues: %x\n", mSwitchValues); +} + +// --- VibratorInputMapper --- + +VibratorInputMapper::VibratorInputMapper(InputDevice* device) : + InputMapper(device), mVibrating(false) { +} + +VibratorInputMapper::~VibratorInputMapper() { +} + +uint32_t VibratorInputMapper::getSources() { + return 0; +} + +void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + info->setVibrator(true); +} + +void VibratorInputMapper::process(const RawEvent* rawEvent) { + // TODO: Handle FF_STATUS, although it does not seem to be widely supported. +} + +void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, + int32_t token) { +#if DEBUG_VIBRATOR + std::string patternStr; + for (size_t i = 0; i < patternSize; i++) { + if (i != 0) { + patternStr += ", "; + } + patternStr += StringPrintf("%" PRId64, pattern[i]); + } + ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", + getDeviceId(), patternStr.c_str(), repeat, token); +#endif + + mVibrating = true; + memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t)); + mPatternSize = patternSize; + mRepeat = repeat; + mToken = token; + mIndex = -1; + + nextStep(); +} + +void VibratorInputMapper::cancelVibrate(int32_t token) { +#if DEBUG_VIBRATOR + ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token); +#endif + + if (mVibrating && mToken == token) { + stopVibrating(); + } +} + +void VibratorInputMapper::timeoutExpired(nsecs_t when) { + if (mVibrating) { + if (when >= mNextStepTime) { + nextStep(); + } else { + getContext()->requestTimeoutAtTime(mNextStepTime); + } + } +} + +void VibratorInputMapper::nextStep() { + mIndex += 1; + if (size_t(mIndex) >= mPatternSize) { + if (mRepeat < 0) { + // We are done. + stopVibrating(); + return; + } + mIndex = mRepeat; + } + + bool vibratorOn = mIndex & 1; + nsecs_t duration = mPattern[mIndex]; + if (vibratorOn) { +#if DEBUG_VIBRATOR + ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration); +#endif + getEventHub()->vibrate(getDeviceId(), duration); + } else { +#if DEBUG_VIBRATOR + ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); +#endif + getEventHub()->cancelVibrate(getDeviceId()); + } + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + mNextStepTime = now + duration; + getContext()->requestTimeoutAtTime(mNextStepTime); +#if DEBUG_VIBRATOR + ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f); +#endif +} + +void VibratorInputMapper::stopVibrating() { + mVibrating = false; +#if DEBUG_VIBRATOR + ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); +#endif + getEventHub()->cancelVibrate(getDeviceId()); +} + +void VibratorInputMapper::dump(std::string& dump) { + dump += INDENT2 "Vibrator Input Mapper:\n"; + dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating)); +} + + +// --- KeyboardInputMapper --- + +KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, + uint32_t source, int32_t keyboardType) : + InputMapper(device), mSource(source), mKeyboardType(keyboardType) { +} + +KeyboardInputMapper::~KeyboardInputMapper() { +} + +uint32_t KeyboardInputMapper::getSources() { + return mSource; +} + +int32_t KeyboardInputMapper::getOrientation() { + if (mViewport) { + return mViewport->orientation; + } + return DISPLAY_ORIENTATION_0; +} + +int32_t KeyboardInputMapper::getDisplayId() { + if (mViewport) { + return mViewport->displayId; + } + return ADISPLAY_ID_NONE; +} + +void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + info->setKeyboardType(mKeyboardType); + info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); +} + +void KeyboardInputMapper::dump(std::string& dump) { + dump += INDENT2 "Keyboard Input Mapper:\n"; + dumpParameters(dump); + dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType); + dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation()); + dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size()); + dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState); + dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); +} + +void KeyboardInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + InputMapper::configure(when, config, changes); + + if (!changes) { // first time only + // Configure basic parameters. + configureParameters(); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + if (mParameters.orientationAware) { + mViewport = config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); + } + } +} + +static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const *property) { + int32_t mapped = 0; + if (config.tryGetProperty(String8(property), mapped) && mapped > 0) { + for (size_t i = 0; i < stemKeyRotationMapSize; i++) { + if (stemKeyRotationMap[i][0] == keyCode) { + stemKeyRotationMap[i][1] = mapped; + return; + } + } + } +} + +void KeyboardInputMapper::configureParameters() { + mParameters.orientationAware = false; + const PropertyMap& config = getDevice()->getConfiguration(); + config.tryGetProperty(String8("keyboard.orientationAware"), + mParameters.orientationAware); + + if (mParameters.orientationAware) { + mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary"); + mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1"); + mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2"); + mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3"); + } + + mParameters.handlesKeyRepeat = false; + config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), + mParameters.handlesKeyRepeat); +} + +void KeyboardInputMapper::dumpParameters(std::string& dump) { + dump += INDENT3 "Parameters:\n"; + dump += StringPrintf(INDENT4 "OrientationAware: %s\n", + toString(mParameters.orientationAware)); + dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n", + toString(mParameters.handlesKeyRepeat)); +} + +void KeyboardInputMapper::reset(nsecs_t when) { + mMetaState = AMETA_NONE; + mDownTime = 0; + mKeyDowns.clear(); + mCurrentHidUsage = 0; + + resetLedState(); + + InputMapper::reset(when); +} + +void KeyboardInputMapper::process(const RawEvent* rawEvent) { + switch (rawEvent->type) { + case EV_KEY: { + int32_t scanCode = rawEvent->code; + int32_t usageCode = mCurrentHidUsage; + mCurrentHidUsage = 0; + + if (isKeyboardOrGamepadKey(scanCode)) { + processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode); + } + break; + } + case EV_MSC: { + if (rawEvent->code == MSC_SCAN) { + mCurrentHidUsage = rawEvent->value; + } + break; + } + case EV_SYN: { + if (rawEvent->code == SYN_REPORT) { + mCurrentHidUsage = 0; + } + } + } +} + +bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { + return scanCode < BTN_MOUSE + || scanCode >= KEY_OK + || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) + || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); +} + +bool KeyboardInputMapper::isMediaKey(int32_t keyCode) { + switch (keyCode) { + case AKEYCODE_MEDIA_PLAY: + case AKEYCODE_MEDIA_PAUSE: + case AKEYCODE_MEDIA_PLAY_PAUSE: + case AKEYCODE_MUTE: + case AKEYCODE_HEADSETHOOK: + case AKEYCODE_MEDIA_STOP: + case AKEYCODE_MEDIA_NEXT: + case AKEYCODE_MEDIA_PREVIOUS: + case AKEYCODE_MEDIA_REWIND: + case AKEYCODE_MEDIA_RECORD: + case AKEYCODE_MEDIA_FAST_FORWARD: + case AKEYCODE_MEDIA_SKIP_FORWARD: + case AKEYCODE_MEDIA_SKIP_BACKWARD: + case AKEYCODE_MEDIA_STEP_FORWARD: + case AKEYCODE_MEDIA_STEP_BACKWARD: + case AKEYCODE_MEDIA_AUDIO_TRACK: + case AKEYCODE_VOLUME_UP: + case AKEYCODE_VOLUME_DOWN: + case AKEYCODE_VOLUME_MUTE: + case AKEYCODE_TV_AUDIO_DESCRIPTION: + case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP: + case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN: + return true; + } + return false; +} + +void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, + int32_t usageCode) { + int32_t keyCode; + int32_t keyMetaState; + uint32_t policyFlags; + + if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState, + &keyCode, &keyMetaState, &policyFlags)) { + keyCode = AKEYCODE_UNKNOWN; + keyMetaState = mMetaState; + policyFlags = 0; + } + + if (down) { + // Rotate key codes according to orientation if needed. + if (mParameters.orientationAware) { + keyCode = rotateKeyCode(keyCode, getOrientation()); + } + + // Add key down. + ssize_t keyDownIndex = findKeyDown(scanCode); + if (keyDownIndex >= 0) { + // key repeat, be sure to use same keycode as before in case of rotation + keyCode = mKeyDowns[keyDownIndex].keyCode; + } else { + // key down + if ((policyFlags & POLICY_FLAG_VIRTUAL) + && mContext->shouldDropVirtualKey(when, + getDevice(), keyCode, scanCode)) { + return; + } + if (policyFlags & POLICY_FLAG_GESTURE) { + mDevice->cancelTouch(when); + } + + KeyDown keyDown; + keyDown.keyCode = keyCode; + keyDown.scanCode = scanCode; + mKeyDowns.push_back(keyDown); + } + + mDownTime = when; + } else { + // Remove key down. + ssize_t keyDownIndex = findKeyDown(scanCode); + if (keyDownIndex >= 0) { + // key up, be sure to use same keycode as before in case of rotation + keyCode = mKeyDowns[keyDownIndex].keyCode; + mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex); + } else { + // key was not actually down + ALOGI("Dropping key up from device %s because the key was not down. " + "keyCode=%d, scanCode=%d", + getDeviceName().c_str(), keyCode, scanCode); + return; + } + } + + if (updateMetaStateIfNeeded(keyCode, down)) { + // If global meta state changed send it along with the key. + // If it has not changed then we'll use what keymap gave us, + // since key replacement logic might temporarily reset a few + // meta bits for given key. + keyMetaState = mMetaState; + } + + nsecs_t downTime = mDownTime; + + // Key down on external an keyboard should wake the device. + // We don't do this for internal keyboards to prevent them from waking up in your pocket. + // For internal keyboards, the key layout file should specify the policy flags for + // each wake key individually. + // TODO: Use the input device configuration to control this behavior more finely. + if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) { + policyFlags |= POLICY_FLAG_WAKE; + } + + if (mParameters.handlesKeyRepeat) { + policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; + } + + NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime); + getListener()->notifyKey(&args); +} + +ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { + size_t n = mKeyDowns.size(); + for (size_t i = 0; i < n; i++) { + if (mKeyDowns[i].scanCode == scanCode) { + return i; + } + } + return -1; +} + +int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); +} + +int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + return getEventHub()->getScanCodeState(getDeviceId(), scanCode); +} + +bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); +} + +int32_t KeyboardInputMapper::getMetaState() { + return mMetaState; +} + +void KeyboardInputMapper::updateMetaState(int32_t keyCode) { + updateMetaStateIfNeeded(keyCode, false); +} + +bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) { + int32_t oldMetaState = mMetaState; + int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState); + bool metaStateChanged = oldMetaState != newMetaState; + if (metaStateChanged) { + mMetaState = newMetaState; + updateLedState(false); + + getContext()->updateGlobalMetaState(); + } + + return metaStateChanged; +} + +void KeyboardInputMapper::resetLedState() { + initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK); + initializeLedState(mNumLockLedState, ALED_NUM_LOCK); + initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK); + + updateLedState(true); +} + +void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { + ledState.avail = getEventHub()->hasLed(getDeviceId(), led); + ledState.on = false; +} + +void KeyboardInputMapper::updateLedState(bool reset) { + updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK, + AMETA_CAPS_LOCK_ON, reset); + updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK, + AMETA_NUM_LOCK_ON, reset); + updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK, + AMETA_SCROLL_LOCK_ON, reset); +} + +void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, + int32_t led, int32_t modifier, bool reset) { + if (ledState.avail) { + bool desiredState = (mMetaState & modifier) != 0; + if (reset || ledState.on != desiredState) { + getEventHub()->setLedState(getDeviceId(), led, desiredState); + ledState.on = desiredState; + } + } +} + + +// --- CursorInputMapper --- + +CursorInputMapper::CursorInputMapper(InputDevice* device) : + InputMapper(device) { +} + +CursorInputMapper::~CursorInputMapper() { +} + +uint32_t CursorInputMapper::getSources() { + return mSource; +} + +void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + if (mParameters.mode == Parameters::MODE_POINTER) { + float minX, minY, maxX, maxY; + if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { + info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f); + } + } else { + info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f); + } + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); + + if (mCursorScrollAccumulator.haveRelativeVWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); + } + if (mCursorScrollAccumulator.haveRelativeHWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); + } +} + +void CursorInputMapper::dump(std::string& dump) { + dump += INDENT2 "Cursor Input Mapper:\n"; + dumpParameters(dump); + dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale); + dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale); + dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision); + dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision); + dump += StringPrintf(INDENT3 "HaveVWheel: %s\n", + toString(mCursorScrollAccumulator.haveRelativeVWheel())); + dump += StringPrintf(INDENT3 "HaveHWheel: %s\n", + toString(mCursorScrollAccumulator.haveRelativeHWheel())); + dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); + dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); + dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation); + dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState); + dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); + dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); +} + +void CursorInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + InputMapper::configure(when, config, changes); + + if (!changes) { // first time only + mCursorScrollAccumulator.configure(getDevice()); + + // Configure basic parameters. + configureParameters(); + + // Configure device mode. + switch (mParameters.mode) { + case Parameters::MODE_POINTER_RELATIVE: + // Should not happen during first time configuration. + ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER"); + mParameters.mode = Parameters::MODE_POINTER; + [[fallthrough]]; + case Parameters::MODE_POINTER: + mSource = AINPUT_SOURCE_MOUSE; + mXPrecision = 1.0f; + mYPrecision = 1.0f; + mXScale = 1.0f; + mYScale = 1.0f; + mPointerController = getPolicy()->obtainPointerController(getDeviceId()); + break; + case Parameters::MODE_NAVIGATION: + mSource = AINPUT_SOURCE_TRACKBALL; + mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; + mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; + mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; + mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; + break; + } + + mVWheelScale = 1.0f; + mHWheelScale = 1.0f; + } + + if ((!changes && config->pointerCapture) + || (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) { + if (config->pointerCapture) { + if (mParameters.mode == Parameters::MODE_POINTER) { + mParameters.mode = Parameters::MODE_POINTER_RELATIVE; + mSource = AINPUT_SOURCE_MOUSE_RELATIVE; + // Keep PointerController around in order to preserve the pointer position. + mPointerController->fade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } else { + ALOGE("Cannot request pointer capture, device is not in MODE_POINTER"); + } + } else { + if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) { + mParameters.mode = Parameters::MODE_POINTER; + mSource = AINPUT_SOURCE_MOUSE; + } else { + ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE"); + } + } + bumpGeneration(); + if (changes) { + getDevice()->notifyReset(when); + } + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { + mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters); + mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); + mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + mOrientation = DISPLAY_ORIENTATION_0; + if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { + std::optional<DisplayViewport> internalViewport = + config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); + if (internalViewport) { + mOrientation = internalViewport->orientation; + } + } + + // Update the PointerController if viewports changed. + if (mParameters.mode == Parameters::MODE_POINTER) { + getPolicy()->obtainPointerController(getDeviceId()); + } + bumpGeneration(); + } +} + +void CursorInputMapper::configureParameters() { + mParameters.mode = Parameters::MODE_POINTER; + String8 cursorModeString; + if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { + if (cursorModeString == "navigation") { + mParameters.mode = Parameters::MODE_NAVIGATION; + } else if (cursorModeString != "pointer" && cursorModeString != "default") { + ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); + } + } + + mParameters.orientationAware = false; + getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), + mParameters.orientationAware); + + mParameters.hasAssociatedDisplay = false; + if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { + mParameters.hasAssociatedDisplay = true; + } +} + +void CursorInputMapper::dumpParameters(std::string& dump) { + dump += INDENT3 "Parameters:\n"; + dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n", + toString(mParameters.hasAssociatedDisplay)); + + switch (mParameters.mode) { + case Parameters::MODE_POINTER: + dump += INDENT4 "Mode: pointer\n"; + break; + case Parameters::MODE_POINTER_RELATIVE: + dump += INDENT4 "Mode: relative pointer\n"; + break; + case Parameters::MODE_NAVIGATION: + dump += INDENT4 "Mode: navigation\n"; + break; + default: + ALOG_ASSERT(false); + } + + dump += StringPrintf(INDENT4 "OrientationAware: %s\n", + toString(mParameters.orientationAware)); +} + +void CursorInputMapper::reset(nsecs_t when) { + mButtonState = 0; + mDownTime = 0; + + mPointerVelocityControl.reset(); + mWheelXVelocityControl.reset(); + mWheelYVelocityControl.reset(); + + mCursorButtonAccumulator.reset(getDevice()); + mCursorMotionAccumulator.reset(getDevice()); + mCursorScrollAccumulator.reset(getDevice()); + + InputMapper::reset(when); +} + +void CursorInputMapper::process(const RawEvent* rawEvent) { + mCursorButtonAccumulator.process(rawEvent); + mCursorMotionAccumulator.process(rawEvent); + mCursorScrollAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void CursorInputMapper::sync(nsecs_t when) { + int32_t lastButtonState = mButtonState; + int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); + mButtonState = currentButtonState; + + bool wasDown = isPointerDown(lastButtonState); + bool down = isPointerDown(currentButtonState); + bool downChanged; + if (!wasDown && down) { + mDownTime = when; + downChanged = true; + } else if (wasDown && !down) { + downChanged = true; + } else { + downChanged = false; + } + nsecs_t downTime = mDownTime; + bool buttonsChanged = currentButtonState != lastButtonState; + int32_t buttonsPressed = currentButtonState & ~lastButtonState; + int32_t buttonsReleased = lastButtonState & ~currentButtonState; + + float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; + float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; + bool moved = deltaX != 0 || deltaY != 0; + + // Rotate delta according to orientation if needed. + if (mParameters.orientationAware && mParameters.hasAssociatedDisplay + && (deltaX != 0.0f || deltaY != 0.0f)) { + rotateDelta(mOrientation, &deltaX, &deltaY); + } + + // Move the pointer. + PointerProperties pointerProperties; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; + + PointerCoords pointerCoords; + pointerCoords.clear(); + + float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); + float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); + bool scrolled = vscroll != 0 || hscroll != 0; + + mWheelYVelocityControl.move(when, nullptr, &vscroll); + mWheelXVelocityControl.move(when, &hscroll, nullptr); + + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + int32_t displayId; + if (mSource == AINPUT_SOURCE_MOUSE) { + if (moved || scrolled || buttonsChanged) { + mPointerController->setPresentation( + PointerControllerInterface::PRESENTATION_POINTER); + + if (moved) { + mPointerController->move(deltaX, deltaY); + } + + if (buttonsChanged) { + mPointerController->setButtonState(currentButtonState); + } + + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } + + float x, y; + mPointerController->getPosition(&x, &y); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); + displayId = mPointerController->getDisplayId(); + } else { + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); + displayId = ADISPLAY_ID_NONE; + } + + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); + + // Moving an external trackball or mouse should wake the device. + // We don't do this for internal cursor devices to prevent them from waking up + // the device in your pocket. + // TODO: Use the input device configuration to control this behavior more finely. + uint32_t policyFlags = 0; + if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { + policyFlags |= POLICY_FLAG_WAKE; + } + + // Synthesize key down from buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + displayId, policyFlags, lastButtonState, currentButtonState); + + // Send motion event. + if (downChanged || moved || scrolled || buttonsChanged) { + int32_t metaState = mContext->getGlobalMetaState(); + int32_t buttonState = lastButtonState; + int32_t motionEventAction; + if (downChanged) { + motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; + } else if (down || (mSource != AINPUT_SOURCE_MOUSE)) { + motionEventAction = AMOTION_EVENT_ACTION_MOVE; + } else { + motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; + } + + if (buttonsReleased) { + BitSet32 released(buttonsReleased); + while (!released.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); + buttonState &= ~actionButton; + NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, + metaState, buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&releaseArgs); + } + } + + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + + if (buttonsPressed) { + BitSet32 pressed(buttonsPressed); + while (!pressed.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); + buttonState |= actionButton; + NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS, + actionButton, 0, metaState, buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&pressArgs); + } + } + + ALOG_ASSERT(buttonState == currentButtonState); + + // Send hover move after UP to tell the application that the mouse is hovering now. + if (motionEventAction == AMOTION_EVENT_ACTION_UP + && (mSource == AINPUT_SOURCE_MOUSE)) { + NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, + metaState, currentButtonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&hoverArgs); + } + + // Send scroll events. + if (scrolled) { + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); + + NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&scrollArgs); + } + } + + // Synthesize key up from buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + displayId, policyFlags, lastButtonState, currentButtonState); + + mCursorMotionAccumulator.finishSync(); + mCursorScrollAccumulator.finishSync(); +} + +int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { + return getEventHub()->getScanCodeState(getDeviceId(), scanCode); + } else { + return AKEY_STATE_UNKNOWN; + } +} + +void CursorInputMapper::fadePointer() { + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + } +} + +std::optional<int32_t> CursorInputMapper::getAssociatedDisplay() { + if (mParameters.hasAssociatedDisplay) { + if (mParameters.mode == Parameters::MODE_POINTER) { + return std::make_optional(mPointerController->getDisplayId()); + } else { + // If the device is orientationAware and not a mouse, + // it expects to dispatch events to any display + return std::make_optional(ADISPLAY_ID_NONE); + } + } + return std::nullopt; +} + +// --- RotaryEncoderInputMapper --- + +RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) : + InputMapper(device), mOrientation(DISPLAY_ORIENTATION_0) { + mSource = AINPUT_SOURCE_ROTARY_ENCODER; +} + +RotaryEncoderInputMapper::~RotaryEncoderInputMapper() { +} + +uint32_t RotaryEncoderInputMapper::getSources() { + return mSource; +} + +void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) { + float res = 0.0f; + if (!mDevice->getConfiguration().tryGetProperty(String8("device.res"), res)) { + ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); + } + if (!mDevice->getConfiguration().tryGetProperty(String8("device.scalingFactor"), + mScalingFactor)) { + ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," + "default to 1.0!\n"); + mScalingFactor = 1.0f; + } + info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, + res * mScalingFactor); + } +} + +void RotaryEncoderInputMapper::dump(std::string& dump) { + dump += INDENT2 "Rotary Encoder Input Mapper:\n"; + dump += StringPrintf(INDENT3 "HaveWheel: %s\n", + toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel())); +} + +void RotaryEncoderInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + InputMapper::configure(when, config, changes); + if (!changes) { + mRotaryEncoderScrollAccumulator.configure(getDevice()); + } + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + std::optional<DisplayViewport> internalViewport = + config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); + if (internalViewport) { + mOrientation = internalViewport->orientation; + } else { + mOrientation = DISPLAY_ORIENTATION_0; + } + } +} + +void RotaryEncoderInputMapper::reset(nsecs_t when) { + mRotaryEncoderScrollAccumulator.reset(getDevice()); + + InputMapper::reset(when); +} + +void RotaryEncoderInputMapper::process(const RawEvent* rawEvent) { + mRotaryEncoderScrollAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void RotaryEncoderInputMapper::sync(nsecs_t when) { + PointerCoords pointerCoords; + pointerCoords.clear(); + + PointerProperties pointerProperties; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + + float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); + bool scrolled = scroll != 0; + + // This is not a pointer, so it's not associated with a display. + int32_t displayId = ADISPLAY_ID_NONE; + + // Moving the rotary encoder should wake the device (if specified). + uint32_t policyFlags = 0; + if (scrolled && getDevice()->isExternal()) { + policyFlags |= POLICY_FLAG_WAKE; + } + + if (mOrientation == DISPLAY_ORIENTATION_180) { + scroll = -scroll; + } + + // Send motion event. + if (scrolled) { + int32_t metaState = mContext->getGlobalMetaState(); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); + + NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + 0, 0, 0, /* videoFrames */ {}); + getListener()->notifyMotion(&scrollArgs); + } + + mRotaryEncoderScrollAccumulator.finishSync(); +} + +// --- TouchInputMapper --- + +TouchInputMapper::TouchInputMapper(InputDevice* device) : + InputMapper(device), + mSource(0), mDeviceMode(DEVICE_MODE_DISABLED), + mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0), + mPhysicalWidth(-1), mPhysicalHeight(-1), mPhysicalLeft(0), mPhysicalTop(0), + mSurfaceOrientation(DISPLAY_ORIENTATION_0) { +} + +TouchInputMapper::~TouchInputMapper() { +} + +uint32_t TouchInputMapper::getSources() { + return mSource; +} + +void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + if (mDeviceMode != DEVICE_MODE_DISABLED) { + info->addMotionRange(mOrientedRanges.x); + info->addMotionRange(mOrientedRanges.y); + info->addMotionRange(mOrientedRanges.pressure); + + if (mOrientedRanges.haveSize) { + info->addMotionRange(mOrientedRanges.size); + } + + if (mOrientedRanges.haveTouchSize) { + info->addMotionRange(mOrientedRanges.touchMajor); + info->addMotionRange(mOrientedRanges.touchMinor); + } + + if (mOrientedRanges.haveToolSize) { + info->addMotionRange(mOrientedRanges.toolMajor); + info->addMotionRange(mOrientedRanges.toolMinor); + } + + if (mOrientedRanges.haveOrientation) { + info->addMotionRange(mOrientedRanges.orientation); + } + + if (mOrientedRanges.haveDistance) { + info->addMotionRange(mOrientedRanges.distance); + } + + if (mOrientedRanges.haveTilt) { + info->addMotionRange(mOrientedRanges.tilt); + } + + if (mCursorScrollAccumulator.haveRelativeVWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, + 0.0f); + } + if (mCursorScrollAccumulator.haveRelativeHWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, + 0.0f); + } + if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { + const InputDeviceInfo::MotionRange& x = mOrientedRanges.x; + const InputDeviceInfo::MotionRange& y = mOrientedRanges.y; + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, + x.fuzz, x.resolution); + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, + y.fuzz, y.resolution); + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, + x.fuzz, x.resolution); + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, + y.fuzz, y.resolution); + } + info->setButtonUnderPad(mParameters.hasButtonUnderPad); + } +} + +void TouchInputMapper::dump(std::string& dump) { + dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode)); + dumpParameters(dump); + dumpVirtualKeys(dump); + dumpRawPointerAxes(dump); + dumpCalibration(dump); + dumpAffineTransformation(dump); + dumpSurface(dump); + + dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n"); + dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate); + dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate); + dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale); + dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale); + dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision); + dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision); + dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); + dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale); + dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale); + dump += StringPrintf(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); + dump += StringPrintf(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); + dump += StringPrintf(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); + dump += StringPrintf(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); + dump += StringPrintf(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); + dump += StringPrintf(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); + dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); + + dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState); + dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n", + mLastRawState.rawPointerData.pointerCount); + for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { + const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; + dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " + "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " + "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " + "toolType=%d, isHovering=%s\n", i, + pointer.id, pointer.x, pointer.y, pointer.pressure, + pointer.touchMajor, pointer.touchMinor, + pointer.toolMajor, pointer.toolMinor, + pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance, + pointer.toolType, toString(pointer.isHovering)); + } + + dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState); + dump += StringPrintf(INDENT3 "Last Cooked Touch: pointerCount=%d\n", + mLastCookedState.cookedPointerData.pointerCount); + for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { + const PointerProperties& pointerProperties = + mLastCookedState.cookedPointerData.pointerProperties[i]; + const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; + dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " + "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " + "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " + "toolType=%d, isHovering=%s\n", i, + pointerProperties.id, + pointerCoords.getX(), + pointerCoords.getY(), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), + pointerProperties.toolType, + toString(mLastCookedState.cookedPointerData.isHovering(i))); + } + + dump += INDENT3 "Stylus Fusion:\n"; + dump += StringPrintf(INDENT4 "ExternalStylusConnected: %s\n", + toString(mExternalStylusConnected)); + dump += StringPrintf(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); + dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", + mExternalStylusFusionTimeout); + dump += INDENT3 "External Stylus State:\n"; + dumpStylusState(dump, mExternalStylusState); + + if (mDeviceMode == DEVICE_MODE_POINTER) { + dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n"); + dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n", + mPointerXMovementScale); + dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n", + mPointerYMovementScale); + dump += StringPrintf(INDENT4 "XZoomScale: %0.3f\n", + mPointerXZoomScale); + dump += StringPrintf(INDENT4 "YZoomScale: %0.3f\n", + mPointerYZoomScale); + dump += StringPrintf(INDENT4 "MaxSwipeWidth: %f\n", + mPointerGestureMaxSwipeWidth); + } +} + +const char* TouchInputMapper::modeToString(DeviceMode deviceMode) { + switch (deviceMode) { + case DEVICE_MODE_DISABLED: + return "disabled"; + case DEVICE_MODE_DIRECT: + return "direct"; + case DEVICE_MODE_UNSCALED: + return "unscaled"; + case DEVICE_MODE_NAVIGATION: + return "navigation"; + case DEVICE_MODE_POINTER: + return "pointer"; + } + return "unknown"; +} + +void TouchInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + InputMapper::configure(when, config, changes); + + mConfig = *config; + + if (!changes) { // first time only + // Configure basic parameters. + configureParameters(); + + // Configure common accumulators. + mCursorScrollAccumulator.configure(getDevice()); + mTouchButtonAccumulator.configure(getDevice()); + + // Configure absolute axis information. + configureRawPointerAxes(); + + // Prepare input device calibration. + parseCalibration(); + resolveCalibration(); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) { + // Update location calibration to reflect current settings + updateAffineTransformation(); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { + // Update pointer speed. + mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); + mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); + mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); + } + + bool resetNeeded = false; + if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO + | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT + | InputReaderConfiguration::CHANGE_SHOW_TOUCHES + | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { + // Configure device sources, surface dimensions, orientation and + // scaling factors. + configureSurface(when, &resetNeeded); + } + + if (changes && resetNeeded) { + // Send reset, unless this is the first time the device has been configured, + // in which case the reader will call reset itself after all mappers are ready. + getDevice()->notifyReset(when); + } +} + +void TouchInputMapper::resolveExternalStylusPresence() { + std::vector<InputDeviceInfo> devices; + mContext->getExternalStylusDevices(devices); + mExternalStylusConnected = !devices.empty(); + + if (!mExternalStylusConnected) { + resetExternalStylus(); + } +} + +void TouchInputMapper::configureParameters() { + // Use the pointer presentation mode for devices that do not support distinct + // multitouch. The spot-based presentation relies on being able to accurately + // locate two or more fingers on the touch pad. + mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) + ? Parameters::GESTURE_MODE_SINGLE_TOUCH : Parameters::GESTURE_MODE_MULTI_TOUCH; + + String8 gestureModeString; + if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), + gestureModeString)) { + if (gestureModeString == "single-touch") { + mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH; + } else if (gestureModeString == "multi-touch") { + mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH; + } else if (gestureModeString != "default") { + ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); + } + } + + if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { + // The device is a touch screen. + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; + } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { + // The device is a pointing device like a track pad. + mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; + } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) + || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { + // The device is a cursor device with a touch pad attached. + // By default don't use the touch pad to move the pointer. + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else { + // The device is a touch pad of unknown purpose. + mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; + } + + mParameters.hasButtonUnderPad= + getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD); + + String8 deviceTypeString; + if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), + deviceTypeString)) { + if (deviceTypeString == "touchScreen") { + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; + } else if (deviceTypeString == "touchPad") { + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else if (deviceTypeString == "touchNavigation") { + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION; + } else if (deviceTypeString == "pointer") { + mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; + } else if (deviceTypeString != "default") { + ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); + } + } + + mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; + getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), + mParameters.orientationAware); + + mParameters.hasAssociatedDisplay = false; + mParameters.associatedDisplayIsExternal = false; + if (mParameters.orientationAware + || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN + || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { + mParameters.hasAssociatedDisplay = true; + if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { + mParameters.associatedDisplayIsExternal = getDevice()->isExternal(); + String8 uniqueDisplayId; + getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"), + uniqueDisplayId); + mParameters.uniqueDisplayId = uniqueDisplayId.c_str(); + } + } + if (getDevice()->getAssociatedDisplayPort()) { + mParameters.hasAssociatedDisplay = true; + } + + // Initial downs on external touch devices should wake the device. + // Normally we don't do this for internal touch screens to prevent them from waking + // up in your pocket but you can enable it using the input device configuration. + mParameters.wake = getDevice()->isExternal(); + getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"), + mParameters.wake); +} + +void TouchInputMapper::dumpParameters(std::string& dump) { + dump += INDENT3 "Parameters:\n"; + + switch (mParameters.gestureMode) { + case Parameters::GESTURE_MODE_SINGLE_TOUCH: + dump += INDENT4 "GestureMode: single-touch\n"; + break; + case Parameters::GESTURE_MODE_MULTI_TOUCH: + dump += INDENT4 "GestureMode: multi-touch\n"; + break; + default: + assert(false); + } + + switch (mParameters.deviceType) { + case Parameters::DEVICE_TYPE_TOUCH_SCREEN: + dump += INDENT4 "DeviceType: touchScreen\n"; + break; + case Parameters::DEVICE_TYPE_TOUCH_PAD: + dump += INDENT4 "DeviceType: touchPad\n"; + break; + case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: + dump += INDENT4 "DeviceType: touchNavigation\n"; + break; + case Parameters::DEVICE_TYPE_POINTER: + dump += INDENT4 "DeviceType: pointer\n"; + break; + default: + ALOG_ASSERT(false); + } + + dump += StringPrintf( + INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, displayId='%s'\n", + toString(mParameters.hasAssociatedDisplay), + toString(mParameters.associatedDisplayIsExternal), + mParameters.uniqueDisplayId.c_str()); + dump += StringPrintf(INDENT4 "OrientationAware: %s\n", + toString(mParameters.orientationAware)); +} + +void TouchInputMapper::configureRawPointerAxes() { + mRawPointerAxes.clear(); +} + +void TouchInputMapper::dumpRawPointerAxes(std::string& dump) { + dump += INDENT3 "Raw Touch Axes:\n"; + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); +} + +bool TouchInputMapper::hasExternalStylus() const { + return mExternalStylusConnected; +} + +/** + * Determine which DisplayViewport to use. + * 1. If display port is specified, return the matching viewport. If matching viewport not + * found, then return. + * 2. If a device has associated display, get the matching viewport by either unique id or by + * the display type (internal or external). + * 3. Otherwise, use a non-display viewport. + */ +std::optional<DisplayViewport> TouchInputMapper::findViewport() { + if (mParameters.hasAssociatedDisplay) { + const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort(); + if (displayPort) { + // Find the viewport that contains the same port + std::optional<DisplayViewport> v = mConfig.getDisplayViewportByPort(*displayPort); + if (!v) { + ALOGW("Input device %s should be associated with display on port %" PRIu8 ", " + "but the corresponding viewport is not found.", + getDeviceName().c_str(), *displayPort); + } + return v; + } + + if (!mParameters.uniqueDisplayId.empty()) { + return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId); + } + + ViewportType viewportTypeToUse; + if (mParameters.associatedDisplayIsExternal) { + viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL; + } else { + viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL; + } + + std::optional<DisplayViewport> viewport = + mConfig.getDisplayViewportByType(viewportTypeToUse); + if (!viewport && viewportTypeToUse == ViewportType::VIEWPORT_EXTERNAL) { + ALOGW("Input device %s should be associated with external display, " + "fallback to internal one for the external viewport is not found.", + getDeviceName().c_str()); + viewport = mConfig.getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); + } + + return viewport; + } + + DisplayViewport newViewport; + // Raw width and height in the natural orientation. + int32_t rawWidth = mRawPointerAxes.getRawWidth(); + int32_t rawHeight = mRawPointerAxes.getRawHeight(); + newViewport.setNonDisplayViewport(rawWidth, rawHeight); + return std::make_optional(newViewport); +} + +void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { + int32_t oldDeviceMode = mDeviceMode; + + resolveExternalStylusPresence(); + + // Determine device mode. + if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER + && mConfig.pointerGesturesEnabled) { + mSource = AINPUT_SOURCE_MOUSE; + mDeviceMode = DEVICE_MODE_POINTER; + if (hasStylus()) { + mSource |= AINPUT_SOURCE_STYLUS; + } + } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN + && mParameters.hasAssociatedDisplay) { + mSource = AINPUT_SOURCE_TOUCHSCREEN; + mDeviceMode = DEVICE_MODE_DIRECT; + if (hasStylus()) { + mSource |= AINPUT_SOURCE_STYLUS; + } + if (hasExternalStylus()) { + mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS; + } + } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { + mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; + mDeviceMode = DEVICE_MODE_NAVIGATION; + } else { + mSource = AINPUT_SOURCE_TOUCHPAD; + mDeviceMode = DEVICE_MODE_UNSCALED; + } + + // Ensure we have valid X and Y axes. + if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { + ALOGW("Touch device '%s' did not report support for X or Y axis! " + "The device will be inoperable.", getDeviceName().c_str()); + mDeviceMode = DEVICE_MODE_DISABLED; + return; + } + + // Get associated display dimensions. + std::optional<DisplayViewport> newViewport = findViewport(); + if (!newViewport) { + ALOGI("Touch device '%s' could not query the properties of its associated " + "display. The device will be inoperable until the display size " + "becomes available.", + getDeviceName().c_str()); + mDeviceMode = DEVICE_MODE_DISABLED; + return; + } + + // Raw width and height in the natural orientation. + int32_t rawWidth = mRawPointerAxes.getRawWidth(); + int32_t rawHeight = mRawPointerAxes.getRawHeight(); + + bool viewportChanged = mViewport != *newViewport; + if (viewportChanged) { + mViewport = *newViewport; + + if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { + // Convert rotated viewport to natural surface coordinates. + int32_t naturalLogicalWidth, naturalLogicalHeight; + int32_t naturalPhysicalWidth, naturalPhysicalHeight; + int32_t naturalPhysicalLeft, naturalPhysicalTop; + int32_t naturalDeviceWidth, naturalDeviceHeight; + switch (mViewport.orientation) { + case DISPLAY_ORIENTATION_90: + naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; + naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; + naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; + naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; + naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; + naturalPhysicalTop = mViewport.physicalLeft; + naturalDeviceWidth = mViewport.deviceHeight; + naturalDeviceHeight = mViewport.deviceWidth; + break; + case DISPLAY_ORIENTATION_180: + naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; + naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; + naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; + naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; + naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; + naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom; + naturalDeviceWidth = mViewport.deviceWidth; + naturalDeviceHeight = mViewport.deviceHeight; + break; + case DISPLAY_ORIENTATION_270: + naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; + naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; + naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; + naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; + naturalPhysicalLeft = mViewport.physicalTop; + naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight; + naturalDeviceWidth = mViewport.deviceHeight; + naturalDeviceHeight = mViewport.deviceWidth; + break; + case DISPLAY_ORIENTATION_0: + default: + naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; + naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; + naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; + naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; + naturalPhysicalLeft = mViewport.physicalLeft; + naturalPhysicalTop = mViewport.physicalTop; + naturalDeviceWidth = mViewport.deviceWidth; + naturalDeviceHeight = mViewport.deviceHeight; + break; + } + + if (naturalPhysicalHeight == 0 || naturalPhysicalWidth == 0) { + ALOGE("Viewport is not set properly: %s", mViewport.toString().c_str()); + naturalPhysicalHeight = naturalPhysicalHeight == 0 ? 1 : naturalPhysicalHeight; + naturalPhysicalWidth = naturalPhysicalWidth == 0 ? 1 : naturalPhysicalWidth; + } + + mPhysicalWidth = naturalPhysicalWidth; + mPhysicalHeight = naturalPhysicalHeight; + mPhysicalLeft = naturalPhysicalLeft; + mPhysicalTop = naturalPhysicalTop; + + mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; + mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; + mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; + mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight; + + mSurfaceOrientation = mParameters.orientationAware ? + mViewport.orientation : DISPLAY_ORIENTATION_0; + } else { + mPhysicalWidth = rawWidth; + mPhysicalHeight = rawHeight; + mPhysicalLeft = 0; + mPhysicalTop = 0; + + mSurfaceWidth = rawWidth; + mSurfaceHeight = rawHeight; + mSurfaceLeft = 0; + mSurfaceTop = 0; + mSurfaceOrientation = DISPLAY_ORIENTATION_0; + } + } + + // If moving between pointer modes, need to reset some state. + bool deviceModeChanged = mDeviceMode != oldDeviceMode; + if (deviceModeChanged) { + mOrientedRanges.clear(); + } + + // Create or update pointer controller if needed. + if (mDeviceMode == DEVICE_MODE_POINTER || + (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { + if (mPointerController == nullptr || viewportChanged) { + mPointerController = getPolicy()->obtainPointerController(getDeviceId()); + } + } else { + mPointerController.clear(); + } + + if (viewportChanged || deviceModeChanged) { + ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " + "display id %d", + getDeviceId(), getDeviceName().c_str(), mSurfaceWidth, mSurfaceHeight, + mSurfaceOrientation, mDeviceMode, mViewport.displayId); + + // Configure X and Y factors. + mXScale = float(mSurfaceWidth) / rawWidth; + mYScale = float(mSurfaceHeight) / rawHeight; + mXTranslate = -mSurfaceLeft; + mYTranslate = -mSurfaceTop; + mXPrecision = 1.0f / mXScale; + mYPrecision = 1.0f / mYScale; + + mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; + mOrientedRanges.x.source = mSource; + mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; + mOrientedRanges.y.source = mSource; + + configureVirtualKeys(); + + // Scale factor for terms that are not oriented in a particular axis. + // If the pixels are square then xScale == yScale otherwise we fake it + // by choosing an average. + mGeometricScale = avg(mXScale, mYScale); + + // Size of diagonal axis. + float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight); + + // Size factors. + if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { + if (mRawPointerAxes.touchMajor.valid + && mRawPointerAxes.touchMajor.maxValue != 0) { + mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; + } else if (mRawPointerAxes.toolMajor.valid + && mRawPointerAxes.toolMajor.maxValue != 0) { + mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; + } else { + mSizeScale = 0.0f; + } + + mOrientedRanges.haveTouchSize = true; + mOrientedRanges.haveToolSize = true; + mOrientedRanges.haveSize = true; + + mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; + mOrientedRanges.touchMajor.source = mSource; + mOrientedRanges.touchMajor.min = 0; + mOrientedRanges.touchMajor.max = diagonalSize; + mOrientedRanges.touchMajor.flat = 0; + mOrientedRanges.touchMajor.fuzz = 0; + mOrientedRanges.touchMajor.resolution = 0; + + mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; + mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; + + mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; + mOrientedRanges.toolMajor.source = mSource; + mOrientedRanges.toolMajor.min = 0; + mOrientedRanges.toolMajor.max = diagonalSize; + mOrientedRanges.toolMajor.flat = 0; + mOrientedRanges.toolMajor.fuzz = 0; + mOrientedRanges.toolMajor.resolution = 0; + + mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; + mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; + + mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; + mOrientedRanges.size.source = mSource; + mOrientedRanges.size.min = 0; + mOrientedRanges.size.max = 1.0; + mOrientedRanges.size.flat = 0; + mOrientedRanges.size.fuzz = 0; + mOrientedRanges.size.resolution = 0; + } else { + mSizeScale = 0.0f; + } + + // Pressure factors. + mPressureScale = 0; + float pressureMax = 1.0; + if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL + || mCalibration.pressureCalibration + == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { + if (mCalibration.havePressureScale) { + mPressureScale = mCalibration.pressureScale; + pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue; + } else if (mRawPointerAxes.pressure.valid + && mRawPointerAxes.pressure.maxValue != 0) { + mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; + } + } + + mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; + mOrientedRanges.pressure.source = mSource; + mOrientedRanges.pressure.min = 0; + mOrientedRanges.pressure.max = pressureMax; + mOrientedRanges.pressure.flat = 0; + mOrientedRanges.pressure.fuzz = 0; + mOrientedRanges.pressure.resolution = 0; + + // Tilt + mTiltXCenter = 0; + mTiltXScale = 0; + mTiltYCenter = 0; + mTiltYScale = 0; + mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; + if (mHaveTilt) { + mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, + mRawPointerAxes.tiltX.maxValue); + mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, + mRawPointerAxes.tiltY.maxValue); + mTiltXScale = M_PI / 180; + mTiltYScale = M_PI / 180; + + mOrientedRanges.haveTilt = true; + + mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; + mOrientedRanges.tilt.source = mSource; + mOrientedRanges.tilt.min = 0; + mOrientedRanges.tilt.max = M_PI_2; + mOrientedRanges.tilt.flat = 0; + mOrientedRanges.tilt.fuzz = 0; + mOrientedRanges.tilt.resolution = 0; + } + + // Orientation + mOrientationScale = 0; + if (mHaveTilt) { + mOrientedRanges.haveOrientation = true; + + mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; + mOrientedRanges.orientation.source = mSource; + mOrientedRanges.orientation.min = -M_PI; + mOrientedRanges.orientation.max = M_PI; + mOrientedRanges.orientation.flat = 0; + mOrientedRanges.orientation.fuzz = 0; + mOrientedRanges.orientation.resolution = 0; + } else if (mCalibration.orientationCalibration != + Calibration::ORIENTATION_CALIBRATION_NONE) { + if (mCalibration.orientationCalibration + == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { + if (mRawPointerAxes.orientation.valid) { + if (mRawPointerAxes.orientation.maxValue > 0) { + mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; + } else if (mRawPointerAxes.orientation.minValue < 0) { + mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; + } else { + mOrientationScale = 0; + } + } + } + + mOrientedRanges.haveOrientation = true; + + mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; + mOrientedRanges.orientation.source = mSource; + mOrientedRanges.orientation.min = -M_PI_2; + mOrientedRanges.orientation.max = M_PI_2; + mOrientedRanges.orientation.flat = 0; + mOrientedRanges.orientation.fuzz = 0; + mOrientedRanges.orientation.resolution = 0; + } + + // Distance + mDistanceScale = 0; + if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { + if (mCalibration.distanceCalibration + == Calibration::DISTANCE_CALIBRATION_SCALED) { + if (mCalibration.haveDistanceScale) { + mDistanceScale = mCalibration.distanceScale; + } else { + mDistanceScale = 1.0f; + } + } + + mOrientedRanges.haveDistance = true; + + mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; + mOrientedRanges.distance.source = mSource; + mOrientedRanges.distance.min = + mRawPointerAxes.distance.minValue * mDistanceScale; + mOrientedRanges.distance.max = + mRawPointerAxes.distance.maxValue * mDistanceScale; + mOrientedRanges.distance.flat = 0; + mOrientedRanges.distance.fuzz = + mRawPointerAxes.distance.fuzz * mDistanceScale; + mOrientedRanges.distance.resolution = 0; + } + + // Compute oriented precision, scales and ranges. + // Note that the maximum value reported is an inclusive maximum value so it is one + // unit less than the total width or height of surface. + switch (mSurfaceOrientation) { + case DISPLAY_ORIENTATION_90: + case DISPLAY_ORIENTATION_270: + mOrientedXPrecision = mYPrecision; + mOrientedYPrecision = mXPrecision; + + mOrientedRanges.x.min = mYTranslate; + mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1; + mOrientedRanges.x.flat = 0; + mOrientedRanges.x.fuzz = 0; + mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; + + mOrientedRanges.y.min = mXTranslate; + mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1; + mOrientedRanges.y.flat = 0; + mOrientedRanges.y.fuzz = 0; + mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; + break; + + default: + mOrientedXPrecision = mXPrecision; + mOrientedYPrecision = mYPrecision; + + mOrientedRanges.x.min = mXTranslate; + mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1; + mOrientedRanges.x.flat = 0; + mOrientedRanges.x.fuzz = 0; + mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; + + mOrientedRanges.y.min = mYTranslate; + mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1; + mOrientedRanges.y.flat = 0; + mOrientedRanges.y.fuzz = 0; + mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; + break; + } + + // Location + updateAffineTransformation(); + + if (mDeviceMode == DEVICE_MODE_POINTER) { + // Compute pointer gesture detection parameters. + float rawDiagonal = hypotf(rawWidth, rawHeight); + float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight); + + // Scale movements such that one whole swipe of the touch pad covers a + // given area relative to the diagonal size of the display when no acceleration + // is applied. + // Assume that the touch pad has a square aspect ratio such that movements in + // X and Y of the same number of raw units cover the same physical distance. + mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio + * displayDiagonal / rawDiagonal; + mPointerYMovementScale = mPointerXMovementScale; + + // Scale zooms to cover a smaller range of the display than movements do. + // This value determines the area around the pointer that is affected by freeform + // pointer gestures. + mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio + * displayDiagonal / rawDiagonal; + mPointerYZoomScale = mPointerXZoomScale; + + // Max width between pointers to detect a swipe gesture is more than some fraction + // of the diagonal axis of the touch pad. Touches that are wider than this are + // translated into freeform gestures. + mPointerGestureMaxSwipeWidth = + mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; + + // Abort current pointer usages because the state has changed. + abortPointerUsage(when, 0 /*policyFlags*/); + } + + // Inform the dispatcher about the changes. + *outResetNeeded = true; + bumpGeneration(); + } +} + +void TouchInputMapper::dumpSurface(std::string& dump) { + dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str()); + dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); + dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); + dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); + dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); + dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth); + dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight); + dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft); + dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop); + dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); +} + +void TouchInputMapper::configureVirtualKeys() { + std::vector<VirtualKeyDefinition> virtualKeyDefinitions; + getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); + + mVirtualKeys.clear(); + + if (virtualKeyDefinitions.size() == 0) { + return; + } + + int32_t touchScreenLeft = mRawPointerAxes.x.minValue; + int32_t touchScreenTop = mRawPointerAxes.y.minValue; + int32_t touchScreenWidth = mRawPointerAxes.getRawWidth(); + int32_t touchScreenHeight = mRawPointerAxes.getRawHeight(); + + for (const VirtualKeyDefinition& virtualKeyDefinition : virtualKeyDefinitions) { + VirtualKey virtualKey; + + virtualKey.scanCode = virtualKeyDefinition.scanCode; + int32_t keyCode; + int32_t dummyKeyMetaState; + uint32_t flags; + if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0, + &keyCode, &dummyKeyMetaState, &flags)) { + ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", + virtualKey.scanCode); + continue; // drop the key + } + + virtualKey.keyCode = keyCode; + virtualKey.flags = flags; + + // convert the key definition's display coordinates into touch coordinates for a hit box + int32_t halfWidth = virtualKeyDefinition.width / 2; + int32_t halfHeight = virtualKeyDefinition.height / 2; + + virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) + * touchScreenWidth / mSurfaceWidth + touchScreenLeft; + virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) + * touchScreenWidth / mSurfaceWidth + touchScreenLeft; + virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) + * touchScreenHeight / mSurfaceHeight + touchScreenTop; + virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) + * touchScreenHeight / mSurfaceHeight + touchScreenTop; + mVirtualKeys.push_back(virtualKey); + } +} + +void TouchInputMapper::dumpVirtualKeys(std::string& dump) { + if (!mVirtualKeys.empty()) { + dump += INDENT3 "Virtual Keys:\n"; + + for (size_t i = 0; i < mVirtualKeys.size(); i++) { + const VirtualKey& virtualKey = mVirtualKeys[i]; + dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, " + "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", + i, virtualKey.scanCode, virtualKey.keyCode, + virtualKey.hitLeft, virtualKey.hitRight, + virtualKey.hitTop, virtualKey.hitBottom); + } + } +} + +void TouchInputMapper::parseCalibration() { + const PropertyMap& in = getDevice()->getConfiguration(); + Calibration& out = mCalibration; + + // Size + out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; + String8 sizeCalibrationString; + if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { + if (sizeCalibrationString == "none") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; + } else if (sizeCalibrationString == "geometric") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; + } else if (sizeCalibrationString == "diameter") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER; + } else if (sizeCalibrationString == "box") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX; + } else if (sizeCalibrationString == "area") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA; + } else if (sizeCalibrationString != "default") { + ALOGW("Invalid value for touch.size.calibration: '%s'", + sizeCalibrationString.string()); + } + } + + out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), + out.sizeScale); + out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), + out.sizeBias); + out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), + out.sizeIsSummed); + + // Pressure + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; + String8 pressureCalibrationString; + if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { + if (pressureCalibrationString == "none") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; + } else if (pressureCalibrationString == "physical") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; + } else if (pressureCalibrationString == "amplitude") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; + } else if (pressureCalibrationString != "default") { + ALOGW("Invalid value for touch.pressure.calibration: '%s'", + pressureCalibrationString.string()); + } + } + + out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), + out.pressureScale); + + // Orientation + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; + String8 orientationCalibrationString; + if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { + if (orientationCalibrationString == "none") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; + } else if (orientationCalibrationString == "interpolated") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; + } else if (orientationCalibrationString == "vector") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR; + } else if (orientationCalibrationString != "default") { + ALOGW("Invalid value for touch.orientation.calibration: '%s'", + orientationCalibrationString.string()); + } + } + + // Distance + out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; + String8 distanceCalibrationString; + if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { + if (distanceCalibrationString == "none") { + out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; + } else if (distanceCalibrationString == "scaled") { + out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; + } else if (distanceCalibrationString != "default") { + ALOGW("Invalid value for touch.distance.calibration: '%s'", + distanceCalibrationString.string()); + } + } + + out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), + out.distanceScale); + + out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT; + String8 coverageCalibrationString; + if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { + if (coverageCalibrationString == "none") { + out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; + } else if (coverageCalibrationString == "box") { + out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX; + } else if (coverageCalibrationString != "default") { + ALOGW("Invalid value for touch.coverage.calibration: '%s'", + coverageCalibrationString.string()); + } + } +} + +void TouchInputMapper::resolveCalibration() { + // Size + if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) { + if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) { + mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; + } + } else { + mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; + } + + // Pressure + if (mRawPointerAxes.pressure.valid) { + if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) { + mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; + } + } else { + mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; + } + + // Orientation + if (mRawPointerAxes.orientation.valid) { + if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) { + mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; + } + } else { + mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; + } + + // Distance + if (mRawPointerAxes.distance.valid) { + if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) { + mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; + } + } else { + mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; + } + + // Coverage + if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) { + mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; + } +} + +void TouchInputMapper::dumpCalibration(std::string& dump) { + dump += INDENT3 "Calibration:\n"; + + // Size + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_NONE: + dump += INDENT4 "touch.size.calibration: none\n"; + break; + case Calibration::SIZE_CALIBRATION_GEOMETRIC: + dump += INDENT4 "touch.size.calibration: geometric\n"; + break; + case Calibration::SIZE_CALIBRATION_DIAMETER: + dump += INDENT4 "touch.size.calibration: diameter\n"; + break; + case Calibration::SIZE_CALIBRATION_BOX: + dump += INDENT4 "touch.size.calibration: box\n"; + break; + case Calibration::SIZE_CALIBRATION_AREA: + dump += INDENT4 "touch.size.calibration: area\n"; + break; + default: + ALOG_ASSERT(false); + } + + if (mCalibration.haveSizeScale) { + dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", + mCalibration.sizeScale); + } + + if (mCalibration.haveSizeBias) { + dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", + mCalibration.sizeBias); + } + + if (mCalibration.haveSizeIsSummed) { + dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n", + toString(mCalibration.sizeIsSummed)); + } + + // Pressure + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_NONE: + dump += INDENT4 "touch.pressure.calibration: none\n"; + break; + case Calibration::PRESSURE_CALIBRATION_PHYSICAL: + dump += INDENT4 "touch.pressure.calibration: physical\n"; + break; + case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: + dump += INDENT4 "touch.pressure.calibration: amplitude\n"; + break; + default: + ALOG_ASSERT(false); + } + + if (mCalibration.havePressureScale) { + dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", + mCalibration.pressureScale); + } + + // Orientation + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_NONE: + dump += INDENT4 "touch.orientation.calibration: none\n"; + break; + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + dump += INDENT4 "touch.orientation.calibration: interpolated\n"; + break; + case Calibration::ORIENTATION_CALIBRATION_VECTOR: + dump += INDENT4 "touch.orientation.calibration: vector\n"; + break; + default: + ALOG_ASSERT(false); + } + + // Distance + switch (mCalibration.distanceCalibration) { + case Calibration::DISTANCE_CALIBRATION_NONE: + dump += INDENT4 "touch.distance.calibration: none\n"; + break; + case Calibration::DISTANCE_CALIBRATION_SCALED: + dump += INDENT4 "touch.distance.calibration: scaled\n"; + break; + default: + ALOG_ASSERT(false); + } + + if (mCalibration.haveDistanceScale) { + dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", + mCalibration.distanceScale); + } + + switch (mCalibration.coverageCalibration) { + case Calibration::COVERAGE_CALIBRATION_NONE: + dump += INDENT4 "touch.coverage.calibration: none\n"; + break; + case Calibration::COVERAGE_CALIBRATION_BOX: + dump += INDENT4 "touch.coverage.calibration: box\n"; + break; + default: + ALOG_ASSERT(false); + } +} + +void TouchInputMapper::dumpAffineTransformation(std::string& dump) { + dump += INDENT3 "Affine Transformation:\n"; + + dump += StringPrintf(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale); + dump += StringPrintf(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix); + dump += StringPrintf(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset); + dump += StringPrintf(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix); + dump += StringPrintf(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale); + dump += StringPrintf(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset); +} + +void TouchInputMapper::updateAffineTransformation() { + mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(), + mSurfaceOrientation); +} + +void TouchInputMapper::reset(nsecs_t when) { + mCursorButtonAccumulator.reset(getDevice()); + mCursorScrollAccumulator.reset(getDevice()); + mTouchButtonAccumulator.reset(getDevice()); + + mPointerVelocityControl.reset(); + mWheelXVelocityControl.reset(); + mWheelYVelocityControl.reset(); + + mRawStatesPending.clear(); + mCurrentRawState.clear(); + mCurrentCookedState.clear(); + mLastRawState.clear(); + mLastCookedState.clear(); + mPointerUsage = POINTER_USAGE_NONE; + mSentHoverEnter = false; + mHavePointerIds = false; + mCurrentMotionAborted = false; + mDownTime = 0; + + mCurrentVirtualKey.down = false; + + mPointerGesture.reset(); + mPointerSimple.reset(); + resetExternalStylus(); + + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + mPointerController->clearSpots(); + } + + InputMapper::reset(when); +} + +void TouchInputMapper::resetExternalStylus() { + mExternalStylusState.clear(); + mExternalStylusId = -1; + mExternalStylusFusionTimeout = LLONG_MAX; + mExternalStylusDataPending = false; +} + +void TouchInputMapper::clearStylusDataPendingFlags() { + mExternalStylusDataPending = false; + mExternalStylusFusionTimeout = LLONG_MAX; +} + +void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) { + nsecs_t now = systemTime(CLOCK_MONOTONIC); + nsecs_t latency = now - evdevTime; + mStatistics.addValue(nanoseconds_to_microseconds(latency)); + nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime; + if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) { + android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, + mStatistics.min, mStatistics.max, + mStatistics.mean(), mStatistics.stdev(), mStatistics.count); + mStatistics.reset(now); + } +} + +void TouchInputMapper::process(const RawEvent* rawEvent) { + mCursorButtonAccumulator.process(rawEvent); + mCursorScrollAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + reportEventForStatistics(rawEvent->when); + sync(rawEvent->when); + } +} + +void TouchInputMapper::sync(nsecs_t when) { + const RawState* last = mRawStatesPending.empty() ? + &mCurrentRawState : &mRawStatesPending.back(); + + // Push a new state. + mRawStatesPending.emplace_back(); + + RawState* next = &mRawStatesPending.back(); + next->clear(); + next->when = when; + + // Sync button state. + next->buttonState = mTouchButtonAccumulator.getButtonState() + | mCursorButtonAccumulator.getButtonState(); + + // Sync scroll + next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); + next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); + mCursorScrollAccumulator.finishSync(); + + // Sync touch + syncTouch(when, next); + + // Assign pointer ids. + if (!mHavePointerIds) { + assignPointerIds(last, next); + } + +#if DEBUG_RAW_EVENTS + ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " + "hovering ids 0x%08x -> 0x%08x", + last->rawPointerData.pointerCount, + next->rawPointerData.pointerCount, + last->rawPointerData.touchingIdBits.value, + next->rawPointerData.touchingIdBits.value, + last->rawPointerData.hoveringIdBits.value, + next->rawPointerData.hoveringIdBits.value); +#endif + + processRawTouches(false /*timeout*/); +} + +void TouchInputMapper::processRawTouches(bool timeout) { + if (mDeviceMode == DEVICE_MODE_DISABLED) { + // Drop all input if the device is disabled. + mCurrentRawState.clear(); + mRawStatesPending.clear(); + return; + } + + // Drain any pending touch states. The invariant here is that the mCurrentRawState is always + // valid and must go through the full cook and dispatch cycle. This ensures that anything + // touching the current state will only observe the events that have been dispatched to the + // rest of the pipeline. + const size_t N = mRawStatesPending.size(); + size_t count; + for(count = 0; count < N; count++) { + const RawState& next = mRawStatesPending[count]; + + // A failure to assign the stylus id means that we're waiting on stylus data + // and so should defer the rest of the pipeline. + if (assignExternalStylusId(next, timeout)) { + break; + } + + // All ready to go. + clearStylusDataPendingFlags(); + mCurrentRawState.copyFrom(next); + if (mCurrentRawState.when < mLastRawState.when) { + mCurrentRawState.when = mLastRawState.when; + } + cookAndDispatch(mCurrentRawState.when); + } + if (count != 0) { + mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count); + } + + if (mExternalStylusDataPending) { + if (timeout) { + nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY; + clearStylusDataPendingFlags(); + mCurrentRawState.copyFrom(mLastRawState); +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, synthesizing event with new stylus data"); +#endif + cookAndDispatch(when); + } else if (mExternalStylusFusionTimeout == LLONG_MAX) { + mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT; + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + } + } +} + +void TouchInputMapper::cookAndDispatch(nsecs_t when) { + // Always start with a clean state. + mCurrentCookedState.clear(); + + // Apply stylus buttons to current raw state. + applyExternalStylusButtonState(when); + + // Handle policy on initial down or hover events. + bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && mCurrentRawState.rawPointerData.pointerCount != 0; + + uint32_t policyFlags = 0; + bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState; + if (initialDown || buttonsPressed) { + // If this is a touch screen, hide the pointer on an initial down. + if (mDeviceMode == DEVICE_MODE_DIRECT) { + getContext()->fadePointer(); + } + + if (mParameters.wake) { + policyFlags |= POLICY_FLAG_WAKE; + } + } + + // Consume raw off-screen touches before cooking pointer data. + // If touches are consumed, subsequent code will not receive any pointer data. + if (consumeRawTouches(when, policyFlags)) { + mCurrentRawState.rawPointerData.clear(); + } + + // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure + // with cooked pointer data that has the same ids and indices as the raw data. + // The following code can use either the raw or cooked data, as needed. + cookPointerData(); + + // Apply stylus pressure to current cooked state. + applyExternalStylusTouchState(when); + + // Synthesize key down from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + mViewport.displayId, policyFlags, + mLastCookedState.buttonState, mCurrentCookedState.buttonState); + + // Dispatch the touches either directly or by translation through a pointer on screen. + if (mDeviceMode == DEVICE_MODE_POINTER) { + for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mCurrentCookedState.fingerIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { + mCurrentCookedState.mouseIdBits.markBit(id); + } + } + for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); + } + } + + // Stylus takes precedence over all tools, then mouse, then finger. + PointerUsage pointerUsage = mPointerUsage; + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + mCurrentCookedState.mouseIdBits.clear(); + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_STYLUS; + } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_MOUSE; + } else if (!mCurrentCookedState.fingerIdBits.isEmpty() || + isPointerDown(mCurrentRawState.buttonState)) { + pointerUsage = POINTER_USAGE_GESTURES; + } + + dispatchPointerUsage(when, policyFlags, pointerUsage); + } else { + if (mDeviceMode == DEVICE_MODE_DIRECT + && mConfig.showTouches && mPointerController != nullptr) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits, + mViewport.displayId); + } + + if (!mCurrentMotionAborted) { + dispatchButtonRelease(when, policyFlags); + dispatchHoverExit(when, policyFlags); + dispatchTouches(when, policyFlags); + dispatchHoverEnterAndMove(when, policyFlags); + dispatchButtonPress(when, policyFlags); + } + + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentMotionAborted = false; + } + } + + // Synthesize key up from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + mViewport.displayId, policyFlags, + mLastCookedState.buttonState, mCurrentCookedState.buttonState); + + // Clear some transient state. + mCurrentRawState.rawVScroll = 0; + mCurrentRawState.rawHScroll = 0; + + // Copy current touch to last touch in preparation for the next cycle. + mLastRawState.copyFrom(mCurrentRawState); + mLastCookedState.copyFrom(mCurrentCookedState); +} + +void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { + if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) { + mCurrentRawState.buttonState |= mExternalStylusState.buttons; + } +} + +void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { + CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData; + const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData; + + if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) { + float pressure = mExternalStylusState.pressure; + if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) { + const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId); + pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); + } + PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId); + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); + + PointerProperties& properties = + currentPointerData.editPointerPropertiesWithId(mExternalStylusId); + if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + properties.toolType = mExternalStylusState.toolType; + } + } +} + +bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) { + if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) { + return false; + } + + const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && state.rawPointerData.pointerCount != 0; + if (initialDown) { + if (mExternalStylusState.pressure != 0.0f) { +#if DEBUG_STYLUS_FUSION + ALOGD("Have both stylus and touch data, beginning fusion"); +#endif + mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); + } else if (timeout) { +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, assuming touch is not a stylus."); +#endif + resetExternalStylus(); + } else { + if (mExternalStylusFusionTimeout == LLONG_MAX) { + mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT; + } +#if DEBUG_STYLUS_FUSION + ALOGD("No stylus data but stylus is connected, requesting timeout " + "(%" PRId64 "ms)", mExternalStylusFusionTimeout); +#endif + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + return true; + } + } + + // Check if the stylus pointer has gone up. + if (mExternalStylusId != -1 && + !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { +#if DEBUG_STYLUS_FUSION + ALOGD("Stylus pointer is going up"); +#endif + mExternalStylusId = -1; + } + + return false; +} + +void TouchInputMapper::timeoutExpired(nsecs_t when) { + if (mDeviceMode == DEVICE_MODE_POINTER) { + if (mPointerUsage == POINTER_USAGE_GESTURES) { + dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); + } + } else if (mDeviceMode == DEVICE_MODE_DIRECT) { + if (mExternalStylusFusionTimeout < when) { + processRawTouches(true /*timeout*/); + } else if (mExternalStylusFusionTimeout != LLONG_MAX) { + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + } + } +} + +void TouchInputMapper::updateExternalStylusState(const StylusState& state) { + mExternalStylusState.copyFrom(state); + if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) { + // We're either in the middle of a fused stream of data or we're waiting on data before + // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus + // data. + mExternalStylusDataPending = true; + processRawTouches(false /*timeout*/); + } +} + +bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { + // Check for release of a virtual key. + if (mCurrentVirtualKey.down) { + if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { + // Pointer went up while virtual key was down. + mCurrentVirtualKey.down = false; + if (!mCurrentVirtualKey.ignored) { +#if DEBUG_VIRTUAL_KEYS + ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", + mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); +#endif + dispatchVirtualKey(when, policyFlags, + AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); + } + return true; + } + + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); + if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { + // Pointer is still within the space of the virtual key. + return true; + } + } + + // Pointer left virtual key area or another pointer also went down. + // Send key cancellation but do not consume the touch yet. + // This is useful when the user swipes through from the virtual key area + // into the main display surface. + mCurrentVirtualKey.down = false; + if (!mCurrentVirtualKey.ignored) { +#if DEBUG_VIRTUAL_KEYS + ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", + mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); +#endif + dispatchVirtualKey(when, policyFlags, + AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY + | AKEY_EVENT_FLAG_CANCELED); + } + } + + if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() + && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { + // Pointer just went down. Check for virtual key press or off-screen touches. + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); + if (!isPointInsideSurface(pointer.x, pointer.y)) { + // If exactly one pointer went down, check for virtual key hit. + // Otherwise we will drop the entire stroke. + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { + const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); + if (virtualKey) { + mCurrentVirtualKey.down = true; + mCurrentVirtualKey.downTime = when; + mCurrentVirtualKey.keyCode = virtualKey->keyCode; + mCurrentVirtualKey.scanCode = virtualKey->scanCode; + mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey( + when, getDevice(), virtualKey->keyCode, virtualKey->scanCode); + + if (!mCurrentVirtualKey.ignored) { +#if DEBUG_VIRTUAL_KEYS + ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", + mCurrentVirtualKey.keyCode, + mCurrentVirtualKey.scanCode); +#endif + dispatchVirtualKey(when, policyFlags, + AKEY_EVENT_ACTION_DOWN, + AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); + } + } + } + return true; + } + } + + // Disable all virtual key touches that happen within a short time interval of the + // most recent touch within the screen area. The idea is to filter out stray + // virtual key presses when interacting with the touch screen. + // + // Problems we're trying to solve: + // + // 1. While scrolling a list or dragging the window shade, the user swipes down into a + // virtual key area that is implemented by a separate touch panel and accidentally + // triggers a virtual key. + // + // 2. While typing in the on screen keyboard, the user taps slightly outside the screen + // area and accidentally triggers a virtual key. This often happens when virtual keys + // are layed out below the screen near to where the on screen keyboard's space bar + // is displayed. + if (mConfig.virtualKeyQuietTime > 0 && + !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { + mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); + } + return false; +} + +void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, + int32_t keyEventAction, int32_t keyEventFlags) { + int32_t keyCode = mCurrentVirtualKey.keyCode; + int32_t scanCode = mCurrentVirtualKey.scanCode; + nsecs_t downTime = mCurrentVirtualKey.downTime; + int32_t metaState = mContext->getGlobalMetaState(); + policyFlags |= POLICY_FLAG_VIRTUAL; + + NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, + mViewport.displayId, + policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); + getListener()->notifyKey(&args); +} + +void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) { + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + if (!currentIdBits.isEmpty()) { + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentCookedState.buttonState; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + currentIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mCurrentMotionAborted = true; + } +} + +void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentCookedState.buttonState; + + if (currentIdBits == lastIdBits) { + if (!currentIdBits.isEmpty()) { + // No pointer id changes so this is a move event. + // The listener takes care of batching moves so we don't have to deal with that here. + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, + AMOTION_EVENT_EDGE_FLAG_NONE, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + currentIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } + } else { + // There may be pointers going up and pointers going down and pointers moving + // all at the same time. + BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); + BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); + BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); + BitSet32 dispatchedIdBits(lastIdBits.value); + + // Update last coordinates of pointers that have moved so that we observe the new + // pointer positions at the same time as other pointers that have just gone up. + bool moveNeeded = updateMovedPointers( + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + moveIdBits); + if (buttonState != mLastCookedState.buttonState) { + moveNeeded = true; + } + + // Dispatch pointer up events. + while (!upIdBits.isEmpty()) { + uint32_t upId = upIdBits.clearFirstMarkedBit(); + + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0, + mCurrentCookedState.deviceTimestamp, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); + dispatchedIdBits.clearBit(upId); + } + + // Dispatch move events if any of the remaining pointers moved from their old locations. + // Although applications receive new locations as part of individual pointer up + // events, they do not generally handle them except when presented in a move event. + if (moveNeeded && !moveIdBits.isEmpty()) { + ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } + + // Dispatch pointer down events using the new pointer locations. + while (!downIdBits.isEmpty()) { + uint32_t downId = downIdBits.clearFirstMarkedBit(); + dispatchedIdBits.markBit(downId); + + if (dispatchedIdBits.count() == 1) { + // First pointer is going down. Set down time. + mDownTime = when; + } + + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } + } +} + +void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { + if (mSentHoverEnter && + (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() + || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) { + int32_t metaState = getContext()->getGlobalMetaState(); + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0, + mLastCookedState.deviceTimestamp, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.hoveringIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mSentHoverEnter = false; + } +} + +void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { + if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() + && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) { + int32_t metaState = getContext()->getGlobalMetaState(); + if (!mSentHoverEnter) { + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, + 0, 0, metaState, mCurrentRawState.buttonState, 0, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mSentHoverEnter = true; + } + + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, 0, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) { + BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState); + const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData); + const int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mLastCookedState.buttonState; + while (!releasedButtons.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit()); + buttonState &= ~actionButton; + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, + 0, metaState, buttonState, 0, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) { + BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState); + const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData); + const int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mLastCookedState.buttonState; + while (!pressedButtons.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit()); + buttonState |= actionButton; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, + 0, metaState, buttonState, 0, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) { + if (!cookedPointerData.touchingIdBits.isEmpty()) { + return cookedPointerData.touchingIdBits; + } + return cookedPointerData.hoveringIdBits; +} + +void TouchInputMapper::cookPointerData() { + uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; + + mCurrentCookedState.cookedPointerData.clear(); + mCurrentCookedState.deviceTimestamp = + mCurrentRawState.deviceTimestamp; + mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; + mCurrentCookedState.cookedPointerData.hoveringIdBits = + mCurrentRawState.rawPointerData.hoveringIdBits; + mCurrentCookedState.cookedPointerData.touchingIdBits = + mCurrentRawState.rawPointerData.touchingIdBits; + + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentCookedState.buttonState = 0; + } else { + mCurrentCookedState.buttonState = mCurrentRawState.buttonState; + } + + // Walk through the the active pointers and map device coordinates onto + // surface coordinates and adjust for display orientation. + for (uint32_t i = 0; i < currentPointerCount; i++) { + const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; + + // Size + float touchMajor, touchMinor, toolMajor, toolMinor, size; + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_GEOMETRIC: + case Calibration::SIZE_CALIBRATION_DIAMETER: + case Calibration::SIZE_CALIBRATION_BOX: + case Calibration::SIZE_CALIBRATION_AREA: + if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { + touchMajor = in.touchMajor; + touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; + toolMajor = in.toolMajor; + toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; + size = mRawPointerAxes.touchMinor.valid + ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; + } else if (mRawPointerAxes.touchMajor.valid) { + toolMajor = touchMajor = in.touchMajor; + toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid + ? in.touchMinor : in.touchMajor; + size = mRawPointerAxes.touchMinor.valid + ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; + } else if (mRawPointerAxes.toolMajor.valid) { + touchMajor = toolMajor = in.toolMajor; + touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid + ? in.toolMinor : in.toolMajor; + size = mRawPointerAxes.toolMinor.valid + ? avg(in.toolMajor, in.toolMinor) : in.toolMajor; + } else { + ALOG_ASSERT(false, "No touch or tool axes. " + "Size calibration should have been resolved to NONE."); + touchMajor = 0; + touchMinor = 0; + toolMajor = 0; + toolMinor = 0; + size = 0; + } + + if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { + uint32_t touchingCount = + mCurrentRawState.rawPointerData.touchingIdBits.count(); + if (touchingCount > 1) { + touchMajor /= touchingCount; + touchMinor /= touchingCount; + toolMajor /= touchingCount; + toolMinor /= touchingCount; + size /= touchingCount; + } + } + + if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { + touchMajor *= mGeometricScale; + touchMinor *= mGeometricScale; + toolMajor *= mGeometricScale; + toolMinor *= mGeometricScale; + } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { + touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; + touchMinor = touchMajor; + toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; + toolMinor = toolMajor; + } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { + touchMinor = touchMajor; + toolMinor = toolMajor; + } + + mCalibration.applySizeScaleAndBias(&touchMajor); + mCalibration.applySizeScaleAndBias(&touchMinor); + mCalibration.applySizeScaleAndBias(&toolMajor); + mCalibration.applySizeScaleAndBias(&toolMinor); + size *= mSizeScale; + break; + default: + touchMajor = 0; + touchMinor = 0; + toolMajor = 0; + toolMinor = 0; + size = 0; + break; + } + + // Pressure + float pressure; + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_PHYSICAL: + case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: + pressure = in.pressure * mPressureScale; + break; + default: + pressure = in.isHovering ? 0 : 1; + break; + } + + // Tilt and Orientation + float tilt; + float orientation; + if (mHaveTilt) { + float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; + float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; + orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); + tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); + } else { + tilt = 0; + + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + orientation = in.orientation * mOrientationScale; + break; + case Calibration::ORIENTATION_CALIBRATION_VECTOR: { + int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); + int32_t c2 = signExtendNybble(in.orientation & 0x0f); + if (c1 != 0 || c2 != 0) { + orientation = atan2f(c1, c2) * 0.5f; + float confidence = hypotf(c1, c2); + float scale = 1.0f + confidence / 16.0f; + touchMajor *= scale; + touchMinor /= scale; + toolMajor *= scale; + toolMinor /= scale; + } else { + orientation = 0; + } + break; + } + default: + orientation = 0; + } + } + + // Distance + float distance; + switch (mCalibration.distanceCalibration) { + case Calibration::DISTANCE_CALIBRATION_SCALED: + distance = in.distance * mDistanceScale; + break; + default: + distance = 0; + } + + // Coverage + int32_t rawLeft, rawTop, rawRight, rawBottom; + switch (mCalibration.coverageCalibration) { + case Calibration::COVERAGE_CALIBRATION_BOX: + rawLeft = (in.toolMinor & 0xffff0000) >> 16; + rawRight = in.toolMinor & 0x0000ffff; + rawBottom = in.toolMajor & 0x0000ffff; + rawTop = (in.toolMajor & 0xffff0000) >> 16; + break; + default: + rawLeft = rawTop = rawRight = rawBottom = 0; + break; + } + + // Adjust X,Y coords for device calibration + // TODO: Adjust coverage coords? + float xTransformed = in.x, yTransformed = in.y; + mAffineTransform.applyTo(xTransformed, yTransformed); + + // Adjust X, Y, and coverage coords for surface orientation. + float x, y; + float left, top, right, bottom; + + switch (mSurfaceOrientation) { + case DISPLAY_ORIENTATION_90: + x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate; + left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; + top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; + orientation -= M_PI_2; + if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { + orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + } + break; + case DISPLAY_ORIENTATION_180: + x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale; + y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate; + left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale; + right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; + bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; + top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; + orientation -= M_PI; + if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { + orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + } + break; + case DISPLAY_ORIENTATION_270: + x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale; + y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale; + right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; + bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + orientation += M_PI_2; + if (mOrientedRanges.haveOrientation && orientation > mOrientedRanges.orientation.max) { + orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + } + break; + default: + x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + break; + } + + // Write output coords. + PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; + out.clear(); + out.setAxisValue(AMOTION_EVENT_AXIS_X, x); + out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); + out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); + out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); + out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); + out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); + out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); + out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); + if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); + } else { + out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); + out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); + } + + // Write output properties. + PointerProperties& properties = + mCurrentCookedState.cookedPointerData.pointerProperties[i]; + uint32_t id = in.id; + properties.clear(); + properties.id = id; + properties.toolType = in.toolType; + + // Write id index. + mCurrentCookedState.cookedPointerData.idToIndex[id] = i; + } +} + +void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, + PointerUsage pointerUsage) { + if (pointerUsage != mPointerUsage) { + abortPointerUsage(when, policyFlags); + mPointerUsage = pointerUsage; + } + + switch (mPointerUsage) { + case POINTER_USAGE_GESTURES: + dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); + break; + case POINTER_USAGE_STYLUS: + dispatchPointerStylus(when, policyFlags); + break; + case POINTER_USAGE_MOUSE: + dispatchPointerMouse(when, policyFlags); + break; + default: + break; + } +} + +void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { + switch (mPointerUsage) { + case POINTER_USAGE_GESTURES: + abortPointerGestures(when, policyFlags); + break; + case POINTER_USAGE_STYLUS: + abortPointerStylus(when, policyFlags); + break; + case POINTER_USAGE_MOUSE: + abortPointerMouse(when, policyFlags); + break; + default: + break; + } + + mPointerUsage = POINTER_USAGE_NONE; +} + +void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, + bool isTimeout) { + // Update current gesture coordinates. + bool cancelPreviousGesture, finishPreviousGesture; + bool sendEvents = preparePointerGestures(when, + &cancelPreviousGesture, &finishPreviousGesture, isTimeout); + if (!sendEvents) { + return; + } + if (finishPreviousGesture) { + cancelPreviousGesture = false; + } + + // Update the pointer presentation and spots. + if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + if (finishPreviousGesture || cancelPreviousGesture) { + mPointerController->clearSpots(); + } + + if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { + mPointerController->setSpots(mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, + mPointerController->getDisplayId()); + } + } else { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + } + + // Show or hide the pointer if needed. + switch (mPointerGesture.currentGestureMode) { + case PointerGesture::NEUTRAL: + case PointerGesture::QUIET: + if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH + && mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) { + // Remind the user of where the pointer is after finishing a gesture with spots. + mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL); + } + break; + case PointerGesture::TAP: + case PointerGesture::TAP_DRAG: + case PointerGesture::BUTTON_CLICK_OR_DRAG: + case PointerGesture::HOVER: + case PointerGesture::PRESS: + case PointerGesture::SWIPE: + // Unfade the pointer when the current gesture manipulates the + // area directly under the pointer. + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + break; + case PointerGesture::FREEFORM: + // Fade the pointer when the current gesture manipulates a different + // area and there are spots to guide the user experience. + if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + } else { + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } + break; + } + + // Send events! + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentCookedState.buttonState; + + // Update last coordinates of pointers that have moved so that we observe the new + // pointer positions at the same time as other pointers that have just gone up. + bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP + || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG + || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG + || mPointerGesture.currentGestureMode == PointerGesture::PRESS + || mPointerGesture.currentGestureMode == PointerGesture::SWIPE + || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; + bool moveNeeded = false; + if (down && !cancelPreviousGesture && !finishPreviousGesture + && !mPointerGesture.lastGestureIdBits.isEmpty() + && !mPointerGesture.currentGestureIdBits.isEmpty()) { + BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value + & mPointerGesture.lastGestureIdBits.value); + moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + mPointerGesture.lastGestureProperties, + mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, + movedGestureIdBits); + if (buttonState != mLastCookedState.buttonState) { + moveNeeded = true; + } + } + + // Send motion events for all pointers that went up or were canceled. + BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); + if (!dispatchedGestureIdBits.isEmpty()) { + if (cancelPreviousGesture) { + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + mPointerGesture.lastGestureProperties, + mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, + dispatchedGestureIdBits, -1, 0, + 0, mPointerGesture.downTime); + + dispatchedGestureIdBits.clear(); + } else { + BitSet32 upGestureIdBits; + if (finishPreviousGesture) { + upGestureIdBits = dispatchedGestureIdBits; + } else { + upGestureIdBits.value = dispatchedGestureIdBits.value + & ~mPointerGesture.currentGestureIdBits.value; + } + while (!upGestureIdBits.isEmpty()) { + uint32_t id = upGestureIdBits.clearFirstMarkedBit(); + + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, + mPointerGesture.lastGestureProperties, + mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, + dispatchedGestureIdBits, id, + 0, 0, mPointerGesture.downTime); + + dispatchedGestureIdBits.clearBit(id); + } + } + } + + // Send motion events for all pointers that moved. + if (moveNeeded) { + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + dispatchedGestureIdBits, -1, + 0, 0, mPointerGesture.downTime); + } + + // Send motion events for all pointers that went down. + if (down) { + BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value + & ~dispatchedGestureIdBits.value); + while (!downGestureIdBits.isEmpty()) { + uint32_t id = downGestureIdBits.clearFirstMarkedBit(); + dispatchedGestureIdBits.markBit(id); + + if (dispatchedGestureIdBits.count() == 1) { + mPointerGesture.downTime = when; + } + + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, + /* deviceTimestamp */ 0, + mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + dispatchedGestureIdBits, id, + 0, 0, mPointerGesture.downTime); + } + } + + // Send motion events for hover. + if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, -1, + 0, 0, mPointerGesture.downTime); + } else if (dispatchedGestureIdBits.isEmpty() + && !mPointerGesture.lastGestureIdBits.isEmpty()) { + // Synthesize a hover move event after all pointers go up to indicate that + // the pointer is hovering again even if the user is not currently touching + // the touch pad. This ensures that a view will receive a fresh hover enter + // event after a tap. + float x, y; + mPointerController->getPosition(&x, &y); + + PointerProperties pointerProperties; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + PointerCoords pointerCoords; + pointerCoords.clear(); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + + const int32_t displayId = mPointerController->getDisplayId(); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, + metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + 0, 0, mPointerGesture.downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + // Update state. + mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; + if (!down) { + mPointerGesture.lastGestureIdBits.clear(); + } else { + mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits; + for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; + mPointerGesture.lastGestureProperties[index].copyFrom( + mPointerGesture.currentGestureProperties[index]); + mPointerGesture.lastGestureCoords[index].copyFrom( + mPointerGesture.currentGestureCoords[index]); + mPointerGesture.lastGestureIdToIndex[id] = index; + } + } +} + +void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { + // Cancel previously dispatches pointers. + if (!mPointerGesture.lastGestureIdBits.isEmpty()) { + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentRawState.buttonState; + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + mPointerGesture.lastGestureProperties, + mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, + mPointerGesture.lastGestureIdBits, -1, + 0, 0, mPointerGesture.downTime); + } + + // Reset the current pointer gesture. + mPointerGesture.reset(); + mPointerVelocityControl.reset(); + + // Remove any current spots. + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + mPointerController->clearSpots(); + } +} + +bool TouchInputMapper::preparePointerGestures(nsecs_t when, + bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) { + *outCancelPreviousGesture = false; + *outFinishPreviousGesture = false; + + // Handle TAP timeout. + if (isTimeout) { +#if DEBUG_GESTURES + ALOGD("Gestures: Processing timeout"); +#endif + + if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { + if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { + // The tap/drag timeout has not yet expired. + getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + + mConfig.pointerGestureTapDragInterval); + } else { + // The tap is finished. +#if DEBUG_GESTURES + ALOGD("Gestures: TAP finished"); +#endif + *outFinishPreviousGesture = true; + + mPointerGesture.activeGestureId = -1; + mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; + mPointerGesture.currentGestureIdBits.clear(); + + mPointerVelocityControl.reset(); + return true; + } + } + + // We did not handle this timeout. + return false; + } + + const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count(); + const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count(); + + // Update the velocity tracker. + { + VelocityTracker::Position positions[MAX_POINTERS]; + uint32_t count = 0; + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + positions[count].x = pointer.x * mPointerXMovementScale; + positions[count].y = pointer.y * mPointerYMovementScale; + } + mPointerGesture.velocityTracker.addMovement(when, + mCurrentCookedState.fingerIdBits, positions); + } + + // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning + // to NEUTRAL, then we should not generate tap event. + if (mPointerGesture.lastGestureMode != PointerGesture::HOVER + && mPointerGesture.lastGestureMode != PointerGesture::TAP + && mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) { + mPointerGesture.resetTap(); + } + + // Pick a new active touch id if needed. + // Choose an arbitrary pointer that just went down, if there is one. + // Otherwise choose an arbitrary remaining pointer. + // This guarantees we always have an active touch id when there is at least one pointer. + // We keep the same active touch id for as long as possible. + int32_t lastActiveTouchId = mPointerGesture.activeTouchId; + int32_t activeTouchId = lastActiveTouchId; + if (activeTouchId < 0) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { + activeTouchId = mPointerGesture.activeTouchId = + mCurrentCookedState.fingerIdBits.firstMarkedBit(); + mPointerGesture.firstTouchTime = when; + } + } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { + activeTouchId = mPointerGesture.activeTouchId = + mCurrentCookedState.fingerIdBits.firstMarkedBit(); + } else { + activeTouchId = mPointerGesture.activeTouchId = -1; + } + } + + // Determine whether we are in quiet time. + bool isQuietTime = false; + if (activeTouchId < 0) { + mPointerGesture.resetQuietTime(); + } else { + isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval; + if (!isQuietTime) { + if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS + || mPointerGesture.lastGestureMode == PointerGesture::SWIPE + || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) + && currentFingerCount < 2) { + // Enter quiet time when exiting swipe or freeform state. + // This is to prevent accidentally entering the hover state and flinging the + // pointer when finishing a swipe and there is still one pointer left onscreen. + isQuietTime = true; + } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG + && currentFingerCount >= 2 + && !isPointerDown(mCurrentRawState.buttonState)) { + // Enter quiet time when releasing the button and there are still two or more + // fingers down. This may indicate that one finger was used to press the button + // but it has not gone up yet. + isQuietTime = true; + } + if (isQuietTime) { + mPointerGesture.quietTime = when; + } + } + } + + // Switch states based on button and pointer state. + if (isQuietTime) { + // Case 1: Quiet time. (QUIET) +#if DEBUG_GESTURES + ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime + + mConfig.pointerGestureQuietInterval - when) * 0.000001f); +#endif + if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { + *outFinishPreviousGesture = true; + } + + mPointerGesture.activeGestureId = -1; + mPointerGesture.currentGestureMode = PointerGesture::QUIET; + mPointerGesture.currentGestureIdBits.clear(); + + mPointerVelocityControl.reset(); + } else if (isPointerDown(mCurrentRawState.buttonState)) { + // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) + // The pointer follows the active touch point. + // Emit DOWN, MOVE, UP events at the pointer location. + // + // Only the active touch matters; other fingers are ignored. This policy helps + // to handle the case where the user places a second finger on the touch pad + // to apply the necessary force to depress an integrated button below the surface. + // We don't want the second finger to be delivered to applications. + // + // For this to work well, we need to make sure to track the pointer that is really + // active. If the user first puts one finger down to click then adds another + // finger to drag then the active pointer should switch to the finger that is + // being dragged. +#if DEBUG_GESTURES + ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " + "currentFingerCount=%d", activeTouchId, currentFingerCount); +#endif + // Reset state when just starting. + if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { + *outFinishPreviousGesture = true; + mPointerGesture.activeGestureId = 0; + } + + // Switch pointers if needed. + // Find the fastest pointer and follow it. + if (activeTouchId >= 0 && currentFingerCount > 1) { + int32_t bestId = -1; + float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + float vx, vy; + if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { + float speed = hypotf(vx, vy); + if (speed > bestSpeed) { + bestId = id; + bestSpeed = speed; + } + } + } + if (bestId >= 0 && bestId != activeTouchId) { + mPointerGesture.activeTouchId = activeTouchId = bestId; +#if DEBUG_GESTURES + ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " + "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); +#endif + } + } + + float deltaX = 0, deltaY = 0; + if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { + const RawPointerData::Pointer& currentPointer = + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); + const RawPointerData::Pointer& lastPointer = + mLastRawState.rawPointerData.pointerForId(activeTouchId); + deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; + deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; + + rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + // Move the pointer using a relative motion. + // When using spots, the click will occur at the position of the anchor + // spot and all other spots will move there. + mPointerController->move(deltaX, deltaY); + } else { + mPointerVelocityControl.reset(); + } + + float x, y; + mPointerController->getPosition(&x, &y); + + mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG; + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + } else if (currentFingerCount == 0) { + // Case 3. No fingers down and button is not pressed. (NEUTRAL) + if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { + *outFinishPreviousGesture = true; + } + + // Watch for taps coming out of HOVER or TAP_DRAG mode. + // Checking for taps after TAP_DRAG allows us to detect double-taps. + bool tapped = false; + if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER + || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) + && lastFingerCount == 1) { + if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { + float x, y; + mPointerController->getPosition(&x, &y); + if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop + && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { +#if DEBUG_GESTURES + ALOGD("Gestures: TAP"); +#endif + + mPointerGesture.tapUpTime = when; + getContext()->requestTimeoutAtTime(when + + mConfig.pointerGestureTapDragInterval); + + mPointerGesture.activeGestureId = 0; + mPointerGesture.currentGestureMode = PointerGesture::TAP; + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit( + mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[ + mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = + mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = + AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue( + AMOTION_EVENT_AXIS_X, mPointerGesture.tapX); + mPointerGesture.currentGestureCoords[0].setAxisValue( + AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY); + mPointerGesture.currentGestureCoords[0].setAxisValue( + AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + + tapped = true; + } else { +#if DEBUG_GESTURES + ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", + x - mPointerGesture.tapX, + y - mPointerGesture.tapY); +#endif + } + } else { +#if DEBUG_GESTURES + if (mPointerGesture.tapDownTime != LLONG_MIN) { + ALOGD("Gestures: Not a TAP, %0.3fms since down", + (when - mPointerGesture.tapDownTime) * 0.000001f); + } else { + ALOGD("Gestures: Not a TAP, incompatible mode transitions"); + } +#endif + } + } + + mPointerVelocityControl.reset(); + + if (!tapped) { +#if DEBUG_GESTURES + ALOGD("Gestures: NEUTRAL"); +#endif + mPointerGesture.activeGestureId = -1; + mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; + mPointerGesture.currentGestureIdBits.clear(); + } + } else if (currentFingerCount == 1) { + // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) + // The pointer follows the active touch point. + // When in HOVER, emit HOVER_MOVE events at the pointer location. + // When in TAP_DRAG, emit MOVE events at the pointer location. + ALOG_ASSERT(activeTouchId >= 0); + + mPointerGesture.currentGestureMode = PointerGesture::HOVER; + if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { + if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { + float x, y; + mPointerController->getPosition(&x, &y); + if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop + && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { + mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; + } else { +#if DEBUG_GESTURES + ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", + x - mPointerGesture.tapX, + y - mPointerGesture.tapY); +#endif + } + } else { +#if DEBUG_GESTURES + ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", + (when - mPointerGesture.tapUpTime) * 0.000001f); +#endif + } + } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) { + mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; + } + + float deltaX = 0, deltaY = 0; + if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { + const RawPointerData::Pointer& currentPointer = + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); + const RawPointerData::Pointer& lastPointer = + mLastRawState.rawPointerData.pointerForId(activeTouchId); + deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; + deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; + + rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + // Move the pointer using a relative motion. + // When using spots, the hover or drag will occur at the position of the anchor spot. + mPointerController->move(deltaX, deltaY); + } else { + mPointerVelocityControl.reset(); + } + + bool down; + if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) { +#if DEBUG_GESTURES + ALOGD("Gestures: TAP_DRAG"); +#endif + down = true; + } else { +#if DEBUG_GESTURES + ALOGD("Gestures: HOVER"); +#endif + if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { + *outFinishPreviousGesture = true; + } + mPointerGesture.activeGestureId = 0; + down = false; + } + + float x, y; + mPointerController->getPosition(&x, &y); + + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = + AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, + down ? 1.0f : 0.0f); + + if (lastFingerCount == 0 && currentFingerCount != 0) { + mPointerGesture.resetTap(); + mPointerGesture.tapDownTime = when; + mPointerGesture.tapX = x; + mPointerGesture.tapY = y; + } + } else { + // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) + // We need to provide feedback for each finger that goes down so we cannot wait + // for the fingers to move before deciding what to do. + // + // The ambiguous case is deciding what to do when there are two fingers down but they + // have not moved enough to determine whether they are part of a drag or part of a + // freeform gesture, or just a press or long-press at the pointer location. + // + // When there are two fingers we start with the PRESS hypothesis and we generate a + // down at the pointer location. + // + // When the two fingers move enough or when additional fingers are added, we make + // a decision to transition into SWIPE or FREEFORM mode accordingly. + ALOG_ASSERT(activeTouchId >= 0); + + bool settled = when >= mPointerGesture.firstTouchTime + + mConfig.pointerGestureMultitouchSettleInterval; + if (mPointerGesture.lastGestureMode != PointerGesture::PRESS + && mPointerGesture.lastGestureMode != PointerGesture::SWIPE + && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { + *outFinishPreviousGesture = true; + } else if (!settled && currentFingerCount > lastFingerCount) { + // Additional pointers have gone down but not yet settled. + // Reset the gesture. +#if DEBUG_GESTURES + ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " + "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + + mConfig.pointerGestureMultitouchSettleInterval - when) + * 0.000001f); +#endif + *outCancelPreviousGesture = true; + } else { + // Continue previous gesture. + mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; + } + + if (*outFinishPreviousGesture || *outCancelPreviousGesture) { + mPointerGesture.currentGestureMode = PointerGesture::PRESS; + mPointerGesture.activeGestureId = 0; + mPointerGesture.referenceIdBits.clear(); + mPointerVelocityControl.reset(); + + // Use the centroid and pointer location as the reference points for the gesture. +#if DEBUG_GESTURES + ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " + "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + + mConfig.pointerGestureMultitouchSettleInterval - when) + * 0.000001f); +#endif + mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers( + &mPointerGesture.referenceTouchX, + &mPointerGesture.referenceTouchY); + mPointerController->getPosition(&mPointerGesture.referenceGestureX, + &mPointerGesture.referenceGestureY); + } + + // Clear the reference deltas for fingers not yet included in the reference calculation. + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value + & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + mPointerGesture.referenceDeltas[id].dx = 0; + mPointerGesture.referenceDeltas[id].dy = 0; + } + mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; + + // Add delta for all fingers and calculate a common movement delta. + float commonDeltaX = 0, commonDeltaY = 0; + BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value); + for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { + bool first = (idBits == commonIdBits); + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id); + const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id); + PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; + delta.dx += cpd.x - lpd.x; + delta.dy += cpd.y - lpd.y; + + if (first) { + commonDeltaX = delta.dx; + commonDeltaY = delta.dy; + } else { + commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); + commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); + } + } + + // Consider transitions from PRESS to SWIPE or MULTITOUCH. + if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { + float dist[MAX_POINTER_ID + 1]; + int32_t distOverThreshold = 0; + for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; + dist[id] = hypotf(delta.dx * mPointerXZoomScale, + delta.dy * mPointerYZoomScale); + if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { + distOverThreshold += 1; + } + } + + // Only transition when at least two pointers have moved further than + // the minimum distance threshold. + if (distOverThreshold >= 2) { + if (currentFingerCount > 2) { + // There are more than two pointers, switch to FREEFORM. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", + currentFingerCount); +#endif + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } else { + // There are exactly two pointers. + BitSet32 idBits(mCurrentCookedState.fingerIdBits); + uint32_t id1 = idBits.clearFirstMarkedBit(); + uint32_t id2 = idBits.firstMarkedBit(); + const RawPointerData::Pointer& p1 = + mCurrentRawState.rawPointerData.pointerForId(id1); + const RawPointerData::Pointer& p2 = + mCurrentRawState.rawPointerData.pointerForId(id2); + float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); + if (mutualDistance > mPointerGestureMaxSwipeWidth) { + // There are two pointers but they are too far apart for a SWIPE, + // switch to FREEFORM. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", + mutualDistance, mPointerGestureMaxSwipeWidth); +#endif + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } else { + // There are two pointers. Wait for both pointers to start moving + // before deciding whether this is a SWIPE or FREEFORM gesture. + float dist1 = dist[id1]; + float dist2 = dist[id2]; + if (dist1 >= mConfig.pointerGestureMultitouchMinDistance + && dist2 >= mConfig.pointerGestureMultitouchMinDistance) { + // Calculate the dot product of the displacement vectors. + // When the vectors are oriented in approximately the same direction, + // the angle betweeen them is near zero and the cosine of the angle + // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). + PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; + PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; + float dx1 = delta1.dx * mPointerXZoomScale; + float dy1 = delta1.dy * mPointerYZoomScale; + float dx2 = delta2.dx * mPointerXZoomScale; + float dy2 = delta2.dy * mPointerYZoomScale; + float dot = dx1 * dx2 + dy1 * dy2; + float cosine = dot / (dist1 * dist2); // denominator always > 0 + if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { + // Pointers are moving in the same direction. Switch to SWIPE. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS transitioned to SWIPE, " + "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " + "cosine %0.3f >= %0.3f", + dist1, mConfig.pointerGestureMultitouchMinDistance, + dist2, mConfig.pointerGestureMultitouchMinDistance, + cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); +#endif + mPointerGesture.currentGestureMode = PointerGesture::SWIPE; + } else { + // Pointers are moving in different directions. Switch to FREEFORM. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS transitioned to FREEFORM, " + "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " + "cosine %0.3f < %0.3f", + dist1, mConfig.pointerGestureMultitouchMinDistance, + dist2, mConfig.pointerGestureMultitouchMinDistance, + cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); +#endif + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } + } + } + } + } + } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { + // Switch from SWIPE to FREEFORM if additional pointers go down. + // Cancel previous gesture. + if (currentFingerCount > 2) { +#if DEBUG_GESTURES + ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", + currentFingerCount); +#endif + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } + } + + // Move the reference points based on the overall group motion of the fingers + // except in PRESS mode while waiting for a transition to occur. + if (mPointerGesture.currentGestureMode != PointerGesture::PRESS + && (commonDeltaX || commonDeltaY)) { + for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; + delta.dx = 0; + delta.dy = 0; + } + + mPointerGesture.referenceTouchX += commonDeltaX; + mPointerGesture.referenceTouchY += commonDeltaY; + + commonDeltaX *= mPointerXMovementScale; + commonDeltaY *= mPointerYMovementScale; + + rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); + mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); + + mPointerGesture.referenceGestureX += commonDeltaX; + mPointerGesture.referenceGestureY += commonDeltaY; + } + + // Report gestures. + if (mPointerGesture.currentGestureMode == PointerGesture::PRESS + || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { + // PRESS or SWIPE mode. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," + "activeGestureId=%d, currentTouchPointerCount=%d", + activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); +#endif + ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); + + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = + AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, + mPointerGesture.referenceGestureX); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, + mPointerGesture.referenceGestureY); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { + // FREEFORM mode. +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM activeTouchId=%d," + "activeGestureId=%d, currentTouchPointerCount=%d", + activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); +#endif + ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); + + mPointerGesture.currentGestureIdBits.clear(); + + BitSet32 mappedTouchIdBits; + BitSet32 usedGestureIdBits; + if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { + // Initially, assign the active gesture id to the active touch point + // if there is one. No other touch id bits are mapped yet. + if (!*outCancelPreviousGesture) { + mappedTouchIdBits.markBit(activeTouchId); + usedGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = + mPointerGesture.activeGestureId; + } else { + mPointerGesture.activeGestureId = -1; + } + } else { + // Otherwise, assume we mapped all touches from the previous frame. + // Reuse all mappings that are still applicable. + mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value; + usedGestureIdBits = mPointerGesture.lastGestureIdBits; + + // Check whether we need to choose a new active gesture id because the + // current went went up. + for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value + & ~mCurrentCookedState.fingerIdBits.value); + !upTouchIdBits.isEmpty(); ) { + uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); + uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; + if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) { + mPointerGesture.activeGestureId = -1; + break; + } + } + } + +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM follow up " + "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " + "activeGestureId=%d", + mappedTouchIdBits.value, usedGestureIdBits.value, + mPointerGesture.activeGestureId); +#endif + + BitSet32 idBits(mCurrentCookedState.fingerIdBits); + for (uint32_t i = 0; i < currentFingerCount; i++) { + uint32_t touchId = idBits.clearFirstMarkedBit(); + uint32_t gestureId; + if (!mappedTouchIdBits.hasBit(touchId)) { + gestureId = usedGestureIdBits.markFirstUnmarkedBit(); + mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM " + "new mapping for touch id %d -> gesture id %d", + touchId, gestureId); +#endif + } else { + gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM " + "existing mapping for touch id %d -> gesture id %d", + touchId, gestureId); +#endif + } + mPointerGesture.currentGestureIdBits.markBit(gestureId); + mPointerGesture.currentGestureIdToIndex[gestureId] = i; + + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(touchId); + float deltaX = (pointer.x - mPointerGesture.referenceTouchX) + * mPointerXZoomScale; + float deltaY = (pointer.y - mPointerGesture.referenceTouchY) + * mPointerYZoomScale; + rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + + mPointerGesture.currentGestureProperties[i].clear(); + mPointerGesture.currentGestureProperties[i].id = gestureId; + mPointerGesture.currentGestureProperties[i].toolType = + AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[i].clear(); + mPointerGesture.currentGestureCoords[i].setAxisValue( + AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX); + mPointerGesture.currentGestureCoords[i].setAxisValue( + AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY); + mPointerGesture.currentGestureCoords[i].setAxisValue( + AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + } + + if (mPointerGesture.activeGestureId < 0) { + mPointerGesture.activeGestureId = + mPointerGesture.currentGestureIdBits.firstMarkedBit(); +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM new " + "activeGestureId=%d", mPointerGesture.activeGestureId); +#endif + } + } + } + + mPointerController->setButtonState(mCurrentRawState.buttonState); + +#if DEBUG_GESTURES + ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " + "currentGestureMode=%d, currentGestureIdBits=0x%08x, " + "lastGestureMode=%d, lastGestureIdBits=0x%08x", + toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), + mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value, + mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value); + for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; + const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; + const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; + ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " + "x=%0.3f, y=%0.3f, pressure=%0.3f", + id, index, properties.toolType, + coords.getAxisValue(AMOTION_EVENT_AXIS_X), + coords.getAxisValue(AMOTION_EVENT_AXIS_Y), + coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); + } + for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; + const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; + const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; + ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " + "x=%0.3f, y=%0.3f, pressure=%0.3f", + id, index, properties.toolType, + coords.getAxisValue(AMOTION_EVENT_AXIS_X), + coords.getAxisValue(AMOTION_EVENT_AXIS_Y), + coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); + } +#endif + return true; +} + +void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { + mPointerSimple.currentCoords.clear(); + mPointerSimple.currentProperties.clear(); + + bool down, hovering; + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); + uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; + float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(); + float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY(); + mPointerController->setPosition(x, y); + + hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); + down = !hovering; + + mPointerController->getPosition(&x, &y); + mPointerSimple.currentCoords.copyFrom( + mCurrentCookedState.cookedPointerData.pointerCoords[index]); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerSimple.currentProperties.id = 0; + mPointerSimple.currentProperties.toolType = + mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType; + } else { + down = false; + hovering = false; + } + + dispatchPointerSimple(when, policyFlags, down, hovering); +} + +void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { + abortPointerSimple(when, policyFlags); +} + +void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { + mPointerSimple.currentCoords.clear(); + mPointerSimple.currentProperties.clear(); + + bool down, hovering; + if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); + uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + float deltaX = 0, deltaY = 0; + if (mLastCookedState.mouseIdBits.hasBit(id)) { + uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x + - mLastRawState.rawPointerData.pointers[lastIndex].x) + * mPointerXMovementScale; + deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y + - mLastRawState.rawPointerData.pointers[lastIndex].y) + * mPointerYMovementScale; + + rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + mPointerController->move(deltaX, deltaY); + } else { + mPointerVelocityControl.reset(); + } + + down = isPointerDown(mCurrentRawState.buttonState); + hovering = !down; + + float x, y; + mPointerController->getPosition(&x, &y); + mPointerSimple.currentCoords.copyFrom( + mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, + hovering ? 0.0f : 1.0f); + mPointerSimple.currentProperties.id = 0; + mPointerSimple.currentProperties.toolType = + mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType; + } else { + mPointerVelocityControl.reset(); + + down = false; + hovering = false; + } + + dispatchPointerSimple(when, policyFlags, down, hovering); +} + +void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { + abortPointerSimple(when, policyFlags); + + mPointerVelocityControl.reset(); +} + +void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, + bool down, bool hovering) { + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t displayId = mViewport.displayId; + + if (mPointerController != nullptr) { + if (down || hovering) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + mPointerController->clearSpots(); + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + } + displayId = mPointerController->getDisplayId(); + } + + if (mPointerSimple.down && !down) { + mPointerSimple.down = false; + + // Send up. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + if (mPointerSimple.hovering && !hovering) { + mPointerSimple.hovering = false; + + // Send hover exit. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + if (down) { + if (!mPointerSimple.down) { + mPointerSimple.down = true; + mPointerSimple.downTime = when; + + // Send down. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, + 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + // Send move. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + if (hovering) { + if (!mPointerSimple.hovering) { + mPointerSimple.hovering = true; + + // Send hover enter. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, + mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + // Send hover move. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { + float vscroll = mCurrentRawState.rawVScroll; + float hscroll = mCurrentRawState.rawHScroll; + mWheelYVelocityControl.move(when, nullptr, &vscroll); + mWheelXVelocityControl.move(when, &hscroll, nullptr); + + // Send scroll. + PointerCoords pointerCoords; + pointerCoords.copyFrom(mPointerSimple.currentCoords); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); + + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + 1, &mPointerSimple.currentProperties, &pointerCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + // Save state. + if (down || hovering) { + mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); + mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); + } else { + mPointerSimple.reset(); + } +} + +void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { + mPointerSimple.currentCoords.clear(); + mPointerSimple.currentProperties.clear(); + + dispatchPointerSimple(when, policyFlags, false, false); +} + +void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, + int32_t action, int32_t actionButton, int32_t flags, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp, + const PointerProperties* properties, const PointerCoords* coords, + const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, + float xPrecision, float yPrecision, nsecs_t downTime) { + PointerCoords pointerCoords[MAX_POINTERS]; + PointerProperties pointerProperties[MAX_POINTERS]; + uint32_t pointerCount = 0; + while (!idBits.isEmpty()) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t index = idToIndex[id]; + pointerProperties[pointerCount].copyFrom(properties[index]); + pointerCoords[pointerCount].copyFrom(coords[index]); + + if (changedId >= 0 && id == uint32_t(changedId)) { + action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + } + + pointerCount += 1; + } + + ALOG_ASSERT(pointerCount != 0); + + if (changedId >= 0 && pointerCount == 1) { + // Replace initial down and final up action. + // We can compare the action without masking off the changed pointer index + // because we know the index is 0. + if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { + action = AMOTION_EVENT_ACTION_DOWN; + } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { + action = AMOTION_EVENT_ACTION_UP; + } else { + // Can't happen. + ALOG_ASSERT(false); + } + } + const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE); + const int32_t deviceId = getDeviceId(); + std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId); + std::for_each(frames.begin(), frames.end(), + [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, + source, displayId, policyFlags, + action, actionButton, flags, metaState, buttonState, MotionClassification::NONE, + edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords, + xPrecision, yPrecision, downTime, std::move(frames)); + getListener()->notifyMotion(&args); +} + +bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, + const PointerCoords* inCoords, const uint32_t* inIdToIndex, + PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex, + BitSet32 idBits) const { + bool changed = false; + while (!idBits.isEmpty()) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t inIndex = inIdToIndex[id]; + uint32_t outIndex = outIdToIndex[id]; + + const PointerProperties& curInProperties = inProperties[inIndex]; + const PointerCoords& curInCoords = inCoords[inIndex]; + PointerProperties& curOutProperties = outProperties[outIndex]; + PointerCoords& curOutCoords = outCoords[outIndex]; + + if (curInProperties != curOutProperties) { + curOutProperties.copyFrom(curInProperties); + changed = true; + } + + if (curInCoords != curOutCoords) { + curOutCoords.copyFrom(curInCoords); + changed = true; + } + } + return changed; +} + +void TouchInputMapper::fadePointer() { + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + } +} + +void TouchInputMapper::cancelTouch(nsecs_t when) { + abortPointerUsage(when, 0 /*policyFlags*/); + abortTouches(when, 0 /* policyFlags*/); +} + +bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { + const float scaledX = x * mXScale; + const float scaledY = y * mYScale; + return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue + && scaledX >= mPhysicalLeft && scaledX <= mPhysicalLeft + mPhysicalWidth + && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue + && scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight; +} + +const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) { + + for (const VirtualKey& virtualKey: mVirtualKeys) { +#if DEBUG_VIRTUAL_KEYS + ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " + "left=%d, top=%d, right=%d, bottom=%d", + x, y, + virtualKey.keyCode, virtualKey.scanCode, + virtualKey.hitLeft, virtualKey.hitTop, + virtualKey.hitRight, virtualKey.hitBottom); +#endif + + if (virtualKey.isHit(x, y)) { + return & virtualKey; + } + } + + return nullptr; +} + +void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) { + uint32_t currentPointerCount = current->rawPointerData.pointerCount; + uint32_t lastPointerCount = last->rawPointerData.pointerCount; + + current->rawPointerData.clearIdBits(); + + if (currentPointerCount == 0) { + // No pointers to assign. + return; + } + + if (lastPointerCount == 0) { + // All pointers are new. + for (uint32_t i = 0; i < currentPointerCount; i++) { + uint32_t id = i; + current->rawPointerData.pointers[i].id = id; + current->rawPointerData.idToIndex[id] = i; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i)); + } + return; + } + + if (currentPointerCount == 1 && lastPointerCount == 1 + && current->rawPointerData.pointers[0].toolType + == last->rawPointerData.pointers[0].toolType) { + // Only one pointer and no change in count so it must have the same id as before. + uint32_t id = last->rawPointerData.pointers[0].id; + current->rawPointerData.pointers[0].id = id; + current->rawPointerData.idToIndex[id] = 0; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0)); + return; + } + + // General case. + // We build a heap of squared euclidean distances between current and last pointers + // associated with the current and last pointer indices. Then, we find the best + // match (by distance) for each current pointer. + // The pointers must have the same tool type but it is possible for them to + // transition from hovering to touching or vice-versa while retaining the same id. + PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; + + uint32_t heapSize = 0; + for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; + currentPointerIndex++) { + for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; + lastPointerIndex++) { + const RawPointerData::Pointer& currentPointer = + current->rawPointerData.pointers[currentPointerIndex]; + const RawPointerData::Pointer& lastPointer = + last->rawPointerData.pointers[lastPointerIndex]; + if (currentPointer.toolType == lastPointer.toolType) { + int64_t deltaX = currentPointer.x - lastPointer.x; + int64_t deltaY = currentPointer.y - lastPointer.y; + + uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); + + // Insert new element into the heap (sift up). + heap[heapSize].currentPointerIndex = currentPointerIndex; + heap[heapSize].lastPointerIndex = lastPointerIndex; + heap[heapSize].distance = distance; + heapSize += 1; + } + } + } + + // Heapify + for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { + startIndex -= 1; + for (uint32_t parentIndex = startIndex; ;) { + uint32_t childIndex = parentIndex * 2 + 1; + if (childIndex >= heapSize) { + break; + } + + if (childIndex + 1 < heapSize + && heap[childIndex + 1].distance < heap[childIndex].distance) { + childIndex += 1; + } + + if (heap[parentIndex].distance <= heap[childIndex].distance) { + break; + } + + swap(heap[parentIndex], heap[childIndex]); + parentIndex = childIndex; + } + } + +#if DEBUG_POINTER_ASSIGNMENT + ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); + for (size_t i = 0; i < heapSize; i++) { + ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, + i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, + heap[i].distance); + } +#endif + + // Pull matches out by increasing order of distance. + // To avoid reassigning pointers that have already been matched, the loop keeps track + // of which last and current pointers have been matched using the matchedXXXBits variables. + // It also tracks the used pointer id bits. + BitSet32 matchedLastBits(0); + BitSet32 matchedCurrentBits(0); + BitSet32 usedIdBits(0); + bool first = true; + for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { + while (heapSize > 0) { + if (first) { + // The first time through the loop, we just consume the root element of + // the heap (the one with smallest distance). + first = false; + } else { + // Previous iterations consumed the root element of the heap. + // Pop root element off of the heap (sift down). + heap[0] = heap[heapSize]; + for (uint32_t parentIndex = 0; ;) { + uint32_t childIndex = parentIndex * 2 + 1; + if (childIndex >= heapSize) { + break; + } + + if (childIndex + 1 < heapSize + && heap[childIndex + 1].distance < heap[childIndex].distance) { + childIndex += 1; + } + + if (heap[parentIndex].distance <= heap[childIndex].distance) { + break; + } + + swap(heap[parentIndex], heap[childIndex]); + parentIndex = childIndex; + } + +#if DEBUG_POINTER_ASSIGNMENT + ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); + for (size_t i = 0; i < heapSize; i++) { + ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, + i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, + heap[i].distance); + } +#endif + } + + heapSize -= 1; + + uint32_t currentPointerIndex = heap[0].currentPointerIndex; + if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched + + uint32_t lastPointerIndex = heap[0].lastPointerIndex; + if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched + + matchedCurrentBits.markBit(currentPointerIndex); + matchedLastBits.markBit(lastPointerIndex); + + uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id; + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); + usedIdBits.markBit(id); + +#if DEBUG_POINTER_ASSIGNMENT + ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32 + ", id=%" PRIu32 ", distance=%" PRIu64, + lastPointerIndex, currentPointerIndex, id, heap[0].distance); +#endif + break; + } + } + + // Assign fresh ids to pointers that were not matched in the process. + for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { + uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); + uint32_t id = usedIdBits.markFirstUnmarkedBit(); + + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); + +#if DEBUG_POINTER_ASSIGNMENT + ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, id); +#endif + } +} + +int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { + return AKEY_STATE_VIRTUAL; + } + + for (const VirtualKey& virtualKey : mVirtualKeys) { + if (virtualKey.keyCode == keyCode) { + return AKEY_STATE_UP; + } + } + + return AKEY_STATE_UNKNOWN; +} + +int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { + return AKEY_STATE_VIRTUAL; + } + + for (const VirtualKey& virtualKey : mVirtualKeys) { + if (virtualKey.scanCode == scanCode) { + return AKEY_STATE_UP; + } + } + + return AKEY_STATE_UNKNOWN; +} + +bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + for (const VirtualKey& virtualKey : mVirtualKeys) { + for (size_t i = 0; i < numCodes; i++) { + if (virtualKey.keyCode == keyCodes[i]) { + outFlags[i] = 1; + } + } + } + + return true; +} + +std::optional<int32_t> TouchInputMapper::getAssociatedDisplay() { + if (mParameters.hasAssociatedDisplay) { + if (mDeviceMode == DEVICE_MODE_POINTER) { + return std::make_optional(mPointerController->getDisplayId()); + } else { + return std::make_optional(mViewport.displayId); + } + } + return std::nullopt; +} + +// --- SingleTouchInputMapper --- + +SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : + TouchInputMapper(device) { +} + +SingleTouchInputMapper::~SingleTouchInputMapper() { +} + +void SingleTouchInputMapper::reset(nsecs_t when) { + mSingleTouchMotionAccumulator.reset(getDevice()); + + TouchInputMapper::reset(when); +} + +void SingleTouchInputMapper::process(const RawEvent* rawEvent) { + TouchInputMapper::process(rawEvent); + + mSingleTouchMotionAccumulator.process(rawEvent); +} + +void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { + if (mTouchButtonAccumulator.isToolActive()) { + outState->rawPointerData.pointerCount = 1; + outState->rawPointerData.idToIndex[0] = 0; + + bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE + && (mTouchButtonAccumulator.isHovering() + || (mRawPointerAxes.pressure.valid + && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); + outState->rawPointerData.markIdBit(0, isHovering); + + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0]; + outPointer.id = 0; + outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); + outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); + outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); + outPointer.touchMajor = 0; + outPointer.touchMinor = 0; + outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); + outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); + outPointer.orientation = 0; + outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); + outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); + outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); + outPointer.toolType = mTouchButtonAccumulator.getToolType(); + if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + } + outPointer.isHovering = isHovering; + } +} + +void SingleTouchInputMapper::configureRawPointerAxes() { + TouchInputMapper::configureRawPointerAxes(); + + getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); + getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); + getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); + getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); + getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); + getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); + getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); +} + +bool SingleTouchInputMapper::hasStylus() const { + return mTouchButtonAccumulator.hasStylus(); +} + + +// --- MultiTouchInputMapper --- + +MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : + TouchInputMapper(device) { +} + +MultiTouchInputMapper::~MultiTouchInputMapper() { +} + +void MultiTouchInputMapper::reset(nsecs_t when) { + mMultiTouchMotionAccumulator.reset(getDevice()); + + mPointerIdBits.clear(); + + TouchInputMapper::reset(when); +} + +void MultiTouchInputMapper::process(const RawEvent* rawEvent) { + TouchInputMapper::process(rawEvent); + + mMultiTouchMotionAccumulator.process(rawEvent); +} + +void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { + size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); + size_t outCount = 0; + BitSet32 newPointerIdBits; + mHavePointerIds = true; + + for (size_t inIndex = 0; inIndex < inCount; inIndex++) { + const MultiTouchMotionAccumulator::Slot* inSlot = + mMultiTouchMotionAccumulator.getSlot(inIndex); + if (!inSlot->isInUse()) { + continue; + } + + if (outCount >= MAX_POINTERS) { +#if DEBUG_POINTERS + ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " + "ignoring the rest.", + getDeviceName().c_str(), MAX_POINTERS); +#endif + break; // too many fingers! + } + + 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.tiltX = 0; + outPointer.tiltY = 0; + + 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; + } + } + + bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE + && (mTouchButtonAccumulator.isHovering() + || (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 id = -1; + if (trackingId >= 0) { + for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { + uint32_t n = idBits.clearFirstMarkedBit(); + if (mPointerTrackingIdMap[n] == trackingId) { + id = n; + } + } + + if (id < 0 && !mPointerIdBits.isFull()) { + id = mPointerIdBits.markFirstUnmarkedBit(); + mPointerTrackingIdMap[id] = trackingId; + } + } + if (id < 0) { + mHavePointerIds = false; + outState->rawPointerData.clearIdBits(); + newPointerIdBits.clear(); + } else { + outPointer.id = id; + outState->rawPointerData.idToIndex[id] = outCount; + outState->rawPointerData.markIdBit(id, isHovering); + newPointerIdBits.markBit(id); + } + } + outCount += 1; + } + + outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp(); + outState->rawPointerData.pointerCount = outCount; + mPointerIdBits = newPointerIdBits; + + mMultiTouchMotionAccumulator.finishSync(); +} + +void MultiTouchInputMapper::configureRawPointerAxes() { + TouchInputMapper::configureRawPointerAxes(); + + getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); + getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); + getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); + getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); + getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); + getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); + getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); + getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); + getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); + getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); + getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); + + if (mRawPointerAxes.trackingId.valid + && mRawPointerAxes.slot.valid + && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { + size_t slotCount = mRawPointerAxes.slot.maxValue + 1; + if (slotCount > MAX_SLOTS) { + ALOGW("MultiTouch Device %s reported %zu slots but the framework " + "only supports a maximum of %zu slots at this time.", + getDeviceName().c_str(), slotCount, MAX_SLOTS); + slotCount = MAX_SLOTS; + } + mMultiTouchMotionAccumulator.configure(getDevice(), + slotCount, true /*usingSlotsProtocol*/); + } else { + mMultiTouchMotionAccumulator.configure(getDevice(), + MAX_POINTERS, false /*usingSlotsProtocol*/); + } +} + +bool MultiTouchInputMapper::hasStylus() const { + return mMultiTouchMotionAccumulator.hasStylus() + || mTouchButtonAccumulator.hasStylus(); +} + +// --- ExternalStylusInputMapper + +ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : + InputMapper(device) { + +} + +uint32_t ExternalStylusInputMapper::getSources() { + return AINPUT_SOURCE_STYLUS; +} + +void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); +} + +void ExternalStylusInputMapper::dump(std::string& dump) { + dump += INDENT2 "External Stylus Input Mapper:\n"; + dump += INDENT3 "Raw Stylus Axes:\n"; + dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); + dump += INDENT3 "Stylus State:\n"; + dumpStylusState(dump, mStylusState); +} + +void ExternalStylusInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); + mTouchButtonAccumulator.configure(getDevice()); +} + +void ExternalStylusInputMapper::reset(nsecs_t when) { + InputDevice* device = getDevice(); + mSingleTouchMotionAccumulator.reset(device); + mTouchButtonAccumulator.reset(device); + InputMapper::reset(when); +} + +void ExternalStylusInputMapper::process(const RawEvent* rawEvent) { + mSingleTouchMotionAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void ExternalStylusInputMapper::sync(nsecs_t when) { + mStylusState.clear(); + + mStylusState.when = when; + + mStylusState.toolType = mTouchButtonAccumulator.getToolType(); + if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + } + + int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); + if (mRawPressureAxis.valid) { + mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue; + } else if (mTouchButtonAccumulator.isToolActive()) { + mStylusState.pressure = 1.0f; + } else { + mStylusState.pressure = 0.0f; + } + + mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); + + mContext->dispatchExternalStylusState(mStylusState); +} + + +// --- JoystickInputMapper --- + +JoystickInputMapper::JoystickInputMapper(InputDevice* device) : + InputMapper(device) { +} + +JoystickInputMapper::~JoystickInputMapper() { +} + +uint32_t JoystickInputMapper::getSources() { + return AINPUT_SOURCE_JOYSTICK; +} + +void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + for (size_t i = 0; i < mAxes.size(); i++) { + const Axis& axis = mAxes.valueAt(i); + addMotionRange(axis.axisInfo.axis, axis, info); + + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + addMotionRange(axis.axisInfo.highAxis, axis, info); + + } + } +} + +void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, + InputDeviceInfo* info) { + info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, + axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); + /* In order to ease the transition for developers from using the old axes + * to the newer, more semantically correct axes, we'll continue to register + * the old axes as duplicates of their corresponding new ones. */ + int32_t compatAxis = getCompatAxis(axisId); + if (compatAxis >= 0) { + info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, + axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); + } +} + +/* A mapping from axes the joystick actually has to the axes that should be + * artificially created for compatibility purposes. + * Returns -1 if no compatibility axis is needed. */ +int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { + switch(axis) { + case AMOTION_EVENT_AXIS_LTRIGGER: + return AMOTION_EVENT_AXIS_BRAKE; + case AMOTION_EVENT_AXIS_RTRIGGER: + return AMOTION_EVENT_AXIS_GAS; + } + return -1; +} + +void JoystickInputMapper::dump(std::string& dump) { + dump += INDENT2 "Joystick Input Mapper:\n"; + + dump += INDENT3 "Axes:\n"; + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + const Axis& axis = mAxes.valueAt(i); + const char* label = getAxisLabel(axis.axisInfo.axis); + if (label) { + dump += StringPrintf(INDENT4 "%s", label); + } else { + dump += StringPrintf(INDENT4 "%d", axis.axisInfo.axis); + } + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + label = getAxisLabel(axis.axisInfo.highAxis); + if (label) { + dump += StringPrintf(" / %s (split at %d)", label, axis.axisInfo.splitValue); + } else { + dump += StringPrintf(" / %d (split at %d)", axis.axisInfo.highAxis, + axis.axisInfo.splitValue); + } + } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { + dump += " (invert)"; + } + + dump += StringPrintf(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", + axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); + dump += StringPrintf(INDENT4 " scale=%0.5f, offset=%0.5f, " + "highScale=%0.5f, highOffset=%0.5f\n", + axis.scale, axis.offset, axis.highScale, axis.highOffset); + dump += StringPrintf(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " + "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", + mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, + axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution); + } +} + +void JoystickInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + InputMapper::configure(when, config, changes); + + if (!changes) { // first time only + // Collect all axes. + for (int32_t abs = 0; abs <= ABS_MAX; abs++) { + if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) + & INPUT_DEVICE_CLASS_JOYSTICK)) { + continue; // axis must be claimed by a different device + } + + RawAbsoluteAxisInfo rawAxisInfo; + getAbsoluteAxisInfo(abs, &rawAxisInfo); + if (rawAxisInfo.valid) { + // Map axis. + AxisInfo axisInfo; + bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); + if (!explicitlyMapped) { + // Axis is not explicitly mapped, will choose a generic axis later. + axisInfo.mode = AxisInfo::MODE_NORMAL; + axisInfo.axis = -1; + } + + // Apply flat override. + int32_t rawFlat = axisInfo.flatOverride < 0 + ? rawAxisInfo.flat : axisInfo.flatOverride; + + // Calculate scaling factors and limits. + Axis axis; + if (axisInfo.mode == AxisInfo::MODE_SPLIT) { + float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); + float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, + scale, 0.0f, highScale, 0.0f, + 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, + rawAxisInfo.resolution * scale); + } else if (isCenteredAxis(axisInfo.axis)) { + float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); + float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, + scale, offset, scale, offset, + -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, + rawAxisInfo.resolution * scale); + } else { + float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, + scale, 0.0f, scale, 0.0f, + 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, + rawAxisInfo.resolution * scale); + } + + // To eliminate noise while the joystick is at rest, filter out small variations + // in axis values up front. + axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f; + + mAxes.add(abs, axis); + } + } + + // If there are too many axes, start dropping them. + // Prefer to keep explicitly mapped axes. + if (mAxes.size() > PointerCoords::MAX_AXES) { + ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.", + getDeviceName().c_str(), mAxes.size(), PointerCoords::MAX_AXES); + pruneAxes(true); + pruneAxes(false); + } + + // Assign generic axis ids to remaining axes. + int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + Axis& axis = mAxes.editValueAt(i); + if (axis.axisInfo.axis < 0) { + while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 + && haveAxis(nextGenericAxisId)) { + nextGenericAxisId += 1; + } + + if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { + axis.axisInfo.axis = nextGenericAxisId; + nextGenericAxisId += 1; + } else { + ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " + "have already been assigned to other axes.", + getDeviceName().c_str(), mAxes.keyAt(i)); + mAxes.removeItemsAt(i--); + numAxes -= 1; + } + } + } + } +} + +bool JoystickInputMapper::haveAxis(int32_t axisId) { + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + const Axis& axis = mAxes.valueAt(i); + if (axis.axisInfo.axis == axisId + || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT + && axis.axisInfo.highAxis == axisId)) { + return true; + } + } + return false; +} + +void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { + size_t i = mAxes.size(); + while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { + if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { + continue; + } + ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", + getDeviceName().c_str(), mAxes.keyAt(i)); + mAxes.removeItemsAt(i); + } +} + +bool JoystickInputMapper::isCenteredAxis(int32_t axis) { + switch (axis) { + case AMOTION_EVENT_AXIS_X: + case AMOTION_EVENT_AXIS_Y: + case AMOTION_EVENT_AXIS_Z: + case AMOTION_EVENT_AXIS_RX: + case AMOTION_EVENT_AXIS_RY: + case AMOTION_EVENT_AXIS_RZ: + case AMOTION_EVENT_AXIS_HAT_X: + case AMOTION_EVENT_AXIS_HAT_Y: + case AMOTION_EVENT_AXIS_ORIENTATION: + case AMOTION_EVENT_AXIS_RUDDER: + case AMOTION_EVENT_AXIS_WHEEL: + return true; + default: + return false; + } +} + +void JoystickInputMapper::reset(nsecs_t when) { + // Recenter all axes. + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + Axis& axis = mAxes.editValueAt(i); + axis.resetValue(); + } + + InputMapper::reset(when); +} + +void JoystickInputMapper::process(const RawEvent* rawEvent) { + switch (rawEvent->type) { + case EV_ABS: { + ssize_t index = mAxes.indexOfKey(rawEvent->code); + if (index >= 0) { + Axis& axis = mAxes.editValueAt(index); + float newValue, highNewValue; + switch (axis.axisInfo.mode) { + case AxisInfo::MODE_INVERT: + newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) + * axis.scale + axis.offset; + highNewValue = 0.0f; + break; + case AxisInfo::MODE_SPLIT: + if (rawEvent->value < axis.axisInfo.splitValue) { + newValue = (axis.axisInfo.splitValue - rawEvent->value) + * axis.scale + axis.offset; + highNewValue = 0.0f; + } else if (rawEvent->value > axis.axisInfo.splitValue) { + newValue = 0.0f; + highNewValue = (rawEvent->value - axis.axisInfo.splitValue) + * axis.highScale + axis.highOffset; + } else { + newValue = 0.0f; + highNewValue = 0.0f; + } + break; + default: + newValue = rawEvent->value * axis.scale + axis.offset; + highNewValue = 0.0f; + break; + } + axis.newValue = newValue; + axis.highNewValue = highNewValue; + } + break; + } + + case EV_SYN: + switch (rawEvent->code) { + case SYN_REPORT: + sync(rawEvent->when, false /*force*/); + break; + } + break; + } +} + +void JoystickInputMapper::sync(nsecs_t when, bool force) { + if (!filterAxes(force)) { + return; + } + + int32_t metaState = mContext->getGlobalMetaState(); + int32_t buttonState = 0; + + PointerProperties pointerProperties; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + + PointerCoords pointerCoords; + pointerCoords.clear(); + + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + const Axis& axis = mAxes.valueAt(i); + setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue); + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis, + axis.highCurrentValue); + } + } + + // Moving a joystick axis should not wake the device because joysticks can + // be fairly noisy even when not in use. On the other hand, pushing a gamepad + // button will likely wake the device. + // TODO: Use the input device configuration to control this behavior more finely. + uint32_t policyFlags = 0; + + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {}); + getListener()->notifyMotion(&args); +} + +void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, + int32_t axis, float value) { + pointerCoords->setAxisValue(axis, value); + /* In order to ease the transition for developers from using the old axes + * to the newer, more semantically correct axes, we'll continue to produce + * values for the old axes as mirrors of the value of their corresponding + * new axes. */ + int32_t compatAxis = getCompatAxis(axis); + if (compatAxis >= 0) { + pointerCoords->setAxisValue(compatAxis, value); + } +} + +bool JoystickInputMapper::filterAxes(bool force) { + bool atLeastOneSignificantChange = force; + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + Axis& axis = mAxes.editValueAt(i); + if (force || hasValueChangedSignificantly(axis.filter, + axis.newValue, axis.currentValue, axis.min, axis.max)) { + axis.currentValue = axis.newValue; + atLeastOneSignificantChange = true; + } + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + if (force || hasValueChangedSignificantly(axis.filter, + axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) { + axis.highCurrentValue = axis.highNewValue; + atLeastOneSignificantChange = true; + } + } + } + return atLeastOneSignificantChange; +} + +bool JoystickInputMapper::hasValueChangedSignificantly( + float filter, float newValue, float currentValue, float min, float max) { + if (newValue != currentValue) { + // Filter out small changes in value unless the value is converging on the axis + // bounds or center point. This is intended to reduce the amount of information + // sent to applications by particularly noisy joysticks (such as PS3). + if (fabs(newValue - currentValue) > filter + || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) + || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) + || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { + return true; + } + } + return false; +} + +bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange( + float filter, float newValue, float currentValue, float thresholdValue) { + float newDistance = fabs(newValue - thresholdValue); + if (newDistance < filter) { + float oldDistance = fabs(currentValue - thresholdValue); + if (newDistance < oldDistance) { + return true; + } + } + return false; +} + +} // namespace android diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h new file mode 100644 index 0000000000..9777779e7d --- /dev/null +++ b/services/inputflinger/InputReader.h @@ -0,0 +1,1809 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UI_INPUT_READER_H +#define _UI_INPUT_READER_H + +#include "EventHub.h" +#include "PointerControllerInterface.h" +#include "InputListener.h" +#include "InputReaderBase.h" + +#include <input/DisplayViewport.h> +#include <input/Input.h> +#include <input/VelocityControl.h> +#include <input/VelocityTracker.h> +#include <ui/DisplayInfo.h> +#include <utils/KeyedVector.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> +#include <utils/Timers.h> +#include <utils/BitSet.h> + +#include <optional> +#include <stddef.h> +#include <unistd.h> +#include <vector> + +namespace android { + +class InputDevice; +class InputMapper; + + +struct StylusState { + /* Time the stylus event was received. */ + nsecs_t when; + /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */ + float pressure; + /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ + uint32_t buttons; + /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ + int32_t toolType; + + void copyFrom(const StylusState& other) { + when = other.when; + pressure = other.pressure; + buttons = other.buttons; + toolType = other.toolType; + } + + void clear() { + when = LLONG_MAX; + pressure = 0.f; + buttons = 0; + toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + } +}; + + +/* Internal interface used by individual input devices to access global input device state + * and parameters maintained by the input reader. + */ +class InputReaderContext { +public: + InputReaderContext() { } + virtual ~InputReaderContext() { } + + virtual void updateGlobalMetaState() = 0; + virtual int32_t getGlobalMetaState() = 0; + + virtual void disableVirtualKeysUntil(nsecs_t time) = 0; + virtual bool shouldDropVirtualKey(nsecs_t now, + InputDevice* device, int32_t keyCode, int32_t scanCode) = 0; + + virtual void fadePointer() = 0; + + virtual void requestTimeoutAtTime(nsecs_t when) = 0; + virtual int32_t bumpGeneration() = 0; + + virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) = 0; + virtual void dispatchExternalStylusState(const StylusState& outState) = 0; + + virtual InputReaderPolicyInterface* getPolicy() = 0; + virtual InputListenerInterface* getListener() = 0; + virtual EventHubInterface* getEventHub() = 0; + + virtual uint32_t getNextSequenceNum() = 0; +}; + + +/* The input reader reads raw event data from the event hub and processes it into input events + * that it sends to the input listener. Some functions of the input reader, such as early + * event filtering in low power states, are controlled by a separate policy object. + * + * The InputReader owns a collection of InputMappers. Most of the work it does happens + * on the input reader thread but the InputReader can receive queries from other system + * components running on arbitrary threads. To keep things manageable, the InputReader + * uses a single Mutex to guard its state. The Mutex may be held while calling into the + * EventHub or the InputReaderPolicy but it is never held while calling into the + * InputListener. + */ +class InputReader : public InputReaderInterface { +public: + InputReader(const sp<EventHubInterface>& eventHub, + const sp<InputReaderPolicyInterface>& policy, + const sp<InputListenerInterface>& listener); + virtual ~InputReader(); + + virtual void dump(std::string& dump); + virtual void monitor(); + + virtual void loopOnce(); + + virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices); + + virtual bool isInputDeviceEnabled(int32_t deviceId); + + virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, + int32_t scanCode); + virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, + int32_t keyCode); + virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, + int32_t sw); + + virtual void toggleCapsLockState(int32_t deviceId); + + virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, + size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); + + virtual void requestRefreshConfiguration(uint32_t changes); + + virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, + ssize_t repeat, int32_t token); + virtual void cancelVibrate(int32_t deviceId, int32_t token); + + virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId); +protected: + // These members are protected so they can be instrumented by test cases. + virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, + const InputDeviceIdentifier& identifier, uint32_t classes); + + class ContextImpl : public InputReaderContext { + InputReader* mReader; + + public: + explicit ContextImpl(InputReader* reader); + + virtual void updateGlobalMetaState(); + virtual int32_t getGlobalMetaState(); + virtual void disableVirtualKeysUntil(nsecs_t time); + virtual bool shouldDropVirtualKey(nsecs_t now, + InputDevice* device, int32_t keyCode, int32_t scanCode); + virtual void fadePointer(); + virtual void requestTimeoutAtTime(nsecs_t when); + virtual int32_t bumpGeneration(); + virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices); + virtual void dispatchExternalStylusState(const StylusState& outState); + virtual InputReaderPolicyInterface* getPolicy(); + virtual InputListenerInterface* getListener(); + virtual EventHubInterface* getEventHub(); + virtual uint32_t getNextSequenceNum(); + } mContext; + + friend class ContextImpl; + +private: + Mutex mLock; + + Condition mReaderIsAliveCondition; + + sp<EventHubInterface> mEventHub; + sp<InputReaderPolicyInterface> mPolicy; + sp<QueuedInputListener> mQueuedListener; + + InputReaderConfiguration mConfig; + + // used by InputReaderContext::getNextSequenceNum() as a counter for event sequence numbers + uint32_t mNextSequenceNum; + + // The event queue. + static const int EVENT_BUFFER_SIZE = 256; + RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; + + KeyedVector<int32_t, InputDevice*> mDevices; + + // low-level input event decoding and device management + void processEventsLocked(const RawEvent* rawEvents, size_t count); + + void addDeviceLocked(nsecs_t when, int32_t deviceId); + void removeDeviceLocked(nsecs_t when, int32_t deviceId); + void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); + void timeoutExpiredLocked(nsecs_t when); + + void handleConfigurationChangedLocked(nsecs_t when); + + int32_t mGlobalMetaState; + void updateGlobalMetaStateLocked(); + int32_t getGlobalMetaStateLocked(); + + void notifyExternalStylusPresenceChanged(); + void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices); + void dispatchExternalStylusState(const StylusState& state); + + void fadePointerLocked(); + + int32_t mGeneration; + int32_t bumpGenerationLocked(); + + void getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices); + + nsecs_t mDisableVirtualKeysTimeout; + void disableVirtualKeysUntilLocked(nsecs_t time); + bool shouldDropVirtualKeyLocked(nsecs_t now, + InputDevice* device, int32_t keyCode, int32_t scanCode); + + nsecs_t mNextTimeout; + void requestTimeoutAtTimeLocked(nsecs_t when); + + uint32_t mConfigurationChangesToRefresh; + void refreshConfigurationLocked(uint32_t changes); + + // state queries + typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); + int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, + GetStateFunc getStateFunc); + bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); +}; + + +/* Represents the state of a single input device. */ +class InputDevice { +public: + InputDevice(InputReaderContext* context, int32_t id, int32_t generation, int32_t + controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes); + ~InputDevice(); + + inline InputReaderContext* getContext() { return mContext; } + inline int32_t getId() const { return mId; } + inline int32_t getControllerNumber() const { return mControllerNumber; } + inline int32_t getGeneration() const { return mGeneration; } + inline const std::string getName() const { return mIdentifier.name; } + inline const std::string getDescriptor() { return mIdentifier.descriptor; } + inline uint32_t getClasses() const { return mClasses; } + inline uint32_t getSources() const { return mSources; } + + inline bool isExternal() { return mIsExternal; } + inline void setExternal(bool external) { mIsExternal = external; } + inline std::optional<uint8_t> getAssociatedDisplayPort() const { + return mAssociatedDisplayPort; + } + + inline void setMic(bool hasMic) { mHasMic = hasMic; } + inline bool hasMic() const { return mHasMic; } + + inline bool isIgnored() { return mMappers.empty(); } + + bool isEnabled(); + void setEnabled(bool enabled, nsecs_t when); + + void dump(std::string& dump); + void addMapper(InputMapper* mapper); + void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + void reset(nsecs_t when); + void process(const RawEvent* rawEvents, size_t count); + void timeoutExpired(nsecs_t when); + void updateExternalStylusState(const StylusState& state); + + void getDeviceInfo(InputDeviceInfo* outDeviceInfo); + int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); + bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); + void cancelVibrate(int32_t token); + void cancelTouch(nsecs_t when); + + int32_t getMetaState(); + void updateMetaState(int32_t keyCode); + + void fadePointer(); + + void bumpGeneration(); + + void notifyReset(nsecs_t when); + + inline const PropertyMap& getConfiguration() { return mConfiguration; } + inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } + + bool hasKey(int32_t code) { + return getEventHub()->hasScanCode(mId, code); + } + + bool hasAbsoluteAxis(int32_t code) { + RawAbsoluteAxisInfo info; + getEventHub()->getAbsoluteAxisInfo(mId, code, &info); + return info.valid; + } + + bool isKeyPressed(int32_t code) { + return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; + } + + int32_t getAbsoluteAxisValue(int32_t code) { + int32_t value; + getEventHub()->getAbsoluteAxisValue(mId, code, &value); + return value; + } + + std::optional<int32_t> getAssociatedDisplay(); +private: + InputReaderContext* mContext; + int32_t mId; + int32_t mGeneration; + int32_t mControllerNumber; + InputDeviceIdentifier mIdentifier; + std::string mAlias; + uint32_t mClasses; + + std::vector<InputMapper*> mMappers; + + uint32_t mSources; + bool mIsExternal; + std::optional<uint8_t> mAssociatedDisplayPort; + bool mHasMic; + bool mDropUntilNextSync; + + typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); + int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); + + PropertyMap mConfiguration; +}; + + +/* Keeps track of the state of mouse or touch pad buttons. */ +class CursorButtonAccumulator { +public: + CursorButtonAccumulator(); + void reset(InputDevice* device); + + void process(const RawEvent* rawEvent); + + uint32_t getButtonState() const; + +private: + bool mBtnLeft; + bool mBtnRight; + bool mBtnMiddle; + bool mBtnBack; + bool mBtnSide; + bool mBtnForward; + bool mBtnExtra; + bool mBtnTask; + + void clearButtons(); +}; + + +/* Keeps track of cursor movements. */ + +class CursorMotionAccumulator { +public: + CursorMotionAccumulator(); + void reset(InputDevice* device); + + void process(const RawEvent* rawEvent); + void finishSync(); + + inline int32_t getRelativeX() const { return mRelX; } + inline int32_t getRelativeY() const { return mRelY; } + +private: + int32_t mRelX; + int32_t mRelY; + + void clearRelativeAxes(); +}; + + +/* Keeps track of cursor scrolling motions. */ + +class CursorScrollAccumulator { +public: + CursorScrollAccumulator(); + void configure(InputDevice* device); + void reset(InputDevice* device); + + void process(const RawEvent* rawEvent); + void finishSync(); + + inline bool haveRelativeVWheel() const { return mHaveRelWheel; } + inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } + + inline int32_t getRelativeX() const { return mRelX; } + inline int32_t getRelativeY() const { return mRelY; } + inline int32_t getRelativeVWheel() const { return mRelWheel; } + inline int32_t getRelativeHWheel() const { return mRelHWheel; } + +private: + bool mHaveRelWheel; + bool mHaveRelHWheel; + + int32_t mRelX; + int32_t mRelY; + int32_t mRelWheel; + int32_t mRelHWheel; + + void clearRelativeAxes(); +}; + + +/* Keeps track of the state of touch, stylus and tool buttons. */ +class TouchButtonAccumulator { +public: + TouchButtonAccumulator(); + void configure(InputDevice* device); + void reset(InputDevice* device); + + void process(const RawEvent* rawEvent); + + uint32_t getButtonState() const; + int32_t getToolType() const; + bool isToolActive() const; + bool isHovering() const; + bool hasStylus() const; + +private: + bool mHaveBtnTouch; + bool mHaveStylus; + + bool mBtnTouch; + bool mBtnStylus; + bool mBtnStylus2; + bool mBtnToolFinger; + bool mBtnToolPen; + bool mBtnToolRubber; + bool mBtnToolBrush; + bool mBtnToolPencil; + bool mBtnToolAirbrush; + bool mBtnToolMouse; + bool mBtnToolLens; + bool mBtnToolDoubleTap; + bool mBtnToolTripleTap; + bool mBtnToolQuadTap; + + void clearButtons(); +}; + + +/* Raw axis information from the driver. */ +struct RawPointerAxes { + RawAbsoluteAxisInfo x; + RawAbsoluteAxisInfo y; + RawAbsoluteAxisInfo pressure; + RawAbsoluteAxisInfo touchMajor; + RawAbsoluteAxisInfo touchMinor; + RawAbsoluteAxisInfo toolMajor; + RawAbsoluteAxisInfo toolMinor; + RawAbsoluteAxisInfo orientation; + RawAbsoluteAxisInfo distance; + RawAbsoluteAxisInfo tiltX; + RawAbsoluteAxisInfo tiltY; + RawAbsoluteAxisInfo trackingId; + RawAbsoluteAxisInfo slot; + + RawPointerAxes(); + inline int32_t getRawWidth() const { return x.maxValue - x.minValue + 1; } + inline int32_t getRawHeight() const { return y.maxValue - y.minValue + 1; } + void clear(); +}; + + +/* Raw data for a collection of pointers including a pointer id mapping table. */ +struct RawPointerData { + struct Pointer { + uint32_t id; + int32_t x; + int32_t y; + int32_t pressure; + int32_t touchMajor; + int32_t touchMinor; + int32_t toolMajor; + int32_t toolMinor; + int32_t orientation; + int32_t distance; + int32_t tiltX; + int32_t tiltY; + int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant + bool isHovering; + }; + + uint32_t pointerCount; + Pointer pointers[MAX_POINTERS]; + BitSet32 hoveringIdBits, touchingIdBits; + uint32_t idToIndex[MAX_POINTER_ID + 1]; + + RawPointerData(); + void clear(); + void copyFrom(const RawPointerData& other); + void getCentroidOfTouchingPointers(float* outX, float* outY) const; + + inline void markIdBit(uint32_t id, bool isHovering) { + if (isHovering) { + hoveringIdBits.markBit(id); + } else { + touchingIdBits.markBit(id); + } + } + + inline void clearIdBits() { + hoveringIdBits.clear(); + touchingIdBits.clear(); + } + + inline const Pointer& pointerForId(uint32_t id) const { + return pointers[idToIndex[id]]; + } + + inline bool isHovering(uint32_t pointerIndex) { + return pointers[pointerIndex].isHovering; + } +}; + + +/* Cooked data for a collection of pointers including a pointer id mapping table. */ +struct CookedPointerData { + uint32_t pointerCount; + PointerProperties pointerProperties[MAX_POINTERS]; + PointerCoords pointerCoords[MAX_POINTERS]; + BitSet32 hoveringIdBits, touchingIdBits; + uint32_t idToIndex[MAX_POINTER_ID + 1]; + + CookedPointerData(); + void clear(); + void copyFrom(const CookedPointerData& other); + + inline const PointerCoords& pointerCoordsForId(uint32_t id) const { + return pointerCoords[idToIndex[id]]; + } + + inline PointerCoords& editPointerCoordsWithId(uint32_t id) { + return pointerCoords[idToIndex[id]]; + } + + inline PointerProperties& editPointerPropertiesWithId(uint32_t id) { + return pointerProperties[idToIndex[id]]; + } + + inline bool isHovering(uint32_t pointerIndex) const { + return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); + } + + inline bool isTouching(uint32_t pointerIndex) const { + return touchingIdBits.hasBit(pointerProperties[pointerIndex].id); + } +}; + +/** + * Basic statistics information. + * Keep track of min, max, average, and standard deviation of the received samples. + * Used to report latency information about input events. + */ +struct LatencyStatistics { + float min; + float max; + // Sum of all samples + float sum; + // Sum of squares of all samples + float sum2; + // The number of samples + size_t count; + // The last time statistics were reported. + nsecs_t lastReportTime; + + LatencyStatistics() { + reset(systemTime(SYSTEM_TIME_MONOTONIC)); + } + + inline void addValue(float x) { + if (x < min) { + min = x; + } + if (x > max) { + max = x; + } + sum += x; + sum2 += x * x; + count++; + } + + // Get the average value. Should not be called if no samples have been added. + inline float mean() { + if (count == 0) { + return 0; + } + return sum / count; + } + + // Get the standard deviation. Should not be called if no samples have been added. + inline float stdev() { + if (count == 0) { + return 0; + } + float average = mean(); + return sqrt(sum2 / count - average * average); + } + + /** + * Reset internal state. The variable 'when' is the time when the data collection started. + * Call this to start a new data collection window. + */ + inline void reset(nsecs_t when) { + max = 0; + min = std::numeric_limits<float>::max(); + sum = 0; + sum2 = 0; + count = 0; + lastReportTime = when; + } +}; + +/* Keeps track of the state of single-touch protocol. */ +class SingleTouchMotionAccumulator { +public: + SingleTouchMotionAccumulator(); + + void process(const RawEvent* rawEvent); + void reset(InputDevice* device); + + inline int32_t getAbsoluteX() const { return mAbsX; } + inline int32_t getAbsoluteY() const { return mAbsY; } + inline int32_t getAbsolutePressure() const { return mAbsPressure; } + inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } + inline int32_t getAbsoluteDistance() const { return mAbsDistance; } + inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } + inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } + +private: + int32_t mAbsX; + int32_t mAbsY; + int32_t mAbsPressure; + int32_t mAbsToolWidth; + int32_t mAbsDistance; + int32_t mAbsTiltX; + int32_t mAbsTiltY; + + void clearAbsoluteAxes(); +}; + + +/* Keeps track of the state of multi-touch protocol. */ +class MultiTouchMotionAccumulator { +public: + class Slot { + public: + inline bool isInUse() const { return mInUse; } + inline int32_t getX() const { return mAbsMTPositionX; } + inline int32_t getY() const { return mAbsMTPositionY; } + inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } + inline int32_t getTouchMinor() const { + return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; } + inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } + inline int32_t getToolMinor() const { + return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; } + inline int32_t getOrientation() const { return mAbsMTOrientation; } + inline int32_t getTrackingId() const { return mAbsMTTrackingId; } + inline int32_t getPressure() const { return mAbsMTPressure; } + inline int32_t getDistance() const { return mAbsMTDistance; } + inline int32_t getToolType() const; + + private: + friend class MultiTouchMotionAccumulator; + + bool mInUse; + bool mHaveAbsMTTouchMinor; + bool mHaveAbsMTWidthMinor; + bool mHaveAbsMTToolType; + + 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; + + Slot(); + void clear(); + }; + + MultiTouchMotionAccumulator(); + ~MultiTouchMotionAccumulator(); + + void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); + void reset(InputDevice* device); + void process(const RawEvent* rawEvent); + void finishSync(); + bool hasStylus() const; + + inline size_t getSlotCount() const { return mSlotCount; } + inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } + inline uint32_t getDeviceTimestamp() const { return mDeviceTimestamp; } + +private: + int32_t mCurrentSlot; + Slot* mSlots; + size_t mSlotCount; + bool mUsingSlotsProtocol; + bool mHaveStylus; + uint32_t mDeviceTimestamp; + + void clearSlots(int32_t initialSlot); +}; + + +/* An input mapper transforms raw input events into cooked event data. + * A single input device can have multiple associated input mappers in order to interpret + * different classes of events. + * + * InputMapper lifecycle: + * - create + * - configure with 0 changes + * - reset + * - process, process, process (may occasionally reconfigure with non-zero changes or reset) + * - reset + * - destroy + */ +class InputMapper { +public: + explicit InputMapper(InputDevice* device); + virtual ~InputMapper(); + + inline InputDevice* getDevice() { return mDevice; } + inline int32_t getDeviceId() { return mDevice->getId(); } + inline const std::string getDeviceName() { return mDevice->getName(); } + inline InputReaderContext* getContext() { return mContext; } + inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } + inline InputListenerInterface* getListener() { return mContext->getListener(); } + inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } + + virtual uint32_t getSources() = 0; + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent) = 0; + virtual void timeoutExpired(nsecs_t when); + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, + int32_t token); + virtual void cancelVibrate(int32_t token); + virtual void cancelTouch(nsecs_t when); + + virtual int32_t getMetaState(); + virtual void updateMetaState(int32_t keyCode); + + virtual void updateExternalStylusState(const StylusState& state); + + virtual void fadePointer(); + virtual std::optional<int32_t> getAssociatedDisplay() { + return std::nullopt; + } +protected: + InputDevice* mDevice; + InputReaderContext* mContext; + + status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); + void bumpGeneration(); + + static void dumpRawAbsoluteAxisInfo(std::string& dump, + const RawAbsoluteAxisInfo& axis, const char* name); + static void dumpStylusState(std::string& dump, const StylusState& state); +}; + + +class SwitchInputMapper : public InputMapper { +public: + explicit SwitchInputMapper(InputDevice* device); + virtual ~SwitchInputMapper(); + + virtual uint32_t getSources(); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); + virtual void dump(std::string& dump); + +private: + uint32_t mSwitchValues; + uint32_t mUpdatedSwitchMask; + + void processSwitch(int32_t switchCode, int32_t switchValue); + void sync(nsecs_t when); +}; + + +class VibratorInputMapper : public InputMapper { +public: + explicit VibratorInputMapper(InputDevice* device); + virtual ~VibratorInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void process(const RawEvent* rawEvent); + + virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, + int32_t token); + virtual void cancelVibrate(int32_t token); + virtual void timeoutExpired(nsecs_t when); + virtual void dump(std::string& dump); + +private: + bool mVibrating; + nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE]; + size_t mPatternSize; + ssize_t mRepeat; + int32_t mToken; + ssize_t mIndex; + nsecs_t mNextStepTime; + + void nextStep(); + void stopVibrating(); +}; + + +class KeyboardInputMapper : public InputMapper { +public: + KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); + virtual ~KeyboardInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + + virtual int32_t getMetaState(); + virtual void updateMetaState(int32_t keyCode); + +private: + // The current viewport. + std::optional<DisplayViewport> mViewport; + + struct KeyDown { + int32_t keyCode; + int32_t scanCode; + }; + + uint32_t mSource; + int32_t mKeyboardType; + + std::vector<KeyDown> mKeyDowns; // keys that are down + int32_t mMetaState; + nsecs_t mDownTime; // time of most recent key down + + int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none + + struct LedState { + bool avail; // led is available + bool on; // we think the led is currently on + }; + LedState mCapsLockLedState; + LedState mNumLockLedState; + LedState mScrollLockLedState; + + // Immutable configuration parameters. + struct Parameters { + bool orientationAware; + bool handlesKeyRepeat; + } mParameters; + + void configureParameters(); + void dumpParameters(std::string& dump); + + int32_t getOrientation(); + int32_t getDisplayId(); + + bool isKeyboardOrGamepadKey(int32_t scanCode); + bool isMediaKey(int32_t keyCode); + + void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode); + + bool updateMetaStateIfNeeded(int32_t keyCode, bool down); + + ssize_t findKeyDown(int32_t scanCode); + + void resetLedState(); + void initializeLedState(LedState& ledState, int32_t led); + void updateLedState(bool reset); + void updateLedStateForModifier(LedState& ledState, int32_t led, + int32_t modifier, bool reset); +}; + + +class CursorInputMapper : public InputMapper { +public: + explicit CursorInputMapper(InputDevice* device); + virtual ~CursorInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + + virtual void fadePointer(); + + virtual std::optional<int32_t> getAssociatedDisplay(); +private: + // Amount that trackball needs to move in order to generate a key event. + static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; + + // Immutable configuration parameters. + struct Parameters { + enum Mode { + MODE_POINTER, + MODE_POINTER_RELATIVE, + MODE_NAVIGATION, + }; + + Mode mode; + bool hasAssociatedDisplay; + bool orientationAware; + } mParameters; + + CursorButtonAccumulator mCursorButtonAccumulator; + CursorMotionAccumulator mCursorMotionAccumulator; + CursorScrollAccumulator mCursorScrollAccumulator; + + int32_t mSource; + float mXScale; + float mYScale; + float mXPrecision; + float mYPrecision; + + float mVWheelScale; + float mHWheelScale; + + // Velocity controls for mouse pointer and wheel movements. + // The controls for X and Y wheel movements are separate to keep them decoupled. + VelocityControl mPointerVelocityControl; + VelocityControl mWheelXVelocityControl; + VelocityControl mWheelYVelocityControl; + + int32_t mOrientation; + + sp<PointerControllerInterface> mPointerController; + + int32_t mButtonState; + nsecs_t mDownTime; + + void configureParameters(); + void dumpParameters(std::string& dump); + + void sync(nsecs_t when); +}; + + +class RotaryEncoderInputMapper : public InputMapper { +public: + explicit RotaryEncoderInputMapper(InputDevice* device); + virtual ~RotaryEncoderInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + +private: + CursorScrollAccumulator mRotaryEncoderScrollAccumulator; + + int32_t mSource; + float mScalingFactor; + int32_t mOrientation; + + void sync(nsecs_t when); +}; + +class TouchInputMapper : public InputMapper { +public: + explicit TouchInputMapper(InputDevice* device); + virtual ~TouchInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + + virtual void fadePointer(); + virtual void cancelTouch(nsecs_t when); + virtual void timeoutExpired(nsecs_t when); + virtual void updateExternalStylusState(const StylusState& state); + virtual std::optional<int32_t> getAssociatedDisplay(); +protected: + CursorButtonAccumulator mCursorButtonAccumulator; + CursorScrollAccumulator mCursorScrollAccumulator; + TouchButtonAccumulator mTouchButtonAccumulator; + + struct VirtualKey { + int32_t keyCode; + int32_t scanCode; + uint32_t flags; + + // computed hit box, specified in touch screen coords based on known display size + int32_t hitLeft; + int32_t hitTop; + int32_t hitRight; + int32_t hitBottom; + + inline bool isHit(int32_t x, int32_t y) const { + return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; + } + }; + + // Input sources and device mode. + uint32_t mSource; + + enum DeviceMode { + DEVICE_MODE_DISABLED, // input is disabled + DEVICE_MODE_DIRECT, // direct mapping (touchscreen) + DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) + DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation) + DEVICE_MODE_POINTER, // pointer mapping (pointer) + }; + DeviceMode mDeviceMode; + + // The reader's configuration. + InputReaderConfiguration mConfig; + + // Immutable configuration parameters. + struct Parameters { + enum DeviceType { + DEVICE_TYPE_TOUCH_SCREEN, + DEVICE_TYPE_TOUCH_PAD, + DEVICE_TYPE_TOUCH_NAVIGATION, + DEVICE_TYPE_POINTER, + }; + + DeviceType deviceType; + bool hasAssociatedDisplay; + bool associatedDisplayIsExternal; + bool orientationAware; + bool hasButtonUnderPad; + std::string uniqueDisplayId; + + enum GestureMode { + GESTURE_MODE_SINGLE_TOUCH, + GESTURE_MODE_MULTI_TOUCH, + }; + GestureMode gestureMode; + + bool wake; + } mParameters; + + // Immutable calibration parameters in parsed form. + struct Calibration { + // Size + enum SizeCalibration { + SIZE_CALIBRATION_DEFAULT, + SIZE_CALIBRATION_NONE, + SIZE_CALIBRATION_GEOMETRIC, + SIZE_CALIBRATION_DIAMETER, + SIZE_CALIBRATION_BOX, + SIZE_CALIBRATION_AREA, + }; + + SizeCalibration sizeCalibration; + + bool haveSizeScale; + float sizeScale; + bool haveSizeBias; + float sizeBias; + bool haveSizeIsSummed; + bool sizeIsSummed; + + // Pressure + enum PressureCalibration { + PRESSURE_CALIBRATION_DEFAULT, + PRESSURE_CALIBRATION_NONE, + PRESSURE_CALIBRATION_PHYSICAL, + PRESSURE_CALIBRATION_AMPLITUDE, + }; + + PressureCalibration pressureCalibration; + bool havePressureScale; + float pressureScale; + + // Orientation + enum OrientationCalibration { + ORIENTATION_CALIBRATION_DEFAULT, + ORIENTATION_CALIBRATION_NONE, + ORIENTATION_CALIBRATION_INTERPOLATED, + ORIENTATION_CALIBRATION_VECTOR, + }; + + OrientationCalibration orientationCalibration; + + // Distance + enum DistanceCalibration { + DISTANCE_CALIBRATION_DEFAULT, + DISTANCE_CALIBRATION_NONE, + DISTANCE_CALIBRATION_SCALED, + }; + + DistanceCalibration distanceCalibration; + bool haveDistanceScale; + float distanceScale; + + enum CoverageCalibration { + COVERAGE_CALIBRATION_DEFAULT, + COVERAGE_CALIBRATION_NONE, + COVERAGE_CALIBRATION_BOX, + }; + + CoverageCalibration coverageCalibration; + + inline void applySizeScaleAndBias(float* outSize) const { + if (haveSizeScale) { + *outSize *= sizeScale; + } + if (haveSizeBias) { + *outSize += sizeBias; + } + if (*outSize < 0) { + *outSize = 0; + } + } + } mCalibration; + + // Affine location transformation/calibration + struct TouchAffineTransformation mAffineTransform; + + RawPointerAxes mRawPointerAxes; + + struct RawState { + nsecs_t when; + uint32_t deviceTimestamp; + + // Raw pointer sample data. + RawPointerData rawPointerData; + + int32_t buttonState; + + // Scroll state. + int32_t rawVScroll; + int32_t rawHScroll; + + void copyFrom(const RawState& other) { + when = other.when; + deviceTimestamp = other.deviceTimestamp; + rawPointerData.copyFrom(other.rawPointerData); + buttonState = other.buttonState; + rawVScroll = other.rawVScroll; + rawHScroll = other.rawHScroll; + } + + void clear() { + when = 0; + deviceTimestamp = 0; + rawPointerData.clear(); + buttonState = 0; + rawVScroll = 0; + rawHScroll = 0; + } + }; + + struct CookedState { + uint32_t deviceTimestamp; + // Cooked pointer sample data. + CookedPointerData cookedPointerData; + + // Id bits used to differentiate fingers, stylus and mouse tools. + BitSet32 fingerIdBits; + BitSet32 stylusIdBits; + BitSet32 mouseIdBits; + + int32_t buttonState; + + void copyFrom(const CookedState& other) { + deviceTimestamp = other.deviceTimestamp; + cookedPointerData.copyFrom(other.cookedPointerData); + fingerIdBits = other.fingerIdBits; + stylusIdBits = other.stylusIdBits; + mouseIdBits = other.mouseIdBits; + buttonState = other.buttonState; + } + + void clear() { + deviceTimestamp = 0; + cookedPointerData.clear(); + fingerIdBits.clear(); + stylusIdBits.clear(); + mouseIdBits.clear(); + buttonState = 0; + } + }; + + std::vector<RawState> mRawStatesPending; + RawState mCurrentRawState; + CookedState mCurrentCookedState; + RawState mLastRawState; + CookedState mLastCookedState; + + // State provided by an external stylus + StylusState mExternalStylusState; + int64_t mExternalStylusId; + nsecs_t mExternalStylusFusionTimeout; + bool mExternalStylusDataPending; + + // True if we sent a HOVER_ENTER event. + bool mSentHoverEnter; + + // Have we assigned pointer IDs for this stream + bool mHavePointerIds; + + // Is the current stream of direct touch events aborted + bool mCurrentMotionAborted; + + // The time the primary pointer last went down. + nsecs_t mDownTime; + + // The pointer controller, or null if the device is not a pointer. + sp<PointerControllerInterface> mPointerController; + + std::vector<VirtualKey> mVirtualKeys; + + virtual void configureParameters(); + virtual void dumpParameters(std::string& dump); + virtual void configureRawPointerAxes(); + virtual void dumpRawPointerAxes(std::string& dump); + virtual void configureSurface(nsecs_t when, bool* outResetNeeded); + virtual void dumpSurface(std::string& dump); + virtual void configureVirtualKeys(); + virtual void dumpVirtualKeys(std::string& dump); + virtual void parseCalibration(); + virtual void resolveCalibration(); + virtual void dumpCalibration(std::string& dump); + virtual void updateAffineTransformation(); + virtual void dumpAffineTransformation(std::string& dump); + virtual void resolveExternalStylusPresence(); + virtual bool hasStylus() const = 0; + virtual bool hasExternalStylus() const; + + virtual void syncTouch(nsecs_t when, RawState* outState) = 0; + +private: + // The current viewport. + // The components of the viewport are specified in the display's rotated orientation. + DisplayViewport mViewport; + + // The surface orientation, width and height set by configureSurface(). + // The width and height are derived from the viewport but are specified + // in the natural orientation. + // The surface origin specifies how the surface coordinates should be translated + // to align with the logical display coordinate space. + int32_t mSurfaceWidth; + int32_t mSurfaceHeight; + int32_t mSurfaceLeft; + int32_t mSurfaceTop; + + // Similar to the surface coordinates, but in the raw display coordinate space rather than in + // the logical coordinate space. + int32_t mPhysicalWidth; + int32_t mPhysicalHeight; + int32_t mPhysicalLeft; + int32_t mPhysicalTop; + + // The orientation may be different from the viewport orientation as it specifies + // the rotation of the surface coordinates required to produce the viewport's + // requested orientation, so it will depend on whether the device is orientation aware. + int32_t mSurfaceOrientation; + + // Translation and scaling factors, orientation-independent. + float mXTranslate; + float mXScale; + float mXPrecision; + + float mYTranslate; + float mYScale; + float mYPrecision; + + float mGeometricScale; + + float mPressureScale; + + float mSizeScale; + + float mOrientationScale; + + float mDistanceScale; + + bool mHaveTilt; + float mTiltXCenter; + float mTiltXScale; + float mTiltYCenter; + float mTiltYScale; + + bool mExternalStylusConnected; + + // Oriented motion ranges for input device info. + struct OrientedRanges { + InputDeviceInfo::MotionRange x; + InputDeviceInfo::MotionRange y; + InputDeviceInfo::MotionRange pressure; + + bool haveSize; + InputDeviceInfo::MotionRange size; + + bool haveTouchSize; + InputDeviceInfo::MotionRange touchMajor; + InputDeviceInfo::MotionRange touchMinor; + + bool haveToolSize; + InputDeviceInfo::MotionRange toolMajor; + InputDeviceInfo::MotionRange toolMinor; + + bool haveOrientation; + InputDeviceInfo::MotionRange orientation; + + bool haveDistance; + InputDeviceInfo::MotionRange distance; + + bool haveTilt; + InputDeviceInfo::MotionRange tilt; + + OrientedRanges() { + clear(); + } + + void clear() { + haveSize = false; + haveTouchSize = false; + haveToolSize = false; + haveOrientation = false; + haveDistance = false; + haveTilt = false; + } + } mOrientedRanges; + + // Oriented dimensions and precision. + float mOrientedXPrecision; + float mOrientedYPrecision; + + struct CurrentVirtualKeyState { + bool down; + bool ignored; + nsecs_t downTime; + int32_t keyCode; + int32_t scanCode; + } mCurrentVirtualKey; + + // Scale factor for gesture or mouse based pointer movements. + float mPointerXMovementScale; + float mPointerYMovementScale; + + // Scale factor for gesture based zooming and other freeform motions. + float mPointerXZoomScale; + float mPointerYZoomScale; + + // The maximum swipe width. + float mPointerGestureMaxSwipeWidth; + + struct PointerDistanceHeapElement { + uint32_t currentPointerIndex : 8; + uint32_t lastPointerIndex : 8; + uint64_t distance : 48; // squared distance + }; + + enum PointerUsage { + POINTER_USAGE_NONE, + POINTER_USAGE_GESTURES, + POINTER_USAGE_STYLUS, + POINTER_USAGE_MOUSE, + }; + PointerUsage mPointerUsage; + + struct PointerGesture { + enum Mode { + // No fingers, button is not pressed. + // Nothing happening. + NEUTRAL, + + // No fingers, button is not pressed. + // Tap detected. + // Emits DOWN and UP events at the pointer location. + TAP, + + // Exactly one finger dragging following a tap. + // Pointer follows the active finger. + // Emits DOWN, MOVE and UP events at the pointer location. + // + // Detect double-taps when the finger goes up while in TAP_DRAG mode. + TAP_DRAG, + + // Button is pressed. + // Pointer follows the active finger if there is one. Other fingers are ignored. + // Emits DOWN, MOVE and UP events at the pointer location. + BUTTON_CLICK_OR_DRAG, + + // Exactly one finger, button is not pressed. + // Pointer follows the active finger. + // Emits HOVER_MOVE events at the pointer location. + // + // Detect taps when the finger goes up while in HOVER mode. + HOVER, + + // Exactly two fingers but neither have moved enough to clearly indicate + // whether a swipe or freeform gesture was intended. We consider the + // pointer to be pressed so this enables clicking or long-pressing on buttons. + // Pointer does not move. + // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate. + PRESS, + + // Exactly two fingers moving in the same direction, button is not pressed. + // Pointer does not move. + // Emits DOWN, MOVE and UP events with a single pointer coordinate that + // follows the midpoint between both fingers. + SWIPE, + + // Two or more fingers moving in arbitrary directions, button is not pressed. + // Pointer does not move. + // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow + // each finger individually relative to the initial centroid of the finger. + FREEFORM, + + // Waiting for quiet time to end before starting the next gesture. + QUIET, + }; + + // Time the first finger went down. + nsecs_t firstTouchTime; + + // The active pointer id from the raw touch data. + int32_t activeTouchId; // -1 if none + + // The active pointer id from the gesture last delivered to the application. + int32_t activeGestureId; // -1 if none + + // Pointer coords and ids for the current and previous pointer gesture. + Mode currentGestureMode; + BitSet32 currentGestureIdBits; + uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; + PointerProperties currentGestureProperties[MAX_POINTERS]; + PointerCoords currentGestureCoords[MAX_POINTERS]; + + Mode lastGestureMode; + BitSet32 lastGestureIdBits; + uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; + PointerProperties lastGestureProperties[MAX_POINTERS]; + PointerCoords lastGestureCoords[MAX_POINTERS]; + + // Time the pointer gesture last went down. + nsecs_t downTime; + + // Time when the pointer went down for a TAP. + nsecs_t tapDownTime; + + // Time when the pointer went up for a TAP. + nsecs_t tapUpTime; + + // Location of initial tap. + float tapX, tapY; + + // Time we started waiting for quiescence. + nsecs_t quietTime; + + // Reference points for multitouch gestures. + float referenceTouchX; // reference touch X/Y coordinates in surface units + float referenceTouchY; + float referenceGestureX; // reference gesture X/Y coordinates in pixels + float referenceGestureY; + + // Distance that each pointer has traveled which has not yet been + // subsumed into the reference gesture position. + BitSet32 referenceIdBits; + struct Delta { + float dx, dy; + }; + Delta referenceDeltas[MAX_POINTER_ID + 1]; + + // Describes how touch ids are mapped to gesture ids for freeform gestures. + uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1]; + + // A velocity tracker for determining whether to switch active pointers during drags. + VelocityTracker velocityTracker; + + void reset() { + firstTouchTime = LLONG_MIN; + activeTouchId = -1; + activeGestureId = -1; + currentGestureMode = NEUTRAL; + currentGestureIdBits.clear(); + lastGestureMode = NEUTRAL; + lastGestureIdBits.clear(); + downTime = 0; + velocityTracker.clear(); + resetTap(); + resetQuietTime(); + } + + void resetTap() { + tapDownTime = LLONG_MIN; + tapUpTime = LLONG_MIN; + } + + void resetQuietTime() { + quietTime = LLONG_MIN; + } + } mPointerGesture; + + struct PointerSimple { + PointerCoords currentCoords; + PointerProperties currentProperties; + PointerCoords lastCoords; + PointerProperties lastProperties; + + // True if the pointer is down. + bool down; + + // True if the pointer is hovering. + bool hovering; + + // Time the pointer last went down. + nsecs_t downTime; + + void reset() { + currentCoords.clear(); + currentProperties.clear(); + lastCoords.clear(); + lastProperties.clear(); + down = false; + hovering = false; + downTime = 0; + } + } mPointerSimple; + + // The pointer and scroll velocity controls. + VelocityControl mPointerVelocityControl; + VelocityControl mWheelXVelocityControl; + VelocityControl mWheelYVelocityControl; + + // Latency statistics for touch events + struct LatencyStatistics mStatistics; + + std::optional<DisplayViewport> findViewport(); + + void resetExternalStylus(); + void clearStylusDataPendingFlags(); + + void sync(nsecs_t when); + + bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); + void processRawTouches(bool timeout); + void cookAndDispatch(nsecs_t when); + void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, + int32_t keyEventAction, int32_t keyEventFlags); + + void dispatchTouches(nsecs_t when, uint32_t policyFlags); + void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); + void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); + void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags); + void dispatchButtonPress(nsecs_t when, uint32_t policyFlags); + const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData); + void cookPointerData(); + void abortTouches(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); + void abortPointerUsage(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); + void abortPointerGestures(nsecs_t when, uint32_t policyFlags); + bool preparePointerGestures(nsecs_t when, + bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, + bool isTimeout); + + void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); + void abortPointerStylus(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); + void abortPointerMouse(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, + bool down, bool hovering); + void abortPointerSimple(nsecs_t when, uint32_t policyFlags); + + bool assignExternalStylusId(const RawState& state, bool timeout); + void applyExternalStylusButtonState(nsecs_t when); + void applyExternalStylusTouchState(nsecs_t when); + + // Dispatches a motion event. + // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the + // method will take care of setting the index and transmuting the action to DOWN or UP + // it is the first / last pointer to go down / up. + void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, + int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, + uint32_t deviceTimestamp, + const PointerProperties* properties, const PointerCoords* coords, + const uint32_t* idToIndex, BitSet32 idBits, + int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); + + // Updates pointer coords and properties for pointers with specified ids that have moved. + // Returns true if any of them changed. + bool updateMovedPointers(const PointerProperties* inProperties, + const PointerCoords* inCoords, const uint32_t* inIdToIndex, + PointerProperties* outProperties, PointerCoords* outCoords, + const uint32_t* outIdToIndex, BitSet32 idBits) const; + + bool isPointInsideSurface(int32_t x, int32_t y); + const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); + + static void assignPointerIds(const RawState* last, RawState* current); + + void reportEventForStatistics(nsecs_t evdevTime); + + const char* modeToString(DeviceMode deviceMode); +}; + + +class SingleTouchInputMapper : public TouchInputMapper { +public: + explicit SingleTouchInputMapper(InputDevice* device); + virtual ~SingleTouchInputMapper(); + + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + +protected: + virtual void syncTouch(nsecs_t when, RawState* outState); + virtual void configureRawPointerAxes(); + virtual bool hasStylus() const; + +private: + SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; +}; + + +class MultiTouchInputMapper : public TouchInputMapper { +public: + explicit MultiTouchInputMapper(InputDevice* device); + virtual ~MultiTouchInputMapper(); + + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + +protected: + virtual void syncTouch(nsecs_t when, RawState* outState); + virtual void configureRawPointerAxes(); + virtual bool hasStylus() const; + +private: + MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; + + // Specifies the pointer id bits that are in use, and their associated tracking id. + BitSet32 mPointerIdBits; + int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; +}; + +class ExternalStylusInputMapper : public InputMapper { +public: + explicit ExternalStylusInputMapper(InputDevice* device); + virtual ~ExternalStylusInputMapper() = default; + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + virtual void sync(nsecs_t when); + +private: + SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; + RawAbsoluteAxisInfo mRawPressureAxis; + TouchButtonAccumulator mTouchButtonAccumulator; + + StylusState mStylusState; +}; + + +class JoystickInputMapper : public InputMapper { +public: + explicit JoystickInputMapper(InputDevice* device); + virtual ~JoystickInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + +private: + struct Axis { + RawAbsoluteAxisInfo rawAxisInfo; + AxisInfo axisInfo; + + bool explicitlyMapped; // true if the axis was explicitly assigned an axis id + + float scale; // scale factor from raw to normalized values + float offset; // offset to add after scaling for normalization + float highScale; // scale factor from raw to normalized values of high split + float highOffset; // offset to add after scaling for normalization of high split + + float min; // normalized inclusive minimum + float max; // normalized inclusive maximum + float flat; // normalized flat region size + float fuzz; // normalized error tolerance + float resolution; // normalized resolution in units/mm + + float filter; // filter out small variations of this size + float currentValue; // current value + float newValue; // most recent value + float highCurrentValue; // current value of high split + float highNewValue; // most recent value of high split + + void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, + bool explicitlyMapped, float scale, float offset, + float highScale, float highOffset, + float min, float max, float flat, float fuzz, float resolution) { + this->rawAxisInfo = rawAxisInfo; + this->axisInfo = axisInfo; + this->explicitlyMapped = explicitlyMapped; + this->scale = scale; + this->offset = offset; + this->highScale = highScale; + this->highOffset = highOffset; + this->min = min; + this->max = max; + this->flat = flat; + this->fuzz = fuzz; + this->resolution = resolution; + this->filter = 0; + resetValue(); + } + + void resetValue() { + this->currentValue = 0; + this->newValue = 0; + this->highCurrentValue = 0; + this->highNewValue = 0; + } + }; + + // Axes indexed by raw ABS_* axis index. + KeyedVector<int32_t, Axis> mAxes; + + void sync(nsecs_t when, bool force); + + bool haveAxis(int32_t axisId); + void pruneAxes(bool ignoreExplicitlyMappedAxes); + bool filterAxes(bool force); + + static bool hasValueChangedSignificantly(float filter, + float newValue, float currentValue, float min, float max); + static bool hasMovedNearerToValueWithinFilteredRange(float filter, + float newValue, float currentValue, float thresholdValue); + + static bool isCenteredAxis(int32_t axis); + static int32_t getCompatAxis(int32_t axis); + + static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info); + static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, + float value); +}; + +} // namespace android + +#endif // _UI_INPUT_READER_H diff --git a/services/inputflinger/reader/InputReaderFactory.cpp b/services/inputflinger/InputReaderFactory.cpp index 9f73680913..3534f6b760 100644 --- a/services/inputflinger/reader/InputReaderFactory.cpp +++ b/services/inputflinger/InputReaderFactory.cpp @@ -15,13 +15,13 @@ */ #include "InputReaderFactory.h" - #include "InputReader.h" namespace android { -sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener) { +sp<InputReaderInterface> createInputReader( + const sp<InputReaderPolicyInterface>& policy, + const sp<InputListenerInterface>& listener) { return new InputReader(new EventHub(), policy, listener); } diff --git a/services/inputflinger/reporter/InputReporter.cpp b/services/inputflinger/InputReporter.cpp index b591d3f909..8d3153c367 100644 --- a/services/inputflinger/reporter/InputReporter.cpp +++ b/services/inputflinger/InputReporter.cpp @@ -27,15 +27,15 @@ public: }; void InputReporter::reportUnhandledKey(uint32_t sequenceNum) { - // do nothing + // do nothing } void InputReporter::reportDroppedKey(uint32_t sequenceNum) { - // do nothing + // do nothing } sp<InputReporterInterface> createInputReporter() { - return new InputReporter(); + return new InputReporter(); } } // namespace android diff --git a/services/inputflinger/reader/TouchVideoDevice.cpp b/services/inputflinger/TouchVideoDevice.cpp index c075078528..19c1313dcd 100644 --- a/services/inputflinger/reader/TouchVideoDevice.cpp +++ b/services/inputflinger/TouchVideoDevice.cpp @@ -37,13 +37,10 @@ using android::base::unique_fd; namespace android { TouchVideoDevice::TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath, - uint32_t height, uint32_t width, - const std::array<const int16_t*, NUM_BUFFERS>& readLocations) - : mFd(fd), - mName(std::move(name)), - mPath(std::move(devicePath)), - mHeight(height), - mWidth(width), + uint32_t height, uint32_t width, + const std::array<const int16_t*, NUM_BUFFERS>& readLocations) : + mFd(fd), mName(std::move(name)), mPath(std::move(devicePath)), + mHeight(height), mWidth(width), mReadLocations(readLocations) { mFrames.reserve(MAX_QUEUE_SIZE); }; @@ -63,11 +60,11 @@ std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePat } if (!(cap.capabilities & V4L2_CAP_TOUCH)) { ALOGE("Capability V4L2_CAP_TOUCH is not present, can't use device for heatmap data. " - "Make sure device specifies V4L2_CAP_TOUCH"); + "Make sure device specifies V4L2_CAP_TOUCH"); return nullptr; } - ALOGI("Opening video device: driver = %s, card = %s, bus_info = %s, version = %i", cap.driver, - cap.card, cap.bus_info, cap.version); + ALOGI("Opening video device: driver = %s, card = %s, bus_info = %s, version = %i", + cap.driver, cap.card, cap.bus_info, cap.version); std::string name = reinterpret_cast<const char*>(cap.card); struct v4l2_input v4l2_input_struct; @@ -80,7 +77,7 @@ std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePat if (v4l2_input_struct.type != V4L2_INPUT_TYPE_TOUCH) { ALOGE("Video device does not provide touch data. " - "Make sure device specifies V4L2_INPUT_TYPE_TOUCH."); + "Make sure device specifies V4L2_INPUT_TYPE_TOUCH."); return nullptr; } @@ -123,14 +120,14 @@ std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePat return nullptr; } if (buf.length != height * width * sizeof(int16_t)) { - ALOGE("Unexpected value of buf.length = %i (offset = %" PRIu32 ")", buf.length, - buf.m.offset); + ALOGE("Unexpected value of buf.length = %i (offset = %" PRIu32 ")", + buf.length, buf.m.offset); return nullptr; } - readLocations[i] = static_cast<const int16_t*>( - mmap(nullptr /* start anywhere */, buf.length, PROT_READ /* required */, - MAP_SHARED /* recommended */, fd.get(), buf.m.offset)); + readLocations[i] = static_cast<const int16_t*>(mmap(nullptr /* start anywhere */, + buf.length, PROT_READ /* required */, MAP_SHARED /* recommended */, + fd.get(), buf.m.offset)); if (readLocations[i] == MAP_FAILED) { ALOGE("%s: map failed: %s", __func__, strerror(errno)); return nullptr; @@ -153,9 +150,8 @@ std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePat } } // Using 'new' to access a non-public constructor. - return std::unique_ptr<TouchVideoDevice>(new TouchVideoDevice(fd.release(), std::move(name), - std::move(devicePath), height, - width, readLocations)); + return std::unique_ptr<TouchVideoDevice>(new TouchVideoDevice( + fd.release(), std::move(name), std::move(devicePath), height, width, readLocations)); } size_t TouchVideoDevice::readAndQueueFrames() { @@ -167,10 +163,10 @@ size_t TouchVideoDevice::readAndQueueFrames() { } // Concatenate the vectors, then clip up to maximum size allowed mFrames.insert(mFrames.end(), std::make_move_iterator(frames.begin()), - std::make_move_iterator(frames.end())); + std::make_move_iterator(frames.end())); if (mFrames.size() > MAX_QUEUE_SIZE) { ALOGE("More than %zu frames have been accumulated. Dropping %zu frames", MAX_QUEUE_SIZE, - mFrames.size() - MAX_QUEUE_SIZE); + mFrames.size() - MAX_QUEUE_SIZE); mFrames.erase(mFrames.begin(), mFrames.end() - MAX_QUEUE_SIZE); } return numFrames; @@ -197,8 +193,8 @@ std::optional<TouchVideoFrame> TouchVideoDevice::readFrame() { if ((buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) != V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) { // We use CLOCK_MONOTONIC for input events, so if the clocks don't match, // we can't compare timestamps. Just log a warning, since this is a driver issue - ALOGW("The timestamp %ld.%ld was not acquired using CLOCK_MONOTONIC", buf.timestamp.tv_sec, - buf.timestamp.tv_usec); + ALOGW("The timestamp %ld.%ld was not acquired using CLOCK_MONOTONIC", + buf.timestamp.tv_sec, buf.timestamp.tv_usec); } std::vector<int16_t> data(mHeight * mWidth); const int16_t* readFrom = mReadLocations[buf.index]; @@ -237,7 +233,7 @@ TouchVideoDevice::~TouchVideoDevice() { } for (const int16_t* buffer : mReadLocations) { void* bufferAddress = static_cast<void*>(const_cast<int16_t*>(buffer)); - result = munmap(bufferAddress, mHeight * mWidth * sizeof(int16_t)); + result = munmap(bufferAddress, mHeight * mWidth * sizeof(int16_t)); if (result == -1) { ALOGE("%s: Couldn't unmap: [%s]", __func__, strerror(errno)); } @@ -246,9 +242,9 @@ TouchVideoDevice::~TouchVideoDevice() { std::string TouchVideoDevice::dump() const { return StringPrintf("Video device %s (%s) : height=%" PRIu32 ", width=%" PRIu32 - ", fd=%i, hasValidFd=%s", - mName.c_str(), mPath.c_str(), mHeight, mWidth, mFd.get(), - hasValidFd() ? "true" : "false"); + ", fd=%i, hasValidFd=%s", + mName.c_str(), mPath.c_str(), mHeight, mWidth, mFd.get(), + hasValidFd() ? "true" : "false"); } } // namespace android diff --git a/services/inputflinger/reader/include/TouchVideoDevice.h b/services/inputflinger/TouchVideoDevice.h index 5a32443f29..0e7e2ef496 100644 --- a/services/inputflinger/reader/include/TouchVideoDevice.h +++ b/services/inputflinger/TouchVideoDevice.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#ifndef _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H -#define _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H +#ifndef _INPUTFLINGER_TOUCH_VIDEO_DEVICE_H +#define _INPUTFLINGER_TOUCH_VIDEO_DEVICE_H +#include <array> #include <android-base/unique_fd.h> #include <input/TouchVideoFrame.h> -#include <stdint.h> -#include <array> #include <optional> +#include <stdint.h> #include <string> #include <vector> @@ -109,9 +109,9 @@ private: * The constructor is private because opening a v4l2 device requires many checks. * To get a new TouchVideoDevice, use 'create' instead. */ - explicit TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath, uint32_t height, - uint32_t width, - const std::array<const int16_t*, NUM_BUFFERS>& readLocations); + explicit TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath, + uint32_t height, uint32_t width, + const std::array<const int16_t*, NUM_BUFFERS>& readLocations); /** * Read all currently available frames. */ @@ -121,7 +121,5 @@ private: */ std::optional<TouchVideoFrame> readFrame(); }; - } // namespace android - -#endif // _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H +#endif //_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp deleted file mode 100644 index b8c3a808f1..0000000000 --- a/services/inputflinger/dispatcher/Android.bp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -cc_library_static { - name: "libinputdispatcher", - defaults: ["inputflinger_defaults"], - srcs: [ - "Connection.cpp", - "Entry.cpp", - "InjectionState.cpp", - "InputDispatcher.cpp", - "InputDispatcherFactory.cpp", - "InputDispatcherThread.cpp", - "InputState.cpp", - "InputTarget.cpp", - "Monitor.cpp", - "TouchState.cpp" - ], - shared_libs: [ - "libbase", - "libcutils", - "libinput", - "libinputreporter", - "libinputflinger_base", - "liblog", - "libui", - "libutils", - ], - - export_include_dirs: ["include"], -} diff --git a/services/inputflinger/dispatcher/CancelationOptions.h b/services/inputflinger/dispatcher/CancelationOptions.h deleted file mode 100644 index 99e2108dbf..0000000000 --- a/services/inputflinger/dispatcher/CancelationOptions.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H -#define _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H - -#include <optional> - -namespace android::inputdispatcher { - -/* Specifies which events are to be canceled and why. */ -struct CancelationOptions { - enum Mode { - CANCEL_ALL_EVENTS = 0, - CANCEL_POINTER_EVENTS = 1, - CANCEL_NON_POINTER_EVENTS = 2, - CANCEL_FALLBACK_EVENTS = 3, - }; - - // The criterion to use to determine which events should be canceled. - Mode mode; - - // Descriptive reason for the cancelation. - const char* reason; - - // The specific keycode of the key event to cancel, or nullopt to cancel any key event. - std::optional<int32_t> keyCode = std::nullopt; - - // The specific device id of events to cancel, or nullopt to cancel events from any device. - std::optional<int32_t> deviceId = std::nullopt; - - // The specific display id of events to cancel, or nullopt to cancel events on any display. - std::optional<int32_t> displayId = std::nullopt; - - CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) {} -}; - -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp deleted file mode 100644 index ef7f6509e4..0000000000 --- a/services/inputflinger/dispatcher/Connection.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2019 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 "Connection.h" - -#include "Entry.h" - -namespace android::inputdispatcher { - -Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor) - : status(STATUS_NORMAL), - inputChannel(inputChannel), - monitor(monitor), - inputPublisher(inputChannel), - inputPublisherBlocked(false) {} - -Connection::~Connection() {} - -const std::string Connection::getWindowName() const { - if (inputChannel != nullptr) { - return inputChannel->getName(); - } - if (monitor) { - return "monitor"; - } - return "?"; -} - -const char* Connection::getStatusLabel() const { - switch (status) { - case STATUS_NORMAL: - return "NORMAL"; - case STATUS_BROKEN: - return "BROKEN"; - case STATUS_ZOMBIE: - return "ZOMBIE"; - default: - return "UNKNOWN"; - } -} - -DispatchEntry* Connection::findWaitQueueEntry(uint32_t seq) { - for (DispatchEntry* entry = waitQueue.head; entry != nullptr; entry = entry->next) { - if (entry->seq == seq) { - return entry; - } - } - return nullptr; -} - -} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h deleted file mode 100644 index ed4eebdff4..0000000000 --- a/services/inputflinger/dispatcher/Connection.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_CONNECTION_H -#define _UI_INPUT_INPUTDISPATCHER_CONNECTION_H - -#include "InputState.h" -#include "Queue.h" - -#include <input/InputTransport.h> -#include <deque> - -namespace android::inputdispatcher { - -struct DispatchEntry; - -/* Manages the dispatch state associated with a single input channel. */ -class Connection : public RefBase { -protected: - virtual ~Connection(); - -public: - enum Status { - // Everything is peachy. - STATUS_NORMAL, - // An unrecoverable communication error has occurred. - STATUS_BROKEN, - // The input channel has been unregistered. - STATUS_ZOMBIE - }; - - Status status; - sp<InputChannel> inputChannel; // never null - bool monitor; - InputPublisher inputPublisher; - InputState inputState; - - // True if the socket is full and no further events can be published until - // the application consumes some of the input. - bool inputPublisherBlocked; - - // Queue of events that need to be published to the connection. - Queue<DispatchEntry> outboundQueue; - - // Queue of events that have been published to the connection but that have not - // yet received a "finished" response from the application. - Queue<DispatchEntry> waitQueue; - - explicit Connection(const sp<InputChannel>& inputChannel, bool monitor); - - inline const std::string getInputChannelName() const { return inputChannel->getName(); } - - const std::string getWindowName() const; - const char* getStatusLabel() const; - - DispatchEntry* findWaitQueueEntry(uint32_t seq); -}; - -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_CONNECTION_H diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp deleted file mode 100644 index 8d05640b38..0000000000 --- a/services/inputflinger/dispatcher/Entry.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2019 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 "Entry.h" - -#include "Connection.h" - -#include <android-base/stringprintf.h> -#include <cutils/atomic.h> -#include <inttypes.h> - -using android::base::StringPrintf; - -namespace android::inputdispatcher { - -static std::string motionActionToString(int32_t action) { - // Convert MotionEvent action to string - switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - return "DOWN"; - case AMOTION_EVENT_ACTION_MOVE: - return "MOVE"; - case AMOTION_EVENT_ACTION_UP: - return "UP"; - case AMOTION_EVENT_ACTION_POINTER_DOWN: - return "POINTER_DOWN"; - case AMOTION_EVENT_ACTION_POINTER_UP: - return "POINTER_UP"; - } - return StringPrintf("%" PRId32, action); -} - -static std::string keyActionToString(int32_t action) { - // Convert KeyEvent action to string - switch (action) { - case AKEY_EVENT_ACTION_DOWN: - return "DOWN"; - case AKEY_EVENT_ACTION_UP: - return "UP"; - case AKEY_EVENT_ACTION_MULTIPLE: - return "MULTIPLE"; - } - return StringPrintf("%" PRId32, action); -} - -// --- EventEntry --- - -EventEntry::EventEntry(uint32_t sequenceNum, int32_t type, nsecs_t eventTime, uint32_t policyFlags) - : sequenceNum(sequenceNum), - refCount(1), - type(type), - eventTime(eventTime), - policyFlags(policyFlags), - injectionState(nullptr), - dispatchInProgress(false) {} - -EventEntry::~EventEntry() { - releaseInjectionState(); -} - -void EventEntry::release() { - refCount -= 1; - if (refCount == 0) { - delete this; - } else { - ALOG_ASSERT(refCount > 0); - } -} - -void EventEntry::releaseInjectionState() { - if (injectionState) { - injectionState->release(); - injectionState = nullptr; - } -} - -// --- ConfigurationChangedEntry --- - -ConfigurationChangedEntry::ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime) - : EventEntry(sequenceNum, TYPE_CONFIGURATION_CHANGED, eventTime, 0) {} - -ConfigurationChangedEntry::~ConfigurationChangedEntry() {} - -void ConfigurationChangedEntry::appendDescription(std::string& msg) const { - msg += StringPrintf("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags); -} - -// --- DeviceResetEntry --- - -DeviceResetEntry::DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId) - : EventEntry(sequenceNum, TYPE_DEVICE_RESET, eventTime, 0), deviceId(deviceId) {} - -DeviceResetEntry::~DeviceResetEntry() {} - -void DeviceResetEntry::appendDescription(std::string& msg) const { - msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", deviceId, policyFlags); -} - -// --- KeyEntry --- - -KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, - nsecs_t downTime) - : EventEntry(sequenceNum, TYPE_KEY, eventTime, policyFlags), - deviceId(deviceId), - source(source), - displayId(displayId), - action(action), - flags(flags), - keyCode(keyCode), - scanCode(scanCode), - metaState(metaState), - repeatCount(repeatCount), - downTime(downTime), - syntheticRepeat(false), - interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), - interceptKeyWakeupTime(0) {} - -KeyEntry::~KeyEntry() {} - -void KeyEntry::appendDescription(std::string& msg) const { - msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, " - "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, " - "repeatCount=%d), policyFlags=0x%08x", - deviceId, source, displayId, keyActionToString(action).c_str(), flags, - keyCode, scanCode, metaState, repeatCount, policyFlags); -} - -void KeyEntry::recycle() { - releaseInjectionState(); - - dispatchInProgress = false; - syntheticRepeat = false; - interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; - interceptKeyWakeupTime = 0; -} - -// --- MotionEntry --- - -MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, int32_t action, - int32_t actionButton, int32_t flags, int32_t metaState, - int32_t buttonState, MotionClassification classification, - int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, - uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xOffset, float yOffset) - : EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags), - eventTime(eventTime), - deviceId(deviceId), - source(source), - displayId(displayId), - action(action), - actionButton(actionButton), - flags(flags), - metaState(metaState), - buttonState(buttonState), - classification(classification), - edgeFlags(edgeFlags), - xPrecision(xPrecision), - yPrecision(yPrecision), - downTime(downTime), - pointerCount(pointerCount) { - for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i].copyFrom(pointerProperties[i]); - this->pointerCoords[i].copyFrom(pointerCoords[i]); - if (xOffset || yOffset) { - this->pointerCoords[i].applyOffset(xOffset, yOffset); - } - } -} - -MotionEntry::~MotionEntry() {} - -void MotionEntry::appendDescription(std::string& msg) const { - msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 - ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, " - "buttonState=0x%08x, " - "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, " - "pointers=[", - deviceId, source, displayId, motionActionToString(action).c_str(), - actionButton, flags, metaState, buttonState, - motionClassificationToString(classification), edgeFlags, xPrecision, - yPrecision); - - for (uint32_t i = 0; i < pointerCount; i++) { - if (i) { - msg += ", "; - } - msg += StringPrintf("%d: (%.1f, %.1f)", pointerProperties[i].id, pointerCoords[i].getX(), - pointerCoords[i].getY()); - } - msg += StringPrintf("]), policyFlags=0x%08x", policyFlags); -} - -// --- DispatchEntry --- - -volatile int32_t DispatchEntry::sNextSeqAtomic; - -DispatchEntry::DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset, - float yOffset, float globalScaleFactor, float windowXScale, - float windowYScale) - : seq(nextSeq()), - eventEntry(eventEntry), - targetFlags(targetFlags), - xOffset(xOffset), - yOffset(yOffset), - globalScaleFactor(globalScaleFactor), - windowXScale(windowXScale), - windowYScale(windowYScale), - deliveryTime(0), - resolvedAction(0), - resolvedFlags(0) { - eventEntry->refCount += 1; -} - -DispatchEntry::~DispatchEntry() { - eventEntry->release(); -} - -uint32_t DispatchEntry::nextSeq() { - // Sequence number 0 is reserved and will never be returned. - uint32_t seq; - do { - seq = android_atomic_inc(&sNextSeqAtomic); - } while (!seq); - return seq; -} - -// --- CommandEntry --- - -CommandEntry::CommandEntry(Command command) - : command(command), - eventTime(0), - keyEntry(nullptr), - userActivityEventType(0), - seq(0), - handled(false) {} - -CommandEntry::~CommandEntry() {} - -} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h deleted file mode 100644 index b904caf671..0000000000 --- a/services/inputflinger/dispatcher/Entry.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_ENTRY_H -#define _UI_INPUT_INPUTDISPATCHER_ENTRY_H - -#include "InjectionState.h" -#include "InputTarget.h" - -#include <input/Input.h> -#include <input/InputApplication.h> -#include <stdint.h> -#include <utils/Timers.h> -#include <functional> -#include <string> - -namespace android::inputdispatcher { - -template <typename T> -struct Link { - T* next; - T* prev; - -protected: - inline Link() : next(nullptr), prev(nullptr) {} -}; - -struct EventEntry : Link<EventEntry> { - enum { TYPE_CONFIGURATION_CHANGED, TYPE_DEVICE_RESET, TYPE_KEY, TYPE_MOTION }; - - uint32_t sequenceNum; - mutable int32_t refCount; - int32_t type; - nsecs_t eventTime; - uint32_t policyFlags; - InjectionState* injectionState; - - bool dispatchInProgress; // initially false, set to true while dispatching - - inline bool isInjected() const { return injectionState != nullptr; } - - void release(); - - virtual void appendDescription(std::string& msg) const = 0; - -protected: - EventEntry(uint32_t sequenceNum, int32_t type, nsecs_t eventTime, uint32_t policyFlags); - virtual ~EventEntry(); - void releaseInjectionState(); -}; - -struct ConfigurationChangedEntry : EventEntry { - explicit ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime); - virtual void appendDescription(std::string& msg) const; - -protected: - virtual ~ConfigurationChangedEntry(); -}; - -struct DeviceResetEntry : EventEntry { - int32_t deviceId; - - DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId); - virtual void appendDescription(std::string& msg) const; - -protected: - virtual ~DeviceResetEntry(); -}; - -struct KeyEntry : EventEntry { - int32_t deviceId; - uint32_t source; - int32_t displayId; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t repeatCount; - nsecs_t downTime; - - bool syntheticRepeat; // set to true for synthetic key repeats - - enum InterceptKeyResult { - INTERCEPT_KEY_RESULT_UNKNOWN, - INTERCEPT_KEY_RESULT_SKIP, - INTERCEPT_KEY_RESULT_CONTINUE, - INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER, - }; - InterceptKeyResult interceptKeyResult; // set based on the interception result - nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER - - KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, - nsecs_t downTime); - virtual void appendDescription(std::string& msg) const; - void recycle(); - -protected: - virtual ~KeyEntry(); -}; - -struct MotionEntry : EventEntry { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - int32_t displayId; - int32_t action; - int32_t actionButton; - int32_t flags; - int32_t metaState; - int32_t buttonState; - MotionClassification classification; - int32_t edgeFlags; - float xPrecision; - float yPrecision; - nsecs_t downTime; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - - MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, - int32_t flags, int32_t metaState, int32_t buttonState, - MotionClassification classification, int32_t edgeFlags, float xPrecision, - float yPrecision, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset); - virtual void appendDescription(std::string& msg) const; - -protected: - virtual ~MotionEntry(); -}; - -// Tracks the progress of dispatching a particular event to a particular connection. -struct DispatchEntry : Link<DispatchEntry> { - const uint32_t seq; // unique sequence number, never 0 - - EventEntry* eventEntry; // the event to dispatch - int32_t targetFlags; - float xOffset; - float yOffset; - float globalScaleFactor; - float windowXScale = 1.0f; - float windowYScale = 1.0f; - nsecs_t deliveryTime; // time when the event was actually delivered - - // Set to the resolved action and flags when the event is enqueued. - int32_t resolvedAction; - int32_t resolvedFlags; - - DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset, float yOffset, - float globalScaleFactor, float windowXScale, float windowYScale); - ~DispatchEntry(); - - inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; } - - inline bool isSplit() const { return targetFlags & InputTarget::FLAG_SPLIT; } - -private: - static volatile int32_t sNextSeqAtomic; - - static uint32_t nextSeq(); -}; - -class InputDispatcher; -// A command entry captures state and behavior for an action to be performed in the -// dispatch loop after the initial processing has taken place. It is essentially -// a kind of continuation used to postpone sensitive policy interactions to a point -// in the dispatch loop where it is safe to release the lock (generally after finishing -// the critical parts of the dispatch cycle). -// -// The special thing about commands is that they can voluntarily release and reacquire -// the dispatcher lock at will. Initially when the command starts running, the -// dispatcher lock is held. However, if the command needs to call into the policy to -// do some work, it can release the lock, do the work, then reacquire the lock again -// before returning. -// -// This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch -// never calls into the policy while holding its lock. -// -// Commands are implicitly 'LockedInterruptible'. -struct CommandEntry; -typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry); - -class Connection; -struct CommandEntry : Link<CommandEntry> { - explicit CommandEntry(Command command); - ~CommandEntry(); - - Command command; - - // parameters for the command (usage varies by command) - sp<Connection> connection; - nsecs_t eventTime; - KeyEntry* keyEntry; - sp<InputApplicationHandle> inputApplicationHandle; - std::string reason; - int32_t userActivityEventType; - uint32_t seq; - bool handled; - sp<InputChannel> inputChannel; - sp<IBinder> oldToken; - sp<IBinder> newToken; -}; - -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_ENTRY_H diff --git a/services/inputflinger/dispatcher/InjectionState.cpp b/services/inputflinger/dispatcher/InjectionState.cpp deleted file mode 100644 index b2d0a26a37..0000000000 --- a/services/inputflinger/dispatcher/InjectionState.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2019 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 "InjectionState.h" - -#include <log/log.h> - -namespace android::inputdispatcher { - -InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) - : refCount(1), - injectorPid(injectorPid), - injectorUid(injectorUid), - injectionResult(INPUT_EVENT_INJECTION_PENDING), - injectionIsAsync(false), - pendingForegroundDispatches(0) {} - -InjectionState::~InjectionState() {} - -void InjectionState::release() { - refCount -= 1; - if (refCount == 0) { - delete this; - } else { - ALOG_ASSERT(refCount > 0); - } -} - -} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h deleted file mode 100644 index 311a0f11ef..0000000000 --- a/services/inputflinger/dispatcher/InjectionState.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H -#define _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H - -#include "InputDispatcherInterface.h" - -#include <stdint.h> - -namespace android::inputdispatcher { - -/* - * Constants used to determine the input event injection synchronization mode. - */ -enum { - /* Injection is asynchronous and is assumed always to be successful. */ - INPUT_EVENT_INJECTION_SYNC_NONE = 0, - - /* Waits for previous events to be dispatched so that the input dispatcher can determine - * whether input event injection willbe permitted based on the current input focus. - * Does not wait for the input event to finish processing. */ - INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1, - - /* Waits for the input event to be completely processed. */ - INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2, -}; - -struct InjectionState { - mutable int32_t refCount; - - int32_t injectorPid; - int32_t injectorUid; - int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING - bool injectionIsAsync; // set to true if injection is not waiting for the result - int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress - - InjectionState(int32_t injectorPid, int32_t injectorUid); - void release(); - -private: - ~InjectionState(); -}; - -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h deleted file mode 100644 index 67bf199cd0..0000000000 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ /dev/null @@ -1,464 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_DISPATCHER_H -#define _UI_INPUT_DISPATCHER_H - -#include "CancelationOptions.h" -#include "Entry.h" -#include "InjectionState.h" -#include "InputDispatcherConfiguration.h" -#include "InputDispatcherInterface.h" -#include "InputDispatcherPolicyInterface.h" -#include "InputState.h" -#include "InputTarget.h" -#include "Monitor.h" -#include "Queue.h" -#include "TouchState.h" -#include "TouchedWindow.h" - -#include <cutils/atomic.h> -#include <input/Input.h> -#include <input/InputApplication.h> -#include <input/InputTransport.h> -#include <input/InputWindow.h> -#include <limits.h> -#include <stddef.h> -#include <ui/Region.h> -#include <unistd.h> -#include <utils/BitSet.h> -#include <utils/Looper.h> -#include <utils/RefBase.h> -#include <utils/Timers.h> -#include <utils/threads.h> -#include <condition_variable> -#include <deque> -#include <optional> -#include <unordered_map> - -#include <InputListener.h> -#include <InputReporterInterface.h> - -namespace android::inputdispatcher { - -class Connection; - -/* Dispatches events to input targets. Some functions of the input dispatcher, such as - * identifying input targets, are controlled by a separate policy object. - * - * IMPORTANT INVARIANT: - * Because the policy can potentially block or cause re-entrance into the input dispatcher, - * the input dispatcher never calls into the policy while holding its internal locks. - * The implementation is also carefully designed to recover from scenarios such as an - * input channel becoming unregistered while identifying input targets or processing timeouts. - * - * Methods marked 'Locked' must be called with the lock acquired. - * - * Methods marked 'LockedInterruptible' must be called with the lock acquired but - * may during the course of their execution release the lock, call into the policy, and - * then reacquire the lock. The caller is responsible for recovering gracefully. - * - * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. - */ -class InputDispatcher : public android::InputDispatcherInterface { -protected: - virtual ~InputDispatcher(); - -public: - explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); - - virtual void dump(std::string& dump) override; - virtual void monitor() override; - - virtual void dispatchOnce() override; - - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; - virtual void notifyKey(const NotifyKeyArgs* args) override; - virtual void notifyMotion(const NotifyMotionArgs* args) override; - virtual void notifySwitch(const NotifySwitchArgs* args) override; - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - - virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, - int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) override; - - virtual void setInputWindows( - const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId, - const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override; - virtual void setFocusedApplication( - int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) override; - virtual void setFocusedDisplay(int32_t displayId) override; - virtual void setInputDispatchMode(bool enabled, bool frozen) override; - virtual void setInputFilterEnabled(bool enabled) override; - - virtual bool transferTouchFocus(const sp<IBinder>& fromToken, - const sp<IBinder>& toToken) override; - - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, - int32_t displayId) override; - virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId, - bool isGestureMonitor) override; - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) override; - virtual status_t pilferPointers(const sp<IBinder>& token) override; - -private: - - enum DropReason { - DROP_REASON_NOT_DROPPED = 0, - DROP_REASON_POLICY = 1, - DROP_REASON_APP_SWITCH = 2, - DROP_REASON_DISABLED = 3, - DROP_REASON_BLOCKED = 4, - DROP_REASON_STALE = 5, - }; - - sp<InputDispatcherPolicyInterface> mPolicy; - android::InputDispatcherConfiguration mConfig; - - std::mutex mLock; - - std::condition_variable mDispatcherIsAlive; - - sp<Looper> mLooper; - - EventEntry* mPendingEvent GUARDED_BY(mLock); - Queue<EventEntry> mInboundQueue GUARDED_BY(mLock); - Queue<EventEntry> mRecentQueue GUARDED_BY(mLock); - Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock); - - DropReason mLastDropReason GUARDED_BY(mLock); - - void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) REQUIRES(mLock); - - // Enqueues an inbound event. Returns true if mLooper->wake() should be called. - bool enqueueInboundEventLocked(EventEntry* entry) REQUIRES(mLock); - - // Cleans up input state when dropping an inbound event. - void dropInboundEventLocked(EventEntry* entry, DropReason dropReason) REQUIRES(mLock); - - // Adds an event to a queue of recent events for debugging purposes. - void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock); - - // App switch latency optimization. - bool mAppSwitchSawKeyDown GUARDED_BY(mLock); - nsecs_t mAppSwitchDueTime GUARDED_BY(mLock); - - bool isAppSwitchKeyEvent(KeyEntry* keyEntry); - bool isAppSwitchPendingLocked() REQUIRES(mLock); - void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock); - - // Stale event latency optimization. - static bool isStaleEvent(nsecs_t currentTime, EventEntry* entry); - - // Blocked event latency optimization. Drops old events when the user intends - // to transfer focus to a new application. - EventEntry* mNextUnblockedEvent GUARDED_BY(mLock); - - sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, - bool addOutsideTargets = false, - bool addPortalWindows = false) REQUIRES(mLock); - - // All registered connections mapped by channel file descriptor. - KeyedVector<int, sp<Connection>> mConnectionsByFd GUARDED_BY(mLock); - - struct IBinderHash { - std::size_t operator()(const sp<IBinder>& b) const { - return std::hash<IBinder*>{}(b.get()); - } - }; - std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken - GUARDED_BY(mLock); - - // Finds the display ID of the gesture monitor identified by the provided token. - std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token) - REQUIRES(mLock); - - ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); - - // Input channels that will receive a copy of all input events sent to the provided display. - std::unordered_map<int32_t, std::vector<Monitor>> mGlobalMonitorsByDisplay GUARDED_BY(mLock); - - // Input channels that will receive pointer events that start within the corresponding display. - // These are a bit special when compared to global monitors since they'll cause gesture streams - // to continue even when there isn't a touched window,and have the ability to steal the rest of - // the pointer stream in order to claim it for a system gesture. - std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay GUARDED_BY(mLock); - - // Event injection and synchronization. - std::condition_variable mInjectionResultAvailable; - bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); - void setInjectionResult(EventEntry* entry, int32_t injectionResult); - - std::condition_variable mInjectionSyncFinished; - void incrementPendingForegroundDispatches(EventEntry* entry); - void decrementPendingForegroundDispatches(EventEntry* entry); - - // Key repeat tracking. - struct KeyRepeatState { - KeyEntry* lastKeyEntry; // or null if no repeat - nsecs_t nextRepeatTime; - } mKeyRepeatState GUARDED_BY(mLock); - - void resetKeyRepeatLocked() REQUIRES(mLock); - KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock); - - // Key replacement tracking - struct KeyReplacement { - int32_t keyCode; - int32_t deviceId; - bool operator==(const KeyReplacement& rhs) const { - return keyCode == rhs.keyCode && deviceId == rhs.deviceId; - } - bool operator<(const KeyReplacement& rhs) const { - return keyCode != rhs.keyCode ? keyCode < rhs.keyCode : deviceId < rhs.deviceId; - } - }; - // Maps the key code replaced, device id tuple to the key code it was replaced with - KeyedVector<KeyReplacement, int32_t> mReplacedKeys GUARDED_BY(mLock); - // Process certain Meta + Key combinations - void accelerateMetaShortcuts(const int32_t deviceId, const int32_t action, int32_t& keyCode, - int32_t& metaState); - - // Deferred command processing. - bool haveCommandsLocked() const REQUIRES(mLock); - bool runCommandsLockedInterruptible() REQUIRES(mLock); - CommandEntry* postCommandLocked(Command command) REQUIRES(mLock); - - // Input filter processing. - bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock); - bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) REQUIRES(mLock); - - // Inbound event processing. - void drainInboundQueueLocked() REQUIRES(mLock); - void releasePendingEventLocked() REQUIRES(mLock); - void releaseInboundEventLocked(EventEntry* entry) REQUIRES(mLock); - - // Dispatch state. - bool mDispatchEnabled GUARDED_BY(mLock); - bool mDispatchFrozen GUARDED_BY(mLock); - bool mInputFilterEnabled GUARDED_BY(mLock); - - std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay - GUARDED_BY(mLock); - // Get window handles by display, return an empty vector if not found. - std::vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const - REQUIRES(mLock); - sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const - REQUIRES(mLock); - sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock); - bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); - - // Focus tracking for keys, trackball, etc. - std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay - GUARDED_BY(mLock); - - KeyedVector<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock); - TouchState mTempTouchState GUARDED_BY(mLock); - - // Focused applications. - std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay - GUARDED_BY(mLock); - - // Top focused display. - int32_t mFocusedDisplayId GUARDED_BY(mLock); - - // Dispatcher state at time of last ANR. - std::string mLastANRState GUARDED_BY(mLock); - - // Dispatch inbound events. - bool dispatchConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry) - REQUIRES(mLock); - bool dispatchDeviceResetLocked(nsecs_t currentTime, DeviceResetEntry* entry) REQUIRES(mLock); - bool dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, - nsecs_t* nextWakeupTime) REQUIRES(mLock); - bool dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, - nsecs_t* nextWakeupTime) REQUIRES(mLock); - void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry, - const std::vector<InputTarget>& inputTargets) REQUIRES(mLock); - - void logOutboundKeyDetails(const char* prefix, const KeyEntry* entry); - void logOutboundMotionDetails(const char* prefix, const MotionEntry* entry); - - // Keeping track of ANR timeouts. - enum InputTargetWaitCause { - INPUT_TARGET_WAIT_CAUSE_NONE, - INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, - INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, - }; - - InputTargetWaitCause mInputTargetWaitCause GUARDED_BY(mLock); - nsecs_t mInputTargetWaitStartTime GUARDED_BY(mLock); - nsecs_t mInputTargetWaitTimeoutTime GUARDED_BY(mLock); - bool mInputTargetWaitTimeoutExpired GUARDED_BY(mLock); - sp<IBinder> mInputTargetWaitApplicationToken GUARDED_BY(mLock); - - // Contains the last window which received a hover event. - sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock); - - // Finding targets for input events. - int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, - const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t* nextWakeupTime, const char* reason) - REQUIRES(mLock); - - void removeWindowByTokenLocked(const sp<IBinder>& token) REQUIRES(mLock); - - void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp<InputChannel>& inputChannel) - REQUIRES(mLock); - nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock); - void resetANRTimeoutsLocked() REQUIRES(mLock); - - int32_t getTargetDisplayId(const EventEntry* entry); - int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, - std::vector<InputTarget>& inputTargets, - nsecs_t* nextWakeupTime) REQUIRES(mLock); - int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, - std::vector<InputTarget>& inputTargets, - nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions) REQUIRES(mLock); - std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked( - int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) - REQUIRES(mLock); - void addGestureMonitors(const std::vector<Monitor>& monitors, - std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0, - float yOffset = 0); - - void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, - BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) - REQUIRES(mLock); - void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset, - std::vector<InputTarget>& inputTargets) REQUIRES(mLock); - void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId, - float xOffset = 0, float yOffset = 0) REQUIRES(mLock); - - void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock); - bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, - const InjectionState* injectionState); - bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x, - int32_t y) const REQUIRES(mLock); - bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); - std::string getApplicationWindowLabel(const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle); - - std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp<InputWindowHandle>& windowHandle, - const EventEntry* eventEntry, - const char* targetType) REQUIRES(mLock); - - // Manage the dispatch cycle for a single connection. - // These methods are deliberately not Interruptible because doing all of the work - // with the mutex held makes it easier to ensure that connection invariants are maintained. - // If needed, the methods post commands to run later once the critical bits are done. - void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget) - REQUIRES(mLock); - void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget) - REQUIRES(mLock); - void enqueueDispatchEntryLocked(const sp<Connection>& connection, EventEntry* eventEntry, - const InputTarget* inputTarget, int32_t dispatchMode) - REQUIRES(mLock); - void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) - REQUIRES(mLock); - void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - uint32_t seq, bool handled) REQUIRES(mLock); - void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - bool notify) REQUIRES(mLock); - void drainDispatchQueue(Queue<DispatchEntry>* queue); - void releaseDispatchEntry(DispatchEntry* dispatchEntry); - static int handleReceiveCallback(int fd, int events, void* data); - // The action sent should only be of type AMOTION_EVENT_* - void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, - const sp<IBinder>& newToken) REQUIRES(mLock); - - void synthesizeCancelationEventsForAllConnectionsLocked(const CancelationOptions& options) - REQUIRES(mLock); - void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options) - REQUIRES(mLock); - void synthesizeCancelationEventsForMonitorsLocked( - const CancelationOptions& options, - std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock); - void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, - const CancelationOptions& options) - REQUIRES(mLock); - void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, - const CancelationOptions& options) - REQUIRES(mLock); - - // Splitting motion events across windows. - MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); - - // Reset and drop everything the dispatcher is doing. - void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock); - - // Dump state. - void dumpDispatchStateLocked(std::string& dump) REQUIRES(mLock); - void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors); - void logDispatchStateLocked() REQUIRES(mLock); - - // Registration. - void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); - void removeMonitorChannelLocked( - const sp<InputChannel>& inputChannel, - std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock); - status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify) - REQUIRES(mLock); - - // Interesting events that we might like to log or tell the framework about. - void onDispatchCycleFinishedLocked(nsecs_t currentTime, const sp<Connection>& connection, - uint32_t seq, bool handled) REQUIRES(mLock); - void onDispatchCycleBrokenLocked(nsecs_t currentTime, const sp<Connection>& connection) - REQUIRES(mLock); - void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus, - const sp<InputWindowHandle>& newFocus) REQUIRES(mLock); - void onANRLocked(nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, nsecs_t eventTime, - nsecs_t waitStartTime, const char* reason) REQUIRES(mLock); - - // Outbound policy interactions. - void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) - REQUIRES(mLock); - void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - void doNotifyANRLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry) - REQUIRES(mLock); - void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - bool afterKeyEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, - bool handled) REQUIRES(mLock); - bool afterMotionEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, - bool handled) REQUIRES(mLock); - void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); - void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - - // Statistics gathering. - void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); - void traceInboundQueueLengthLocked() REQUIRES(mLock); - void traceOutboundQueueLength(const sp<Connection>& connection); - void traceWaitQueueLength(const sp<Connection>& connection); - - sp<InputReporterInterface> mReporter; -}; - -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_DISPATCHER_H diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp deleted file mode 100644 index 7d9b03a70e..0000000000 --- a/services/inputflinger/dispatcher/InputState.cpp +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2019 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 "InputState.h" - -namespace android::inputdispatcher { - -InputState::InputState() {} - -InputState::~InputState() {} - -bool InputState::isNeutral() const { - return mKeyMementos.empty() && mMotionMementos.empty(); -} - -bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const { - for (const MotionMemento& memento : mMotionMementos) { - if (memento.deviceId == deviceId && memento.source == source && - memento.displayId == displayId && memento.hovering) { - return true; - } - } - return false; -} - -bool InputState::trackKey(const KeyEntry* entry, int32_t action, int32_t flags) { - switch (action) { - case AKEY_EVENT_ACTION_UP: { - if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) { - for (size_t i = 0; i < mFallbackKeys.size();) { - if (mFallbackKeys.valueAt(i) == entry->keyCode) { - mFallbackKeys.removeItemsAt(i); - } else { - i += 1; - } - } - } - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.erase(mKeyMementos.begin() + index); - return true; - } - /* FIXME: We can't just drop the key up event because that prevents creating - * popup windows that are automatically shown when a key is held and then - * dismissed when the key is released. The problem is that the popup will - * not have received the original key down, so the key up will be considered - * to be inconsistent with its observed state. We could perhaps handle this - * by synthesizing a key down but that will cause other problems. - * - * So for now, allow inconsistent key up events to be dispatched. - * - #if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " - "keyCode=%d, scanCode=%d", - entry->deviceId, entry->source, entry->keyCode, entry->scanCode); - #endif - return false; - */ - return true; - } - - case AKEY_EVENT_ACTION_DOWN: { - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.erase(mKeyMementos.begin() + index); - } - addKeyMemento(entry, flags); - return true; - } - - default: - return true; - } -} - -bool InputState::trackMotion(const MotionEntry* entry, int32_t action, int32_t flags) { - int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; - switch (actionMasked) { - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.erase(mMotionMementos.begin() + index); - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, " - "displayId=%" PRId32 ", actionMasked=%d", - entry->deviceId, entry->source, entry->displayId, actionMasked); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_DOWN: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.erase(mMotionMementos.begin() + index); - } - addMotionMemento(entry, flags, false /*hovering*/); - return true; - } - - case AMOTION_EVENT_ACTION_POINTER_UP: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_MOVE: { - if (entry->source & AINPUT_SOURCE_CLASS_NAVIGATION) { - // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need - // to generate cancellation events for these since they're based in relative rather - // than absolute units. - return true; - } - - ssize_t index = findMotionMemento(entry, false /*hovering*/); - - if (entry->source & AINPUT_SOURCE_CLASS_JOYSTICK) { - // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all - // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral. - // Any other value and we need to track the motion so we can send cancellation - // events for anything generating fallback events (e.g. DPad keys for joystick - // movements). - if (index >= 0) { - if (entry->pointerCoords[0].isEmpty()) { - mMotionMementos.erase(mMotionMementos.begin() + index); - } else { - MotionMemento& memento = mMotionMementos[index]; - memento.setPointers(entry); - } - } else if (!entry->pointerCoords[0].isEmpty()) { - addMotionMemento(entry, flags, false /*hovering*/); - } - - // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP. - return true; - } - if (index >= 0) { - MotionMemento& memento = mMotionMementos[index]; - memento.setPointers(entry); - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion pointer up/down or move event: " - "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d", - entry->deviceId, entry->source, entry->displayId, actionMasked); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_HOVER_EXIT: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.erase(mMotionMementos.begin() + index); - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, " - "displayId=%" PRId32, - entry->deviceId, entry->source, entry->displayId); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.erase(mMotionMementos.begin() + index); - } - addMotionMemento(entry, flags, true /*hovering*/); - return true; - } - - default: - return true; - } -} - -ssize_t InputState::findKeyMemento(const KeyEntry* entry) const { - for (size_t i = 0; i < mKeyMementos.size(); i++) { - const KeyMemento& memento = mKeyMementos[i]; - if (memento.deviceId == entry->deviceId && memento.source == entry->source && - memento.displayId == entry->displayId && memento.keyCode == entry->keyCode && - memento.scanCode == entry->scanCode) { - return i; - } - } - return -1; -} - -ssize_t InputState::findMotionMemento(const MotionEntry* entry, bool hovering) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos[i]; - if (memento.deviceId == entry->deviceId && memento.source == entry->source && - memento.displayId == entry->displayId && memento.hovering == hovering) { - return i; - } - } - return -1; -} - -void InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) { - KeyMemento memento; - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.displayId = entry->displayId; - memento.keyCode = entry->keyCode; - memento.scanCode = entry->scanCode; - memento.metaState = entry->metaState; - memento.flags = flags; - memento.downTime = entry->downTime; - memento.policyFlags = entry->policyFlags; - mKeyMementos.push_back(memento); -} - -void InputState::addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering) { - MotionMemento memento; - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.displayId = entry->displayId; - memento.flags = flags; - memento.xPrecision = entry->xPrecision; - memento.yPrecision = entry->yPrecision; - memento.downTime = entry->downTime; - memento.setPointers(entry); - memento.hovering = hovering; - memento.policyFlags = entry->policyFlags; - mMotionMementos.push_back(memento); -} - -void InputState::MotionMemento::setPointers(const MotionEntry* entry) { - pointerCount = entry->pointerCount; - for (uint32_t i = 0; i < entry->pointerCount; i++) { - pointerProperties[i].copyFrom(entry->pointerProperties[i]); - pointerCoords[i].copyFrom(entry->pointerCoords[i]); - } -} - -void InputState::synthesizeCancelationEvents(nsecs_t currentTime, - std::vector<EventEntry*>& outEvents, - const CancelationOptions& options) { - for (KeyMemento& memento : mKeyMementos) { - if (shouldCancelKey(memento, options)) { - outEvents.push_back(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, - memento.deviceId, memento.source, memento.displayId, - memento.policyFlags, AKEY_EVENT_ACTION_UP, - memento.flags | AKEY_EVENT_FLAG_CANCELED, - memento.keyCode, memento.scanCode, memento.metaState, - 0, memento.downTime)); - } - } - - for (const MotionMemento& memento : mMotionMementos) { - if (shouldCancelMotion(memento, options)) { - const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT - : AMOTION_EVENT_ACTION_CANCEL; - outEvents.push_back( - new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, memento.deviceId, - memento.source, memento.displayId, memento.policyFlags, action, - 0 /*actionButton*/, memento.flags, AMETA_NONE, - 0 /*buttonState*/, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, - memento.yPrecision, memento.downTime, memento.pointerCount, - memento.pointerProperties, memento.pointerCoords, 0 /*xOffset*/, - 0 /*yOffset*/)); - } - } -} - -void InputState::clear() { - mKeyMementos.clear(); - mMotionMementos.clear(); - mFallbackKeys.clear(); -} - -void InputState::copyPointerStateTo(InputState& other) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos[i]; - if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { - for (size_t j = 0; j < other.mMotionMementos.size();) { - const MotionMemento& otherMemento = other.mMotionMementos[j]; - if (memento.deviceId == otherMemento.deviceId && - memento.source == otherMemento.source && - memento.displayId == otherMemento.displayId) { - other.mMotionMementos.erase(other.mMotionMementos.begin() + j); - } else { - j += 1; - } - } - other.mMotionMementos.push_back(memento); - } - } -} - -int32_t InputState::getFallbackKey(int32_t originalKeyCode) { - ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); - return index >= 0 ? mFallbackKeys.valueAt(index) : -1; -} - -void InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) { - ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); - if (index >= 0) { - mFallbackKeys.replaceValueAt(index, fallbackKeyCode); - } else { - mFallbackKeys.add(originalKeyCode, fallbackKeyCode); - } -} - -void InputState::removeFallbackKey(int32_t originalKeyCode) { - mFallbackKeys.removeItem(originalKeyCode); -} - -bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) { - if (options.keyCode && memento.keyCode != options.keyCode.value()) { - return false; - } - - if (options.deviceId && memento.deviceId != options.deviceId.value()) { - return false; - } - - if (options.displayId && memento.displayId != options.displayId.value()) { - return false; - } - - switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return true; - case CancelationOptions::CANCEL_FALLBACK_EVENTS: - return memento.flags & AKEY_EVENT_FLAG_FALLBACK; - default: - return false; - } -} - -bool InputState::shouldCancelMotion(const MotionMemento& memento, - const CancelationOptions& options) { - if (options.deviceId && memento.deviceId != options.deviceId.value()) { - return false; - } - - if (options.displayId && memento.displayId != options.displayId.value()) { - return false; - } - - switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - return true; - case CancelationOptions::CANCEL_POINTER_EVENTS: - return memento.source & AINPUT_SOURCE_CLASS_POINTER; - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); - default: - return false; - } -} - -} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h deleted file mode 100644 index 205b64728a..0000000000 --- a/services/inputflinger/dispatcher/InputState.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H - -#include "CancelationOptions.h" -#include "Entry.h" - -#include <utils/Timers.h> - -namespace android::inputdispatcher { - -// Sequence number for synthesized or injected events. -constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0; - -/* Tracks dispatched key and motion event state so that cancellation events can be - * synthesized when events are dropped. */ -class InputState { -public: - InputState(); - ~InputState(); - - // Returns true if there is no state to be canceled. - bool isNeutral() const; - - // Returns true if the specified source is known to have received a hover enter - // motion event. - bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const; - - // Records tracking information for a key event that has just been published. - // Returns true if the event should be delivered, false if it is inconsistent - // and should be skipped. - bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags); - - // Records tracking information for a motion event that has just been published. - // Returns true if the event should be delivered, false if it is inconsistent - // and should be skipped. - bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags); - - // Synthesizes cancelation events for the current state and resets the tracked state. - void synthesizeCancelationEvents(nsecs_t currentTime, std::vector<EventEntry*>& outEvents, - const CancelationOptions& options); - - // Clears the current state. - void clear(); - - // Copies pointer-related parts of the input state to another instance. - void copyPointerStateTo(InputState& other) const; - - // Gets the fallback key associated with a keycode. - // Returns -1 if none. - // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy. - int32_t getFallbackKey(int32_t originalKeyCode); - - // Sets the fallback key for a particular keycode. - void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode); - - // Removes the fallback key for a particular keycode. - void removeFallbackKey(int32_t originalKeyCode); - - inline const KeyedVector<int32_t, int32_t>& getFallbackKeys() const { return mFallbackKeys; } - -private: - struct KeyMemento { - int32_t deviceId; - uint32_t source; - int32_t displayId; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t flags; - nsecs_t downTime; - uint32_t policyFlags; - }; - - struct MotionMemento { - int32_t deviceId; - uint32_t source; - int32_t displayId; - int32_t flags; - float xPrecision; - float yPrecision; - nsecs_t downTime; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - bool hovering; - uint32_t policyFlags; - - void setPointers(const MotionEntry* entry); - }; - - std::vector<KeyMemento> mKeyMementos; - std::vector<MotionMemento> mMotionMementos; - KeyedVector<int32_t, int32_t> mFallbackKeys; - - ssize_t findKeyMemento(const KeyEntry* entry) const; - ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const; - - void addKeyMemento(const KeyEntry* entry, int32_t flags); - void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering); - - static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options); - static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options); -}; - -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp deleted file mode 100644 index 80fa2cb995..0000000000 --- a/services/inputflinger/dispatcher/InputTarget.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2019 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 "InputTarget.h" - -#include <android-base/stringprintf.h> -#include <inttypes.h> -#include <string> - -using android::base::StringPrintf; - -namespace android::inputdispatcher { - -std::string dispatchModeToString(int32_t dispatchMode) { - switch (dispatchMode) { - case InputTarget::FLAG_DISPATCH_AS_IS: - return "DISPATCH_AS_IS"; - case InputTarget::FLAG_DISPATCH_AS_OUTSIDE: - return "DISPATCH_AS_OUTSIDE"; - case InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER: - return "DISPATCH_AS_HOVER_ENTER"; - case InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT: - return "DISPATCH_AS_HOVER_EXIT"; - case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT: - return "DISPATCH_AS_SLIPPERY_EXIT"; - case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER: - return "DISPATCH_AS_SLIPPERY_ENTER"; - } - return StringPrintf("%" PRId32, dispatchMode); -} - -} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h deleted file mode 100644 index 5acf92b1b1..0000000000 --- a/services/inputflinger/dispatcher/InputTarget.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H - -#include <input/InputTransport.h> -#include <utils/BitSet.h> -#include <utils/RefBase.h> - -namespace android::inputdispatcher { - -/* - * An input target specifies how an input event is to be dispatched to a particular window - * including the window's input channel, control flags, a timeout, and an X / Y offset to - * be added to input event coordinates to compensate for the absolute position of the - * window area. - */ -struct InputTarget { - enum { - /* This flag indicates that the event is being delivered to a foreground application. */ - FLAG_FOREGROUND = 1 << 0, - - /* This flag indicates that the MotionEvent falls within the area of the target - * obscured by another visible window above it. The motion event should be - * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ - FLAG_WINDOW_IS_OBSCURED = 1 << 1, - - /* This flag indicates that a motion event is being split across multiple windows. */ - FLAG_SPLIT = 1 << 2, - - /* This flag indicates that the pointer coordinates dispatched to the application - * will be zeroed out to avoid revealing information to an application. This is - * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing - * the same UID from watching all touches. */ - FLAG_ZERO_COORDS = 1 << 3, - - /* This flag indicates that the event should be sent as is. - * Should always be set unless the event is to be transmuted. */ - FLAG_DISPATCH_AS_IS = 1 << 8, - - /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside - * of the area of this target and so should instead be delivered as an - * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ - FLAG_DISPATCH_AS_OUTSIDE = 1 << 9, - - /* This flag indicates that a hover sequence is starting in the given window. - * The event is transmuted into ACTION_HOVER_ENTER. */ - FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10, - - /* This flag indicates that a hover event happened outside of a window which handled - * previous hover events, signifying the end of the current hover sequence for that - * window. - * The event is transmuted into ACTION_HOVER_ENTER. */ - FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, - - /* This flag indicates that the event should be canceled. - * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips - * outside of a window. */ - FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12, - - /* This flag indicates that the event should be dispatched as an initial down. - * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips - * into a new window. */ - FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13, - - /* Mask for all dispatch modes. */ - FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS | FLAG_DISPATCH_AS_OUTSIDE | - FLAG_DISPATCH_AS_HOVER_ENTER | FLAG_DISPATCH_AS_HOVER_EXIT | - FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER, - - /* This flag indicates that the target of a MotionEvent is partly or wholly - * obscured by another visible window above it. The motion event should be - * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */ - FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14, - - }; - - // The input channel to be targeted. - sp<InputChannel> inputChannel; - - // Flags for the input target. - int32_t flags; - - // The x and y offset to add to a MotionEvent as it is delivered. - // (ignored for KeyEvents) - float xOffset, yOffset; - - // Scaling factor to apply to MotionEvent as it is delivered. - // (ignored for KeyEvents) - float globalScaleFactor; - float windowXScale = 1.0f; - float windowYScale = 1.0f; - - // The subset of pointer ids to include in motion events dispatched to this input target - // if FLAG_SPLIT is set. - BitSet32 pointerIds; -}; - -std::string dispatchModeToString(int32_t dispatchMode); - -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H diff --git a/services/inputflinger/dispatcher/Monitor.cpp b/services/inputflinger/dispatcher/Monitor.cpp deleted file mode 100644 index 289b0848bf..0000000000 --- a/services/inputflinger/dispatcher/Monitor.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2019 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 "Monitor.h" - -namespace android::inputdispatcher { - -// --- Monitor --- -Monitor::Monitor(const sp<InputChannel>& inputChannel) : inputChannel(inputChannel) {} - -// --- TouchedMonitor --- -TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset) - : monitor(monitor), xOffset(xOffset), yOffset(yOffset) {} - -} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/Monitor.h b/services/inputflinger/dispatcher/Monitor.h deleted file mode 100644 index b67c9eb507..0000000000 --- a/services/inputflinger/dispatcher/Monitor.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_MONITOR_H -#define _UI_INPUT_INPUTDISPATCHER_MONITOR_H - -#include <input/InputTransport.h> - -namespace android::inputdispatcher { - -struct Monitor { - sp<InputChannel> inputChannel; // never null - - explicit Monitor(const sp<InputChannel>& inputChannel); -}; - -// For tracking the offsets we need to apply when adding gesture monitor targets. -struct TouchedMonitor { - Monitor monitor; - float xOffset = 0.f; - float yOffset = 0.f; - - explicit TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset); -}; - -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_MONITOR_H diff --git a/services/inputflinger/dispatcher/Queue.h b/services/inputflinger/dispatcher/Queue.h deleted file mode 100644 index 0e75821661..0000000000 --- a/services/inputflinger/dispatcher/Queue.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_QUEUE_H -#define _UI_INPUT_INPUTDISPATCHER_QUEUE_H - -namespace android::inputdispatcher { - -// Generic queue implementation. -template <typename T> -struct Queue { - T* head; - T* tail; - uint32_t entryCount; - - inline Queue() : head(nullptr), tail(nullptr), entryCount(0) {} - - inline bool isEmpty() const { return !head; } - - inline void enqueueAtTail(T* entry) { - entryCount++; - entry->prev = tail; - if (tail) { - tail->next = entry; - } else { - head = entry; - } - entry->next = nullptr; - tail = entry; - } - - inline void enqueueAtHead(T* entry) { - entryCount++; - entry->next = head; - if (head) { - head->prev = entry; - } else { - tail = entry; - } - entry->prev = nullptr; - head = entry; - } - - inline void dequeue(T* entry) { - entryCount--; - if (entry->prev) { - entry->prev->next = entry->next; - } else { - head = entry->next; - } - if (entry->next) { - entry->next->prev = entry->prev; - } else { - tail = entry->prev; - } - } - - inline T* dequeueAtHead() { - entryCount--; - T* entry = head; - head = entry->next; - if (head) { - head->prev = nullptr; - } else { - tail = nullptr; - } - return entry; - } - - uint32_t count() const { return entryCount; } -}; - -} // namespace android::inputdispatcher - -#endif // _UI_INPUT_INPUTDISPATCHER_QUEUE_H diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp deleted file mode 100644 index 18848a0c2f..0000000000 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2019 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 <input/InputWindow.h> - -#include "InputTarget.h" - -#include "TouchState.h" - -using android::InputWindowHandle; - -namespace android::inputdispatcher { - -TouchState::TouchState() - : down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) {} - -TouchState::~TouchState() {} - -void TouchState::reset() { - down = false; - split = false; - deviceId = -1; - source = 0; - displayId = ADISPLAY_ID_NONE; - windows.clear(); - portalWindows.clear(); - gestureMonitors.clear(); -} - -void TouchState::copyFrom(const TouchState& other) { - down = other.down; - split = other.split; - deviceId = other.deviceId; - source = other.source; - displayId = other.displayId; - windows = other.windows; - portalWindows = other.portalWindows; - gestureMonitors = other.gestureMonitors; -} - -void TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, - BitSet32 pointerIds) { - if (targetFlags & InputTarget::FLAG_SPLIT) { - split = true; - } - - for (size_t i = 0; i < windows.size(); i++) { - TouchedWindow& touchedWindow = windows[i]; - if (touchedWindow.windowHandle == windowHandle) { - touchedWindow.targetFlags |= targetFlags; - if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; - } - touchedWindow.pointerIds.value |= pointerIds.value; - return; - } - } - - TouchedWindow touchedWindow; - touchedWindow.windowHandle = windowHandle; - touchedWindow.targetFlags = targetFlags; - touchedWindow.pointerIds = pointerIds; - windows.push_back(touchedWindow); -} - -void TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) { - size_t numWindows = portalWindows.size(); - for (size_t i = 0; i < numWindows; i++) { - if (portalWindows[i] == windowHandle) { - return; - } - } - portalWindows.push_back(windowHandle); -} - -void TouchState::addGestureMonitors(const std::vector<TouchedMonitor>& newMonitors) { - const size_t newSize = gestureMonitors.size() + newMonitors.size(); - gestureMonitors.reserve(newSize); - gestureMonitors.insert(std::end(gestureMonitors), std::begin(newMonitors), - std::end(newMonitors)); -} - -void TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) { - for (size_t i = 0; i < windows.size(); i++) { - if (windows[i].windowHandle == windowHandle) { - windows.erase(windows.begin() + i); - return; - } - } -} - -void TouchState::removeWindowByToken(const sp<IBinder>& token) { - for (size_t i = 0; i < windows.size(); i++) { - if (windows[i].windowHandle->getToken() == token) { - windows.erase(windows.begin() + i); - return; - } - } -} - -void TouchState::filterNonAsIsTouchWindows() { - for (size_t i = 0; i < windows.size();) { - TouchedWindow& window = windows[i]; - if (window.targetFlags & - (InputTarget::FLAG_DISPATCH_AS_IS | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) { - window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK; - window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS; - i += 1; - } else { - windows.erase(windows.begin() + i); - } - } -} - -void TouchState::filterNonMonitors() { - windows.clear(); - portalWindows.clear(); -} - -sp<InputWindowHandle> TouchState::getFirstForegroundWindowHandle() const { - for (size_t i = 0; i < windows.size(); i++) { - const TouchedWindow& window = windows[i]; - if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - return window.windowHandle; - } - } - return nullptr; -} - -bool TouchState::isSlippery() const { - // Must have exactly one foreground window. - bool haveSlipperyForegroundWindow = false; - for (const TouchedWindow& window : windows) { - if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - if (haveSlipperyForegroundWindow || - !(window.windowHandle->getInfo()->layoutParamsFlags & - InputWindowInfo::FLAG_SLIPPERY)) { - return false; - } - haveSlipperyForegroundWindow = true; - } - } - return haveSlipperyForegroundWindow; -} - -} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h deleted file mode 100644 index 3e0e0eb897..0000000000 --- a/services/inputflinger/dispatcher/TouchState.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H -#define _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H - -#include "Monitor.h" -#include "TouchedWindow.h" - -namespace android { - -class InputWindowHandle; - -namespace inputdispatcher { - -struct TouchState { - bool down; - bool split; - int32_t deviceId; // id of the device that is currently down, others are rejected - uint32_t source; // source of the device that is current down, others are rejected - int32_t displayId; // id to the display that currently has a touch, others are rejected - std::vector<TouchedWindow> windows; - - // This collects the portal windows that the touch has gone through. Each portal window - // targets a display (embedded display for most cases). With this info, we can add the - // monitoring channels of the displays touched. - std::vector<sp<android::InputWindowHandle>> portalWindows; - - std::vector<TouchedMonitor> gestureMonitors; - - TouchState(); - ~TouchState(); - void reset(); - void copyFrom(const TouchState& other); - void addOrUpdateWindow(const sp<android::InputWindowHandle>& windowHandle, int32_t targetFlags, - BitSet32 pointerIds); - void addPortalWindow(const sp<android::InputWindowHandle>& windowHandle); - void addGestureMonitors(const std::vector<TouchedMonitor>& monitors); - void removeWindow(const sp<android::InputWindowHandle>& windowHandle); - void removeWindowByToken(const sp<IBinder>& token); - void filterNonAsIsTouchWindows(); - void filterNonMonitors(); - sp<InputWindowHandle> getFirstForegroundWindowHandle() const; - bool isSlippery() const; -}; - -} // namespace inputdispatcher -} // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h deleted file mode 100644 index 8713aa3f56..0000000000 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H -#define _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H - -namespace android { - -class InputWindowHandle; - -namespace inputdispatcher { - -// Focus tracking for touch. -struct TouchedWindow { - sp<android::InputWindowHandle> windowHandle; - int32_t targetFlags; - BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set -}; - -} // namespace inputdispatcher -} // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H diff --git a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h deleted file mode 100644 index 00abf47cd2..0000000000 --- a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H - -#include <utils/Timers.h> - -namespace android { - -/* - * Input dispatcher configuration. - * - * Specifies various options that modify the behavior of the input dispatcher. - * The values provided here are merely defaults. The actual values will come from ViewConfiguration - * and are passed into the dispatcher during initialization. - */ -struct InputDispatcherConfiguration { - // The key repeat initial timeout. - nsecs_t keyRepeatTimeout; - - // The key repeat inter-key delay. - nsecs_t keyRepeatDelay; - - InputDispatcherConfiguration() - : keyRepeatTimeout(500 * 1000000LL), keyRepeatDelay(50 * 1000000LL) {} -}; - -} // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H diff --git a/services/inputflinger/dispatcher/include/InputDispatcherFactory.h b/services/inputflinger/dispatcher/include/InputDispatcherFactory.h deleted file mode 100644 index a359557f80..0000000000 --- a/services/inputflinger/dispatcher/include/InputDispatcherFactory.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H - -#include <utils/RefBase.h> - -#include "InputDispatcherInterface.h" -#include "InputDispatcherPolicyInterface.h" - -namespace android { - -// This factory method is used to encapsulate implementation details in internal header files. -sp<InputDispatcherInterface> createInputDispatcher( - const sp<InputDispatcherPolicyInterface>& policy); - -} // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h deleted file mode 100644 index 9329ca664e..0000000000 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H - -#include <InputListener.h> -#include <input/ISetInputWindowsListener.h> - -namespace android { - -class InputApplicationHandle; -class InputChannel; -class InputWindowHandle; - -/* - * Constants used to report the outcome of input event injection. - */ -enum { - /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */ - INPUT_EVENT_INJECTION_PENDING = -1, - - /* Injection succeeded. */ - INPUT_EVENT_INJECTION_SUCCEEDED = 0, - - /* Injection failed because the injector did not have permission to inject - * into the application with input focus. */ - INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1, - - /* Injection failed because there were no available input targets. */ - INPUT_EVENT_INJECTION_FAILED = 2, - - /* Injection failed due to a timeout. */ - INPUT_EVENT_INJECTION_TIMED_OUT = 3 -}; - -/* Notifies the system about input events generated by the input reader. - * The dispatcher is expected to be mostly asynchronous. */ -class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface { -protected: - InputDispatcherInterface() {} - virtual ~InputDispatcherInterface() {} - -public: - /* Dumps the state of the input dispatcher. - * - * This method may be called on any thread (usually by the input manager). */ - virtual void dump(std::string& dump) = 0; - - /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ - virtual void monitor() = 0; - - /* Runs a single iteration of the dispatch loop. - * Nominally processes one queued event, a timeout, or a response from an input consumer. - * - * This method should only be called on the input dispatcher thread. - */ - virtual void dispatchOnce() = 0; - - /* Injects an input event and optionally waits for sync. - * The synchronization mode determines whether the method blocks while waiting for - * input injection to proceed. - * Returns one of the INPUT_EVENT_INJECTION_XXX constants. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, - int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) = 0; - - /* Sets the list of input windows. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setInputWindows( - const std::vector<sp<InputWindowHandle> >& inputWindowHandles, int32_t displayId, - const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) = 0; - - /* Sets the focused application on the given display. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setFocusedApplication( - int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) = 0; - - /* Sets the focused display. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setFocusedDisplay(int32_t displayId) = 0; - - /* Sets the input dispatching mode. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setInputDispatchMode(bool enabled, bool frozen) = 0; - - /* Sets whether input event filtering is enabled. - * When enabled, incoming input events are sent to the policy's filterInputEvent - * method instead of being dispatched. The filter is expected to use - * injectInputEvent to inject the events it would like to have dispatched. - * It should include POLICY_FLAG_FILTERED in the policy flags during injection. - */ - virtual void setInputFilterEnabled(bool enabled) = 0; - - /* Transfers touch focus from one window to another window. - * - * Returns true on success. False if the window did not actually have touch focus. - */ - virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0; - - /* Registers input channels that may be used as targets for input events. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, - int32_t displayId) = 0; - - /* Registers input channels to be used to monitor input events. - * - * Each monitor must target a specific display and will only receive input events sent to that - * display. If the monitor is a gesture monitor, it will only receive pointer events on the - * targeted display. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId, - bool gestureMonitor) = 0; - - /* Unregister input channels that will no longer receive input events. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; - - /* Allows an input monitor steal the current pointer stream away from normal input windows. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual status_t pilferPointers(const sp<IBinder>& token) = 0; -}; - -} // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h deleted file mode 100644 index 4214488f04..0000000000 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H - -#include "InputDispatcherConfiguration.h" - -#include <binder/IBinder.h> -#include <input/Input.h> -#include <utils/RefBase.h> - -namespace android { - -class InputApplicationHandle; - -/* - * Input dispatcher policy interface. - * - * The input reader policy is used by the input reader to interact with the Window Manager - * and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - */ -class InputDispatcherPolicyInterface : public virtual RefBase { -protected: - InputDispatcherPolicyInterface() {} - virtual ~InputDispatcherPolicyInterface() {} - -public: - /* Notifies the system that a configuration change has occurred. */ - virtual void notifyConfigurationChanged(nsecs_t when) = 0; - - /* Notifies the system that an application is not responding. - * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ - virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<IBinder>& token, const std::string& reason) = 0; - - /* Notifies the system that an input channel is unrecoverably broken. */ - virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0; - virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0; - - /* Gets the input dispatcher configuration. */ - virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; - - /* Filters an input event. - * Return true to dispatch the event unmodified, false to consume the event. - * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED - * to injectInputEvent. - */ - virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0; - - /* Intercepts a key event immediately before queueing it. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event - * should be dispatched to applications. - */ - virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; - - /* Intercepts a touch, trackball or other motion event before queueing it. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event - * should be dispatched to applications. - */ - virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when, - uint32_t& policyFlags) = 0; - - /* Allows the policy a chance to intercept a key before dispatching. */ - virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token, - const KeyEvent* keyEvent, - uint32_t policyFlags) = 0; - - /* Allows the policy a chance to perform default processing for an unhandled key. - * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */ - virtual bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent, - uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0; - - /* Notifies the policy about switch events. - */ - virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask, - uint32_t policyFlags) = 0; - - /* Poke user activity for an event dispatched to a window. */ - virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; - - /* Checks whether a given application pid/uid has permission to inject input events - * into other applications. - * - * This method is special in that its implementation promises to be non-reentrant and - * is safe to call while holding other locks. (Most other methods make no such guarantees!) - */ - virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid, - int32_t injectorUid) = 0; - - /* Notifies the policy that a pointer down event has occurred outside the current focused - * window. - * - * The touchedToken passed as an argument is the window that received the input event. - */ - virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0; -}; - -} // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H diff --git a/services/inputflinger/dispatcher/include/InputDispatcherThread.h b/services/inputflinger/dispatcher/include/InputDispatcherThread.h deleted file mode 100644 index 2604959656..0000000000 --- a/services/inputflinger/dispatcher/include/InputDispatcherThread.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERTHREAD_H -#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERTHREAD_H - -#include <utils/RefBase.h> -#include <utils/threads.h> - -namespace android { - -class InputDispatcherInterface; - -/* Enqueues and dispatches input events, endlessly. */ -class InputDispatcherThread : public Thread { -public: - explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher); - ~InputDispatcherThread(); - -private: - virtual bool threadLoop(); - - sp<InputDispatcherInterface> mDispatcher; -}; - -} // namespace android - -#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERTHREAD_H diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp index 683c05d8a0..2f046c3527 100644 --- a/services/inputflinger/host/InputDriver.cpp +++ b/services/inputflinger/host/InputDriver.cpp @@ -127,10 +127,10 @@ input_device_identifier_t* InputDriver::createDeviceIdentifier( input_bus_t bus, const char* uniqueId) { auto identifier = new ::input_device_identifier { .name = name, - .uniqueId = uniqueId, - .bus = bus, - .vendorId = vendorId, .productId = productId, + .vendorId = vendorId, + .bus = bus, + .uniqueId = uniqueId, }; // TODO: store this identifier somewhere return identifier; diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h index d8b352cbc6..973b4f92fa 100644 --- a/services/inputflinger/host/InputFlinger.h +++ b/services/inputflinger/host/InputFlinger.h @@ -42,7 +42,6 @@ public: virtual status_t dump(int fd, const Vector<String16>& args); void setInputWindows(const std::vector<InputWindowInfo>&, const sp<ISetInputWindowsListener>&) {} - void transferTouchFocus(const sp<IBinder>&, const sp<IBinder>&) {} void registerInputChannel(const sp<InputChannel>&) {} void unregisterInputChannel(const sp<InputChannel>&) {} diff --git a/services/inputflinger/reporter/InputReporterInterface.h b/services/inputflinger/include/InputReporterInterface.h index e5d360609f..906d7f25f2 100644 --- a/services/inputflinger/reporter/InputReporterInterface.h +++ b/services/inputflinger/include/InputReporterInterface.h @@ -27,7 +27,7 @@ namespace android { */ class InputReporterInterface : public virtual RefBase { protected: - virtual ~InputReporterInterface() {} + virtual ~InputReporterInterface() { } public: // Report a key that was not handled by the system or apps. diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp deleted file mode 100644 index 4e97397e2b..0000000000 --- a/services/inputflinger/reader/Android.bp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -cc_library_headers { - name: "libinputreader_headers", - export_include_dirs: [ - "include", - "mapper", - "mapper/accumulator", - ], -} - -cc_library_shared { - name: "libinputreader", - defaults: ["inputflinger_defaults"], - - srcs: [ - "EventHub.cpp", - "InputDevice.cpp", - "mapper/accumulator/CursorButtonAccumulator.cpp", - "mapper/accumulator/CursorScrollAccumulator.cpp", - "mapper/accumulator/SingleTouchMotionAccumulator.cpp", - "mapper/accumulator/TouchButtonAccumulator.cpp", - "mapper/CursorInputMapper.cpp", - "mapper/ExternalStylusInputMapper.cpp", - "mapper/InputMapper.cpp", - "mapper/JoystickInputMapper.cpp", - "mapper/KeyboardInputMapper.cpp", - "mapper/MultiTouchInputMapper.cpp", - "mapper/RotaryEncoderInputMapper.cpp", - "mapper/SingleTouchInputMapper.cpp", - "mapper/SwitchInputMapper.cpp", - "mapper/TouchInputMapper.cpp", - "mapper/VibratorInputMapper.cpp", - "InputReader.cpp", - "InputReaderFactory.cpp", - "TouchVideoDevice.cpp", - ], - - shared_libs: [ - "libbase", - "libinputflinger_base", - "libcrypto", - "libcutils", - "libinput", - "liblog", - "libui", - "libutils", - "libhardware_legacy", - "libstatslog", - ], - - header_libs: [ - "libinputflinger_headers", - "libinputreader_headers", - ], - - export_header_lib_headers: [ - "libinputflinger_headers", - ], -} diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp deleted file mode 100644 index d0613b0c69..0000000000 --- a/services/inputflinger/reader/InputDevice.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "InputDevice.h" - -#include "InputMapper.h" - -namespace android { - -InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - int32_t controllerNumber, const InputDeviceIdentifier& identifier, - uint32_t classes) - : mContext(context), - mId(id), - mGeneration(generation), - mControllerNumber(controllerNumber), - mIdentifier(identifier), - mClasses(classes), - mSources(0), - mIsExternal(false), - mHasMic(false), - mDropUntilNextSync(false) {} - -InputDevice::~InputDevice() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - delete mMappers[i]; - } - mMappers.clear(); -} - -bool InputDevice::isEnabled() { - return getEventHub()->isDeviceEnabled(mId); -} - -void InputDevice::setEnabled(bool enabled, nsecs_t when) { - if (isEnabled() == enabled) { - return; - } - - if (enabled) { - getEventHub()->enableDevice(mId); - reset(when); - } else { - reset(when); - getEventHub()->disableDevice(mId); - } - // Must change generation to flag this device as changed - bumpGeneration(); -} - -void InputDevice::dump(std::string& dump) { - InputDeviceInfo deviceInfo; - getDeviceInfo(&deviceInfo); - - dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(), - deviceInfo.getDisplayName().c_str()); - dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration); - dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); - dump += StringPrintf(INDENT2 "AssociatedDisplayPort: "); - if (mAssociatedDisplayPort) { - dump += StringPrintf("%" PRIu8 "\n", *mAssociatedDisplayPort); - } else { - dump += "<none>\n"; - } - dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic)); - dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); - dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); - - const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); - if (!ranges.empty()) { - dump += INDENT2 "Motion Ranges:\n"; - for (size_t i = 0; i < ranges.size(); i++) { - const InputDeviceInfo::MotionRange& range = ranges[i]; - const char* label = getAxisLabel(range.axis); - char name[32]; - if (label) { - strncpy(name, label, sizeof(name)); - name[sizeof(name) - 1] = '\0'; - } else { - snprintf(name, sizeof(name), "%d", range.axis); - } - dump += StringPrintf(INDENT3 - "%s: source=0x%08x, " - "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n", - name, range.source, range.min, range.max, range.flat, range.fuzz, - range.resolution); - } - } - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->dump(dump); - } -} - -void InputDevice::addMapper(InputMapper* mapper) { - mMappers.push_back(mapper); -} - -void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, - uint32_t changes) { - mSources = 0; - - if (!isIgnored()) { - if (!changes) { // first time only - mContext->getEventHub()->getConfiguration(mId, &mConfiguration); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - sp<KeyCharacterMap> keyboardLayout = - mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier); - if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { - bumpGeneration(); - } - } - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); - if (mAlias != alias) { - mAlias = alias; - bumpGeneration(); - } - } - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) { - ssize_t index = config->disabledDevices.indexOf(mId); - bool enabled = index < 0; - setEnabled(enabled, when); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - // In most situations, no port will be specified. - mAssociatedDisplayPort = std::nullopt; - // Find the display port that corresponds to the current input port. - const std::string& inputPort = mIdentifier.location; - if (!inputPort.empty()) { - const std::unordered_map<std::string, uint8_t>& ports = config->portAssociations; - const auto& displayPort = ports.find(inputPort); - if (displayPort != ports.end()) { - mAssociatedDisplayPort = std::make_optional(displayPort->second); - } - } - } - - for (InputMapper* mapper : mMappers) { - mapper->configure(when, config, changes); - mSources |= mapper->getSources(); - } - } -} - -void InputDevice::reset(nsecs_t when) { - for (InputMapper* mapper : mMappers) { - mapper->reset(when); - } - - mContext->updateGlobalMetaState(); - - notifyReset(when); -} - -void InputDevice::process(const RawEvent* rawEvents, size_t count) { - // Process all of the events in order for each mapper. - // We cannot simply ask each mapper to process them in bulk because mappers may - // have side-effects that must be interleaved. For example, joystick movement events and - // gamepad button presses are handled by different mappers but they should be dispatched - // in the order received. - for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { -#if DEBUG_RAW_EVENTS - ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64, - rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, rawEvent->when); -#endif - - if (mDropUntilNextSync) { - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - mDropUntilNextSync = false; -#if DEBUG_RAW_EVENTS - ALOGD("Recovered from input event buffer overrun."); -#endif - } else { -#if DEBUG_RAW_EVENTS - ALOGD("Dropped input event while waiting for next input sync."); -#endif - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { - ALOGI("Detected input event buffer overrun for device %s.", getName().c_str()); - mDropUntilNextSync = true; - reset(rawEvent->when); - } else { - for (InputMapper* mapper : mMappers) { - mapper->process(rawEvent); - } - } - --count; - } -} - -void InputDevice::timeoutExpired(nsecs_t when) { - for (InputMapper* mapper : mMappers) { - mapper->timeoutExpired(when); - } -} - -void InputDevice::updateExternalStylusState(const StylusState& state) { - for (InputMapper* mapper : mMappers) { - mapper->updateExternalStylusState(state); - } -} - -void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { - outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal, - mHasMic); - for (InputMapper* mapper : mMappers) { - mapper->populateDeviceInfo(outDeviceInfo); - } -} - -int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getState(sourceMask, keyCode, &InputMapper::getKeyCodeState); -} - -int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getState(sourceMask, scanCode, &InputMapper::getScanCodeState); -} - -int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getState(sourceMask, switchCode, &InputMapper::getSwitchState); -} - -int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - for (InputMapper* mapper : mMappers) { - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. - int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - return result; -} - -bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - for (InputMapper* mapper : mMappers) { - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); - } - } - return result; -} - -void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { - for (InputMapper* mapper : mMappers) { - mapper->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputDevice::cancelVibrate(int32_t token) { - for (InputMapper* mapper : mMappers) { - mapper->cancelVibrate(token); - } -} - -void InputDevice::cancelTouch(nsecs_t when) { - for (InputMapper* mapper : mMappers) { - mapper->cancelTouch(when); - } -} - -int32_t InputDevice::getMetaState() { - int32_t result = 0; - for (InputMapper* mapper : mMappers) { - result |= mapper->getMetaState(); - } - return result; -} - -void InputDevice::updateMetaState(int32_t keyCode) { - for (InputMapper* mapper : mMappers) { - mapper->updateMetaState(keyCode); - } -} - -void InputDevice::fadePointer() { - for (InputMapper* mapper : mMappers) { - mapper->fadePointer(); - } -} - -void InputDevice::bumpGeneration() { - mGeneration = mContext->bumpGeneration(); -} - -void InputDevice::notifyReset(nsecs_t when) { - NotifyDeviceResetArgs args(mContext->getNextSequenceNum(), when, mId); - mContext->getListener()->notifyDeviceReset(&args); -} - -std::optional<int32_t> InputDevice::getAssociatedDisplay() { - for (InputMapper* mapper : mMappers) { - std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay(); - if (associatedDisplayId) { - return associatedDisplayId; - } - } - - return std::nullopt; -} - -} // namespace android diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp deleted file mode 100644 index 27cbf192d3..0000000000 --- a/services/inputflinger/reader/InputReader.cpp +++ /dev/null @@ -1,767 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Macros.h" - -#include "InputReader.h" - -#include "CursorInputMapper.h" -#include "ExternalStylusInputMapper.h" -#include "InputReaderContext.h" -#include "JoystickInputMapper.h" -#include "KeyboardInputMapper.h" -#include "MultiTouchInputMapper.h" -#include "RotaryEncoderInputMapper.h" -#include "SingleTouchInputMapper.h" -#include "SwitchInputMapper.h" -#include "VibratorInputMapper.h" - -#include <errno.h> -#include <inttypes.h> -#include <limits.h> -#include <math.h> -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> - -#include <log/log.h> - -#include <android-base/stringprintf.h> -#include <input/Keyboard.h> -#include <input/VirtualKeyMap.h> - - -using android::base::StringPrintf; - -namespace android { - -InputReader::InputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener) - : mContext(this), - mEventHub(eventHub), - mPolicy(policy), - mNextSequenceNum(1), - mGlobalMetaState(0), - mGeneration(1), - mDisableVirtualKeysTimeout(LLONG_MIN), - mNextTimeout(LLONG_MAX), - mConfigurationChangesToRefresh(0) { - mQueuedListener = new QueuedInputListener(listener); - - { // acquire lock - AutoMutex _l(mLock); - - refreshConfigurationLocked(0); - updateGlobalMetaStateLocked(); - } // release lock -} - -InputReader::~InputReader() { - for (size_t i = 0; i < mDevices.size(); i++) { - delete mDevices.valueAt(i); - } -} - -void InputReader::loopOnce() { - int32_t oldGeneration; - int32_t timeoutMillis; - bool inputDevicesChanged = false; - std::vector<InputDeviceInfo> inputDevices; - { // acquire lock - AutoMutex _l(mLock); - - oldGeneration = mGeneration; - timeoutMillis = -1; - - uint32_t changes = mConfigurationChangesToRefresh; - if (changes) { - mConfigurationChangesToRefresh = 0; - timeoutMillis = 0; - refreshConfigurationLocked(changes); - } else if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); - } - } // release lock - - size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); - - { // acquire lock - AutoMutex _l(mLock); - mReaderIsAliveCondition.broadcast(); - - if (count) { - processEventsLocked(mEventBuffer, count); - } - - if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (now >= mNextTimeout) { -#if DEBUG_RAW_EVENTS - ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); -#endif - mNextTimeout = LLONG_MAX; - timeoutExpiredLocked(now); - } - } - - if (oldGeneration != mGeneration) { - inputDevicesChanged = true; - getInputDevicesLocked(inputDevices); - } - } // release lock - - // Send out a message that the describes the changed input devices. - if (inputDevicesChanged) { - mPolicy->notifyInputDevicesChanged(inputDevices); - } - - // Flush queued events out to the listener. - // This must happen outside of the lock because the listener could potentially call - // back into the InputReader's methods, such as getScanCodeState, or become blocked - // on another thread similarly waiting to acquire the InputReader lock thereby - // resulting in a deadlock. This situation is actually quite plausible because the - // listener is actually the input dispatcher, which calls into the window manager, - // which occasionally calls into the input reader. - mQueuedListener->flush(); -} - -void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { - for (const RawEvent* rawEvent = rawEvents; count;) { - int32_t type = rawEvent->type; - size_t batchSize = 1; - if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { - int32_t deviceId = rawEvent->deviceId; - while (batchSize < count) { - if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || - rawEvent[batchSize].deviceId != deviceId) { - break; - } - batchSize += 1; - } -#if DEBUG_RAW_EVENTS - ALOGD("BatchSize: %zu Count: %zu", batchSize, count); -#endif - processEventsForDeviceLocked(deviceId, rawEvent, batchSize); - } else { - switch (rawEvent->type) { - case EventHubInterface::DEVICE_ADDED: - addDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::DEVICE_REMOVED: - removeDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::FINISHED_DEVICE_SCAN: - handleConfigurationChangedLocked(rawEvent->when); - break; - default: - ALOG_ASSERT(false); // can't happen - break; - } - } - count -= batchSize; - rawEvent += batchSize; - } -} - -void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); - return; - } - - InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); - uint32_t classes = mEventHub->getDeviceClasses(deviceId); - int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); - - InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); - device->configure(when, &mConfig, 0); - device->reset(when); - - if (device->isIgnored()) { - ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, - identifier.name.c_str()); - } else { - ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, identifier.name.c_str(), - device->getSources()); - } - - mDevices.add(deviceId, device); - bumpGenerationLocked(); - - if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { - notifyExternalStylusPresenceChanged(); - } -} - -void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { - InputDevice* device = nullptr; - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); - return; - } - - device = mDevices.valueAt(deviceIndex); - mDevices.removeItemsAt(deviceIndex, 1); - bumpGenerationLocked(); - - if (device->isIgnored()) { - ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(), - device->getName().c_str()); - } else { - ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", device->getId(), - device->getName().c_str(), device->getSources()); - } - - if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { - notifyExternalStylusPresenceChanged(); - } - - device->reset(when); - delete device; -} - -InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, - uint32_t classes) { - InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), - controllerNumber, identifier, classes); - - // External devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { - device->setExternal(true); - } - - // Devices with mics. - if (classes & INPUT_DEVICE_CLASS_MIC) { - device->setMic(true); - } - - // Switch-like devices. - if (classes & INPUT_DEVICE_CLASS_SWITCH) { - device->addMapper(new SwitchInputMapper(device)); - } - - // Scroll wheel-like devices. - if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) { - device->addMapper(new RotaryEncoderInputMapper(device)); - } - - // Vibrator-like devices. - if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { - device->addMapper(new VibratorInputMapper(device)); - } - - // Keyboard-like devices. - uint32_t keyboardSource = 0; - int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; - if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { - keyboardSource |= AINPUT_SOURCE_KEYBOARD; - } - if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { - keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; - } - if (classes & INPUT_DEVICE_CLASS_DPAD) { - keyboardSource |= AINPUT_SOURCE_DPAD; - } - if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { - keyboardSource |= AINPUT_SOURCE_GAMEPAD; - } - - if (keyboardSource != 0) { - device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); - } - - // Cursor-like devices. - if (classes & INPUT_DEVICE_CLASS_CURSOR) { - device->addMapper(new CursorInputMapper(device)); - } - - // Touchscreens and touchpad devices. - if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { - device->addMapper(new MultiTouchInputMapper(device)); - } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { - device->addMapper(new SingleTouchInputMapper(device)); - } - - // Joystick-like devices. - if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { - device->addMapper(new JoystickInputMapper(device)); - } - - // External stylus-like devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { - device->addMapper(new ExternalStylusInputMapper(device)); - } - - return device; -} - -void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, - size_t count) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Discarding event for unknown deviceId %d.", deviceId); - return; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - // ALOGD("Discarding event for ignored deviceId %d.", deviceId); - return; - } - - device->process(rawEvents, count); -} - -void InputReader::timeoutExpiredLocked(nsecs_t when) { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - device->timeoutExpired(when); - } - } -} - -void InputReader::handleConfigurationChangedLocked(nsecs_t when) { - // Reset global meta state because it depends on the list of all configured devices. - updateGlobalMetaStateLocked(); - - // Enqueue configuration changed. - NotifyConfigurationChangedArgs args(mContext.getNextSequenceNum(), when); - mQueuedListener->notifyConfigurationChanged(&args); -} - -void InputReader::refreshConfigurationLocked(uint32_t changes) { - mPolicy->getReaderConfiguration(&mConfig); - mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); - - if (changes) { - ALOGI("Reconfiguring input devices. changes=0x%08x", changes); - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { - mEventHub->requestReopenDevices(); - } else { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->configure(now, &mConfig, changes); - } - } - } -} - -void InputReader::updateGlobalMetaStateLocked() { - mGlobalMetaState = 0; - - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - mGlobalMetaState |= device->getMetaState(); - } -} - -int32_t InputReader::getGlobalMetaStateLocked() { - return mGlobalMetaState; -} - -void InputReader::notifyExternalStylusPresenceChanged() { - refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); -} - -void InputReader::getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { - InputDeviceInfo info; - device->getDeviceInfo(&info); - outDevices.push_back(info); - } - } -} - -void InputReader::dispatchExternalStylusState(const StylusState& state) { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->updateExternalStylusState(state); - } -} - -void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { - mDisableVirtualKeysTimeout = time; -} - -bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, - int32_t scanCode) { - if (now < mDisableVirtualKeysTimeout) { - ALOGI("Dropping virtual key from device %s because virtual keys are " - "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", - device->getName().c_str(), (mDisableVirtualKeysTimeout - now) * 0.000001, keyCode, - scanCode); - return true; - } else { - return false; - } -} - -void InputReader::fadePointerLocked() { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->fadePointer(); - } -} - -void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { - if (when < mNextTimeout) { - mNextTimeout = when; - mEventHub->wake(); - } -} - -int32_t InputReader::bumpGenerationLocked() { - return ++mGeneration; -} - -void InputReader::getInputDevices(std::vector<InputDeviceInfo>& outInputDevices) { - AutoMutex _l(mLock); - getInputDevicesLocked(outInputDevices); -} - -void InputReader::getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices) { - outInputDevices.clear(); - - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - InputDeviceInfo info; - device->getDeviceInfo(&info); - outInputDevices.push_back(info); - } - } -} - -int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState); -} - -int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState); -} - -int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState); -} - -int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = (device->*getStateFunc)(sourceMask, code); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. - int32_t currentResult = (device->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - } - return result; -} - -void InputReader::toggleCapsLockState(int32_t deviceId) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId); - return; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - return; - } - - device->updateMetaState(AKEYCODE_CAPS_LOCK); -} - -bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - AutoMutex _l(mLock); - - memset(outFlags, 0, numCodes); - return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); -} - -bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) { - bool result = false; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result |= device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); - } - } - } - return result; -} - -void InputReader::requestRefreshConfiguration(uint32_t changes) { - AutoMutex _l(mLock); - - if (changes) { - bool needWake = !mConfigurationChangesToRefresh; - mConfigurationChangesToRefresh |= changes; - - if (needWake) { - mEventHub->wake(); - } - } -} - -void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->cancelVibrate(token); - } -} - -bool InputReader::isInputDeviceEnabled(int32_t deviceId) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - return device->isEnabled(); - } - ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); - return false; -} - -bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); - return false; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplay(); - // No associated display. By default, can dispatch to all displays. - if (!associatedDisplayId) { - return true; - } - - if (*associatedDisplayId == ADISPLAY_ID_NONE) { - ALOGW("Device has associated, but no associated display id."); - return true; - } - - return *associatedDisplayId == displayId; -} - -void InputReader::dump(std::string& dump) { - AutoMutex _l(mLock); - - mEventHub->dump(dump); - dump += "\n"; - - dump += "Input Reader State:\n"; - - for (size_t i = 0; i < mDevices.size(); i++) { - mDevices.valueAt(i)->dump(dump); - } - - dump += INDENT "Configuration:\n"; - dump += INDENT2 "ExcludedDeviceNames: ["; - for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { - if (i != 0) { - dump += ", "; - } - dump += mConfig.excludedDeviceNames[i]; - } - dump += "]\n"; - dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", - mConfig.virtualKeyQuietTime * 0.000001f); - - dump += StringPrintf(INDENT2 "PointerVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, " - "acceleration=%0.3f\n", - mConfig.pointerVelocityControlParameters.scale, - mConfig.pointerVelocityControlParameters.lowThreshold, - mConfig.pointerVelocityControlParameters.highThreshold, - mConfig.pointerVelocityControlParameters.acceleration); - - dump += StringPrintf(INDENT2 "WheelVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, " - "acceleration=%0.3f\n", - mConfig.wheelVelocityControlParameters.scale, - mConfig.wheelVelocityControlParameters.lowThreshold, - mConfig.wheelVelocityControlParameters.highThreshold, - mConfig.wheelVelocityControlParameters.acceleration); - - dump += StringPrintf(INDENT2 "PointerGesture:\n"); - dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(mConfig.pointerGesturesEnabled)); - dump += StringPrintf(INDENT3 "QuietInterval: %0.1fms\n", - mConfig.pointerGestureQuietInterval * 0.000001f); - dump += StringPrintf(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", - mConfig.pointerGestureDragMinSwitchSpeed); - dump += StringPrintf(INDENT3 "TapInterval: %0.1fms\n", - mConfig.pointerGestureTapInterval * 0.000001f); - dump += StringPrintf(INDENT3 "TapDragInterval: %0.1fms\n", - mConfig.pointerGestureTapDragInterval * 0.000001f); - dump += StringPrintf(INDENT3 "TapSlop: %0.1fpx\n", mConfig.pointerGestureTapSlop); - dump += StringPrintf(INDENT3 "MultitouchSettleInterval: %0.1fms\n", - mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); - dump += StringPrintf(INDENT3 "MultitouchMinDistance: %0.1fpx\n", - mConfig.pointerGestureMultitouchMinDistance); - dump += StringPrintf(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", - mConfig.pointerGestureSwipeTransitionAngleCosine); - dump += StringPrintf(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", - mConfig.pointerGestureSwipeMaxWidthRatio); - dump += StringPrintf(INDENT3 "MovementSpeedRatio: %0.1f\n", - mConfig.pointerGestureMovementSpeedRatio); - dump += StringPrintf(INDENT3 "ZoomSpeedRatio: %0.1f\n", mConfig.pointerGestureZoomSpeedRatio); - - dump += INDENT3 "Viewports:\n"; - mConfig.dump(dump); -} - -void InputReader::monitor() { - // Acquire and release the lock to ensure that the reader has not deadlocked. - mLock.lock(); - mEventHub->wake(); - mReaderIsAliveCondition.wait(mLock); - mLock.unlock(); - - // Check the EventHub - mEventHub->monitor(); -} - -// --- InputReader::ContextImpl --- - -InputReader::ContextImpl::ContextImpl(InputReader* reader) : mReader(reader) {} - -void InputReader::ContextImpl::updateGlobalMetaState() { - // lock is already held by the input loop - mReader->updateGlobalMetaStateLocked(); -} - -int32_t InputReader::ContextImpl::getGlobalMetaState() { - // lock is already held by the input loop - return mReader->getGlobalMetaStateLocked(); -} - -void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { - // lock is already held by the input loop - mReader->disableVirtualKeysUntilLocked(time); -} - -bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, InputDevice* device, - int32_t keyCode, int32_t scanCode) { - // lock is already held by the input loop - return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); -} - -void InputReader::ContextImpl::fadePointer() { - // lock is already held by the input loop - mReader->fadePointerLocked(); -} - -void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { - // lock is already held by the input loop - mReader->requestTimeoutAtTimeLocked(when); -} - -int32_t InputReader::ContextImpl::bumpGeneration() { - // lock is already held by the input loop - return mReader->bumpGenerationLocked(); -} - -void InputReader::ContextImpl::getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) { - // lock is already held by whatever called refreshConfigurationLocked - mReader->getExternalStylusDevicesLocked(outDevices); -} - -void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) { - mReader->dispatchExternalStylusState(state); -} - -InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { - return mReader->mPolicy.get(); -} - -InputListenerInterface* InputReader::ContextImpl::getListener() { - return mReader->mQueuedListener.get(); -} - -EventHubInterface* InputReader::ContextImpl::getEventHub() { - return mReader->mEventHub.get(); -} - -uint32_t InputReader::ContextImpl::getNextSequenceNum() { - return (mReader->mNextSequenceNum)++; -} - -} // namespace android diff --git a/services/inputflinger/reader/Macros.h b/services/inputflinger/reader/Macros.h deleted file mode 100644 index 827e31a1bd..0000000000 --- a/services/inputflinger/reader/Macros.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_MACROS_H -#define _UI_INPUTREADER_MACROS_H - -#define LOG_TAG "InputReader" - -//#define LOG_NDEBUG 0 - -// Log debug messages for each raw event received from the EventHub. -#define DEBUG_RAW_EVENTS 0 - -// Log debug messages about touch screen filtering hacks. -#define DEBUG_HACKS 0 - -// Log debug messages about virtual key processing. -#define DEBUG_VIRTUAL_KEYS 0 - -// Log debug messages about pointers. -#define DEBUG_POINTERS 0 - -// Log debug messages about pointer assignment calculations. -#define DEBUG_POINTER_ASSIGNMENT 0 - -// Log debug messages about gesture detection. -#define DEBUG_GESTURES 0 - -// Log debug messages about the vibrator. -#define DEBUG_VIBRATOR 0 - -// Log debug messages about fusing stylus data. -#define DEBUG_STYLUS_FUSION 0 - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " -#define INDENT4 " " -#define INDENT5 " " - -#include <input/Input.h> - -namespace android { - -// --- Static Functions --- - -template <typename T> -inline static T abs(const T& value) { - return value < 0 ? -value : value; -} - -template <typename T> -inline static T min(const T& a, const T& b) { - return a < b ? a : b; -} - -inline static float avg(float x, float y) { - return (x + y) / 2; -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { - return (sources & sourceMask & ~AINPUT_SOURCE_CLASS_MASK) != 0; -} - -} // namespace android - -#endif // _UI_INPUTREADER_MACROS_H
\ No newline at end of file diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h deleted file mode 100644 index 57f0b319c8..0000000000 --- a/services/inputflinger/reader/include/InputDevice.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_INPUT_DEVICE_H -#define _UI_INPUTREADER_INPUT_DEVICE_H - -#include "EventHub.h" -#include "InputReaderBase.h" -#include "InputReaderContext.h" - -#include <input/DisplayViewport.h> -#include <input/InputDevice.h> -#include <utils/PropertyMap.h> - -#include <stdint.h> -#include <optional> -#include <vector> - -namespace android { - -class InputMapper; - -/* Represents the state of a single input device. */ -class InputDevice { -public: - InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - int32_t controllerNumber, const InputDeviceIdentifier& identifier, - uint32_t classes); - ~InputDevice(); - - inline InputReaderContext* getContext() { return mContext; } - inline int32_t getId() const { return mId; } - inline int32_t getControllerNumber() const { return mControllerNumber; } - inline int32_t getGeneration() const { return mGeneration; } - inline const std::string getName() const { return mIdentifier.name; } - inline const std::string getDescriptor() { return mIdentifier.descriptor; } - inline uint32_t getClasses() const { return mClasses; } - inline uint32_t getSources() const { return mSources; } - - inline bool isExternal() { return mIsExternal; } - inline void setExternal(bool external) { mIsExternal = external; } - inline std::optional<uint8_t> getAssociatedDisplayPort() const { - return mAssociatedDisplayPort; - } - - inline void setMic(bool hasMic) { mHasMic = hasMic; } - inline bool hasMic() const { return mHasMic; } - - inline bool isIgnored() { return mMappers.empty(); } - - bool isEnabled(); - void setEnabled(bool enabled, nsecs_t when); - - void dump(std::string& dump); - void addMapper(InputMapper* mapper); - void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - void reset(nsecs_t when); - void process(const RawEvent* rawEvents, size_t count); - void timeoutExpired(nsecs_t when); - void updateExternalStylusState(const StylusState& state); - - void getDeviceInfo(InputDeviceInfo* outDeviceInfo); - int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags); - void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); - void cancelVibrate(int32_t token); - void cancelTouch(nsecs_t when); - - int32_t getMetaState(); - void updateMetaState(int32_t keyCode); - - void fadePointer(); - - void bumpGeneration(); - - void notifyReset(nsecs_t when); - - inline const PropertyMap& getConfiguration() { return mConfiguration; } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - bool hasKey(int32_t code) { return getEventHub()->hasScanCode(mId, code); } - - bool hasAbsoluteAxis(int32_t code) { - RawAbsoluteAxisInfo info; - getEventHub()->getAbsoluteAxisInfo(mId, code, &info); - return info.valid; - } - - bool isKeyPressed(int32_t code) { - return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; - } - - int32_t getAbsoluteAxisValue(int32_t code) { - int32_t value; - getEventHub()->getAbsoluteAxisValue(mId, code, &value); - return value; - } - - std::optional<int32_t> getAssociatedDisplay(); - -private: - InputReaderContext* mContext; - int32_t mId; - int32_t mGeneration; - int32_t mControllerNumber; - InputDeviceIdentifier mIdentifier; - std::string mAlias; - uint32_t mClasses; - - std::vector<InputMapper*> mMappers; - - uint32_t mSources; - bool mIsExternal; - std::optional<uint8_t> mAssociatedDisplayPort; - bool mHasMic; - bool mDropUntilNextSync; - - typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); - - PropertyMap mConfiguration; -}; - -} // namespace android - -#endif //_UI_INPUTREADER_INPUT_DEVICE_H diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h deleted file mode 100644 index e29c8f219c..0000000000 --- a/services/inputflinger/reader/include/InputReader.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_INPUT_READER_H -#define _UI_INPUTREADER_INPUT_READER_H - -#include "EventHub.h" -#include "InputListener.h" -#include "InputReaderBase.h" -#include "InputReaderContext.h" - -#include <utils/BitSet.h> -#include <utils/Condition.h> -#include <utils/KeyedVector.h> -#include <utils/Mutex.h> -#include <utils/Timers.h> - -#include <vector> - -namespace android { - -class InputDevice; -class InputMapper; -struct StylusState; - -/* The input reader reads raw event data from the event hub and processes it into input events - * that it sends to the input listener. Some functions of the input reader, such as early - * event filtering in low power states, are controlled by a separate policy object. - * - * The InputReader owns a collection of InputMappers. Most of the work it does happens - * on the input reader thread but the InputReader can receive queries from other system - * components running on arbitrary threads. To keep things manageable, the InputReader - * uses a single Mutex to guard its state. The Mutex may be held while calling into the - * EventHub or the InputReaderPolicy but it is never held while calling into the - * InputListener. - */ -class InputReader : public InputReaderInterface { -public: - InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener); - virtual ~InputReader(); - - virtual void dump(std::string& dump); - virtual void monitor(); - - virtual void loopOnce(); - - virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices); - - virtual bool isInputDeviceEnabled(int32_t deviceId); - - virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode); - virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode); - virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw); - - virtual void toggleCapsLockState(int32_t deviceId); - - virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual void requestRefreshConfiguration(uint32_t changes); - - virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token); - virtual void cancelVibrate(int32_t deviceId, int32_t token); - - virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId); -protected: - // These members are protected so they can be instrumented by test cases. - virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, - uint32_t classes); - - class ContextImpl : public InputReaderContext { - InputReader* mReader; - - public: - explicit ContextImpl(InputReader* reader); - - virtual void updateGlobalMetaState(); - virtual int32_t getGlobalMetaState(); - virtual void disableVirtualKeysUntil(nsecs_t time); - virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, - int32_t scanCode); - virtual void fadePointer(); - virtual void requestTimeoutAtTime(nsecs_t when); - virtual int32_t bumpGeneration(); - virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices); - virtual void dispatchExternalStylusState(const StylusState& outState); - virtual InputReaderPolicyInterface* getPolicy(); - virtual InputListenerInterface* getListener(); - virtual EventHubInterface* getEventHub(); - virtual uint32_t getNextSequenceNum(); - } mContext; - - friend class ContextImpl; - -private: - Mutex mLock; - - Condition mReaderIsAliveCondition; - - sp<EventHubInterface> mEventHub; - sp<InputReaderPolicyInterface> mPolicy; - sp<QueuedInputListener> mQueuedListener; - - InputReaderConfiguration mConfig; - - // used by InputReaderContext::getNextSequenceNum() as a counter for event sequence numbers - uint32_t mNextSequenceNum; - - // The event queue. - static const int EVENT_BUFFER_SIZE = 256; - RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; - - KeyedVector<int32_t, InputDevice*> mDevices; - - // low-level input event decoding and device management - void processEventsLocked(const RawEvent* rawEvents, size_t count); - - void addDeviceLocked(nsecs_t when, int32_t deviceId); - void removeDeviceLocked(nsecs_t when, int32_t deviceId); - void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); - void timeoutExpiredLocked(nsecs_t when); - - void handleConfigurationChangedLocked(nsecs_t when); - - int32_t mGlobalMetaState; - void updateGlobalMetaStateLocked(); - int32_t getGlobalMetaStateLocked(); - - void notifyExternalStylusPresenceChanged(); - void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices); - void dispatchExternalStylusState(const StylusState& state); - - void fadePointerLocked(); - - int32_t mGeneration; - int32_t bumpGenerationLocked(); - - void getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices); - - nsecs_t mDisableVirtualKeysTimeout; - void disableVirtualKeysUntilLocked(nsecs_t time); - bool shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, - int32_t scanCode); - - nsecs_t mNextTimeout; - void requestTimeoutAtTimeLocked(nsecs_t when); - - uint32_t mConfigurationChangesToRefresh; - void refreshConfigurationLocked(uint32_t changes); - - // state queries - typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc); - bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_INPUT_READER_H diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h deleted file mode 100644 index 3472346d44..0000000000 --- a/services/inputflinger/reader/include/InputReaderContext.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_INPUT_READER_CONTEXT_H -#define _UI_INPUTREADER_INPUT_READER_CONTEXT_H - -#include <input/InputDevice.h> - -#include <vector> - -namespace android { - -class EventHubInterface; -class InputDevice; -class InputListenerInterface; -class InputMapper; -class InputReaderPolicyInterface; -struct StylusState; - -/* Internal interface used by individual input devices to access global input device state - * and parameters maintained by the input reader. - */ -class InputReaderContext { -public: - InputReaderContext() {} - virtual ~InputReaderContext() {} - - virtual void updateGlobalMetaState() = 0; - virtual int32_t getGlobalMetaState() = 0; - - virtual void disableVirtualKeysUntil(nsecs_t time) = 0; - virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, - int32_t scanCode) = 0; - - virtual void fadePointer() = 0; - - virtual void requestTimeoutAtTime(nsecs_t when) = 0; - virtual int32_t bumpGeneration() = 0; - - virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) = 0; - virtual void dispatchExternalStylusState(const StylusState& outState) = 0; - - virtual InputReaderPolicyInterface* getPolicy() = 0; - virtual InputListenerInterface* getListener() = 0; - virtual EventHubInterface* getEventHub() = 0; - - virtual uint32_t getNextSequenceNum() = 0; -}; - -} // namespace android - -#endif // _UI_INPUTREADER_INPUT_READER_CONTEXT_H diff --git a/services/inputflinger/reader/include/StylusState.h b/services/inputflinger/reader/include/StylusState.h deleted file mode 100644 index 17f158c9e1..0000000000 --- a/services/inputflinger/reader/include/StylusState.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_STYLUS_STATE_H -#define _UI_INPUTREADER_STYLUS_STATE_H - -#include <input/Input.h> - -#include <limits.h> - -namespace android { - -struct StylusState { - /* Time the stylus event was received. */ - nsecs_t when; - /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */ - float pressure; - /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ - uint32_t buttons; - /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ - int32_t toolType; - - void copyFrom(const StylusState& other) { - when = other.when; - pressure = other.pressure; - buttons = other.buttons; - toolType = other.toolType; - } - - void clear() { - when = LLONG_MAX; - pressure = 0.f; - buttons = 0; - toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; - } -}; - -} // namespace android - -#endif // _UI_INPUTREADER_STYLUS_STATE_H diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp deleted file mode 100644 index da85fda0e9..0000000000 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "CursorInputMapper.h" - -#include "CursorButtonAccumulator.h" -#include "CursorScrollAccumulator.h" -#include "TouchCursorInputMapperCommon.h" - -namespace android { - -// --- CursorMotionAccumulator --- - -CursorMotionAccumulator::CursorMotionAccumulator() { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::clearRelativeAxes() { - mRelX = 0; - mRelY = 0; -} - -void CursorMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_X: - mRelX = rawEvent->value; - break; - case REL_Y: - mRelY = rawEvent->value; - break; - } - } -} - -void CursorMotionAccumulator::finishSync() { - clearRelativeAxes(); -} - -// --- CursorInputMapper --- - -CursorInputMapper::CursorInputMapper(InputDevice* device) : InputMapper(device) {} - -CursorInputMapper::~CursorInputMapper() {} - -uint32_t CursorInputMapper::getSources() { - return mSource; -} - -void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mParameters.mode == Parameters::MODE_POINTER) { - float minX, minY, maxX, maxY; - if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f); - } - } else { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f); - } - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } -} - -void CursorInputMapper::dump(std::string& dump) { - dump += INDENT2 "Cursor Input Mapper:\n"; - dumpParameters(dump); - dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale); - dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale); - dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision); - dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision); - dump += StringPrintf(INDENT3 "HaveVWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeVWheel())); - dump += StringPrintf(INDENT3 "HaveHWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeHWheel())); - dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); - dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); - dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation); - dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState); - dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); - dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); -} - -void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, - uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - mCursorScrollAccumulator.configure(getDevice()); - - // Configure basic parameters. - configureParameters(); - - // Configure device mode. - switch (mParameters.mode) { - case Parameters::MODE_POINTER_RELATIVE: - // Should not happen during first time configuration. - ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER"); - mParameters.mode = Parameters::MODE_POINTER; - [[fallthrough]]; - case Parameters::MODE_POINTER: - mSource = AINPUT_SOURCE_MOUSE; - mXPrecision = 1.0f; - mYPrecision = 1.0f; - mXScale = 1.0f; - mYScale = 1.0f; - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - break; - case Parameters::MODE_NAVIGATION: - mSource = AINPUT_SOURCE_TRACKBALL; - mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - break; - } - - mVWheelScale = 1.0f; - mHWheelScale = 1.0f; - } - - if ((!changes && config->pointerCapture) || - (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) { - if (config->pointerCapture) { - if (mParameters.mode == Parameters::MODE_POINTER) { - mParameters.mode = Parameters::MODE_POINTER_RELATIVE; - mSource = AINPUT_SOURCE_MOUSE_RELATIVE; - // Keep PointerController around in order to preserve the pointer position. - mPointerController->fade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } else { - ALOGE("Cannot request pointer capture, device is not in MODE_POINTER"); - } - } else { - if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) { - mParameters.mode = Parameters::MODE_POINTER; - mSource = AINPUT_SOURCE_MOUSE; - } else { - ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE"); - } - } - bumpGeneration(); - if (changes) { - getDevice()->notifyReset(when); - } - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - mOrientation = DISPLAY_ORIENTATION_0; - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - std::optional<DisplayViewport> internalViewport = - config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); - if (internalViewport) { - mOrientation = internalViewport->orientation; - } - } - - // Update the PointerController if viewports changed. - if (mParameters.mode == Parameters::MODE_POINTER) { - getPolicy()->obtainPointerController(getDeviceId()); - } - bumpGeneration(); - } -} - -void CursorInputMapper::configureParameters() { - mParameters.mode = Parameters::MODE_POINTER; - String8 cursorModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { - if (cursorModeString == "navigation") { - mParameters.mode = Parameters::MODE_NAVIGATION; - } else if (cursorModeString != "pointer" && cursorModeString != "default") { - ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); - } - } - - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { - mParameters.hasAssociatedDisplay = true; - } -} - -void CursorInputMapper::dumpParameters(std::string& dump) { - dump += INDENT3 "Parameters:\n"; - dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n", - toString(mParameters.hasAssociatedDisplay)); - - switch (mParameters.mode) { - case Parameters::MODE_POINTER: - dump += INDENT4 "Mode: pointer\n"; - break; - case Parameters::MODE_POINTER_RELATIVE: - dump += INDENT4 "Mode: relative pointer\n"; - break; - case Parameters::MODE_NAVIGATION: - dump += INDENT4 "Mode: navigation\n"; - break; - default: - ALOG_ASSERT(false); - } - - dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); -} - -void CursorInputMapper::reset(nsecs_t when) { - mButtonState = 0; - mDownTime = 0; - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mCursorButtonAccumulator.reset(getDevice()); - mCursorMotionAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - - InputMapper::reset(when); -} - -void CursorInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorMotionAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void CursorInputMapper::sync(nsecs_t when) { - int32_t lastButtonState = mButtonState; - int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); - mButtonState = currentButtonState; - - bool wasDown = isPointerDown(lastButtonState); - bool down = isPointerDown(currentButtonState); - bool downChanged; - if (!wasDown && down) { - mDownTime = when; - downChanged = true; - } else if (wasDown && !down) { - downChanged = true; - } else { - downChanged = false; - } - nsecs_t downTime = mDownTime; - bool buttonsChanged = currentButtonState != lastButtonState; - int32_t buttonsPressed = currentButtonState & ~lastButtonState; - int32_t buttonsReleased = lastButtonState & ~currentButtonState; - - float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; - float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; - bool moved = deltaX != 0 || deltaY != 0; - - // Rotate delta according to orientation if needed. - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay && - (deltaX != 0.0f || deltaY != 0.0f)) { - rotateDelta(mOrientation, &deltaX, &deltaY); - } - - // Move the pointer. - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); - float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); - bool scrolled = vscroll != 0 || hscroll != 0; - - mWheelYVelocityControl.move(when, nullptr, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, nullptr); - - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - int32_t displayId; - if (mSource == AINPUT_SOURCE_MOUSE) { - if (moved || scrolled || buttonsChanged) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - - if (moved) { - mPointerController->move(deltaX, deltaY); - } - - if (buttonsChanged) { - mPointerController->setButtonState(currentButtonState); - } - - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - - float x, y; - mPointerController->getPosition(&x, &y); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); - displayId = mPointerController->getDisplayId(); - } else { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); - displayId = ADISPLAY_ID_NONE; - } - - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); - - // Moving an external trackball or mouse should wake the device. - // We don't do this for internal cursor devices to prevent them from waking up - // the device in your pocket. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE; - } - - // Synthesize key down from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - displayId, policyFlags, lastButtonState, currentButtonState); - - // Send motion event. - if (downChanged || moved || scrolled || buttonsChanged) { - int32_t metaState = mContext->getGlobalMetaState(); - int32_t buttonState = lastButtonState; - int32_t motionEventAction; - if (downChanged) { - motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else if (down || (mSource != AINPUT_SOURCE_MOUSE)) { - motionEventAction = AMOTION_EVENT_ACTION_MOVE; - } else { - motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; - } - - if (buttonsReleased) { - BitSet32 released(buttonsReleased); - while (!released.isEmpty()) { - int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); - buttonState &= ~actionButton; - NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, - metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, - &pointerCoords, mXPrecision, mYPrecision, downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&releaseArgs); - } - } - - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, motionEventAction, 0, 0, metaState, - currentButtonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - - if (buttonsPressed) { - BitSet32 pressed(buttonsPressed); - while (!pressed.isEmpty()) { - int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); - buttonState |= actionButton; - NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, - metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, - &pointerCoords, mXPrecision, mYPrecision, downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&pressArgs); - } - } - - ALOG_ASSERT(buttonState == currentButtonState); - - // Send hover move after UP to tell the application that the mouse is hovering now. - if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) { - NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - 0, metaState, currentButtonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, - &pointerCoords, mXPrecision, mYPrecision, downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&hoverArgs); - } - - // Send scroll events. - if (scrolled) { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, - currentButtonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, - &pointerCoords, mXPrecision, mYPrecision, downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&scrollArgs); - } - } - - // Synthesize key up from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - displayId, policyFlags, lastButtonState, currentButtonState); - - mCursorMotionAccumulator.finishSync(); - mCursorScrollAccumulator.finishSync(); -} - -int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); - } else { - return AKEY_STATE_UNKNOWN; - } -} - -void CursorInputMapper::fadePointer() { - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - -std::optional<int32_t> CursorInputMapper::getAssociatedDisplay() { - if (mParameters.hasAssociatedDisplay) { - if (mParameters.mode == Parameters::MODE_POINTER) { - return std::make_optional(mPointerController->getDisplayId()); - } else { - // If the device is orientationAware and not a mouse, - // it expects to dispatch events to any display - return std::make_optional(ADISPLAY_ID_NONE); - } - } - return std::nullopt; -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h deleted file mode 100644 index eb2ad54c80..0000000000 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H -#define _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H - -#include "CursorButtonAccumulator.h" -#include "CursorScrollAccumulator.h" -#include "InputMapper.h" - -#include <PointerControllerInterface.h> -#include <input/VelocityControl.h> - -namespace android { - -class VelocityControl; -class PointerControllerInterface; - -class CursorButtonAccumulator; -class CursorScrollAccumulator; - -/* Keeps track of cursor movements. */ -class CursorMotionAccumulator { -public: - CursorMotionAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - -private: - int32_t mRelX; - int32_t mRelY; - - void clearRelativeAxes(); -}; - -class CursorInputMapper : public InputMapper { -public: - explicit CursorInputMapper(InputDevice* device); - virtual ~CursorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - - virtual void fadePointer(); - - virtual std::optional<int32_t> getAssociatedDisplay(); - -private: - // Amount that trackball needs to move in order to generate a key event. - static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; - - // Immutable configuration parameters. - struct Parameters { - enum Mode { - MODE_POINTER, - MODE_POINTER_RELATIVE, - MODE_NAVIGATION, - }; - - Mode mode; - bool hasAssociatedDisplay; - bool orientationAware; - } mParameters; - - CursorButtonAccumulator mCursorButtonAccumulator; - CursorMotionAccumulator mCursorMotionAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - - int32_t mSource; - float mXScale; - float mYScale; - float mXPrecision; - float mYPrecision; - - float mVWheelScale; - float mHWheelScale; - - // Velocity controls for mouse pointer and wheel movements. - // The controls for X and Y wheel movements are separate to keep them decoupled. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - int32_t mOrientation; - - sp<PointerControllerInterface> mPointerController; - - int32_t mButtonState; - nsecs_t mDownTime; - - void configureParameters(); - void dumpParameters(std::string& dump); - - void sync(nsecs_t when); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp deleted file mode 100644 index 9aa0770245..0000000000 --- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "ExternalStylusInputMapper.h" - -#include "SingleTouchMotionAccumulator.h" -#include "TouchButtonAccumulator.h" - -namespace android { - -ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : InputMapper(device) {} - -uint32_t ExternalStylusInputMapper::getSources() { - return AINPUT_SOURCE_STYLUS; -} - -void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f); -} - -void ExternalStylusInputMapper::dump(std::string& dump) { - dump += INDENT2 "External Stylus Input Mapper:\n"; - dump += INDENT3 "Raw Stylus Axes:\n"; - dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); - dump += INDENT3 "Stylus State:\n"; - dumpStylusState(dump, mStylusState); -} - -void ExternalStylusInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, - uint32_t changes) { - getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); - mTouchButtonAccumulator.configure(getDevice()); -} - -void ExternalStylusInputMapper::reset(nsecs_t when) { - InputDevice* device = getDevice(); - mSingleTouchMotionAccumulator.reset(device); - mTouchButtonAccumulator.reset(device); - InputMapper::reset(when); -} - -void ExternalStylusInputMapper::process(const RawEvent* rawEvent) { - mSingleTouchMotionAccumulator.process(rawEvent); - mTouchButtonAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void ExternalStylusInputMapper::sync(nsecs_t when) { - mStylusState.clear(); - - mStylusState.when = when; - - mStylusState.toolType = mTouchButtonAccumulator.getToolType(); - if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - - int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); - if (mRawPressureAxis.valid) { - mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue; - } else if (mTouchButtonAccumulator.isToolActive()) { - mStylusState.pressure = 1.0f; - } else { - mStylusState.pressure = 0.0f; - } - - mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); - - mContext->dispatchExternalStylusState(mStylusState); -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h deleted file mode 100644 index 9764fbb3c1..0000000000 --- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H -#define _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H - -#include "InputMapper.h" - -#include "SingleTouchMotionAccumulator.h" -#include "StylusState.h" -#include "TouchButtonAccumulator.h" - -namespace android { - -class ExternalStylusInputMapper : public InputMapper { -public: - explicit ExternalStylusInputMapper(InputDevice* device); - virtual ~ExternalStylusInputMapper() = default; - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - virtual void sync(nsecs_t when); - -private: - SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; - RawAbsoluteAxisInfo mRawPressureAxis; - TouchButtonAccumulator mTouchButtonAccumulator; - - StylusState mStylusState; -}; - -} // namespace android - -#endif // _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp deleted file mode 100644 index d941528d14..0000000000 --- a/services/inputflinger/reader/mapper/InputMapper.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "InputMapper.h" - -#include "InputDevice.h" - -namespace android { - -InputMapper::InputMapper(InputDevice* device) : mDevice(device), mContext(device->getContext()) {} - -InputMapper::~InputMapper() {} - -void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { - info->addSource(getSources()); -} - -void InputMapper::dump(std::string& dump) {} - -void InputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, - uint32_t changes) {} - -void InputMapper::reset(nsecs_t when) {} - -void InputMapper::timeoutExpired(nsecs_t when) {} - -int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return AKEY_STATE_UNKNOWN; -} - -bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return false; -} - -void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) {} - -void InputMapper::cancelVibrate(int32_t token) {} - -void InputMapper::cancelTouch(nsecs_t when) {} - -int32_t InputMapper::getMetaState() { - return 0; -} - -void InputMapper::updateMetaState(int32_t keyCode) {} - -void InputMapper::updateExternalStylusState(const StylusState& state) {} - -void InputMapper::fadePointer() {} - -status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { - return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); -} - -void InputMapper::bumpGeneration() { - mDevice->bumpGeneration(); -} - -void InputMapper::dumpRawAbsoluteAxisInfo(std::string& dump, const RawAbsoluteAxisInfo& axis, - const char* name) { - if (axis.valid) { - dump += StringPrintf(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", name, - axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); - } else { - dump += StringPrintf(INDENT4 "%s: unknown range\n", name); - } -} - -void InputMapper::dumpStylusState(std::string& dump, const StylusState& state) { - dump += StringPrintf(INDENT4 "When: %" PRId64 "\n", state.when); - dump += StringPrintf(INDENT4 "Pressure: %f\n", state.pressure); - dump += StringPrintf(INDENT4 "Button State: 0x%08x\n", state.buttons); - dump += StringPrintf(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h deleted file mode 100644 index cfd207cc4d..0000000000 --- a/services/inputflinger/reader/mapper/InputMapper.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_INPUT_MAPPER_H -#define _UI_INPUTREADER_INPUT_MAPPER_H - -#include "EventHub.h" -#include "InputDevice.h" -#include "InputListener.h" -#include "InputReaderContext.h" -#include "StylusState.h" - -namespace android { - -/* An input mapper transforms raw input events into cooked event data. - * A single input device can have multiple associated input mappers in order to interpret - * different classes of events. - * - * InputMapper lifecycle: - * - create - * - configure with 0 changes - * - reset - * - process, process, process (may occasionally reconfigure with non-zero changes or reset) - * - reset - * - destroy - */ -class InputMapper { -public: - explicit InputMapper(InputDevice* device); - virtual ~InputMapper(); - - inline InputDevice* getDevice() { return mDevice; } - inline int32_t getDeviceId() { return mDevice->getId(); } - inline const std::string getDeviceName() { return mDevice->getName(); } - inline InputReaderContext* getContext() { return mContext; } - inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } - inline InputListenerInterface* getListener() { return mContext->getListener(); } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - virtual uint32_t getSources() = 0; - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent) = 0; - virtual void timeoutExpired(nsecs_t when); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); - virtual void cancelVibrate(int32_t token); - virtual void cancelTouch(nsecs_t when); - - virtual int32_t getMetaState(); - virtual void updateMetaState(int32_t keyCode); - - virtual void updateExternalStylusState(const StylusState& state); - - virtual void fadePointer(); - virtual std::optional<int32_t> getAssociatedDisplay() { return std::nullopt; } - -protected: - InputDevice* mDevice; - InputReaderContext* mContext; - - status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); - void bumpGeneration(); - - static void dumpRawAbsoluteAxisInfo(std::string& dump, const RawAbsoluteAxisInfo& axis, - const char* name); - static void dumpStylusState(std::string& dump, const StylusState& state); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_INPUT_MAPPER_H diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp deleted file mode 100644 index b493e8368f..0000000000 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "JoystickInputMapper.h" - -namespace android { - -JoystickInputMapper::JoystickInputMapper(InputDevice* device) : InputMapper(device) {} - -JoystickInputMapper::~JoystickInputMapper() {} - -uint32_t JoystickInputMapper::getSources() { - return AINPUT_SOURCE_JOYSTICK; -} - -void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - for (size_t i = 0; i < mAxes.size(); i++) { - const Axis& axis = mAxes.valueAt(i); - addMotionRange(axis.axisInfo.axis, axis, info); - - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - addMotionRange(axis.axisInfo.highAxis, axis, info); - } - } -} - -void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info) { - info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, axis.fuzz, - axis.resolution); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to register - * the old axes as duplicates of their corresponding new ones. */ - int32_t compatAxis = getCompatAxis(axisId); - if (compatAxis >= 0) { - info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, - axis.fuzz, axis.resolution); - } -} - -/* A mapping from axes the joystick actually has to the axes that should be - * artificially created for compatibility purposes. - * Returns -1 if no compatibility axis is needed. */ -int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { - switch (axis) { - case AMOTION_EVENT_AXIS_LTRIGGER: - return AMOTION_EVENT_AXIS_BRAKE; - case AMOTION_EVENT_AXIS_RTRIGGER: - return AMOTION_EVENT_AXIS_GAS; - } - return -1; -} - -void JoystickInputMapper::dump(std::string& dump) { - dump += INDENT2 "Joystick Input Mapper:\n"; - - dump += INDENT3 "Axes:\n"; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - const char* label = getAxisLabel(axis.axisInfo.axis); - if (label) { - dump += StringPrintf(INDENT4 "%s", label); - } else { - dump += StringPrintf(INDENT4 "%d", axis.axisInfo.axis); - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - label = getAxisLabel(axis.axisInfo.highAxis); - if (label) { - dump += StringPrintf(" / %s (split at %d)", label, axis.axisInfo.splitValue); - } else { - dump += StringPrintf(" / %d (split at %d)", axis.axisInfo.highAxis, - axis.axisInfo.splitValue); - } - } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { - dump += " (invert)"; - } - - dump += StringPrintf(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - dump += StringPrintf(INDENT4 " scale=%0.5f, offset=%0.5f, " - "highScale=%0.5f, highOffset=%0.5f\n", - axis.scale, axis.offset, axis.highScale, axis.highOffset); - dump += StringPrintf(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " - "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", - mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, - axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, - axis.rawAxisInfo.resolution); - } -} - -void JoystickInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, - uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Collect all axes. - for (int32_t abs = 0; abs <= ABS_MAX; abs++) { - if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) & INPUT_DEVICE_CLASS_JOYSTICK)) { - continue; // axis must be claimed by a different device - } - - RawAbsoluteAxisInfo rawAxisInfo; - getAbsoluteAxisInfo(abs, &rawAxisInfo); - if (rawAxisInfo.valid) { - // Map axis. - AxisInfo axisInfo; - bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); - if (!explicitlyMapped) { - // Axis is not explicitly mapped, will choose a generic axis later. - axisInfo.mode = AxisInfo::MODE_NORMAL; - axisInfo.axis = -1; - } - - // Apply flat override. - int32_t rawFlat = - axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride; - - // Calculate scaling factors and limits. - Axis axis; - if (axisInfo.mode == AxisInfo::MODE_SPLIT) { - float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); - float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, highScale, - 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else if (isCenteredAxis(axisInfo.axis)) { - float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, offset, scale, - offset, -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else { - float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, scale, - 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } - - // To eliminate noise while the joystick is at rest, filter out small variations - // in axis values up front. - axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f; - - mAxes.add(abs, axis); - } - } - - // If there are too many axes, start dropping them. - // Prefer to keep explicitly mapped axes. - if (mAxes.size() > PointerCoords::MAX_AXES) { - ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.", - getDeviceName().c_str(), mAxes.size(), PointerCoords::MAX_AXES); - pruneAxes(true); - pruneAxes(false); - } - - // Assign generic axis ids to remaining axes. - int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (axis.axisInfo.axis < 0) { - while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 && - haveAxis(nextGenericAxisId)) { - nextGenericAxisId += 1; - } - - if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { - axis.axisInfo.axis = nextGenericAxisId; - nextGenericAxisId += 1; - } else { - ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " - "have already been assigned to other axes.", - getDeviceName().c_str(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i--); - numAxes -= 1; - } - } - } - } -} - -bool JoystickInputMapper::haveAxis(int32_t axisId) { - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - if (axis.axisInfo.axis == axisId || - (axis.axisInfo.mode == AxisInfo::MODE_SPLIT && axis.axisInfo.highAxis == axisId)) { - return true; - } - } - return false; -} - -void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { - size_t i = mAxes.size(); - while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { - if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { - continue; - } - ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", - getDeviceName().c_str(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i); - } -} - -bool JoystickInputMapper::isCenteredAxis(int32_t axis) { - switch (axis) { - case AMOTION_EVENT_AXIS_X: - case AMOTION_EVENT_AXIS_Y: - case AMOTION_EVENT_AXIS_Z: - case AMOTION_EVENT_AXIS_RX: - case AMOTION_EVENT_AXIS_RY: - case AMOTION_EVENT_AXIS_RZ: - case AMOTION_EVENT_AXIS_HAT_X: - case AMOTION_EVENT_AXIS_HAT_Y: - case AMOTION_EVENT_AXIS_ORIENTATION: - case AMOTION_EVENT_AXIS_RUDDER: - case AMOTION_EVENT_AXIS_WHEEL: - return true; - default: - return false; - } -} - -void JoystickInputMapper::reset(nsecs_t when) { - // Recenter all axes. - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - axis.resetValue(); - } - - InputMapper::reset(when); -} - -void JoystickInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_ABS: { - ssize_t index = mAxes.indexOfKey(rawEvent->code); - if (index >= 0) { - Axis& axis = mAxes.editValueAt(index); - float newValue, highNewValue; - switch (axis.axisInfo.mode) { - case AxisInfo::MODE_INVERT: - newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) * axis.scale + - axis.offset; - highNewValue = 0.0f; - break; - case AxisInfo::MODE_SPLIT: - if (rawEvent->value < axis.axisInfo.splitValue) { - newValue = (axis.axisInfo.splitValue - rawEvent->value) * axis.scale + - axis.offset; - highNewValue = 0.0f; - } else if (rawEvent->value > axis.axisInfo.splitValue) { - newValue = 0.0f; - highNewValue = - (rawEvent->value - axis.axisInfo.splitValue) * axis.highScale + - axis.highOffset; - } else { - newValue = 0.0f; - highNewValue = 0.0f; - } - break; - default: - newValue = rawEvent->value * axis.scale + axis.offset; - highNewValue = 0.0f; - break; - } - axis.newValue = newValue; - axis.highNewValue = highNewValue; - } - break; - } - - case EV_SYN: - switch (rawEvent->code) { - case SYN_REPORT: - sync(rawEvent->when, false /*force*/); - break; - } - break; - } -} - -void JoystickInputMapper::sync(nsecs_t when, bool force) { - if (!filterAxes(force)) { - return; - } - - int32_t metaState = mContext->getGlobalMetaState(); - int32_t buttonState = 0; - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue); - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis, - axis.highCurrentValue); - } - } - - // Moving a joystick axis should not wake the device because joysticks can - // be fairly noisy even when not in use. On the other hand, pushing a gamepad - // button will likely wake the device. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, 0, - /* videoFrames */ {}); - getListener()->notifyMotion(&args); -} - -void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, - float value) { - pointerCoords->setAxisValue(axis, value); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to produce - * values for the old axes as mirrors of the value of their corresponding - * new axes. */ - int32_t compatAxis = getCompatAxis(axis); - if (compatAxis >= 0) { - pointerCoords->setAxisValue(compatAxis, value); - } -} - -bool JoystickInputMapper::filterAxes(bool force) { - bool atLeastOneSignificantChange = force; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (force || - hasValueChangedSignificantly(axis.filter, axis.newValue, axis.currentValue, axis.min, - axis.max)) { - axis.currentValue = axis.newValue; - atLeastOneSignificantChange = true; - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - if (force || - hasValueChangedSignificantly(axis.filter, axis.highNewValue, axis.highCurrentValue, - axis.min, axis.max)) { - axis.highCurrentValue = axis.highNewValue; - atLeastOneSignificantChange = true; - } - } - } - return atLeastOneSignificantChange; -} - -bool JoystickInputMapper::hasValueChangedSignificantly(float filter, float newValue, - float currentValue, float min, float max) { - if (newValue != currentValue) { - // Filter out small changes in value unless the value is converging on the axis - // bounds or center point. This is intended to reduce the amount of information - // sent to applications by particularly noisy joysticks (such as PS3). - if (fabs(newValue - currentValue) > filter || - hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) || - hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) || - hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { - return true; - } - } - return false; -} - -bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange(float filter, float newValue, - float currentValue, - float thresholdValue) { - float newDistance = fabs(newValue - thresholdValue); - if (newDistance < filter) { - float oldDistance = fabs(currentValue - thresholdValue); - if (newDistance < oldDistance) { - return true; - } - } - return false; -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h deleted file mode 100644 index 1b071d0480..0000000000 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H -#define _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H - -#include "InputMapper.h" - -namespace android { - -class JoystickInputMapper : public InputMapper { -public: - explicit JoystickInputMapper(InputDevice* device); - virtual ~JoystickInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -private: - struct Axis { - RawAbsoluteAxisInfo rawAxisInfo; - AxisInfo axisInfo; - - bool explicitlyMapped; // true if the axis was explicitly assigned an axis id - - float scale; // scale factor from raw to normalized values - float offset; // offset to add after scaling for normalization - float highScale; // scale factor from raw to normalized values of high split - float highOffset; // offset to add after scaling for normalization of high split - - float min; // normalized inclusive minimum - float max; // normalized inclusive maximum - float flat; // normalized flat region size - float fuzz; // normalized error tolerance - float resolution; // normalized resolution in units/mm - - float filter; // filter out small variations of this size - float currentValue; // current value - float newValue; // most recent value - float highCurrentValue; // current value of high split - float highNewValue; // most recent value of high split - - void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, - bool explicitlyMapped, float scale, float offset, float highScale, - float highOffset, float min, float max, float flat, float fuzz, - float resolution) { - this->rawAxisInfo = rawAxisInfo; - this->axisInfo = axisInfo; - this->explicitlyMapped = explicitlyMapped; - this->scale = scale; - this->offset = offset; - this->highScale = highScale; - this->highOffset = highOffset; - this->min = min; - this->max = max; - this->flat = flat; - this->fuzz = fuzz; - this->resolution = resolution; - this->filter = 0; - resetValue(); - } - - void resetValue() { - this->currentValue = 0; - this->newValue = 0; - this->highCurrentValue = 0; - this->highNewValue = 0; - } - }; - - // Axes indexed by raw ABS_* axis index. - KeyedVector<int32_t, Axis> mAxes; - - void sync(nsecs_t when, bool force); - - bool haveAxis(int32_t axisId); - void pruneAxes(bool ignoreExplicitlyMappedAxes); - bool filterAxes(bool force); - - static bool hasValueChangedSignificantly(float filter, float newValue, float currentValue, - float min, float max); - static bool hasMovedNearerToValueWithinFilteredRange(float filter, float newValue, - float currentValue, float thresholdValue); - - static bool isCenteredAxis(int32_t axis); - static int32_t getCompatAxis(int32_t axis); - - static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info); - static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, float value); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp deleted file mode 100644 index 0e91c0e2cc..0000000000 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "KeyboardInputMapper.h" - -namespace android { - -// --- Static Definitions --- - -static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, - const int32_t map[][4], size_t mapSize) { - if (orientation != DISPLAY_ORIENTATION_0) { - for (size_t i = 0; i < mapSize; i++) { - if (value == map[i][0]) { - return map[i][orientation]; - } - } - } - return value; -} - -static const int32_t keyCodeRotationMap[][4] = { - // key codes enumerated counter-clockwise with the original (unrotated) key first - // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation - {AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT}, - {AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN}, - {AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT}, - {AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP}, - {AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT, - AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT}, - {AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP, - AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN}, - {AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT, - AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT}, - {AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN, - AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP}, -}; - -static const size_t keyCodeRotationMapSize = - sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); - -static int32_t rotateStemKey(int32_t value, int32_t orientation, const int32_t map[][2], - size_t mapSize) { - if (orientation == DISPLAY_ORIENTATION_180) { - for (size_t i = 0; i < mapSize; i++) { - if (value == map[i][0]) { - return map[i][1]; - } - } - } - return value; -} - -// The mapping can be defined using input device configuration properties keyboard.rotated.stem_X -static int32_t stemKeyRotationMap[][2] = { - // key codes enumerated with the original (unrotated) key first - // no rotation, 180 degree rotation - {AKEYCODE_STEM_PRIMARY, AKEYCODE_STEM_PRIMARY}, - {AKEYCODE_STEM_1, AKEYCODE_STEM_1}, - {AKEYCODE_STEM_2, AKEYCODE_STEM_2}, - {AKEYCODE_STEM_3, AKEYCODE_STEM_3}, -}; - -static const size_t stemKeyRotationMapSize = - sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]); - -static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { - keyCode = rotateStemKey(keyCode, orientation, stemKeyRotationMap, stemKeyRotationMapSize); - return rotateValueUsingRotationMap(keyCode, orientation, keyCodeRotationMap, - keyCodeRotationMapSize); -} - -// --- KeyboardInputMapper --- - -KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType) - : InputMapper(device), mSource(source), mKeyboardType(keyboardType) {} - -KeyboardInputMapper::~KeyboardInputMapper() {} - -uint32_t KeyboardInputMapper::getSources() { - return mSource; -} - -int32_t KeyboardInputMapper::getOrientation() { - if (mViewport) { - return mViewport->orientation; - } - return DISPLAY_ORIENTATION_0; -} - -int32_t KeyboardInputMapper::getDisplayId() { - if (mViewport) { - return mViewport->displayId; - } - return ADISPLAY_ID_NONE; -} - -void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setKeyboardType(mKeyboardType); - info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); -} - -void KeyboardInputMapper::dump(std::string& dump) { - dump += INDENT2 "Keyboard Input Mapper:\n"; - dumpParameters(dump); - dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType); - dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation()); - dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size()); - dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState); - dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); -} - -void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, - uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - if (mParameters.orientationAware) { - mViewport = config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); - } - } -} - -static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* property) { - int32_t mapped = 0; - if (config.tryGetProperty(String8(property), mapped) && mapped > 0) { - for (size_t i = 0; i < stemKeyRotationMapSize; i++) { - if (stemKeyRotationMap[i][0] == keyCode) { - stemKeyRotationMap[i][1] = mapped; - return; - } - } - } -} - -void KeyboardInputMapper::configureParameters() { - mParameters.orientationAware = false; - const PropertyMap& config = getDevice()->getConfiguration(); - config.tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware); - - if (mParameters.orientationAware) { - mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary"); - mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1"); - mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2"); - mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3"); - } - - mParameters.handlesKeyRepeat = false; - config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), mParameters.handlesKeyRepeat); -} - -void KeyboardInputMapper::dumpParameters(std::string& dump) { - dump += INDENT3 "Parameters:\n"; - dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); - dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n", toString(mParameters.handlesKeyRepeat)); -} - -void KeyboardInputMapper::reset(nsecs_t when) { - mMetaState = AMETA_NONE; - mDownTime = 0; - mKeyDowns.clear(); - mCurrentHidUsage = 0; - - resetLedState(); - - InputMapper::reset(when); -} - -void KeyboardInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_KEY: { - int32_t scanCode = rawEvent->code; - int32_t usageCode = mCurrentHidUsage; - mCurrentHidUsage = 0; - - if (isKeyboardOrGamepadKey(scanCode)) { - processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode); - } - break; - } - case EV_MSC: { - if (rawEvent->code == MSC_SCAN) { - mCurrentHidUsage = rawEvent->value; - } - break; - } - case EV_SYN: { - if (rawEvent->code == SYN_REPORT) { - mCurrentHidUsage = 0; - } - } - } -} - -bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { - return scanCode < BTN_MOUSE || scanCode >= KEY_OK || - (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) || - (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); -} - -bool KeyboardInputMapper::isMediaKey(int32_t keyCode) { - switch (keyCode) { - case AKEYCODE_MEDIA_PLAY: - case AKEYCODE_MEDIA_PAUSE: - case AKEYCODE_MEDIA_PLAY_PAUSE: - case AKEYCODE_MUTE: - case AKEYCODE_HEADSETHOOK: - case AKEYCODE_MEDIA_STOP: - case AKEYCODE_MEDIA_NEXT: - case AKEYCODE_MEDIA_PREVIOUS: - case AKEYCODE_MEDIA_REWIND: - case AKEYCODE_MEDIA_RECORD: - case AKEYCODE_MEDIA_FAST_FORWARD: - case AKEYCODE_MEDIA_SKIP_FORWARD: - case AKEYCODE_MEDIA_SKIP_BACKWARD: - case AKEYCODE_MEDIA_STEP_FORWARD: - case AKEYCODE_MEDIA_STEP_BACKWARD: - case AKEYCODE_MEDIA_AUDIO_TRACK: - case AKEYCODE_VOLUME_UP: - case AKEYCODE_VOLUME_DOWN: - case AKEYCODE_VOLUME_MUTE: - case AKEYCODE_TV_AUDIO_DESCRIPTION: - case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP: - case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN: - return true; - } - return false; -} - -void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) { - int32_t keyCode; - int32_t keyMetaState; - uint32_t policyFlags; - - if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState, &keyCode, - &keyMetaState, &policyFlags)) { - keyCode = AKEYCODE_UNKNOWN; - keyMetaState = mMetaState; - policyFlags = 0; - } - - if (down) { - // Rotate key codes according to orientation if needed. - if (mParameters.orientationAware) { - keyCode = rotateKeyCode(keyCode, getOrientation()); - } - - // Add key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key repeat, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns[keyDownIndex].keyCode; - } else { - // key down - if ((policyFlags & POLICY_FLAG_VIRTUAL) && - mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) { - return; - } - if (policyFlags & POLICY_FLAG_GESTURE) { - mDevice->cancelTouch(when); - } - - KeyDown keyDown; - keyDown.keyCode = keyCode; - keyDown.scanCode = scanCode; - mKeyDowns.push_back(keyDown); - } - - mDownTime = when; - } else { - // Remove key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key up, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns[keyDownIndex].keyCode; - mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex); - } else { - // key was not actually down - ALOGI("Dropping key up from device %s because the key was not down. " - "keyCode=%d, scanCode=%d", - getDeviceName().c_str(), keyCode, scanCode); - return; - } - } - - if (updateMetaStateIfNeeded(keyCode, down)) { - // If global meta state changed send it along with the key. - // If it has not changed then we'll use what keymap gave us, - // since key replacement logic might temporarily reset a few - // meta bits for given key. - keyMetaState = mMetaState; - } - - nsecs_t downTime = mDownTime; - - // Key down on external an keyboard should wake the device. - // We don't do this for internal keyboards to prevent them from waking up in your pocket. - // For internal keyboards, the key layout file should specify the policy flags for - // each wake key individually. - // TODO: Use the input device configuration to control this behavior more finely. - if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) { - policyFlags |= POLICY_FLAG_WAKE; - } - - if (mParameters.handlesKeyRepeat) { - policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; - } - - NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, getDisplayId(), - policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime); - getListener()->notifyKey(&args); -} - -ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { - size_t n = mKeyDowns.size(); - for (size_t i = 0; i < n; i++) { - if (mKeyDowns[i].scanCode == scanCode) { - return i; - } - } - return -1; -} - -int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); -} - -int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); -} - -bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); -} - -int32_t KeyboardInputMapper::getMetaState() { - return mMetaState; -} - -void KeyboardInputMapper::updateMetaState(int32_t keyCode) { - updateMetaStateIfNeeded(keyCode, false); -} - -bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) { - int32_t oldMetaState = mMetaState; - int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState); - bool metaStateChanged = oldMetaState != newMetaState; - if (metaStateChanged) { - mMetaState = newMetaState; - updateLedState(false); - - getContext()->updateGlobalMetaState(); - } - - return metaStateChanged; -} - -void KeyboardInputMapper::resetLedState() { - initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK); - initializeLedState(mNumLockLedState, ALED_NUM_LOCK); - initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK); - - updateLedState(true); -} - -void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { - ledState.avail = getEventHub()->hasLed(getDeviceId(), led); - ledState.on = false; -} - -void KeyboardInputMapper::updateLedState(bool reset) { - updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK, AMETA_CAPS_LOCK_ON, reset); - updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK, AMETA_NUM_LOCK_ON, reset); - updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, reset); -} - -void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, int32_t led, - int32_t modifier, bool reset) { - if (ledState.avail) { - bool desiredState = (mMetaState & modifier) != 0; - if (reset || ledState.on != desiredState) { - getEventHub()->setLedState(getDeviceId(), led, desiredState); - ledState.on = desiredState; - } - } -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h deleted file mode 100644 index 7a68fc33f8..0000000000 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H -#define _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H - -#include "InputMapper.h" - -namespace android { - -class KeyboardInputMapper : public InputMapper { -public: - KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); - virtual ~KeyboardInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual int32_t getMetaState(); - virtual void updateMetaState(int32_t keyCode); - -private: - // The current viewport. - std::optional<DisplayViewport> mViewport; - - struct KeyDown { - int32_t keyCode; - int32_t scanCode; - }; - - uint32_t mSource; - int32_t mKeyboardType; - - std::vector<KeyDown> mKeyDowns; // keys that are down - int32_t mMetaState; - nsecs_t mDownTime; // time of most recent key down - - int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none - - struct LedState { - bool avail; // led is available - bool on; // we think the led is currently on - }; - LedState mCapsLockLedState; - LedState mNumLockLedState; - LedState mScrollLockLedState; - - // Immutable configuration parameters. - struct Parameters { - bool orientationAware; - bool handlesKeyRepeat; - } mParameters; - - void configureParameters(); - void dumpParameters(std::string& dump); - - int32_t getOrientation(); - int32_t getDisplayId(); - - bool isKeyboardOrGamepadKey(int32_t scanCode); - bool isMediaKey(int32_t keyCode); - - void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode); - - bool updateMetaStateIfNeeded(int32_t keyCode, bool down); - - ssize_t findKeyDown(int32_t scanCode); - - void resetLedState(); - void initializeLedState(LedState& ledState, int32_t led); - void updateLedState(bool reset); - void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp deleted file mode 100644 index 7460a3130e..0000000000 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "MultiTouchInputMapper.h" - -namespace android { - -// --- Constants --- - -// Maximum number of slots supported when using the slot-based Multitouch Protocol B. -static constexpr size_t MAX_SLOTS = 32; - -// --- MultiTouchMotionAccumulator --- - -MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() - : mCurrentSlot(-1), - mSlots(nullptr), - mSlotCount(0), - mUsingSlotsProtocol(false), - mHaveStylus(false) {} - -MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { - delete[] mSlots; -} - -void MultiTouchMotionAccumulator::configure(InputDevice* device, size_t slotCount, - bool usingSlotsProtocol) { - mSlotCount = slotCount; - mUsingSlotsProtocol = usingSlotsProtocol; - mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); - - delete[] mSlots; - mSlots = new Slot[slotCount]; -} - -void MultiTouchMotionAccumulator::reset(InputDevice* device) { - // Unfortunately there is no way to read the initial contents of the slots. - // So when we reset the accumulator, we must assume they are all zeroes. - if (mUsingSlotsProtocol) { - // Query the driver for the current slot index and use it as the initial slot - // before we start reading events from the device. It is possible that the - // current slot index will not be the same as it was when the first event was - // written into the evdev buffer, which means the input mapper could start - // out of sync with the initial state of the events in the evdev buffer. - // In the extremely unlikely case that this happens, the data from - // two slots will be confused until the next ABS_MT_SLOT event is received. - // This can cause the touch point to "jump", but at least there will be - // no stuck touches. - int32_t initialSlot; - status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), ABS_MT_SLOT, - &initialSlot); - if (status) { - ALOGD("Could not retrieve current multitouch slot index. status=%d", status); - initialSlot = -1; - } - clearSlots(initialSlot); - } else { - clearSlots(-1); - } - mDeviceTimestamp = 0; -} - -void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { - if (mSlots) { - for (size_t i = 0; i < mSlotCount; i++) { - mSlots[i].clear(); - } - } - mCurrentSlot = initialSlot; -} - -void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { - bool newSlot = false; - if (mUsingSlotsProtocol) { - if (rawEvent->code == ABS_MT_SLOT) { - mCurrentSlot = rawEvent->value; - newSlot = true; - } - } else if (mCurrentSlot < 0) { - mCurrentSlot = 0; - } - - if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { -#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); - } -#endif - } else { - Slot* slot = &mSlots[mCurrentSlot]; - - switch (rawEvent->code) { - case ABS_MT_POSITION_X: - slot->mInUse = true; - slot->mAbsMTPositionX = rawEvent->value; - break; - case ABS_MT_POSITION_Y: - slot->mInUse = true; - slot->mAbsMTPositionY = rawEvent->value; - break; - case ABS_MT_TOUCH_MAJOR: - slot->mInUse = true; - slot->mAbsMTTouchMajor = rawEvent->value; - break; - case ABS_MT_TOUCH_MINOR: - slot->mInUse = true; - slot->mAbsMTTouchMinor = rawEvent->value; - slot->mHaveAbsMTTouchMinor = true; - break; - case ABS_MT_WIDTH_MAJOR: - slot->mInUse = true; - slot->mAbsMTWidthMajor = rawEvent->value; - break; - case ABS_MT_WIDTH_MINOR: - slot->mInUse = true; - slot->mAbsMTWidthMinor = rawEvent->value; - slot->mHaveAbsMTWidthMinor = true; - break; - case ABS_MT_ORIENTATION: - slot->mInUse = true; - 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; - } else { - slot->mInUse = true; - slot->mAbsMTTrackingId = rawEvent->value; - } - break; - case ABS_MT_PRESSURE: - slot->mInUse = true; - slot->mAbsMTPressure = rawEvent->value; - break; - case ABS_MT_DISTANCE: - slot->mInUse = true; - slot->mAbsMTDistance = rawEvent->value; - break; - case ABS_MT_TOOL_TYPE: - slot->mInUse = true; - slot->mAbsMTToolType = rawEvent->value; - slot->mHaveAbsMTToolType = true; - break; - } - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { - // MultiTouch Sync: The driver has returned all data for *one* of the pointers. - mCurrentSlot += 1; - } else if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) { - mDeviceTimestamp = rawEvent->value; - } -} - -void MultiTouchMotionAccumulator::finishSync() { - if (!mUsingSlotsProtocol) { - clearSlots(-1); - } -} - -bool MultiTouchMotionAccumulator::hasStylus() const { - return mHaveStylus; -} - -// --- 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) { - case MT_TOOL_FINGER: - return AMOTION_EVENT_TOOL_TYPE_FINGER; - case MT_TOOL_PEN: - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - -// --- MultiTouchInputMapper --- - -MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : TouchInputMapper(device) {} - -MultiTouchInputMapper::~MultiTouchInputMapper() {} - -void MultiTouchInputMapper::reset(nsecs_t when) { - mMultiTouchMotionAccumulator.reset(getDevice()); - - mPointerIdBits.clear(); - - TouchInputMapper::reset(when); -} - -void MultiTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mMultiTouchMotionAccumulator.process(rawEvent); -} - -void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { - size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); - size_t outCount = 0; - BitSet32 newPointerIdBits; - mHavePointerIds = true; - - for (size_t inIndex = 0; inIndex < inCount; inIndex++) { - const MultiTouchMotionAccumulator::Slot* inSlot = - mMultiTouchMotionAccumulator.getSlot(inIndex); - if (!inSlot->isInUse()) { - continue; - } - - if (outCount >= MAX_POINTERS) { -#if DEBUG_POINTERS - ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " - "ignoring the rest.", - getDeviceName().c_str(), MAX_POINTERS); -#endif - break; // too many fingers! - } - - 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.tiltX = 0; - outPointer.tiltY = 0; - - 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; - } - } - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && - (mTouchButtonAccumulator.isHovering() || - (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 id = -1; - if (trackingId >= 0) { - for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) { - uint32_t n = idBits.clearFirstMarkedBit(); - if (mPointerTrackingIdMap[n] == trackingId) { - id = n; - } - } - - if (id < 0 && !mPointerIdBits.isFull()) { - id = mPointerIdBits.markFirstUnmarkedBit(); - mPointerTrackingIdMap[id] = trackingId; - } - } - if (id < 0) { - mHavePointerIds = false; - outState->rawPointerData.clearIdBits(); - newPointerIdBits.clear(); - } else { - outPointer.id = id; - outState->rawPointerData.idToIndex[id] = outCount; - outState->rawPointerData.markIdBit(id, isHovering); - newPointerIdBits.markBit(id); - } - } - outCount += 1; - } - - outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp(); - outState->rawPointerData.pointerCount = outCount; - mPointerIdBits = newPointerIdBits; - - mMultiTouchMotionAccumulator.finishSync(); -} - -void MultiTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); - getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); - getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); - getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); - - if (mRawPointerAxes.trackingId.valid && mRawPointerAxes.slot.valid && - mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { - size_t slotCount = mRawPointerAxes.slot.maxValue + 1; - if (slotCount > MAX_SLOTS) { - ALOGW("MultiTouch Device %s reported %zu slots but the framework " - "only supports a maximum of %zu slots at this time.", - getDeviceName().c_str(), slotCount, MAX_SLOTS); - slotCount = MAX_SLOTS; - } - mMultiTouchMotionAccumulator.configure(getDevice(), slotCount, true /*usingSlotsProtocol*/); - } else { - mMultiTouchMotionAccumulator.configure(getDevice(), MAX_POINTERS, - false /*usingSlotsProtocol*/); - } -} - -bool MultiTouchInputMapper::hasStylus() const { - return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus(); -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h deleted file mode 100644 index 873dda1aec..0000000000 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H -#define _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H - -#include "TouchInputMapper.h" - -namespace android { - -/* Keeps track of the state of multi-touch protocol. */ -class MultiTouchMotionAccumulator { -public: - class Slot { - public: - inline bool isInUse() const { return mInUse; } - inline int32_t getX() const { return mAbsMTPositionX; } - inline int32_t getY() const { return mAbsMTPositionY; } - inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } - inline int32_t getTouchMinor() const { - return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; - } - inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } - inline int32_t getToolMinor() const { - return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; - } - inline int32_t getOrientation() const { return mAbsMTOrientation; } - inline int32_t getTrackingId() const { return mAbsMTTrackingId; } - inline int32_t getPressure() const { return mAbsMTPressure; } - inline int32_t getDistance() const { return mAbsMTDistance; } - inline int32_t getToolType() const; - - private: - friend class MultiTouchMotionAccumulator; - - bool mInUse; - bool mHaveAbsMTTouchMinor; - bool mHaveAbsMTWidthMinor; - bool mHaveAbsMTToolType; - - 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; - - Slot(); - void clear(); - }; - - MultiTouchMotionAccumulator(); - ~MultiTouchMotionAccumulator(); - - void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); - void reset(InputDevice* device); - void process(const RawEvent* rawEvent); - void finishSync(); - bool hasStylus() const; - - inline size_t getSlotCount() const { return mSlotCount; } - inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } - inline uint32_t getDeviceTimestamp() const { return mDeviceTimestamp; } - -private: - int32_t mCurrentSlot; - Slot* mSlots; - size_t mSlotCount; - bool mUsingSlotsProtocol; - bool mHaveStylus; - uint32_t mDeviceTimestamp; - - void clearSlots(int32_t initialSlot); -}; - -class MultiTouchInputMapper : public TouchInputMapper { -public: - explicit MultiTouchInputMapper(InputDevice* device); - virtual ~MultiTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, RawState* outState); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; - - // Specifies the pointer id bits that are in use, and their associated tracking id. - BitSet32 mPointerIdBits; - int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; -}; - -} // namespace android - -#endif // _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp deleted file mode 100644 index 803fdf3656..0000000000 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "RotaryEncoderInputMapper.h" - -#include "CursorScrollAccumulator.h" - -namespace android { - -RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) - : InputMapper(device), mOrientation(DISPLAY_ORIENTATION_0) { - mSource = AINPUT_SOURCE_ROTARY_ENCODER; -} - -RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {} - -uint32_t RotaryEncoderInputMapper::getSources() { - return mSource; -} - -void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) { - float res = 0.0f; - if (!mDevice->getConfiguration().tryGetProperty(String8("device.res"), res)) { - ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); - } - if (!mDevice->getConfiguration().tryGetProperty(String8("device.scalingFactor"), - mScalingFactor)) { - ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," - "default to 1.0!\n"); - mScalingFactor = 1.0f; - } - info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - res * mScalingFactor); - } -} - -void RotaryEncoderInputMapper::dump(std::string& dump) { - dump += INDENT2 "Rotary Encoder Input Mapper:\n"; - dump += StringPrintf(INDENT3 "HaveWheel: %s\n", - toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel())); -} - -void RotaryEncoderInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, - uint32_t changes) { - InputMapper::configure(when, config, changes); - if (!changes) { - mRotaryEncoderScrollAccumulator.configure(getDevice()); - } - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - std::optional<DisplayViewport> internalViewport = - config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); - if (internalViewport) { - mOrientation = internalViewport->orientation; - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } -} - -void RotaryEncoderInputMapper::reset(nsecs_t when) { - mRotaryEncoderScrollAccumulator.reset(getDevice()); - - InputMapper::reset(when); -} - -void RotaryEncoderInputMapper::process(const RawEvent* rawEvent) { - mRotaryEncoderScrollAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void RotaryEncoderInputMapper::sync(nsecs_t when) { - PointerCoords pointerCoords; - pointerCoords.clear(); - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; - - float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); - bool scrolled = scroll != 0; - - // This is not a pointer, so it's not associated with a display. - int32_t displayId = ADISPLAY_ID_NONE; - - // Moving the rotary encoder should wake the device (if specified). - uint32_t policyFlags = 0; - if (scrolled && getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE; - } - - if (mOrientation == DISPLAY_ORIENTATION_180) { - scroll = -scroll; - } - - // Send motion event. - if (scrolled) { - int32_t metaState = mContext->getGlobalMetaState(); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); - - NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, - metaState, /* buttonState */ 0, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - 0, 0, 0, /* videoFrames */ {}); - getListener()->notifyMotion(&scrollArgs); - } - - mRotaryEncoderScrollAccumulator.finishSync(); -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h deleted file mode 100644 index 26488373bd..0000000000 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H -#define _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H - -#include "CursorScrollAccumulator.h" -#include "InputMapper.h" - -namespace android { - -class RotaryEncoderInputMapper : public InputMapper { -public: - explicit RotaryEncoderInputMapper(InputDevice* device); - virtual ~RotaryEncoderInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -private: - CursorScrollAccumulator mRotaryEncoderScrollAccumulator; - - int32_t mSource; - float mScalingFactor; - int32_t mOrientation; - - void sync(nsecs_t when); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp b/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp deleted file mode 100644 index 440d282686..0000000000 --- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2019 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 "SingleTouchInputMapper.h" - -namespace android { - -SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : TouchInputMapper(device) {} - -SingleTouchInputMapper::~SingleTouchInputMapper() {} - -void SingleTouchInputMapper::reset(nsecs_t when) { - mSingleTouchMotionAccumulator.reset(getDevice()); - - TouchInputMapper::reset(when); -} - -void SingleTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mSingleTouchMotionAccumulator.process(rawEvent); -} - -void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { - if (mTouchButtonAccumulator.isToolActive()) { - outState->rawPointerData.pointerCount = 1; - outState->rawPointerData.idToIndex[0] = 0; - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && - (mTouchButtonAccumulator.isHovering() || - (mRawPointerAxes.pressure.valid && - mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); - outState->rawPointerData.markIdBit(0, isHovering); - - RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0]; - outPointer.id = 0; - outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); - outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); - outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); - outPointer.touchMajor = 0; - outPointer.touchMinor = 0; - outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.orientation = 0; - outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); - outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); - outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); - outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - outPointer.isHovering = isHovering; - } -} - -void SingleTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); - getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); -} - -bool SingleTouchInputMapper::hasStylus() const { - return mTouchButtonAccumulator.hasStylus(); -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h deleted file mode 100644 index d6b1455b68..0000000000 --- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H -#define _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H - -#include "SingleTouchMotionAccumulator.h" -#include "TouchInputMapper.h" - -namespace android { - -class SingleTouchInputMapper : public TouchInputMapper { -public: - explicit SingleTouchInputMapper(InputDevice* device); - virtual ~SingleTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, RawState* outState); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; -}; - -} // namespace android - -#endif // _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp deleted file mode 100644 index 4ff941f5cf..0000000000 --- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "SwitchInputMapper.h" - -namespace android { - -SwitchInputMapper::SwitchInputMapper(InputDevice* device) - : InputMapper(device), mSwitchValues(0), mUpdatedSwitchMask(0) {} - -SwitchInputMapper::~SwitchInputMapper() {} - -uint32_t SwitchInputMapper::getSources() { - return AINPUT_SOURCE_SWITCH; -} - -void SwitchInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_SW: - processSwitch(rawEvent->code, rawEvent->value); - break; - - case EV_SYN: - if (rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } - } -} - -void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { - if (switchCode >= 0 && switchCode < 32) { - if (switchValue) { - mSwitchValues |= 1 << switchCode; - } else { - mSwitchValues &= ~(1 << switchCode); - } - mUpdatedSwitchMask |= 1 << switchCode; - } -} - -void SwitchInputMapper::sync(nsecs_t when) { - if (mUpdatedSwitchMask) { - uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask; - NotifySwitchArgs args(mContext->getNextSequenceNum(), when, 0, updatedSwitchValues, - mUpdatedSwitchMask); - getListener()->notifySwitch(&args); - - mUpdatedSwitchMask = 0; - } -} - -int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getEventHub()->getSwitchState(getDeviceId(), switchCode); -} - -void SwitchInputMapper::dump(std::string& dump) { - dump += INDENT2 "Switch Input Mapper:\n"; - dump += StringPrintf(INDENT3 "SwitchValues: %x\n", mSwitchValues); -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.h b/services/inputflinger/reader/mapper/SwitchInputMapper.h deleted file mode 100644 index dd4bb9ed65..0000000000 --- a/services/inputflinger/reader/mapper/SwitchInputMapper.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H -#define _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H - -#include "InputMapper.h" - -namespace android { - -class SwitchInputMapper : public InputMapper { -public: - explicit SwitchInputMapper(InputDevice* device); - virtual ~SwitchInputMapper(); - - virtual uint32_t getSources(); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - virtual void dump(std::string& dump); - -private: - uint32_t mSwitchValues; - uint32_t mUpdatedSwitchMask; - - void processSwitch(int32_t switchCode, int32_t switchValue); - void sync(nsecs_t when); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h deleted file mode 100644 index efa3d6d2b2..0000000000 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H -#define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H - -#include "EventHub.h" -#include "InputListener.h" -#include "InputReaderContext.h" - -#include <stdint.h> - -namespace android { - -// --- Static Definitions --- - -static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { - float temp; - switch (orientation) { - case DISPLAY_ORIENTATION_90: - temp = *deltaX; - *deltaX = *deltaY; - *deltaY = -temp; - break; - - case DISPLAY_ORIENTATION_180: - *deltaX = -*deltaX; - *deltaY = -*deltaY; - break; - - case DISPLAY_ORIENTATION_270: - temp = *deltaX; - *deltaX = -*deltaY; - *deltaY = temp; - break; - } -} - -// Returns true if the pointer should be reported as being down given the specified -// button states. This determines whether the event is reported as a touch event. -static bool isPointerDown(int32_t buttonState) { - return buttonState & - (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY | - AMOTION_EVENT_BUTTON_TERTIARY); -} - -static void synthesizeButtonKey(InputReaderContext* context, int32_t action, nsecs_t when, - int32_t deviceId, uint32_t source, int32_t displayId, - uint32_t policyFlags, int32_t lastButtonState, - int32_t currentButtonState, int32_t buttonState, int32_t keyCode) { - if ((action == AKEY_EVENT_ACTION_DOWN && !(lastButtonState & buttonState) && - (currentButtonState & buttonState)) || - (action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) && - !(currentButtonState & buttonState))) { - NotifyKeyArgs args(context->getNextSequenceNum(), when, deviceId, source, displayId, - policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when); - context->getListener()->notifyKey(&args); - } -} - -static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, nsecs_t when, - int32_t deviceId, uint32_t source, int32_t displayId, - uint32_t policyFlags, int32_t lastButtonState, - int32_t currentButtonState) { - synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags, - lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_BACK, - AKEYCODE_BACK); - synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags, - lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_FORWARD, - AKEYCODE_FORWARD); -} - -} // namespace android - -#endif // _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp deleted file mode 100644 index 32ed97bffe..0000000000 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ /dev/null @@ -1,3909 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "TouchInputMapper.h" - -#include "CursorButtonAccumulator.h" -#include "CursorScrollAccumulator.h" -#include "TouchButtonAccumulator.h" -#include "TouchCursorInputMapperCommon.h" - -#include <statslog.h> - -// How often to report input event statistics -static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60); - -namespace android { - -// --- Constants --- - -// Maximum amount of latency to add to touch events while waiting for data from an -// external stylus. -static constexpr nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); - -// Maximum amount of time to wait on touch data before pushing out new pressure data. -static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); - -// Artificial latency on synthetic events created from stylus data without corresponding touch -// data. -static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); - -// --- Static Definitions --- - -template <typename T> -inline static void swap(T& a, T& b) { - T temp = a; - a = b; - b = temp; -} - -static float calculateCommonVector(float a, float b) { - if (a > 0 && b > 0) { - return a < b ? a : b; - } else if (a < 0 && b < 0) { - return a > b ? a : b; - } else { - return 0; - } -} - -inline static float distance(float x1, float y1, float x2, float y2) { - return hypotf(x1 - x2, y1 - y2); -} - -inline static int32_t signExtendNybble(int32_t value) { - return value >= 8 ? value - 16 : value; -} - -// --- RawPointerAxes --- - -RawPointerAxes::RawPointerAxes() { - clear(); -} - -void RawPointerAxes::clear() { - x.clear(); - y.clear(); - pressure.clear(); - touchMajor.clear(); - touchMinor.clear(); - toolMajor.clear(); - toolMinor.clear(); - orientation.clear(); - distance.clear(); - tiltX.clear(); - tiltY.clear(); - trackingId.clear(); - slot.clear(); -} - -// --- RawPointerData --- - -RawPointerData::RawPointerData() { - clear(); -} - -void RawPointerData::clear() { - pointerCount = 0; - clearIdBits(); -} - -void RawPointerData::copyFrom(const RawPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointers[i] = other.pointers[i]; - - int id = pointers[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - -void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { - float x = 0, y = 0; - uint32_t count = touchingIdBits.count(); - if (count) { - for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - const Pointer& pointer = pointerForId(id); - x += pointer.x; - y += pointer.y; - } - x /= count; - y /= count; - } - *outX = x; - *outY = y; -} - -// --- CookedPointerData --- - -CookedPointerData::CookedPointerData() { - clear(); -} - -void CookedPointerData::clear() { - pointerCount = 0; - hoveringIdBits.clear(); - touchingIdBits.clear(); -} - -void CookedPointerData::copyFrom(const CookedPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(other.pointerProperties[i]); - pointerCoords[i].copyFrom(other.pointerCoords[i]); - - int id = pointerProperties[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - -// --- TouchInputMapper --- - -TouchInputMapper::TouchInputMapper(InputDevice* device) - : InputMapper(device), - mSource(0), - mDeviceMode(DEVICE_MODE_DISABLED), - mSurfaceWidth(-1), - mSurfaceHeight(-1), - mSurfaceLeft(0), - mSurfaceTop(0), - mPhysicalWidth(-1), - mPhysicalHeight(-1), - mPhysicalLeft(0), - mPhysicalTop(0), - mSurfaceOrientation(DISPLAY_ORIENTATION_0) {} - -TouchInputMapper::~TouchInputMapper() {} - -uint32_t TouchInputMapper::getSources() { - return mSource; -} - -void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mDeviceMode != DEVICE_MODE_DISABLED) { - info->addMotionRange(mOrientedRanges.x); - info->addMotionRange(mOrientedRanges.y); - info->addMotionRange(mOrientedRanges.pressure); - - if (mOrientedRanges.haveSize) { - info->addMotionRange(mOrientedRanges.size); - } - - if (mOrientedRanges.haveTouchSize) { - info->addMotionRange(mOrientedRanges.touchMajor); - info->addMotionRange(mOrientedRanges.touchMinor); - } - - if (mOrientedRanges.haveToolSize) { - info->addMotionRange(mOrientedRanges.toolMajor); - info->addMotionRange(mOrientedRanges.toolMinor); - } - - if (mOrientedRanges.haveOrientation) { - info->addMotionRange(mOrientedRanges.orientation); - } - - if (mOrientedRanges.haveDistance) { - info->addMotionRange(mOrientedRanges.distance); - } - - if (mOrientedRanges.haveTilt) { - info->addMotionRange(mOrientedRanges.tilt); - } - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - const InputDeviceInfo::MotionRange& x = mOrientedRanges.x; - const InputDeviceInfo::MotionRange& y = mOrientedRanges.y; - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - } - info->setButtonUnderPad(mParameters.hasButtonUnderPad); - } -} - -void TouchInputMapper::dump(std::string& dump) { - dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode)); - dumpParameters(dump); - dumpVirtualKeys(dump); - dumpRawPointerAxes(dump); - dumpCalibration(dump); - dumpAffineTransformation(dump); - dumpSurface(dump); - - dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n"); - dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate); - dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate); - dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale); - dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale); - dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision); - dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision); - dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); - dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale); - dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale); - dump += StringPrintf(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); - dump += StringPrintf(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); - dump += StringPrintf(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); - dump += StringPrintf(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); - dump += StringPrintf(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); - dump += StringPrintf(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); - dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - - dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState); - dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n", - mLastRawState.rawPointerData.pointerCount); - for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { - const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; - dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " - "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " - "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " - "toolType=%d, isHovering=%s\n", - i, pointer.id, pointer.x, pointer.y, pointer.pressure, - pointer.touchMajor, pointer.touchMinor, pointer.toolMajor, - pointer.toolMinor, pointer.orientation, pointer.tiltX, pointer.tiltY, - pointer.distance, pointer.toolType, toString(pointer.isHovering)); - } - - dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n", - mLastCookedState.buttonState); - dump += StringPrintf(INDENT3 "Last Cooked Touch: pointerCount=%d\n", - mLastCookedState.cookedPointerData.pointerCount); - for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { - const PointerProperties& pointerProperties = - mLastCookedState.cookedPointerData.pointerProperties[i]; - const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; - dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " - "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, " - "toolMinor=%0.3f, " - "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " - "toolType=%d, isHovering=%s\n", - i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), - pointerProperties.toolType, - toString(mLastCookedState.cookedPointerData.isHovering(i))); - } - - dump += INDENT3 "Stylus Fusion:\n"; - dump += StringPrintf(INDENT4 "ExternalStylusConnected: %s\n", - toString(mExternalStylusConnected)); - dump += StringPrintf(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); - dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", - mExternalStylusFusionTimeout); - dump += INDENT3 "External Stylus State:\n"; - dumpStylusState(dump, mExternalStylusState); - - if (mDeviceMode == DEVICE_MODE_POINTER) { - dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n"); - dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n", mPointerXMovementScale); - dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n", mPointerYMovementScale); - dump += StringPrintf(INDENT4 "XZoomScale: %0.3f\n", mPointerXZoomScale); - dump += StringPrintf(INDENT4 "YZoomScale: %0.3f\n", mPointerYZoomScale); - dump += StringPrintf(INDENT4 "MaxSwipeWidth: %f\n", mPointerGestureMaxSwipeWidth); - } -} - -const char* TouchInputMapper::modeToString(DeviceMode deviceMode) { - switch (deviceMode) { - case DEVICE_MODE_DISABLED: - return "disabled"; - case DEVICE_MODE_DIRECT: - return "direct"; - case DEVICE_MODE_UNSCALED: - return "unscaled"; - case DEVICE_MODE_NAVIGATION: - return "navigation"; - case DEVICE_MODE_POINTER: - return "pointer"; - } - return "unknown"; -} - -void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, - uint32_t changes) { - InputMapper::configure(when, config, changes); - - mConfig = *config; - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - - // Configure common accumulators. - mCursorScrollAccumulator.configure(getDevice()); - mTouchButtonAccumulator.configure(getDevice()); - - // Configure absolute axis information. - configureRawPointerAxes(); - - // Prepare input device calibration. - parseCalibration(); - resolveCalibration(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) { - // Update location calibration to reflect current settings - updateAffineTransformation(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - // Update pointer speed. - mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - } - - bool resetNeeded = false; - if (!changes || - (changes & - (InputReaderConfiguration::CHANGE_DISPLAY_INFO | - InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT | - InputReaderConfiguration::CHANGE_SHOW_TOUCHES | - InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { - // Configure device sources, surface dimensions, orientation and - // scaling factors. - configureSurface(when, &resetNeeded); - } - - if (changes && resetNeeded) { - // Send reset, unless this is the first time the device has been configured, - // in which case the reader will call reset itself after all mappers are ready. - getDevice()->notifyReset(when); - } -} - -void TouchInputMapper::resolveExternalStylusPresence() { - std::vector<InputDeviceInfo> devices; - mContext->getExternalStylusDevices(devices); - mExternalStylusConnected = !devices.empty(); - - if (!mExternalStylusConnected) { - resetExternalStylus(); - } -} - -void TouchInputMapper::configureParameters() { - // Use the pointer presentation mode for devices that do not support distinct - // multitouch. The spot-based presentation relies on being able to accurately - // locate two or more fingers on the touch pad. - mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) - ? Parameters::GESTURE_MODE_SINGLE_TOUCH - : Parameters::GESTURE_MODE_MULTI_TOUCH; - - String8 gestureModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), - gestureModeString)) { - if (gestureModeString == "single-touch") { - mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH; - } else if (gestureModeString == "multi-touch") { - mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH; - } else if (gestureModeString != "default") { - ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); - } - } - - if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { - // The device is a touch screen. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { - // The device is a pointing device like a track pad. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) || - getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { - // The device is a cursor device with a touch pad attached. - // By default don't use the touch pad to move the pointer. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else { - // The device is a touch pad of unknown purpose. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } - - mParameters.hasButtonUnderPad = - getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD); - - String8 deviceTypeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), - deviceTypeString)) { - if (deviceTypeString == "touchScreen") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (deviceTypeString == "touchPad") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else if (deviceTypeString == "touchNavigation") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION; - } else if (deviceTypeString == "pointer") { - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (deviceTypeString != "default") { - ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); - } - } - - mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; - getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - mParameters.associatedDisplayIsExternal = false; - if (mParameters.orientationAware || - mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN || - mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { - mParameters.hasAssociatedDisplay = true; - if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { - mParameters.associatedDisplayIsExternal = getDevice()->isExternal(); - String8 uniqueDisplayId; - getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"), - uniqueDisplayId); - mParameters.uniqueDisplayId = uniqueDisplayId.c_str(); - } - } - if (getDevice()->getAssociatedDisplayPort()) { - mParameters.hasAssociatedDisplay = true; - } - - // Initial downs on external touch devices should wake the device. - // Normally we don't do this for internal touch screens to prevent them from waking - // up in your pocket but you can enable it using the input device configuration. - mParameters.wake = getDevice()->isExternal(); - getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake); -} - -void TouchInputMapper::dumpParameters(std::string& dump) { - dump += INDENT3 "Parameters:\n"; - - switch (mParameters.gestureMode) { - case Parameters::GESTURE_MODE_SINGLE_TOUCH: - dump += INDENT4 "GestureMode: single-touch\n"; - break; - case Parameters::GESTURE_MODE_MULTI_TOUCH: - dump += INDENT4 "GestureMode: multi-touch\n"; - break; - default: - assert(false); - } - - switch (mParameters.deviceType) { - case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - dump += INDENT4 "DeviceType: touchScreen\n"; - break; - case Parameters::DEVICE_TYPE_TOUCH_PAD: - dump += INDENT4 "DeviceType: touchPad\n"; - break; - case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: - dump += INDENT4 "DeviceType: touchNavigation\n"; - break; - case Parameters::DEVICE_TYPE_POINTER: - dump += INDENT4 "DeviceType: pointer\n"; - break; - default: - ALOG_ASSERT(false); - } - - dump += StringPrintf(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, " - "displayId='%s'\n", - toString(mParameters.hasAssociatedDisplay), - toString(mParameters.associatedDisplayIsExternal), - mParameters.uniqueDisplayId.c_str()); - dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); -} - -void TouchInputMapper::configureRawPointerAxes() { - mRawPointerAxes.clear(); -} - -void TouchInputMapper::dumpRawPointerAxes(std::string& dump) { - dump += INDENT3 "Raw Touch Axes:\n"; - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); -} - -bool TouchInputMapper::hasExternalStylus() const { - return mExternalStylusConnected; -} - -/** - * Determine which DisplayViewport to use. - * 1. If display port is specified, return the matching viewport. If matching viewport not - * found, then return. - * 2. If a device has associated display, get the matching viewport by either unique id or by - * the display type (internal or external). - * 3. Otherwise, use a non-display viewport. - */ -std::optional<DisplayViewport> TouchInputMapper::findViewport() { - if (mParameters.hasAssociatedDisplay) { - const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort(); - if (displayPort) { - // Find the viewport that contains the same port - std::optional<DisplayViewport> v = mConfig.getDisplayViewportByPort(*displayPort); - if (!v) { - ALOGW("Input device %s should be associated with display on port %" PRIu8 ", " - "but the corresponding viewport is not found.", - getDeviceName().c_str(), *displayPort); - } - return v; - } - - if (!mParameters.uniqueDisplayId.empty()) { - return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId); - } - - ViewportType viewportTypeToUse; - if (mParameters.associatedDisplayIsExternal) { - viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL; - } else { - viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL; - } - - std::optional<DisplayViewport> viewport = - mConfig.getDisplayViewportByType(viewportTypeToUse); - if (!viewport && viewportTypeToUse == ViewportType::VIEWPORT_EXTERNAL) { - ALOGW("Input device %s should be associated with external display, " - "fallback to internal one for the external viewport is not found.", - getDeviceName().c_str()); - viewport = mConfig.getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); - } - - return viewport; - } - - DisplayViewport newViewport; - // Raw width and height in the natural orientation. - int32_t rawWidth = mRawPointerAxes.getRawWidth(); - int32_t rawHeight = mRawPointerAxes.getRawHeight(); - newViewport.setNonDisplayViewport(rawWidth, rawHeight); - return std::make_optional(newViewport); -} - -void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { - int32_t oldDeviceMode = mDeviceMode; - - resolveExternalStylusPresence(); - - // Determine device mode. - if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER && - mConfig.pointerGesturesEnabled) { - mSource = AINPUT_SOURCE_MOUSE; - mDeviceMode = DEVICE_MODE_POINTER; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN && - mParameters.hasAssociatedDisplay) { - mSource = AINPUT_SOURCE_TOUCHSCREEN; - mDeviceMode = DEVICE_MODE_DIRECT; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - if (hasExternalStylus()) { - mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { - mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; - mDeviceMode = DEVICE_MODE_NAVIGATION; - } else { - mSource = AINPUT_SOURCE_TOUCHPAD; - mDeviceMode = DEVICE_MODE_UNSCALED; - } - - // Ensure we have valid X and Y axes. - if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { - ALOGW("Touch device '%s' did not report support for X or Y axis! " - "The device will be inoperable.", - getDeviceName().c_str()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - - // Get associated display dimensions. - std::optional<DisplayViewport> newViewport = findViewport(); - if (!newViewport) { - ALOGI("Touch device '%s' could not query the properties of its associated " - "display. The device will be inoperable until the display size " - "becomes available.", - getDeviceName().c_str()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - - // Raw width and height in the natural orientation. - int32_t rawWidth = mRawPointerAxes.getRawWidth(); - int32_t rawHeight = mRawPointerAxes.getRawHeight(); - - bool viewportChanged = mViewport != *newViewport; - if (viewportChanged) { - mViewport = *newViewport; - - if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { - // Convert rotated viewport to natural surface coordinates. - int32_t naturalLogicalWidth, naturalLogicalHeight; - int32_t naturalPhysicalWidth, naturalPhysicalHeight; - int32_t naturalPhysicalLeft, naturalPhysicalTop; - int32_t naturalDeviceWidth, naturalDeviceHeight; - switch (mViewport.orientation) { - case DISPLAY_ORIENTATION_90: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; - naturalPhysicalTop = mViewport.physicalLeft; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_180: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; - naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - case DISPLAY_ORIENTATION_270: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.physicalTop; - naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_0: - default: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.physicalLeft; - naturalPhysicalTop = mViewport.physicalTop; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - } - - if (naturalPhysicalHeight == 0 || naturalPhysicalWidth == 0) { - ALOGE("Viewport is not set properly: %s", mViewport.toString().c_str()); - naturalPhysicalHeight = naturalPhysicalHeight == 0 ? 1 : naturalPhysicalHeight; - naturalPhysicalWidth = naturalPhysicalWidth == 0 ? 1 : naturalPhysicalWidth; - } - - mPhysicalWidth = naturalPhysicalWidth; - mPhysicalHeight = naturalPhysicalHeight; - mPhysicalLeft = naturalPhysicalLeft; - mPhysicalTop = naturalPhysicalTop; - - mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; - mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; - mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; - mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight; - - mSurfaceOrientation = - mParameters.orientationAware ? mViewport.orientation : DISPLAY_ORIENTATION_0; - } else { - mPhysicalWidth = rawWidth; - mPhysicalHeight = rawHeight; - mPhysicalLeft = 0; - mPhysicalTop = 0; - - mSurfaceWidth = rawWidth; - mSurfaceHeight = rawHeight; - mSurfaceLeft = 0; - mSurfaceTop = 0; - mSurfaceOrientation = DISPLAY_ORIENTATION_0; - } - } - - // If moving between pointer modes, need to reset some state. - bool deviceModeChanged = mDeviceMode != oldDeviceMode; - if (deviceModeChanged) { - mOrientedRanges.clear(); - } - - // Create or update pointer controller if needed. - if (mDeviceMode == DEVICE_MODE_POINTER || - (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { - if (mPointerController == nullptr || viewportChanged) { - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - } - } else { - mPointerController.clear(); - } - - if (viewportChanged || deviceModeChanged) { - ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " - "display id %d", - getDeviceId(), getDeviceName().c_str(), mSurfaceWidth, mSurfaceHeight, - mSurfaceOrientation, mDeviceMode, mViewport.displayId); - - // Configure X and Y factors. - mXScale = float(mSurfaceWidth) / rawWidth; - mYScale = float(mSurfaceHeight) / rawHeight; - mXTranslate = -mSurfaceLeft; - mYTranslate = -mSurfaceTop; - mXPrecision = 1.0f / mXScale; - mYPrecision = 1.0f / mYScale; - - mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; - mOrientedRanges.x.source = mSource; - mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; - mOrientedRanges.y.source = mSource; - - configureVirtualKeys(); - - // Scale factor for terms that are not oriented in a particular axis. - // If the pixels are square then xScale == yScale otherwise we fake it - // by choosing an average. - mGeometricScale = avg(mXScale, mYScale); - - // Size of diagonal axis. - float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Size factors. - if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { - if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; - } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; - } else { - mSizeScale = 0.0f; - } - - mOrientedRanges.haveTouchSize = true; - mOrientedRanges.haveToolSize = true; - mOrientedRanges.haveSize = true; - - mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; - mOrientedRanges.touchMajor.source = mSource; - mOrientedRanges.touchMajor.min = 0; - mOrientedRanges.touchMajor.max = diagonalSize; - mOrientedRanges.touchMajor.flat = 0; - mOrientedRanges.touchMajor.fuzz = 0; - mOrientedRanges.touchMajor.resolution = 0; - - mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; - mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; - - mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; - mOrientedRanges.toolMajor.source = mSource; - mOrientedRanges.toolMajor.min = 0; - mOrientedRanges.toolMajor.max = diagonalSize; - mOrientedRanges.toolMajor.flat = 0; - mOrientedRanges.toolMajor.fuzz = 0; - mOrientedRanges.toolMajor.resolution = 0; - - mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; - mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; - - mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; - mOrientedRanges.size.source = mSource; - mOrientedRanges.size.min = 0; - mOrientedRanges.size.max = 1.0; - mOrientedRanges.size.flat = 0; - mOrientedRanges.size.fuzz = 0; - mOrientedRanges.size.resolution = 0; - } else { - mSizeScale = 0.0f; - } - - // Pressure factors. - mPressureScale = 0; - float pressureMax = 1.0; - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL || - mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { - if (mCalibration.havePressureScale) { - mPressureScale = mCalibration.pressureScale; - pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue; - } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) { - mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; - } - } - - mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; - mOrientedRanges.pressure.source = mSource; - mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = pressureMax; - mOrientedRanges.pressure.flat = 0; - mOrientedRanges.pressure.fuzz = 0; - mOrientedRanges.pressure.resolution = 0; - - // Tilt - mTiltXCenter = 0; - mTiltXScale = 0; - mTiltYCenter = 0; - mTiltYScale = 0; - mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; - if (mHaveTilt) { - mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue); - mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue); - mTiltXScale = M_PI / 180; - mTiltYScale = M_PI / 180; - - mOrientedRanges.haveTilt = true; - - mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; - mOrientedRanges.tilt.source = mSource; - mOrientedRanges.tilt.min = 0; - mOrientedRanges.tilt.max = M_PI_2; - mOrientedRanges.tilt.flat = 0; - mOrientedRanges.tilt.fuzz = 0; - mOrientedRanges.tilt.resolution = 0; - } - - // Orientation - mOrientationScale = 0; - if (mHaveTilt) { - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI; - mOrientedRanges.orientation.max = M_PI; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } else if (mCalibration.orientationCalibration != - Calibration::ORIENTATION_CALIBRATION_NONE) { - if (mCalibration.orientationCalibration == - Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { - if (mRawPointerAxes.orientation.valid) { - if (mRawPointerAxes.orientation.maxValue > 0) { - mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; - } else if (mRawPointerAxes.orientation.minValue < 0) { - mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; - } else { - mOrientationScale = 0; - } - } - } - - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI_2; - mOrientedRanges.orientation.max = M_PI_2; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } - - // Distance - mDistanceScale = 0; - if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { - if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_SCALED) { - if (mCalibration.haveDistanceScale) { - mDistanceScale = mCalibration.distanceScale; - } else { - mDistanceScale = 1.0f; - } - } - - mOrientedRanges.haveDistance = true; - - mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; - mOrientedRanges.distance.source = mSource; - mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale; - mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale; - mOrientedRanges.distance.flat = 0; - mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale; - mOrientedRanges.distance.resolution = 0; - } - - // Compute oriented precision, scales and ranges. - // Note that the maximum value reported is an inclusive maximum value so it is one - // unit less than the total width or height of surface. - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - mOrientedXPrecision = mYPrecision; - mOrientedYPrecision = mXPrecision; - - mOrientedRanges.x.min = mYTranslate; - mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; - - mOrientedRanges.y.min = mXTranslate; - mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; - break; - - default: - mOrientedXPrecision = mXPrecision; - mOrientedYPrecision = mYPrecision; - - mOrientedRanges.x.min = mXTranslate; - mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; - - mOrientedRanges.y.min = mYTranslate; - mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; - break; - } - - // Location - updateAffineTransformation(); - - if (mDeviceMode == DEVICE_MODE_POINTER) { - // Compute pointer gesture detection parameters. - float rawDiagonal = hypotf(rawWidth, rawHeight); - float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Scale movements such that one whole swipe of the touch pad covers a - // given area relative to the diagonal size of the display when no acceleration - // is applied. - // Assume that the touch pad has a square aspect ratio such that movements in - // X and Y of the same number of raw units cover the same physical distance. - mPointerXMovementScale = - mConfig.pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal; - mPointerYMovementScale = mPointerXMovementScale; - - // Scale zooms to cover a smaller range of the display than movements do. - // This value determines the area around the pointer that is affected by freeform - // pointer gestures. - mPointerXZoomScale = - mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal; - mPointerYZoomScale = mPointerXZoomScale; - - // Max width between pointers to detect a swipe gesture is more than some fraction - // of the diagonal axis of the touch pad. Touches that are wider than this are - // translated into freeform gestures. - mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; - - // Abort current pointer usages because the state has changed. - abortPointerUsage(when, 0 /*policyFlags*/); - } - - // Inform the dispatcher about the changes. - *outResetNeeded = true; - bumpGeneration(); - } -} - -void TouchInputMapper::dumpSurface(std::string& dump) { - dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str()); - dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); - dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); - dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); - dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); - dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth); - dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight); - dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft); - dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop); - dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); -} - -void TouchInputMapper::configureVirtualKeys() { - std::vector<VirtualKeyDefinition> virtualKeyDefinitions; - getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); - - mVirtualKeys.clear(); - - if (virtualKeyDefinitions.size() == 0) { - return; - } - - int32_t touchScreenLeft = mRawPointerAxes.x.minValue; - int32_t touchScreenTop = mRawPointerAxes.y.minValue; - int32_t touchScreenWidth = mRawPointerAxes.getRawWidth(); - int32_t touchScreenHeight = mRawPointerAxes.getRawHeight(); - - for (const VirtualKeyDefinition& virtualKeyDefinition : virtualKeyDefinitions) { - VirtualKey virtualKey; - - virtualKey.scanCode = virtualKeyDefinition.scanCode; - int32_t keyCode; - int32_t dummyKeyMetaState; - uint32_t flags; - if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0, &keyCode, - &dummyKeyMetaState, &flags)) { - ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); - continue; // drop the key - } - - virtualKey.keyCode = keyCode; - virtualKey.flags = flags; - - // convert the key definition's display coordinates into touch coordinates for a hit box - int32_t halfWidth = virtualKeyDefinition.width / 2; - int32_t halfHeight = virtualKeyDefinition.height / 2; - - virtualKey.hitLeft = - (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mSurfaceWidth + - touchScreenLeft; - virtualKey.hitRight = - (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mSurfaceWidth + - touchScreenLeft; - virtualKey.hitTop = - (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mSurfaceHeight + - touchScreenTop; - virtualKey.hitBottom = - (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mSurfaceHeight + - touchScreenTop; - mVirtualKeys.push_back(virtualKey); - } -} - -void TouchInputMapper::dumpVirtualKeys(std::string& dump) { - if (!mVirtualKeys.empty()) { - dump += INDENT3 "Virtual Keys:\n"; - - for (size_t i = 0; i < mVirtualKeys.size(); i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, " - "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", - i, virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft, - virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom); - } - } -} - -void TouchInputMapper::parseCalibration() { - const PropertyMap& in = getDevice()->getConfiguration(); - Calibration& out = mCalibration; - - // Size - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; - String8 sizeCalibrationString; - if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { - if (sizeCalibrationString == "none") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } else if (sizeCalibrationString == "geometric") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } else if (sizeCalibrationString == "diameter") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER; - } else if (sizeCalibrationString == "box") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX; - } else if (sizeCalibrationString == "area") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA; - } else if (sizeCalibrationString != "default") { - ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string()); - } - } - - out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), out.sizeScale); - out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), out.sizeBias); - out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed); - - // Pressure - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; - String8 pressureCalibrationString; - if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { - if (pressureCalibrationString == "none") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } else if (pressureCalibrationString == "physical") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } else if (pressureCalibrationString == "amplitude") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; - } else if (pressureCalibrationString != "default") { - ALOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); - } - } - - out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale); - - // Orientation - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; - String8 orientationCalibrationString; - if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { - if (orientationCalibrationString == "none") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } else if (orientationCalibrationString == "interpolated") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } else if (orientationCalibrationString == "vector") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR; - } else if (orientationCalibrationString != "default") { - ALOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); - } - } - - // Distance - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; - String8 distanceCalibrationString; - if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { - if (distanceCalibrationString == "none") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } else if (distanceCalibrationString == "scaled") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } else if (distanceCalibrationString != "default") { - ALOGW("Invalid value for touch.distance.calibration: '%s'", - distanceCalibrationString.string()); - } - } - - out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale); - - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT; - String8 coverageCalibrationString; - if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { - if (coverageCalibrationString == "none") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } else if (coverageCalibrationString == "box") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX; - } else if (coverageCalibrationString != "default") { - ALOGW("Invalid value for touch.coverage.calibration: '%s'", - coverageCalibrationString.string()); - } - } -} - -void TouchInputMapper::resolveCalibration() { - // Size - if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) { - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } - } else { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } - - // Pressure - if (mRawPointerAxes.pressure.valid) { - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } - } else { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } - - // Orientation - if (mRawPointerAxes.orientation.valid) { - if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } - } else { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } - - // Distance - if (mRawPointerAxes.distance.valid) { - if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } - } else { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } - - // Coverage - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) { - mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } -} - -void TouchInputMapper::dumpCalibration(std::string& dump) { - dump += INDENT3 "Calibration:\n"; - - // Size - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_NONE: - dump += INDENT4 "touch.size.calibration: none\n"; - break; - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - dump += INDENT4 "touch.size.calibration: geometric\n"; - break; - case Calibration::SIZE_CALIBRATION_DIAMETER: - dump += INDENT4 "touch.size.calibration: diameter\n"; - break; - case Calibration::SIZE_CALIBRATION_BOX: - dump += INDENT4 "touch.size.calibration: box\n"; - break; - case Calibration::SIZE_CALIBRATION_AREA: - dump += INDENT4 "touch.size.calibration: area\n"; - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveSizeScale) { - dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale); - } - - if (mCalibration.haveSizeBias) { - dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", mCalibration.sizeBias); - } - - if (mCalibration.haveSizeIsSummed) { - dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n", - toString(mCalibration.sizeIsSummed)); - } - - // Pressure - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_NONE: - dump += INDENT4 "touch.pressure.calibration: none\n"; - break; - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - dump += INDENT4 "touch.pressure.calibration: physical\n"; - break; - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - dump += INDENT4 "touch.pressure.calibration: amplitude\n"; - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.havePressureScale) { - dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", mCalibration.pressureScale); - } - - // Orientation - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_NONE: - dump += INDENT4 "touch.orientation.calibration: none\n"; - break; - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - dump += INDENT4 "touch.orientation.calibration: interpolated\n"; - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: - dump += INDENT4 "touch.orientation.calibration: vector\n"; - break; - default: - ALOG_ASSERT(false); - } - - // Distance - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_NONE: - dump += INDENT4 "touch.distance.calibration: none\n"; - break; - case Calibration::DISTANCE_CALIBRATION_SCALED: - dump += INDENT4 "touch.distance.calibration: scaled\n"; - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveDistanceScale) { - dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale); - } - - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_NONE: - dump += INDENT4 "touch.coverage.calibration: none\n"; - break; - case Calibration::COVERAGE_CALIBRATION_BOX: - dump += INDENT4 "touch.coverage.calibration: box\n"; - break; - default: - ALOG_ASSERT(false); - } -} - -void TouchInputMapper::dumpAffineTransformation(std::string& dump) { - dump += INDENT3 "Affine Transformation:\n"; - - dump += StringPrintf(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale); - dump += StringPrintf(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix); - dump += StringPrintf(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset); - dump += StringPrintf(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix); - dump += StringPrintf(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale); - dump += StringPrintf(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset); -} - -void TouchInputMapper::updateAffineTransformation() { - mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(), - mSurfaceOrientation); -} - -void TouchInputMapper::reset(nsecs_t when) { - mCursorButtonAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - mTouchButtonAccumulator.reset(getDevice()); - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mRawStatesPending.clear(); - mCurrentRawState.clear(); - mCurrentCookedState.clear(); - mLastRawState.clear(); - mLastCookedState.clear(); - mPointerUsage = POINTER_USAGE_NONE; - mSentHoverEnter = false; - mHavePointerIds = false; - mCurrentMotionAborted = false; - mDownTime = 0; - - mCurrentVirtualKey.down = false; - - mPointerGesture.reset(); - mPointerSimple.reset(); - resetExternalStylus(); - - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } - - InputMapper::reset(when); -} - -void TouchInputMapper::resetExternalStylus() { - mExternalStylusState.clear(); - mExternalStylusId = -1; - mExternalStylusFusionTimeout = LLONG_MAX; - mExternalStylusDataPending = false; -} - -void TouchInputMapper::clearStylusDataPendingFlags() { - mExternalStylusDataPending = false; - mExternalStylusFusionTimeout = LLONG_MAX; -} - -void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) { - nsecs_t now = systemTime(CLOCK_MONOTONIC); - nsecs_t latency = now - evdevTime; - mStatistics.addValue(nanoseconds_to_microseconds(latency)); - nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime; - if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) { - android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, mStatistics.min, - mStatistics.max, mStatistics.mean(), mStatistics.stdev(), - mStatistics.count); - mStatistics.reset(now); - } -} - -void TouchInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - mTouchButtonAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - reportEventForStatistics(rawEvent->when); - sync(rawEvent->when); - } -} - -void TouchInputMapper::sync(nsecs_t when) { - const RawState* last = - mRawStatesPending.empty() ? &mCurrentRawState : &mRawStatesPending.back(); - - // Push a new state. - mRawStatesPending.emplace_back(); - - RawState* next = &mRawStatesPending.back(); - next->clear(); - next->when = when; - - // Sync button state. - next->buttonState = - mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); - - // Sync scroll - next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); - next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); - mCursorScrollAccumulator.finishSync(); - - // Sync touch - syncTouch(when, next); - - // Assign pointer ids. - if (!mHavePointerIds) { - assignPointerIds(last, next); - } - -#if DEBUG_RAW_EVENTS - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", - last->rawPointerData.pointerCount, next->rawPointerData.pointerCount, - last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value, - last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value); -#endif - - processRawTouches(false /*timeout*/); -} - -void TouchInputMapper::processRawTouches(bool timeout) { - if (mDeviceMode == DEVICE_MODE_DISABLED) { - // Drop all input if the device is disabled. - mCurrentRawState.clear(); - mRawStatesPending.clear(); - return; - } - - // Drain any pending touch states. The invariant here is that the mCurrentRawState is always - // valid and must go through the full cook and dispatch cycle. This ensures that anything - // touching the current state will only observe the events that have been dispatched to the - // rest of the pipeline. - const size_t N = mRawStatesPending.size(); - size_t count; - for (count = 0; count < N; count++) { - const RawState& next = mRawStatesPending[count]; - - // A failure to assign the stylus id means that we're waiting on stylus data - // and so should defer the rest of the pipeline. - if (assignExternalStylusId(next, timeout)) { - break; - } - - // All ready to go. - clearStylusDataPendingFlags(); - mCurrentRawState.copyFrom(next); - if (mCurrentRawState.when < mLastRawState.when) { - mCurrentRawState.when = mLastRawState.when; - } - cookAndDispatch(mCurrentRawState.when); - } - if (count != 0) { - mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count); - } - - if (mExternalStylusDataPending) { - if (timeout) { - nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY; - clearStylusDataPendingFlags(); - mCurrentRawState.copyFrom(mLastRawState); -#if DEBUG_STYLUS_FUSION - ALOGD("Timeout expired, synthesizing event with new stylus data"); -#endif - cookAndDispatch(when); - } else if (mExternalStylusFusionTimeout == LLONG_MAX) { - mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT; - getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); - } - } -} - -void TouchInputMapper::cookAndDispatch(nsecs_t when) { - // Always start with a clean state. - mCurrentCookedState.clear(); - - // Apply stylus buttons to current raw state. - applyExternalStylusButtonState(when); - - // Handle policy on initial down or hover events. - bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 && - mCurrentRawState.rawPointerData.pointerCount != 0; - - uint32_t policyFlags = 0; - bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState; - if (initialDown || buttonsPressed) { - // If this is a touch screen, hide the pointer on an initial down. - if (mDeviceMode == DEVICE_MODE_DIRECT) { - getContext()->fadePointer(); - } - - if (mParameters.wake) { - policyFlags |= POLICY_FLAG_WAKE; - } - } - - // Consume raw off-screen touches before cooking pointer data. - // If touches are consumed, subsequent code will not receive any pointer data. - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawState.rawPointerData.clear(); - } - - // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure - // with cooked pointer data that has the same ids and indices as the raw data. - // The following code can use either the raw or cooked data, as needed. - cookPointerData(); - - // Apply stylus pressure to current cooked state. - applyExternalStylusTouchState(when); - - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - mViewport.displayId, policyFlags, mLastCookedState.buttonState, - mCurrentCookedState.buttonState); - - // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DEVICE_MODE_POINTER) { - for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || - pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentCookedState.stylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER || - pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mCurrentCookedState.fingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { - mCurrentCookedState.mouseIdBits.markBit(id); - } - } - for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || - pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentCookedState.stylusIdBits.markBit(id); - } - } - - // Stylus takes precedence over all tools, then mouse, then finger. - PointerUsage pointerUsage = mPointerUsage; - if (!mCurrentCookedState.stylusIdBits.isEmpty()) { - mCurrentCookedState.mouseIdBits.clear(); - mCurrentCookedState.fingerIdBits.clear(); - pointerUsage = POINTER_USAGE_STYLUS; - } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) { - mCurrentCookedState.fingerIdBits.clear(); - pointerUsage = POINTER_USAGE_MOUSE; - } else if (!mCurrentCookedState.fingerIdBits.isEmpty() || - isPointerDown(mCurrentRawState.buttonState)) { - pointerUsage = POINTER_USAGE_GESTURES; - } - - dispatchPointerUsage(when, policyFlags, pointerUsage); - } else { - if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches && - mPointerController != nullptr) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - - mPointerController->setButtonState(mCurrentRawState.buttonState); - mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.touchingIdBits, - mViewport.displayId); - } - - if (!mCurrentMotionAborted) { - dispatchButtonRelease(when, policyFlags); - dispatchHoverExit(when, policyFlags); - dispatchTouches(when, policyFlags); - dispatchHoverEnterAndMove(when, policyFlags); - dispatchButtonPress(when, policyFlags); - } - - if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { - mCurrentMotionAborted = false; - } - } - - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - mViewport.displayId, policyFlags, mLastCookedState.buttonState, - mCurrentCookedState.buttonState); - - // Clear some transient state. - mCurrentRawState.rawVScroll = 0; - mCurrentRawState.rawHScroll = 0; - - // Copy current touch to last touch in preparation for the next cycle. - mLastRawState.copyFrom(mCurrentRawState); - mLastCookedState.copyFrom(mCurrentCookedState); -} - -void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { - if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) { - mCurrentRawState.buttonState |= mExternalStylusState.buttons; - } -} - -void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { - CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData; - const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData; - - if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) { - float pressure = mExternalStylusState.pressure; - if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) { - const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId); - pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); - } - PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId); - coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - - PointerProperties& properties = - currentPointerData.editPointerPropertiesWithId(mExternalStylusId); - if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - properties.toolType = mExternalStylusState.toolType; - } - } -} - -bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) { - if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) { - return false; - } - - const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 && - state.rawPointerData.pointerCount != 0; - if (initialDown) { - if (mExternalStylusState.pressure != 0.0f) { -#if DEBUG_STYLUS_FUSION - ALOGD("Have both stylus and touch data, beginning fusion"); -#endif - mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); - } else if (timeout) { -#if DEBUG_STYLUS_FUSION - ALOGD("Timeout expired, assuming touch is not a stylus."); -#endif - resetExternalStylus(); - } else { - if (mExternalStylusFusionTimeout == LLONG_MAX) { - mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT; - } -#if DEBUG_STYLUS_FUSION - ALOGD("No stylus data but stylus is connected, requesting timeout " - "(%" PRId64 "ms)", - mExternalStylusFusionTimeout); -#endif - getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); - return true; - } - } - - // Check if the stylus pointer has gone up. - if (mExternalStylusId != -1 && !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { -#if DEBUG_STYLUS_FUSION - ALOGD("Stylus pointer is going up"); -#endif - mExternalStylusId = -1; - } - - return false; -} - -void TouchInputMapper::timeoutExpired(nsecs_t when) { - if (mDeviceMode == DEVICE_MODE_POINTER) { - if (mPointerUsage == POINTER_USAGE_GESTURES) { - dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); - } - } else if (mDeviceMode == DEVICE_MODE_DIRECT) { - if (mExternalStylusFusionTimeout < when) { - processRawTouches(true /*timeout*/); - } else if (mExternalStylusFusionTimeout != LLONG_MAX) { - getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); - } - } -} - -void TouchInputMapper::updateExternalStylusState(const StylusState& state) { - mExternalStylusState.copyFrom(state); - if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) { - // We're either in the middle of a fused stream of data or we're waiting on data before - // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus - // data. - mExternalStylusDataPending = true; - processRawTouches(false /*timeout*/); - } -} - -bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { - // Check for release of a virtual key. - if (mCurrentVirtualKey.down) { - if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { - // Pointer went up while virtual key was down. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - return true; - } - - if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { - uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(id); - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { - // Pointer is still within the space of the virtual key. - return true; - } - } - - // Pointer left virtual key area or another pointer also went down. - // Send key cancellation but do not consume the touch yet. - // This is useful when the user swipes through from the virtual key area - // into the main display surface. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, - mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | - AKEY_EVENT_FLAG_CANCELED); - } - } - - if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() && - !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { - // Pointer just went down. Check for virtual key press or off-screen touches. - uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); - if (!isPointInsideSurface(pointer.x, pointer.y)) { - // If exactly one pointer went down, check for virtual key hit. - // Otherwise we will drop the entire stroke. - if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey) { - mCurrentVirtualKey.down = true; - mCurrentVirtualKey.downTime = when; - mCurrentVirtualKey.keyCode = virtualKey->keyCode; - mCurrentVirtualKey.scanCode = virtualKey->scanCode; - mCurrentVirtualKey.ignored = - mContext->shouldDropVirtualKey(when, getDevice(), virtualKey->keyCode, - virtualKey->scanCode); - - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_DOWN, - AKEY_EVENT_FLAG_FROM_SYSTEM | - AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - } - } - return true; - } - } - - // Disable all virtual key touches that happen within a short time interval of the - // most recent touch within the screen area. The idea is to filter out stray - // virtual key presses when interacting with the touch screen. - // - // Problems we're trying to solve: - // - // 1. While scrolling a list or dragging the window shade, the user swipes down into a - // virtual key area that is implemented by a separate touch panel and accidentally - // triggers a virtual key. - // - // 2. While typing in the on screen keyboard, the user taps slightly outside the screen - // area and accidentally triggers a virtual key. This often happens when virtual keys - // are layed out below the screen near to where the on screen keyboard's space bar - // is displayed. - if (mConfig.virtualKeyQuietTime > 0 && - !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { - mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); - } - return false; -} - -void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags) { - int32_t keyCode = mCurrentVirtualKey.keyCode; - int32_t scanCode = mCurrentVirtualKey.scanCode; - nsecs_t downTime = mCurrentVirtualKey.downTime; - int32_t metaState = mContext->getGlobalMetaState(); - policyFlags |= POLICY_FLAG_VIRTUAL; - - NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, - mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode, - scanCode, metaState, downTime); - getListener()->notifyKey(&args); -} - -void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; - if (!currentIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentCookedState.buttonState; - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, - buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mCurrentMotionAborted = true; - } -} - -void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; - BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentCookedState.buttonState; - - if (currentIdBits == lastIdBits) { - if (!currentIdBits.isEmpty()) { - // No pointer id changes so this is a move event. - // The listener takes care of batching moves so we don't have to deal with that here. - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, - buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } else { - // There may be pointers going up and pointers going down and pointers moving - // all at the same time. - BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); - BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); - BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); - BitSet32 dispatchedIdBits(lastIdBits.value); - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool moveNeeded = - updateMovedPointers(mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mLastCookedState.cookedPointerData.pointerProperties, - mLastCookedState.cookedPointerData.pointerCoords, - mLastCookedState.cookedPointerData.idToIndex, moveIdBits); - if (buttonState != mLastCookedState.buttonState) { - moveNeeded = true; - } - - // Dispatch pointer up events. - while (!upIdBits.isEmpty()) { - uint32_t upId = upIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, - metaState, buttonState, 0, mCurrentCookedState.deviceTimestamp, - mLastCookedState.cookedPointerData.pointerProperties, - mLastCookedState.cookedPointerData.pointerCoords, - mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - dispatchedIdBits.clearBit(upId); - } - - // Dispatch move events if any of the remaining pointers moved from their old locations. - // Although applications receive new locations as part of individual pointer up - // events, they do not generally handle them except when presented in a move event. - if (moveNeeded && !moveIdBits.isEmpty()) { - ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, - buttonState, 0, mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - - // Dispatch pointer down events using the new pointer locations. - while (!downIdBits.isEmpty()) { - uint32_t downId = downIdBits.clearFirstMarkedBit(); - dispatchedIdBits.markBit(downId); - - if (dispatchedIdBits.count() == 1) { - // First pointer is going down. Set down time. - mDownTime = when; - } - - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, - metaState, buttonState, 0, mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, - downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } -} - -void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { - if (mSentHoverEnter && - (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() || - !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) { - int32_t metaState = getContext()->getGlobalMetaState(); - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, - mLastCookedState.buttonState, 0, mLastCookedState.deviceTimestamp, - mLastCookedState.cookedPointerData.pointerProperties, - mLastCookedState.cookedPointerData.pointerCoords, - mLastCookedState.cookedPointerData.idToIndex, - mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, - mOrientedYPrecision, mDownTime); - mSentHoverEnter = false; - } -} - -void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() && - !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, - metaState, mCurrentRawState.buttonState, 0, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mSentHoverEnter = true; - } - - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, - mCurrentRawState.buttonState, 0, mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } -} - -void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) { - BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState); - const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData); - const int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mLastCookedState.buttonState; - while (!releasedButtons.isEmpty()) { - int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit()); - buttonState &= ~actionButton; - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_RELEASE, - actionButton, 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } -} - -void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) { - BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState); - const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData); - const int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mLastCookedState.buttonState; - while (!pressedButtons.isEmpty()) { - int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit()); - buttonState |= actionButton; - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, - 0, metaState, buttonState, 0, mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } -} - -const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) { - if (!cookedPointerData.touchingIdBits.isEmpty()) { - return cookedPointerData.touchingIdBits; - } - return cookedPointerData.hoveringIdBits; -} - -void TouchInputMapper::cookPointerData() { - uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; - - mCurrentCookedState.cookedPointerData.clear(); - mCurrentCookedState.deviceTimestamp = mCurrentRawState.deviceTimestamp; - mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; - mCurrentCookedState.cookedPointerData.hoveringIdBits = - mCurrentRawState.rawPointerData.hoveringIdBits; - mCurrentCookedState.cookedPointerData.touchingIdBits = - mCurrentRawState.rawPointerData.touchingIdBits; - - if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { - mCurrentCookedState.buttonState = 0; - } else { - mCurrentCookedState.buttonState = mCurrentRawState.buttonState; - } - - // Walk through the the active pointers and map device coordinates onto - // surface coordinates and adjust for display orientation. - for (uint32_t i = 0; i < currentPointerCount; i++) { - const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; - - // Size - float touchMajor, touchMinor, toolMajor, toolMinor, size; - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - case Calibration::SIZE_CALIBRATION_DIAMETER: - case Calibration::SIZE_CALIBRATION_BOX: - case Calibration::SIZE_CALIBRATION_AREA: - if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { - touchMajor = in.touchMajor; - touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; - toolMajor = in.toolMajor; - toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) - : in.touchMajor; - } else if (mRawPointerAxes.touchMajor.valid) { - toolMajor = touchMajor = in.touchMajor; - toolMinor = touchMinor = - mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; - size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) - : in.touchMajor; - } else if (mRawPointerAxes.toolMajor.valid) { - touchMajor = toolMajor = in.toolMajor; - touchMinor = toolMinor = - mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.toolMinor.valid ? avg(in.toolMajor, in.toolMinor) - : in.toolMajor; - } else { - ALOG_ASSERT(false, - "No touch or tool axes. " - "Size calibration should have been resolved to NONE."); - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - } - - if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { - uint32_t touchingCount = mCurrentRawState.rawPointerData.touchingIdBits.count(); - if (touchingCount > 1) { - touchMajor /= touchingCount; - touchMinor /= touchingCount; - toolMajor /= touchingCount; - toolMinor /= touchingCount; - size /= touchingCount; - } - } - - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { - touchMajor *= mGeometricScale; - touchMinor *= mGeometricScale; - toolMajor *= mGeometricScale; - toolMinor *= mGeometricScale; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { - touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; - touchMinor = touchMajor; - toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; - toolMinor = toolMajor; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { - touchMinor = touchMajor; - toolMinor = toolMajor; - } - - mCalibration.applySizeScaleAndBias(&touchMajor); - mCalibration.applySizeScaleAndBias(&touchMinor); - mCalibration.applySizeScaleAndBias(&toolMajor); - mCalibration.applySizeScaleAndBias(&toolMinor); - size *= mSizeScale; - break; - default: - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - break; - } - - // Pressure - float pressure; - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - pressure = in.pressure * mPressureScale; - break; - default: - pressure = in.isHovering ? 0 : 1; - break; - } - - // Tilt and Orientation - float tilt; - float orientation; - if (mHaveTilt) { - float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; - float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; - orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); - tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); - } else { - tilt = 0; - - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - orientation = in.orientation * mOrientationScale; - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: { - int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); - int32_t c2 = signExtendNybble(in.orientation & 0x0f); - if (c1 != 0 || c2 != 0) { - orientation = atan2f(c1, c2) * 0.5f; - float confidence = hypotf(c1, c2); - float scale = 1.0f + confidence / 16.0f; - touchMajor *= scale; - touchMinor /= scale; - toolMajor *= scale; - toolMinor /= scale; - } else { - orientation = 0; - } - break; - } - default: - orientation = 0; - } - } - - // Distance - float distance; - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_SCALED: - distance = in.distance * mDistanceScale; - break; - default: - distance = 0; - } - - // Coverage - int32_t rawLeft, rawTop, rawRight, rawBottom; - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_BOX: - rawLeft = (in.toolMinor & 0xffff0000) >> 16; - rawRight = in.toolMinor & 0x0000ffff; - rawBottom = in.toolMajor & 0x0000ffff; - rawTop = (in.toolMajor & 0xffff0000) >> 16; - break; - default: - rawLeft = rawTop = rawRight = rawBottom = 0; - break; - } - - // Adjust X,Y coords for device calibration - // TODO: Adjust coverage coords? - float xTransformed = in.x, yTransformed = in.y; - mAffineTransform.applyTo(xTransformed, yTransformed); - - // Adjust X, Y, and coverage coords for surface orientation. - float x, y; - float left, top, right, bottom; - - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate; - left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; - top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; - orientation -= M_PI_2; - if (mOrientedRanges.haveOrientation && - orientation < mOrientedRanges.orientation.min) { - orientation += - (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); - } - break; - case DISPLAY_ORIENTATION_180: - x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale; - y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate; - left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale; - right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; - bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; - top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; - orientation -= M_PI; - if (mOrientedRanges.haveOrientation && - orientation < mOrientedRanges.orientation.min) { - orientation += - (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); - } - break; - case DISPLAY_ORIENTATION_270: - x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale; - y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale; - right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; - bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - orientation += M_PI_2; - if (mOrientedRanges.haveOrientation && - orientation > mOrientedRanges.orientation.max) { - orientation -= - (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); - } - break; - default: - x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - break; - } - - // Write output coords. - PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; - out.clear(); - out.setAxisValue(AMOTION_EVENT_AXIS_X, x); - out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); - out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); - out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); - out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); - } else { - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); - } - - // Write output properties. - PointerProperties& properties = mCurrentCookedState.cookedPointerData.pointerProperties[i]; - uint32_t id = in.id; - properties.clear(); - properties.id = id; - properties.toolType = in.toolType; - - // Write id index. - mCurrentCookedState.cookedPointerData.idToIndex[id] = i; - } -} - -void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, - PointerUsage pointerUsage) { - if (pointerUsage != mPointerUsage) { - abortPointerUsage(when, policyFlags); - mPointerUsage = pointerUsage; - } - - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); - break; - case POINTER_USAGE_STYLUS: - dispatchPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - dispatchPointerMouse(when, policyFlags); - break; - default: - break; - } -} - -void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - abortPointerGestures(when, policyFlags); - break; - case POINTER_USAGE_STYLUS: - abortPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - abortPointerMouse(when, policyFlags); - break; - default: - break; - } - - mPointerUsage = POINTER_USAGE_NONE; -} - -void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) { - // Update current gesture coordinates. - bool cancelPreviousGesture, finishPreviousGesture; - bool sendEvents = - preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture, isTimeout); - if (!sendEvents) { - return; - } - if (finishPreviousGesture) { - cancelPreviousGesture = false; - } - - // Update the pointer presentation and spots. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - if (finishPreviousGesture || cancelPreviousGesture) { - mPointerController->clearSpots(); - } - - if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { - mPointerController->setSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, - mPointerController->getDisplayId()); - } - } else { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - } - - // Show or hide the pointer if needed. - switch (mPointerGesture.currentGestureMode) { - case PointerGesture::NEUTRAL: - case PointerGesture::QUIET: - if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH && - mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) { - // Remind the user of where the pointer is after finishing a gesture with spots. - mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL); - } - break; - case PointerGesture::TAP: - case PointerGesture::TAP_DRAG: - case PointerGesture::BUTTON_CLICK_OR_DRAG: - case PointerGesture::HOVER: - case PointerGesture::PRESS: - case PointerGesture::SWIPE: - // Unfade the pointer when the current gesture manipulates the - // area directly under the pointer. - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - break; - case PointerGesture::FREEFORM: - // Fade the pointer when the current gesture manipulates a different - // area and there are spots to guide the user experience. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } else { - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - break; - } - - // Send events! - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentCookedState.buttonState; - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP || - mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG || - mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG || - mPointerGesture.currentGestureMode == PointerGesture::PRESS || - mPointerGesture.currentGestureMode == PointerGesture::SWIPE || - mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; - bool moveNeeded = false; - if (down && !cancelPreviousGesture && !finishPreviousGesture && - !mPointerGesture.lastGestureIdBits.isEmpty() && - !mPointerGesture.currentGestureIdBits.isEmpty()) { - BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value & - mPointerGesture.lastGestureIdBits.value); - moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, - mPointerGesture.lastGestureIdToIndex, movedGestureIdBits); - if (buttonState != mLastCookedState.buttonState) { - moveNeeded = true; - } - } - - // Send motion events for all pointers that went up or were canceled. - BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); - if (!dispatchedGestureIdBits.isEmpty()) { - if (cancelPreviousGesture) { - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, - buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, - mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, - mPointerGesture.downTime); - - dispatchedGestureIdBits.clear(); - } else { - BitSet32 upGestureIdBits; - if (finishPreviousGesture) { - upGestureIdBits = dispatchedGestureIdBits; - } else { - upGestureIdBits.value = - dispatchedGestureIdBits.value & ~mPointerGesture.currentGestureIdBits.value; - } - while (!upGestureIdBits.isEmpty()) { - uint32_t id = upGestureIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, - mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0, - 0, mPointerGesture.downTime); - - dispatchedGestureIdBits.clearBit(id); - } - } - } - - // Send motion events for all pointers that moved. - if (moveNeeded) { - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, - buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, - mPointerGesture.downTime); - } - - // Send motion events for all pointers that went down. - if (down) { - BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value & - ~dispatchedGestureIdBits.value); - while (!downGestureIdBits.isEmpty()) { - uint32_t id = downGestureIdBits.clearFirstMarkedBit(); - dispatchedGestureIdBits.markBit(id); - - if (dispatchedGestureIdBits.count() == 1) { - mPointerGesture.downTime = when; - } - - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, - metaState, buttonState, 0, - /* deviceTimestamp */ 0, mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0, - 0, mPointerGesture.downTime); - } - } - - // Send motion events for hover. - if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, - buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime); - } else if (dispatchedGestureIdBits.isEmpty() && !mPointerGesture.lastGestureIdBits.isEmpty()) { - // Synthesize a hover move event after all pointers go up to indicate that - // the pointer is hovering again even if the user is not currently touching - // the touch pad. This ensures that a view will receive a fresh hover enter - // event after a tap. - float x, y; - mPointerController->getPosition(&x, &y); - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - - PointerCoords pointerCoords; - pointerCoords.clear(); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - - const int32_t displayId = mPointerController->getDisplayId(); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, - mPointerGesture.downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - // Update state. - mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; - if (!down) { - mPointerGesture.lastGestureIdBits.clear(); - } else { - mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits; - for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - mPointerGesture.lastGestureProperties[index].copyFrom( - mPointerGesture.currentGestureProperties[index]); - mPointerGesture.lastGestureCoords[index].copyFrom( - mPointerGesture.currentGestureCoords[index]); - mPointerGesture.lastGestureIdToIndex[id] = index; - } - } -} - -void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { - // Cancel previously dispatches pointers. - if (!mPointerGesture.lastGestureIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentRawState.buttonState; - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, - buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, - mPointerGesture.lastGestureIdToIndex, mPointerGesture.lastGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } - - // Reset the current pointer gesture. - mPointerGesture.reset(); - mPointerVelocityControl.reset(); - - // Remove any current spots. - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } -} - -bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, - bool* outFinishPreviousGesture, bool isTimeout) { - *outCancelPreviousGesture = false; - *outFinishPreviousGesture = false; - - // Handle TAP timeout. - if (isTimeout) { -#if DEBUG_GESTURES - ALOGD("Gestures: Processing timeout"); -#endif - - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - // The tap/drag timeout has not yet expired. - getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + - mConfig.pointerGestureTapDragInterval); - } else { - // The tap is finished. -#if DEBUG_GESTURES - ALOGD("Gestures: TAP finished"); -#endif - *outFinishPreviousGesture = true; - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - return true; - } - } - - // We did not handle this timeout. - return false; - } - - const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count(); - const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count(); - - // Update the velocity tracker. - { - VelocityTracker::Position positions[MAX_POINTERS]; - uint32_t count = 0; - for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(id); - positions[count].x = pointer.x * mPointerXMovementScale; - positions[count].y = pointer.y * mPointerYMovementScale; - } - mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits, - positions); - } - - // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning - // to NEUTRAL, then we should not generate tap event. - if (mPointerGesture.lastGestureMode != PointerGesture::HOVER && - mPointerGesture.lastGestureMode != PointerGesture::TAP && - mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) { - mPointerGesture.resetTap(); - } - - // Pick a new active touch id if needed. - // Choose an arbitrary pointer that just went down, if there is one. - // Otherwise choose an arbitrary remaining pointer. - // This guarantees we always have an active touch id when there is at least one pointer. - // We keep the same active touch id for as long as possible. - int32_t lastActiveTouchId = mPointerGesture.activeTouchId; - int32_t activeTouchId = lastActiveTouchId; - if (activeTouchId < 0) { - if (!mCurrentCookedState.fingerIdBits.isEmpty()) { - activeTouchId = mPointerGesture.activeTouchId = - mCurrentCookedState.fingerIdBits.firstMarkedBit(); - mPointerGesture.firstTouchTime = when; - } - } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { - if (!mCurrentCookedState.fingerIdBits.isEmpty()) { - activeTouchId = mPointerGesture.activeTouchId = - mCurrentCookedState.fingerIdBits.firstMarkedBit(); - } else { - activeTouchId = mPointerGesture.activeTouchId = -1; - } - } - - // Determine whether we are in quiet time. - bool isQuietTime = false; - if (activeTouchId < 0) { - mPointerGesture.resetQuietTime(); - } else { - isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval; - if (!isQuietTime) { - if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS || - mPointerGesture.lastGestureMode == PointerGesture::SWIPE || - mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) && - currentFingerCount < 2) { - // Enter quiet time when exiting swipe or freeform state. - // This is to prevent accidentally entering the hover state and flinging the - // pointer when finishing a swipe and there is still one pointer left onscreen. - isQuietTime = true; - } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG && - currentFingerCount >= 2 && !isPointerDown(mCurrentRawState.buttonState)) { - // Enter quiet time when releasing the button and there are still two or more - // fingers down. This may indicate that one finger was used to press the button - // but it has not gone up yet. - isQuietTime = true; - } - if (isQuietTime) { - mPointerGesture.quietTime = when; - } - } - } - - // Switch states based on button and pointer state. - if (isQuietTime) { - // Case 1: Quiet time. (QUIET) -#if DEBUG_GESTURES - ALOGD("Gestures: QUIET for next %0.3fms", - (mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) * 0.000001f); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { - *outFinishPreviousGesture = true; - } - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::QUIET; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - } else if (isPointerDown(mCurrentRawState.buttonState)) { - // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) - // The pointer follows the active touch point. - // Emit DOWN, MOVE, UP events at the pointer location. - // - // Only the active touch matters; other fingers are ignored. This policy helps - // to handle the case where the user places a second finger on the touch pad - // to apply the necessary force to depress an integrated button below the surface. - // We don't want the second finger to be delivered to applications. - // - // For this to work well, we need to make sure to track the pointer that is really - // active. If the user first puts one finger down to click then adds another - // finger to drag then the active pointer should switch to the finger that is - // being dragged. -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " - "currentFingerCount=%d", - activeTouchId, currentFingerCount); -#endif - // Reset state when just starting. - if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { - *outFinishPreviousGesture = true; - mPointerGesture.activeGestureId = 0; - } - - // Switch pointers if needed. - // Find the fastest pointer and follow it. - if (activeTouchId >= 0 && currentFingerCount > 1) { - int32_t bestId = -1; - float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - float vx, vy; - if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { - float speed = hypotf(vx, vy); - if (speed > bestSpeed) { - bestId = id; - bestSpeed = speed; - } - } - } - if (bestId >= 0 && bestId != activeTouchId) { - mPointerGesture.activeTouchId = activeTouchId = bestId; -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " - "bestId=%d, bestSpeed=%0.3f", - bestId, bestSpeed); -#endif - } - } - - float deltaX = 0, deltaY = 0; - if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawState.rawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawState.rawPointerData.pointerForId(activeTouchId); - deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; - deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the click will occur at the position of the anchor - // spot and all other spots will move there. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (currentFingerCount == 0) { - // Case 3. No fingers down and button is not pressed. (NEUTRAL) - if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { - *outFinishPreviousGesture = true; - } - - // Watch for taps coming out of HOVER or TAP_DRAG mode. - // Checking for taps after TAP_DRAG allows us to detect double-taps. - bool tapped = false; - if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER || - mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) && - lastFingerCount == 1) { - if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && - fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP"); -#endif - - mPointerGesture.tapUpTime = when; - getContext()->requestTimeoutAtTime(when + - mConfig.pointerGestureTapDragInterval); - - mPointerGesture.activeGestureId = 0; - mPointerGesture.currentGestureMode = PointerGesture::TAP; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = - mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, - mPointerGesture.tapX); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, - mPointerGesture.tapY); - mPointerGesture.currentGestureCoords[0] - .setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - - tapped = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", x - mPointerGesture.tapX, - y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - if (mPointerGesture.tapDownTime != LLONG_MIN) { - ALOGD("Gestures: Not a TAP, %0.3fms since down", - (when - mPointerGesture.tapDownTime) * 0.000001f); - } else { - ALOGD("Gestures: Not a TAP, incompatible mode transitions"); - } -#endif - } - } - - mPointerVelocityControl.reset(); - - if (!tapped) { -#if DEBUG_GESTURES - ALOGD("Gestures: NEUTRAL"); -#endif - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - } - } else if (currentFingerCount == 1) { - // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) - // The pointer follows the active touch point. - // When in HOVER, emit HOVER_MOVE events at the pointer location. - // When in TAP_DRAG, emit MOVE events at the pointer location. - ALOG_ASSERT(activeTouchId >= 0); - - mPointerGesture.currentGestureMode = PointerGesture::HOVER; - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && - fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", - (when - mPointerGesture.tapUpTime) * 0.000001f); -#endif - } - } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } - - float deltaX = 0, deltaY = 0; - if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawState.rawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawState.rawPointerData.pointerForId(activeTouchId); - deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; - deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the hover or drag will occur at the position of the anchor spot. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - bool down; - if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP_DRAG"); -#endif - down = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: HOVER"); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { - *outFinishPreviousGesture = true; - } - mPointerGesture.activeGestureId = 0; - down = false; - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - down ? 1.0f : 0.0f); - - if (lastFingerCount == 0 && currentFingerCount != 0) { - mPointerGesture.resetTap(); - mPointerGesture.tapDownTime = when; - mPointerGesture.tapX = x; - mPointerGesture.tapY = y; - } - } else { - // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) - // We need to provide feedback for each finger that goes down so we cannot wait - // for the fingers to move before deciding what to do. - // - // The ambiguous case is deciding what to do when there are two fingers down but they - // have not moved enough to determine whether they are part of a drag or part of a - // freeform gesture, or just a press or long-press at the pointer location. - // - // When there are two fingers we start with the PRESS hypothesis and we generate a - // down at the pointer location. - // - // When the two fingers move enough or when additional fingers are added, we make - // a decision to transition into SWIPE or FREEFORM mode accordingly. - ALOG_ASSERT(activeTouchId >= 0); - - bool settled = when >= - mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval; - if (mPointerGesture.lastGestureMode != PointerGesture::PRESS && - mPointerGesture.lastGestureMode != PointerGesture::SWIPE && - mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - *outFinishPreviousGesture = true; - } else if (!settled && currentFingerCount > lastFingerCount) { - // Additional pointers have gone down but not yet settled. - // Reset the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " - "settle time remaining %0.3fms", - (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval - - when) * 0.000001f); -#endif - *outCancelPreviousGesture = true; - } else { - // Continue previous gesture. - mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; - } - - if (*outFinishPreviousGesture || *outCancelPreviousGesture) { - mPointerGesture.currentGestureMode = PointerGesture::PRESS; - mPointerGesture.activeGestureId = 0; - mPointerGesture.referenceIdBits.clear(); - mPointerVelocityControl.reset(); - - // Use the centroid and pointer location as the reference points for the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " - "settle time remaining %0.3fms", - (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval - - when) * 0.000001f); -#endif - mCurrentRawState.rawPointerData - .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX, - &mPointerGesture.referenceTouchY); - mPointerController->getPosition(&mPointerGesture.referenceGestureX, - &mPointerGesture.referenceGestureY); - } - - // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value & - ~mPointerGesture.referenceIdBits.value); - !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - mPointerGesture.referenceDeltas[id].dx = 0; - mPointerGesture.referenceDeltas[id].dy = 0; - } - mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; - - // Add delta for all fingers and calculate a common movement delta. - float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value & - mCurrentCookedState.fingerIdBits.value); - for (BitSet32 idBits(commonIdBits); !idBits.isEmpty();) { - bool first = (idBits == commonIdBits); - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id); - const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx += cpd.x - lpd.x; - delta.dy += cpd.y - lpd.y; - - if (first) { - commonDeltaX = delta.dx; - commonDeltaY = delta.dy; - } else { - commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); - commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); - } - } - - // Consider transitions from PRESS to SWIPE or MULTITOUCH. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { - float dist[MAX_POINTER_ID + 1]; - int32_t distOverThreshold = 0; - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - dist[id] = hypotf(delta.dx * mPointerXZoomScale, delta.dy * mPointerYZoomScale); - if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { - distOverThreshold += 1; - } - } - - // Only transition when at least two pointers have moved further than - // the minimum distance threshold. - if (distOverThreshold >= 2) { - if (currentFingerCount > 2) { - // There are more than two pointers, switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are exactly two pointers. - BitSet32 idBits(mCurrentCookedState.fingerIdBits); - uint32_t id1 = idBits.clearFirstMarkedBit(); - uint32_t id2 = idBits.firstMarkedBit(); - const RawPointerData::Pointer& p1 = - mCurrentRawState.rawPointerData.pointerForId(id1); - const RawPointerData::Pointer& p2 = - mCurrentRawState.rawPointerData.pointerForId(id2); - float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); - if (mutualDistance > mPointerGestureMaxSwipeWidth) { - // There are two pointers but they are too far apart for a SWIPE, - // switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", - mutualDistance, mPointerGestureMaxSwipeWidth); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are two pointers. Wait for both pointers to start moving - // before deciding whether this is a SWIPE or FREEFORM gesture. - float dist1 = dist[id1]; - float dist2 = dist[id2]; - if (dist1 >= mConfig.pointerGestureMultitouchMinDistance && - dist2 >= mConfig.pointerGestureMultitouchMinDistance) { - // Calculate the dot product of the displacement vectors. - // When the vectors are oriented in approximately the same direction, - // the angle betweeen them is near zero and the cosine of the angle - // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * - // mag(v2). - PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; - PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; - float dx1 = delta1.dx * mPointerXZoomScale; - float dy1 = delta1.dy * mPointerYZoomScale; - float dx2 = delta2.dx * mPointerXZoomScale; - float dy2 = delta2.dy * mPointerYZoomScale; - float dot = dx1 * dx2 + dy1 * dy2; - float cosine = dot / (dist1 * dist2); // denominator always > 0 - if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { - // Pointers are moving in the same direction. Switch to SWIPE. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to SWIPE, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f >= %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, - mConfig.pointerGestureMultitouchMinDistance, cosine, - mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - mPointerGesture.currentGestureMode = PointerGesture::SWIPE; - } else { - // Pointers are moving in different directions. Switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f < %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, - mConfig.pointerGestureMultitouchMinDistance, cosine, - mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - } - } - } - } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // Switch from SWIPE to FREEFORM if additional pointers go down. - // Cancel previous gesture. - if (currentFingerCount > 2) { -#if DEBUG_GESTURES - ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - - // Move the reference points based on the overall group motion of the fingers - // except in PRESS mode while waiting for a transition to occur. - if (mPointerGesture.currentGestureMode != PointerGesture::PRESS && - (commonDeltaX || commonDeltaY)) { - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx = 0; - delta.dy = 0; - } - - mPointerGesture.referenceTouchX += commonDeltaX; - mPointerGesture.referenceTouchY += commonDeltaY; - - commonDeltaX *= mPointerXMovementScale; - commonDeltaY *= mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); - mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); - - mPointerGesture.referenceGestureX += commonDeltaX; - mPointerGesture.referenceGestureY += commonDeltaY; - } - - // Report gestures. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS || - mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // PRESS or SWIPE mode. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, - mPointerGesture.referenceGestureX); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, - mPointerGesture.referenceGestureY); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { - // FREEFORM mode. -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - - BitSet32 mappedTouchIdBits; - BitSet32 usedGestureIdBits; - if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - // Initially, assign the active gesture id to the active touch point - // if there is one. No other touch id bits are mapped yet. - if (!*outCancelPreviousGesture) { - mappedTouchIdBits.markBit(activeTouchId); - usedGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = - mPointerGesture.activeGestureId; - } else { - mPointerGesture.activeGestureId = -1; - } - } else { - // Otherwise, assume we mapped all touches from the previous frame. - // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value & - mCurrentCookedState.fingerIdBits.value; - usedGestureIdBits = mPointerGesture.lastGestureIdBits; - - // Check whether we need to choose a new active gesture id because the - // current went went up. - for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value & - ~mCurrentCookedState.fingerIdBits.value); - !upTouchIdBits.isEmpty();) { - uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); - uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; - if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) { - mPointerGesture.activeGestureId = -1; - break; - } - } - } - -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM follow up " - "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " - "activeGestureId=%d", - mappedTouchIdBits.value, usedGestureIdBits.value, - mPointerGesture.activeGestureId); -#endif - - BitSet32 idBits(mCurrentCookedState.fingerIdBits); - for (uint32_t i = 0; i < currentFingerCount; i++) { - uint32_t touchId = idBits.clearFirstMarkedBit(); - uint32_t gestureId; - if (!mappedTouchIdBits.hasBit(touchId)) { - gestureId = usedGestureIdBits.markFirstUnmarkedBit(); - mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "new mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } else { - gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "existing mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } - mPointerGesture.currentGestureIdBits.markBit(gestureId); - mPointerGesture.currentGestureIdToIndex[gestureId] = i; - - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(touchId); - float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale; - float deltaY = (pointer.y - mPointerGesture.referenceTouchY) * mPointerYZoomScale; - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - - mPointerGesture.currentGestureProperties[i].clear(); - mPointerGesture.currentGestureProperties[i].id = gestureId; - mPointerGesture.currentGestureProperties[i].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[i].clear(); - mPointerGesture.currentGestureCoords[i] - .setAxisValue(AMOTION_EVENT_AXIS_X, - mPointerGesture.referenceGestureX + deltaX); - mPointerGesture.currentGestureCoords[i] - .setAxisValue(AMOTION_EVENT_AXIS_Y, - mPointerGesture.referenceGestureY + deltaY); - mPointerGesture.currentGestureCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - 1.0f); - } - - if (mPointerGesture.activeGestureId < 0) { - mPointerGesture.activeGestureId = - mPointerGesture.currentGestureIdBits.firstMarkedBit(); -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM new " - "activeGestureId=%d", - mPointerGesture.activeGestureId); -#endif - } - } - } - - mPointerController->setButtonState(mCurrentRawState.buttonState); - -#if DEBUG_GESTURES - ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " - "currentGestureMode=%d, currentGestureIdBits=0x%08x, " - "lastGestureMode=%d, lastGestureIdBits=0x%08x", - toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), - mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value, - mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value); - for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; - ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } - for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty();) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; - ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } -#endif - return true; -} - -void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentCookedState.stylusIdBits.isEmpty()) { - uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); - uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; - float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(); - float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY(); - mPointerController->setPosition(x, y); - - hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); - down = !hovering; - - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom( - mCurrentCookedState.cookedPointerData.pointerCoords[index]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType; - } else { - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); -} - -void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentCookedState.mouseIdBits.isEmpty()) { - uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; - float deltaX = 0, deltaY = 0; - if (mLastCookedState.mouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; - deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x - - mLastRawState.rawPointerData.pointers[lastIndex].x) * - mPointerXMovementScale; - deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y - - mLastRawState.rawPointerData.pointers[lastIndex].y) * - mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - down = isPointerDown(mCurrentRawState.buttonState); - hovering = !down; - - float x, y; - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom( - mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - hovering ? 0.0f : 1.0f); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType; - } else { - mPointerVelocityControl.reset(); - - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); - - mPointerVelocityControl.reset(); -} - -void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, - bool hovering) { - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t displayId = mViewport.displayId; - - if (mPointerController != nullptr) { - if (down || hovering) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentRawState.buttonState); - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } - displayId = mPointerController->getDisplayId(); - } - - if (mPointerSimple.down && !down) { - mPointerSimple.down = false; - - // Send up. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, - mLastRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - if (mPointerSimple.hovering && !hovering) { - mPointerSimple.hovering = false; - - // Send hover exit. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, - metaState, mLastRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - if (down) { - if (!mPointerSimple.down) { - mPointerSimple.down = true; - mPointerSimple.downTime = when; - - // Send down. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0, - metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, - &mPointerSimple.currentCoords, mOrientedXPrecision, - mOrientedYPrecision, mPointerSimple.downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - // Send move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, - mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - if (hovering) { - if (!mPointerSimple.hovering) { - mPointerSimple.hovering = true; - - // Send hover enter. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, - metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, - &mPointerSimple.currentCoords, mOrientedXPrecision, - mOrientedYPrecision, mPointerSimple.downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - // Send hover move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { - float vscroll = mCurrentRawState.rawVScroll; - float hscroll = mCurrentRawState.rawHScroll; - mWheelYVelocityControl.move(when, nullptr, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, nullptr); - - // Send scroll. - PointerCoords pointerCoords; - pointerCoords.copyFrom(mPointerSimple.currentCoords); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, - mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.currentProperties, &pointerCoords, - mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, - /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - // Save state. - if (down || hovering) { - mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); - mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); - } else { - mPointerSimple.reset(); - } -} - -void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - dispatchPointerSimple(when, policyFlags, false, false); -} - -void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t actionButton, int32_t flags, - int32_t metaState, int32_t buttonState, int32_t edgeFlags, - uint32_t deviceTimestamp, const PointerProperties* properties, - const PointerCoords* coords, const uint32_t* idToIndex, - BitSet32 idBits, int32_t changedId, float xPrecision, - float yPrecision, nsecs_t downTime) { - PointerCoords pointerCoords[MAX_POINTERS]; - PointerProperties pointerProperties[MAX_POINTERS]; - uint32_t pointerCount = 0; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = idToIndex[id]; - pointerProperties[pointerCount].copyFrom(properties[index]); - pointerCoords[pointerCount].copyFrom(coords[index]); - - if (changedId >= 0 && id == uint32_t(changedId)) { - action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - } - - pointerCount += 1; - } - - ALOG_ASSERT(pointerCount != 0); - - if (changedId >= 0 && pointerCount == 1) { - // Replace initial down and final up action. - // We can compare the action without masking off the changed pointer index - // because we know the index is 0. - if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { - action = AMOTION_EVENT_ACTION_DOWN; - } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { - action = AMOTION_EVENT_ACTION_UP; - } else { - // Can't happen. - ALOG_ASSERT(false); - } - } - const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE); - const int32_t deviceId = getDeviceId(); - std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId); - std::for_each(frames.begin(), frames.end(), - [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, source, displayId, - policyFlags, action, actionButton, flags, metaState, buttonState, - MotionClassification::NONE, edgeFlags, deviceTimestamp, pointerCount, - pointerProperties, pointerCoords, xPrecision, yPrecision, downTime, - std::move(frames)); - getListener()->notifyMotion(&args); -} - -bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, - const PointerCoords* inCoords, - const uint32_t* inIdToIndex, - PointerProperties* outProperties, - PointerCoords* outCoords, const uint32_t* outIdToIndex, - BitSet32 idBits) const { - bool changed = false; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t inIndex = inIdToIndex[id]; - uint32_t outIndex = outIdToIndex[id]; - - const PointerProperties& curInProperties = inProperties[inIndex]; - const PointerCoords& curInCoords = inCoords[inIndex]; - PointerProperties& curOutProperties = outProperties[outIndex]; - PointerCoords& curOutCoords = outCoords[outIndex]; - - if (curInProperties != curOutProperties) { - curOutProperties.copyFrom(curInProperties); - changed = true; - } - - if (curInCoords != curOutCoords) { - curOutCoords.copyFrom(curInCoords); - changed = true; - } - } - return changed; -} - -void TouchInputMapper::fadePointer() { - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - -void TouchInputMapper::cancelTouch(nsecs_t when) { - abortPointerUsage(when, 0 /*policyFlags*/); - abortTouches(when, 0 /* policyFlags*/); -} - -bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { - const float scaledX = x * mXScale; - const float scaledY = y * mYScale; - return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && - scaledX >= mPhysicalLeft && scaledX <= mPhysicalLeft + mPhysicalWidth && - y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue && - scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight; -} - -const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) { - for (const VirtualKey& virtualKey : mVirtualKeys) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " - "left=%d, top=%d, right=%d, bottom=%d", - x, y, virtualKey.keyCode, virtualKey.scanCode, virtualKey.hitLeft, virtualKey.hitTop, - virtualKey.hitRight, virtualKey.hitBottom); -#endif - - if (virtualKey.isHit(x, y)) { - return &virtualKey; - } - } - - return nullptr; -} - -void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) { - uint32_t currentPointerCount = current->rawPointerData.pointerCount; - uint32_t lastPointerCount = last->rawPointerData.pointerCount; - - current->rawPointerData.clearIdBits(); - - if (currentPointerCount == 0) { - // No pointers to assign. - return; - } - - if (lastPointerCount == 0) { - // All pointers are new. - for (uint32_t i = 0; i < currentPointerCount; i++) { - uint32_t id = i; - current->rawPointerData.pointers[i].id = id; - current->rawPointerData.idToIndex[id] = i; - current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i)); - } - return; - } - - if (currentPointerCount == 1 && lastPointerCount == 1 && - current->rawPointerData.pointers[0].toolType == last->rawPointerData.pointers[0].toolType) { - // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = last->rawPointerData.pointers[0].id; - current->rawPointerData.pointers[0].id = id; - current->rawPointerData.idToIndex[id] = 0; - current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0)); - return; - } - - // General case. - // We build a heap of squared euclidean distances between current and last pointers - // associated with the current and last pointer indices. Then, we find the best - // match (by distance) for each current pointer. - // The pointers must have the same tool type but it is possible for them to - // transition from hovering to touching or vice-versa while retaining the same id. - PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; - - uint32_t heapSize = 0; - for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; - currentPointerIndex++) { - for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; - lastPointerIndex++) { - const RawPointerData::Pointer& currentPointer = - current->rawPointerData.pointers[currentPointerIndex]; - const RawPointerData::Pointer& lastPointer = - last->rawPointerData.pointers[lastPointerIndex]; - if (currentPointer.toolType == lastPointer.toolType) { - int64_t deltaX = currentPointer.x - lastPointer.x; - int64_t deltaY = currentPointer.y - lastPointer.y; - - uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); - - // Insert new element into the heap (sift up). - heap[heapSize].currentPointerIndex = currentPointerIndex; - heap[heapSize].lastPointerIndex = lastPointerIndex; - heap[heapSize].distance = distance; - heapSize += 1; - } - } - } - - // Heapify - for (uint32_t startIndex = heapSize / 2; startIndex != 0;) { - startIndex -= 1; - for (uint32_t parentIndex = startIndex;;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize && - heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i, - heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); - } -#endif - - // Pull matches out by increasing order of distance. - // To avoid reassigning pointers that have already been matched, the loop keeps track - // of which last and current pointers have been matched using the matchedXXXBits variables. - // It also tracks the used pointer id bits. - BitSet32 matchedLastBits(0); - BitSet32 matchedCurrentBits(0); - BitSet32 usedIdBits(0); - bool first = true; - for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { - while (heapSize > 0) { - if (first) { - // The first time through the loop, we just consume the root element of - // the heap (the one with smallest distance). - first = false; - } else { - // Previous iterations consumed the root element of the heap. - // Pop root element off of the heap (sift down). - heap[0] = heap[heapSize]; - for (uint32_t parentIndex = 0;;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize && - heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i, - heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); - } -#endif - } - - heapSize -= 1; - - uint32_t currentPointerIndex = heap[0].currentPointerIndex; - if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched - - uint32_t lastPointerIndex = heap[0].lastPointerIndex; - if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched - - matchedCurrentBits.markBit(currentPointerIndex); - matchedLastBits.markBit(lastPointerIndex); - - uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id; - current->rawPointerData.pointers[currentPointerIndex].id = id; - current->rawPointerData.idToIndex[id] = currentPointerIndex; - current->rawPointerData.markIdBit(id, - current->rawPointerData.isHovering( - currentPointerIndex)); - usedIdBits.markBit(id); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32 ", id=%" PRIu32 - ", distance=%" PRIu64, - lastPointerIndex, currentPointerIndex, id, heap[0].distance); -#endif - break; - } - } - - // Assign fresh ids to pointers that were not matched in the process. - for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { - uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); - uint32_t id = usedIdBits.markFirstUnmarkedBit(); - - current->rawPointerData.pointers[currentPointerIndex].id = id; - current->rawPointerData.idToIndex[id] = currentPointerIndex; - current->rawPointerData.markIdBit(id, - current->rawPointerData.isHovering(currentPointerIndex)); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, id); -#endif - } -} - -int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { - return AKEY_STATE_VIRTUAL; - } - - for (const VirtualKey& virtualKey : mVirtualKeys) { - if (virtualKey.keyCode == keyCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { - return AKEY_STATE_VIRTUAL; - } - - for (const VirtualKey& virtualKey : mVirtualKeys) { - if (virtualKey.scanCode == scanCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - for (const VirtualKey& virtualKey : mVirtualKeys) { - for (size_t i = 0; i < numCodes; i++) { - if (virtualKey.keyCode == keyCodes[i]) { - outFlags[i] = 1; - } - } - } - - return true; -} - -std::optional<int32_t> TouchInputMapper::getAssociatedDisplay() { - if (mParameters.hasAssociatedDisplay) { - if (mDeviceMode == DEVICE_MODE_POINTER) { - return std::make_optional(mPointerController->getDisplayId()); - } else { - return std::make_optional(mViewport.displayId); - } - } - return std::nullopt; -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h deleted file mode 100644 index d14812aecd..0000000000 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ /dev/null @@ -1,838 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H -#define _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H - -#include "CursorButtonAccumulator.h" -#include "CursorScrollAccumulator.h" -#include "EventHub.h" -#include "InputMapper.h" -#include "InputReaderBase.h" -#include "TouchButtonAccumulator.h" - -#include <stdint.h> - -namespace android { - -/** - * Basic statistics information. - * Keep track of min, max, average, and standard deviation of the received samples. - * Used to report latency information about input events. - */ -struct LatencyStatistics { - float min; - float max; - // Sum of all samples - float sum; - // Sum of squares of all samples - float sum2; - // The number of samples - size_t count; - // The last time statistics were reported. - nsecs_t lastReportTime; - - LatencyStatistics() { reset(systemTime(SYSTEM_TIME_MONOTONIC)); } - - inline void addValue(float x) { - if (x < min) { - min = x; - } - if (x > max) { - max = x; - } - sum += x; - sum2 += x * x; - count++; - } - - // Get the average value. Should not be called if no samples have been added. - inline float mean() { - if (count == 0) { - return 0; - } - return sum / count; - } - - // Get the standard deviation. Should not be called if no samples have been added. - inline float stdev() { - if (count == 0) { - return 0; - } - float average = mean(); - return sqrt(sum2 / count - average * average); - } - - /** - * Reset internal state. The variable 'when' is the time when the data collection started. - * Call this to start a new data collection window. - */ - inline void reset(nsecs_t when) { - max = 0; - min = std::numeric_limits<float>::max(); - sum = 0; - sum2 = 0; - count = 0; - lastReportTime = when; - } -}; - -/* Raw axis information from the driver. */ -struct RawPointerAxes { - RawAbsoluteAxisInfo x; - RawAbsoluteAxisInfo y; - RawAbsoluteAxisInfo pressure; - RawAbsoluteAxisInfo touchMajor; - RawAbsoluteAxisInfo touchMinor; - RawAbsoluteAxisInfo toolMajor; - RawAbsoluteAxisInfo toolMinor; - RawAbsoluteAxisInfo orientation; - RawAbsoluteAxisInfo distance; - RawAbsoluteAxisInfo tiltX; - RawAbsoluteAxisInfo tiltY; - RawAbsoluteAxisInfo trackingId; - RawAbsoluteAxisInfo slot; - - RawPointerAxes(); - inline int32_t getRawWidth() const { return x.maxValue - x.minValue + 1; } - inline int32_t getRawHeight() const { return y.maxValue - y.minValue + 1; } - void clear(); -}; - -/* Raw data for a collection of pointers including a pointer id mapping table. */ -struct RawPointerData { - struct Pointer { - uint32_t id; - int32_t x; - int32_t y; - int32_t pressure; - int32_t touchMajor; - int32_t touchMinor; - int32_t toolMajor; - int32_t toolMinor; - int32_t orientation; - int32_t distance; - int32_t tiltX; - int32_t tiltY; - int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant - bool isHovering; - }; - - uint32_t pointerCount; - Pointer pointers[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - RawPointerData(); - void clear(); - void copyFrom(const RawPointerData& other); - void getCentroidOfTouchingPointers(float* outX, float* outY) const; - - inline void markIdBit(uint32_t id, bool isHovering) { - if (isHovering) { - hoveringIdBits.markBit(id); - } else { - touchingIdBits.markBit(id); - } - } - - inline void clearIdBits() { - hoveringIdBits.clear(); - touchingIdBits.clear(); - } - - inline const Pointer& pointerForId(uint32_t id) const { return pointers[idToIndex[id]]; } - - inline bool isHovering(uint32_t pointerIndex) { return pointers[pointerIndex].isHovering; } -}; - -/* Cooked data for a collection of pointers including a pointer id mapping table. */ -struct CookedPointerData { - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - CookedPointerData(); - void clear(); - void copyFrom(const CookedPointerData& other); - - inline const PointerCoords& pointerCoordsForId(uint32_t id) const { - return pointerCoords[idToIndex[id]]; - } - - inline PointerCoords& editPointerCoordsWithId(uint32_t id) { - return pointerCoords[idToIndex[id]]; - } - - inline PointerProperties& editPointerPropertiesWithId(uint32_t id) { - return pointerProperties[idToIndex[id]]; - } - - inline bool isHovering(uint32_t pointerIndex) const { - return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); - } - - inline bool isTouching(uint32_t pointerIndex) const { - return touchingIdBits.hasBit(pointerProperties[pointerIndex].id); - } -}; - -class TouchInputMapper : public InputMapper { -public: - explicit TouchInputMapper(InputDevice* device); - virtual ~TouchInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual void fadePointer(); - virtual void cancelTouch(nsecs_t when); - virtual void timeoutExpired(nsecs_t when); - virtual void updateExternalStylusState(const StylusState& state); - virtual std::optional<int32_t> getAssociatedDisplay(); - -protected: - CursorButtonAccumulator mCursorButtonAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - TouchButtonAccumulator mTouchButtonAccumulator; - - struct VirtualKey { - int32_t keyCode; - int32_t scanCode; - uint32_t flags; - - // computed hit box, specified in touch screen coords based on known display size - int32_t hitLeft; - int32_t hitTop; - int32_t hitRight; - int32_t hitBottom; - - inline bool isHit(int32_t x, int32_t y) const { - return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; - } - }; - - // Input sources and device mode. - uint32_t mSource; - - enum DeviceMode { - DEVICE_MODE_DISABLED, // input is disabled - DEVICE_MODE_DIRECT, // direct mapping (touchscreen) - DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) - DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation) - DEVICE_MODE_POINTER, // pointer mapping (pointer) - }; - DeviceMode mDeviceMode; - - // The reader's configuration. - InputReaderConfiguration mConfig; - - // Immutable configuration parameters. - struct Parameters { - enum DeviceType { - DEVICE_TYPE_TOUCH_SCREEN, - DEVICE_TYPE_TOUCH_PAD, - DEVICE_TYPE_TOUCH_NAVIGATION, - DEVICE_TYPE_POINTER, - }; - - DeviceType deviceType; - bool hasAssociatedDisplay; - bool associatedDisplayIsExternal; - bool orientationAware; - bool hasButtonUnderPad; - std::string uniqueDisplayId; - - enum GestureMode { - GESTURE_MODE_SINGLE_TOUCH, - GESTURE_MODE_MULTI_TOUCH, - }; - GestureMode gestureMode; - - bool wake; - } mParameters; - - // Immutable calibration parameters in parsed form. - struct Calibration { - // Size - enum SizeCalibration { - SIZE_CALIBRATION_DEFAULT, - SIZE_CALIBRATION_NONE, - SIZE_CALIBRATION_GEOMETRIC, - SIZE_CALIBRATION_DIAMETER, - SIZE_CALIBRATION_BOX, - SIZE_CALIBRATION_AREA, - }; - - SizeCalibration sizeCalibration; - - bool haveSizeScale; - float sizeScale; - bool haveSizeBias; - float sizeBias; - bool haveSizeIsSummed; - bool sizeIsSummed; - - // Pressure - enum PressureCalibration { - PRESSURE_CALIBRATION_DEFAULT, - PRESSURE_CALIBRATION_NONE, - PRESSURE_CALIBRATION_PHYSICAL, - PRESSURE_CALIBRATION_AMPLITUDE, - }; - - PressureCalibration pressureCalibration; - bool havePressureScale; - float pressureScale; - - // Orientation - enum OrientationCalibration { - ORIENTATION_CALIBRATION_DEFAULT, - ORIENTATION_CALIBRATION_NONE, - ORIENTATION_CALIBRATION_INTERPOLATED, - ORIENTATION_CALIBRATION_VECTOR, - }; - - OrientationCalibration orientationCalibration; - - // Distance - enum DistanceCalibration { - DISTANCE_CALIBRATION_DEFAULT, - DISTANCE_CALIBRATION_NONE, - DISTANCE_CALIBRATION_SCALED, - }; - - DistanceCalibration distanceCalibration; - bool haveDistanceScale; - float distanceScale; - - enum CoverageCalibration { - COVERAGE_CALIBRATION_DEFAULT, - COVERAGE_CALIBRATION_NONE, - COVERAGE_CALIBRATION_BOX, - }; - - CoverageCalibration coverageCalibration; - - inline void applySizeScaleAndBias(float* outSize) const { - if (haveSizeScale) { - *outSize *= sizeScale; - } - if (haveSizeBias) { - *outSize += sizeBias; - } - if (*outSize < 0) { - *outSize = 0; - } - } - } mCalibration; - - // Affine location transformation/calibration - struct TouchAffineTransformation mAffineTransform; - - RawPointerAxes mRawPointerAxes; - - struct RawState { - nsecs_t when; - uint32_t deviceTimestamp; - - // Raw pointer sample data. - RawPointerData rawPointerData; - - int32_t buttonState; - - // Scroll state. - int32_t rawVScroll; - int32_t rawHScroll; - - void copyFrom(const RawState& other) { - when = other.when; - deviceTimestamp = other.deviceTimestamp; - rawPointerData.copyFrom(other.rawPointerData); - buttonState = other.buttonState; - rawVScroll = other.rawVScroll; - rawHScroll = other.rawHScroll; - } - - void clear() { - when = 0; - deviceTimestamp = 0; - rawPointerData.clear(); - buttonState = 0; - rawVScroll = 0; - rawHScroll = 0; - } - }; - - struct CookedState { - uint32_t deviceTimestamp; - // Cooked pointer sample data. - CookedPointerData cookedPointerData; - - // Id bits used to differentiate fingers, stylus and mouse tools. - BitSet32 fingerIdBits; - BitSet32 stylusIdBits; - BitSet32 mouseIdBits; - - int32_t buttonState; - - void copyFrom(const CookedState& other) { - deviceTimestamp = other.deviceTimestamp; - cookedPointerData.copyFrom(other.cookedPointerData); - fingerIdBits = other.fingerIdBits; - stylusIdBits = other.stylusIdBits; - mouseIdBits = other.mouseIdBits; - buttonState = other.buttonState; - } - - void clear() { - deviceTimestamp = 0; - cookedPointerData.clear(); - fingerIdBits.clear(); - stylusIdBits.clear(); - mouseIdBits.clear(); - buttonState = 0; - } - }; - - std::vector<RawState> mRawStatesPending; - RawState mCurrentRawState; - CookedState mCurrentCookedState; - RawState mLastRawState; - CookedState mLastCookedState; - - // State provided by an external stylus - StylusState mExternalStylusState; - int64_t mExternalStylusId; - nsecs_t mExternalStylusFusionTimeout; - bool mExternalStylusDataPending; - - // True if we sent a HOVER_ENTER event. - bool mSentHoverEnter; - - // Have we assigned pointer IDs for this stream - bool mHavePointerIds; - - // Is the current stream of direct touch events aborted - bool mCurrentMotionAborted; - - // The time the primary pointer last went down. - nsecs_t mDownTime; - - // The pointer controller, or null if the device is not a pointer. - sp<PointerControllerInterface> mPointerController; - - std::vector<VirtualKey> mVirtualKeys; - - virtual void configureParameters(); - virtual void dumpParameters(std::string& dump); - virtual void configureRawPointerAxes(); - virtual void dumpRawPointerAxes(std::string& dump); - virtual void configureSurface(nsecs_t when, bool* outResetNeeded); - virtual void dumpSurface(std::string& dump); - virtual void configureVirtualKeys(); - virtual void dumpVirtualKeys(std::string& dump); - virtual void parseCalibration(); - virtual void resolveCalibration(); - virtual void dumpCalibration(std::string& dump); - virtual void updateAffineTransformation(); - virtual void dumpAffineTransformation(std::string& dump); - virtual void resolveExternalStylusPresence(); - virtual bool hasStylus() const = 0; - virtual bool hasExternalStylus() const; - - virtual void syncTouch(nsecs_t when, RawState* outState) = 0; - -private: - // The current viewport. - // The components of the viewport are specified in the display's rotated orientation. - DisplayViewport mViewport; - - // The surface orientation, width and height set by configureSurface(). - // The width and height are derived from the viewport but are specified - // in the natural orientation. - // The surface origin specifies how the surface coordinates should be translated - // to align with the logical display coordinate space. - int32_t mSurfaceWidth; - int32_t mSurfaceHeight; - int32_t mSurfaceLeft; - int32_t mSurfaceTop; - - // Similar to the surface coordinates, but in the raw display coordinate space rather than in - // the logical coordinate space. - int32_t mPhysicalWidth; - int32_t mPhysicalHeight; - int32_t mPhysicalLeft; - int32_t mPhysicalTop; - - // The orientation may be different from the viewport orientation as it specifies - // the rotation of the surface coordinates required to produce the viewport's - // requested orientation, so it will depend on whether the device is orientation aware. - int32_t mSurfaceOrientation; - - // Translation and scaling factors, orientation-independent. - float mXTranslate; - float mXScale; - float mXPrecision; - - float mYTranslate; - float mYScale; - float mYPrecision; - - float mGeometricScale; - - float mPressureScale; - - float mSizeScale; - - float mOrientationScale; - - float mDistanceScale; - - bool mHaveTilt; - float mTiltXCenter; - float mTiltXScale; - float mTiltYCenter; - float mTiltYScale; - - bool mExternalStylusConnected; - - // Oriented motion ranges for input device info. - struct OrientedRanges { - InputDeviceInfo::MotionRange x; - InputDeviceInfo::MotionRange y; - InputDeviceInfo::MotionRange pressure; - - bool haveSize; - InputDeviceInfo::MotionRange size; - - bool haveTouchSize; - InputDeviceInfo::MotionRange touchMajor; - InputDeviceInfo::MotionRange touchMinor; - - bool haveToolSize; - InputDeviceInfo::MotionRange toolMajor; - InputDeviceInfo::MotionRange toolMinor; - - bool haveOrientation; - InputDeviceInfo::MotionRange orientation; - - bool haveDistance; - InputDeviceInfo::MotionRange distance; - - bool haveTilt; - InputDeviceInfo::MotionRange tilt; - - OrientedRanges() { clear(); } - - void clear() { - haveSize = false; - haveTouchSize = false; - haveToolSize = false; - haveOrientation = false; - haveDistance = false; - haveTilt = false; - } - } mOrientedRanges; - - // Oriented dimensions and precision. - float mOrientedXPrecision; - float mOrientedYPrecision; - - struct CurrentVirtualKeyState { - bool down; - bool ignored; - nsecs_t downTime; - int32_t keyCode; - int32_t scanCode; - } mCurrentVirtualKey; - - // Scale factor for gesture or mouse based pointer movements. - float mPointerXMovementScale; - float mPointerYMovementScale; - - // Scale factor for gesture based zooming and other freeform motions. - float mPointerXZoomScale; - float mPointerYZoomScale; - - // The maximum swipe width. - float mPointerGestureMaxSwipeWidth; - - struct PointerDistanceHeapElement { - uint32_t currentPointerIndex : 8; - uint32_t lastPointerIndex : 8; - uint64_t distance : 48; // squared distance - }; - - enum PointerUsage { - POINTER_USAGE_NONE, - POINTER_USAGE_GESTURES, - POINTER_USAGE_STYLUS, - POINTER_USAGE_MOUSE, - }; - PointerUsage mPointerUsage; - - struct PointerGesture { - enum Mode { - // No fingers, button is not pressed. - // Nothing happening. - NEUTRAL, - - // No fingers, button is not pressed. - // Tap detected. - // Emits DOWN and UP events at the pointer location. - TAP, - - // Exactly one finger dragging following a tap. - // Pointer follows the active finger. - // Emits DOWN, MOVE and UP events at the pointer location. - // - // Detect double-taps when the finger goes up while in TAP_DRAG mode. - TAP_DRAG, - - // Button is pressed. - // Pointer follows the active finger if there is one. Other fingers are ignored. - // Emits DOWN, MOVE and UP events at the pointer location. - BUTTON_CLICK_OR_DRAG, - - // Exactly one finger, button is not pressed. - // Pointer follows the active finger. - // Emits HOVER_MOVE events at the pointer location. - // - // Detect taps when the finger goes up while in HOVER mode. - HOVER, - - // Exactly two fingers but neither have moved enough to clearly indicate - // whether a swipe or freeform gesture was intended. We consider the - // pointer to be pressed so this enables clicking or long-pressing on buttons. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate. - PRESS, - - // Exactly two fingers moving in the same direction, button is not pressed. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single pointer coordinate that - // follows the midpoint between both fingers. - SWIPE, - - // Two or more fingers moving in arbitrary directions, button is not pressed. - // Pointer does not move. - // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow - // each finger individually relative to the initial centroid of the finger. - FREEFORM, - - // Waiting for quiet time to end before starting the next gesture. - QUIET, - }; - - // Time the first finger went down. - nsecs_t firstTouchTime; - - // The active pointer id from the raw touch data. - int32_t activeTouchId; // -1 if none - - // The active pointer id from the gesture last delivered to the application. - int32_t activeGestureId; // -1 if none - - // Pointer coords and ids for the current and previous pointer gesture. - Mode currentGestureMode; - BitSet32 currentGestureIdBits; - uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties currentGestureProperties[MAX_POINTERS]; - PointerCoords currentGestureCoords[MAX_POINTERS]; - - Mode lastGestureMode; - BitSet32 lastGestureIdBits; - uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties lastGestureProperties[MAX_POINTERS]; - PointerCoords lastGestureCoords[MAX_POINTERS]; - - // Time the pointer gesture last went down. - nsecs_t downTime; - - // Time when the pointer went down for a TAP. - nsecs_t tapDownTime; - - // Time when the pointer went up for a TAP. - nsecs_t tapUpTime; - - // Location of initial tap. - float tapX, tapY; - - // Time we started waiting for quiescence. - nsecs_t quietTime; - - // Reference points for multitouch gestures. - float referenceTouchX; // reference touch X/Y coordinates in surface units - float referenceTouchY; - float referenceGestureX; // reference gesture X/Y coordinates in pixels - float referenceGestureY; - - // Distance that each pointer has traveled which has not yet been - // subsumed into the reference gesture position. - BitSet32 referenceIdBits; - struct Delta { - float dx, dy; - }; - Delta referenceDeltas[MAX_POINTER_ID + 1]; - - // Describes how touch ids are mapped to gesture ids for freeform gestures. - uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1]; - - // A velocity tracker for determining whether to switch active pointers during drags. - VelocityTracker velocityTracker; - - void reset() { - firstTouchTime = LLONG_MIN; - activeTouchId = -1; - activeGestureId = -1; - currentGestureMode = NEUTRAL; - currentGestureIdBits.clear(); - lastGestureMode = NEUTRAL; - lastGestureIdBits.clear(); - downTime = 0; - velocityTracker.clear(); - resetTap(); - resetQuietTime(); - } - - void resetTap() { - tapDownTime = LLONG_MIN; - tapUpTime = LLONG_MIN; - } - - void resetQuietTime() { quietTime = LLONG_MIN; } - } mPointerGesture; - - struct PointerSimple { - PointerCoords currentCoords; - PointerProperties currentProperties; - PointerCoords lastCoords; - PointerProperties lastProperties; - - // True if the pointer is down. - bool down; - - // True if the pointer is hovering. - bool hovering; - - // Time the pointer last went down. - nsecs_t downTime; - - void reset() { - currentCoords.clear(); - currentProperties.clear(); - lastCoords.clear(); - lastProperties.clear(); - down = false; - hovering = false; - downTime = 0; - } - } mPointerSimple; - - // The pointer and scroll velocity controls. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - // Latency statistics for touch events - struct LatencyStatistics mStatistics; - - std::optional<DisplayViewport> findViewport(); - - void resetExternalStylus(); - void clearStylusDataPendingFlags(); - - void sync(nsecs_t when); - - bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); - void processRawTouches(bool timeout); - void cookAndDispatch(nsecs_t when); - void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, - int32_t keyEventFlags); - - void dispatchTouches(nsecs_t when, uint32_t policyFlags); - void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); - void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); - void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags); - void dispatchButtonPress(nsecs_t when, uint32_t policyFlags); - const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData); - void cookPointerData(); - void abortTouches(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); - void abortPointerUsage(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); - void abortPointerGestures(nsecs_t when, uint32_t policyFlags); - bool preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, - bool* outFinishPreviousGesture, bool isTimeout); - - void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); - void abortPointerStylus(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); - void abortPointerMouse(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, bool hovering); - void abortPointerSimple(nsecs_t when, uint32_t policyFlags); - - bool assignExternalStylusId(const RawState& state, bool timeout); - void applyExternalStylusButtonState(nsecs_t when); - void applyExternalStylusTouchState(nsecs_t when); - - // Dispatches a motion event. - // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the - // method will take care of setting the index and transmuting the action to DOWN or UP - // it is the first / last pointer to go down / up. - void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, - int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, uint32_t deviceTimestamp, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, - float xPrecision, float yPrecision, nsecs_t downTime); - - // Updates pointer coords and properties for pointers with specified ids that have moved. - // Returns true if any of them changed. - bool updateMovedPointers(const PointerProperties* inProperties, const PointerCoords* inCoords, - const uint32_t* inIdToIndex, PointerProperties* outProperties, - PointerCoords* outCoords, const uint32_t* outIdToIndex, - BitSet32 idBits) const; - - bool isPointInsideSurface(int32_t x, int32_t y); - const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); - - static void assignPointerIds(const RawState* last, RawState* current); - - void reportEventForStatistics(nsecs_t evdevTime); - - const char* modeToString(DeviceMode deviceMode); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp deleted file mode 100644 index a27fab4581..0000000000 --- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2019 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 "Macros.h" - -#include "VibratorInputMapper.h" - -namespace android { - -VibratorInputMapper::VibratorInputMapper(InputDevice* device) - : InputMapper(device), mVibrating(false) {} - -VibratorInputMapper::~VibratorInputMapper() {} - -uint32_t VibratorInputMapper::getSources() { - return 0; -} - -void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setVibrator(true); -} - -void VibratorInputMapper::process(const RawEvent* rawEvent) { - // TODO: Handle FF_STATUS, although it does not seem to be widely supported. -} - -void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { -#if DEBUG_VIBRATOR - std::string patternStr; - for (size_t i = 0; i < patternSize; i++) { - if (i != 0) { - patternStr += ", "; - } - patternStr += StringPrintf("%" PRId64, pattern[i]); - } - ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", getDeviceId(), - patternStr.c_str(), repeat, token); -#endif - - mVibrating = true; - memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t)); - mPatternSize = patternSize; - mRepeat = repeat; - mToken = token; - mIndex = -1; - - nextStep(); -} - -void VibratorInputMapper::cancelVibrate(int32_t token) { -#if DEBUG_VIBRATOR - ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token); -#endif - - if (mVibrating && mToken == token) { - stopVibrating(); - } -} - -void VibratorInputMapper::timeoutExpired(nsecs_t when) { - if (mVibrating) { - if (when >= mNextStepTime) { - nextStep(); - } else { - getContext()->requestTimeoutAtTime(mNextStepTime); - } - } -} - -void VibratorInputMapper::nextStep() { - mIndex += 1; - if (size_t(mIndex) >= mPatternSize) { - if (mRepeat < 0) { - // We are done. - stopVibrating(); - return; - } - mIndex = mRepeat; - } - - bool vibratorOn = mIndex & 1; - nsecs_t duration = mPattern[mIndex]; - if (vibratorOn) { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration); -#endif - getEventHub()->vibrate(getDeviceId(), duration); - } else { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); - } - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - mNextStepTime = now + duration; - getContext()->requestTimeoutAtTime(mNextStepTime); -#if DEBUG_VIBRATOR - ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f); -#endif -} - -void VibratorInputMapper::stopVibrating() { - mVibrating = false; -#if DEBUG_VIBRATOR - ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); -} - -void VibratorInputMapper::dump(std::string& dump) { - dump += INDENT2 "Vibrator Input Mapper:\n"; - dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating)); -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h deleted file mode 100644 index 6b33f4811e..0000000000 --- a/services/inputflinger/reader/mapper/VibratorInputMapper.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H -#define _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H - -#include "InputMapper.h" - -namespace android { - -class VibratorInputMapper : public InputMapper { -public: - explicit VibratorInputMapper(InputDevice* device); - virtual ~VibratorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void process(const RawEvent* rawEvent); - - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); - virtual void cancelVibrate(int32_t token); - virtual void timeoutExpired(nsecs_t when); - virtual void dump(std::string& dump); - -private: - bool mVibrating; - nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE]; - size_t mPatternSize; - ssize_t mRepeat; - int32_t mToken; - ssize_t mIndex; - nsecs_t mNextStepTime; - - void nextStep(); - void stopVibrating(); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp deleted file mode 100644 index 0337d51126..0000000000 --- a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2019 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 "CursorButtonAccumulator.h" - -#include "EventHub.h" -#include "InputDevice.h" - -namespace android { - -CursorButtonAccumulator::CursorButtonAccumulator() { - clearButtons(); -} - -void CursorButtonAccumulator::reset(InputDevice* device) { - mBtnLeft = device->isKeyPressed(BTN_LEFT); - mBtnRight = device->isKeyPressed(BTN_RIGHT); - mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); - mBtnBack = device->isKeyPressed(BTN_BACK); - mBtnSide = device->isKeyPressed(BTN_SIDE); - mBtnForward = device->isKeyPressed(BTN_FORWARD); - mBtnExtra = device->isKeyPressed(BTN_EXTRA); - mBtnTask = device->isKeyPressed(BTN_TASK); -} - -void CursorButtonAccumulator::clearButtons() { - mBtnLeft = 0; - mBtnRight = 0; - mBtnMiddle = 0; - mBtnBack = 0; - mBtnSide = 0; - mBtnForward = 0; - mBtnExtra = 0; - mBtnTask = 0; -} - -void CursorButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_LEFT: - mBtnLeft = rawEvent->value; - break; - case BTN_RIGHT: - mBtnRight = rawEvent->value; - break; - case BTN_MIDDLE: - mBtnMiddle = rawEvent->value; - break; - case BTN_BACK: - mBtnBack = rawEvent->value; - break; - case BTN_SIDE: - mBtnSide = rawEvent->value; - break; - case BTN_FORWARD: - mBtnForward = rawEvent->value; - break; - case BTN_EXTRA: - mBtnExtra = rawEvent->value; - break; - case BTN_TASK: - mBtnTask = rawEvent->value; - break; - } - } -} - -uint32_t CursorButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnLeft) { - result |= AMOTION_EVENT_BUTTON_PRIMARY; - } - if (mBtnRight) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; - } - if (mBtnMiddle) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; - } - if (mBtnBack || mBtnSide) { - result |= AMOTION_EVENT_BUTTON_BACK; - } - if (mBtnForward || mBtnExtra) { - result |= AMOTION_EVENT_BUTTON_FORWARD; - } - return result; -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h deleted file mode 100644 index d9123109a3..0000000000 --- a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H -#define _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H - -#include <stdint.h> - -namespace android { - -class InputDevice; -struct RawEvent; - -/* Keeps track of the state of mouse or touch pad buttons. */ -class CursorButtonAccumulator { -public: - CursorButtonAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - -private: - bool mBtnLeft; - bool mBtnRight; - bool mBtnMiddle; - bool mBtnBack; - bool mBtnSide; - bool mBtnForward; - bool mBtnExtra; - bool mBtnTask; - - void clearButtons(); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp deleted file mode 100644 index d744096d94..0000000000 --- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2019 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 "CursorScrollAccumulator.h" - -#include "EventHub.h" -#include "InputDevice.h" - -namespace android { - -CursorScrollAccumulator::CursorScrollAccumulator() : mHaveRelWheel(false), mHaveRelHWheel(false) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::configure(InputDevice* device) { - mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); - mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); -} - -void CursorScrollAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::clearRelativeAxes() { - mRelWheel = 0; - mRelHWheel = 0; -} - -void CursorScrollAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_WHEEL: - mRelWheel = rawEvent->value; - break; - case REL_HWHEEL: - mRelHWheel = rawEvent->value; - break; - } - } -} - -void CursorScrollAccumulator::finishSync() { - clearRelativeAxes(); -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h deleted file mode 100644 index 85f331fd8a..0000000000 --- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H -#define _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H - -#include <stdint.h> - -namespace android { - -class InputDevice; -struct RawEvent; - -/* Keeps track of cursor scrolling motions. */ - -class CursorScrollAccumulator { -public: - CursorScrollAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline bool haveRelativeVWheel() const { return mHaveRelWheel; } - inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - inline int32_t getRelativeVWheel() const { return mRelWheel; } - inline int32_t getRelativeHWheel() const { return mRelHWheel; } - -private: - bool mHaveRelWheel; - bool mHaveRelHWheel; - - int32_t mRelX; - int32_t mRelY; - int32_t mRelWheel; - int32_t mRelHWheel; - - void clearRelativeAxes(); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp deleted file mode 100644 index e9ba727a0d..0000000000 --- a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2019 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 "SingleTouchMotionAccumulator.h" - -#include "EventHub.h" -#include "InputDevice.h" - -namespace android { - -SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { - clearAbsoluteAxes(); -} - -void SingleTouchMotionAccumulator::reset(InputDevice* device) { - mAbsX = device->getAbsoluteAxisValue(ABS_X); - mAbsY = device->getAbsoluteAxisValue(ABS_Y); - mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); - mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); - mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); - mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); - mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); -} - -void SingleTouchMotionAccumulator::clearAbsoluteAxes() { - mAbsX = 0; - mAbsY = 0; - mAbsPressure = 0; - mAbsToolWidth = 0; - mAbsDistance = 0; - mAbsTiltX = 0; - mAbsTiltY = 0; -} - -void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { - switch (rawEvent->code) { - case ABS_X: - mAbsX = rawEvent->value; - break; - case ABS_Y: - mAbsY = rawEvent->value; - break; - case ABS_PRESSURE: - mAbsPressure = rawEvent->value; - break; - case ABS_TOOL_WIDTH: - mAbsToolWidth = rawEvent->value; - break; - case ABS_DISTANCE: - mAbsDistance = rawEvent->value; - break; - case ABS_TILT_X: - mAbsTiltX = rawEvent->value; - break; - case ABS_TILT_Y: - mAbsTiltY = rawEvent->value; - break; - } - } -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h deleted file mode 100644 index 75f8a961b3..0000000000 --- a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H -#define _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H - -#include <stdint.h> - -namespace android { - -class InputDevice; -struct RawEvent; - -/* Keeps track of the state of single-touch protocol. */ -class SingleTouchMotionAccumulator { -public: - SingleTouchMotionAccumulator(); - - void process(const RawEvent* rawEvent); - void reset(InputDevice* device); - - inline int32_t getAbsoluteX() const { return mAbsX; } - inline int32_t getAbsoluteY() const { return mAbsY; } - inline int32_t getAbsolutePressure() const { return mAbsPressure; } - inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } - inline int32_t getAbsoluteDistance() const { return mAbsDistance; } - inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } - inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } - -private: - int32_t mAbsX; - int32_t mAbsY; - int32_t mAbsPressure; - int32_t mAbsToolWidth; - int32_t mAbsDistance; - int32_t mAbsTiltX; - int32_t mAbsTiltY; - - void clearAbsoluteAxes(); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp deleted file mode 100644 index d2f06c86fd..0000000000 --- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2019 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 "TouchButtonAccumulator.h" - -#include "EventHub.h" -#include "InputDevice.h" - -namespace android { - -TouchButtonAccumulator::TouchButtonAccumulator() : mHaveBtnTouch(false), mHaveStylus(false) { - clearButtons(); -} - -void TouchButtonAccumulator::configure(InputDevice* device) { - mHaveBtnTouch = device->hasKey(BTN_TOUCH); - mHaveStylus = device->hasKey(BTN_TOOL_PEN) || device->hasKey(BTN_TOOL_RUBBER) || - device->hasKey(BTN_TOOL_BRUSH) || device->hasKey(BTN_TOOL_PENCIL) || - device->hasKey(BTN_TOOL_AIRBRUSH); -} - -void TouchButtonAccumulator::reset(InputDevice* device) { - mBtnTouch = device->isKeyPressed(BTN_TOUCH); - mBtnStylus = device->isKeyPressed(BTN_STYLUS); - // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch - mBtnStylus2 = device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); - mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); - mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); - mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); - mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); - mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); - mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); - mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); - mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); - mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); - mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); - mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); -} - -void TouchButtonAccumulator::clearButtons() { - mBtnTouch = 0; - mBtnStylus = 0; - mBtnStylus2 = 0; - mBtnToolFinger = 0; - mBtnToolPen = 0; - mBtnToolRubber = 0; - mBtnToolBrush = 0; - mBtnToolPencil = 0; - mBtnToolAirbrush = 0; - mBtnToolMouse = 0; - mBtnToolLens = 0; - mBtnToolDoubleTap = 0; - mBtnToolTripleTap = 0; - mBtnToolQuadTap = 0; -} - -void TouchButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_TOUCH: - mBtnTouch = rawEvent->value; - break; - case BTN_STYLUS: - mBtnStylus = rawEvent->value; - break; - case BTN_STYLUS2: - case BTN_0: // BTN_0 is what gets mapped for the HID usage - // Digitizers.SecondaryBarrelSwitch - mBtnStylus2 = rawEvent->value; - break; - case BTN_TOOL_FINGER: - mBtnToolFinger = rawEvent->value; - break; - case BTN_TOOL_PEN: - mBtnToolPen = rawEvent->value; - break; - case BTN_TOOL_RUBBER: - mBtnToolRubber = rawEvent->value; - break; - case BTN_TOOL_BRUSH: - mBtnToolBrush = rawEvent->value; - break; - case BTN_TOOL_PENCIL: - mBtnToolPencil = rawEvent->value; - break; - case BTN_TOOL_AIRBRUSH: - mBtnToolAirbrush = rawEvent->value; - break; - case BTN_TOOL_MOUSE: - mBtnToolMouse = rawEvent->value; - break; - case BTN_TOOL_LENS: - mBtnToolLens = rawEvent->value; - break; - case BTN_TOOL_DOUBLETAP: - mBtnToolDoubleTap = rawEvent->value; - break; - case BTN_TOOL_TRIPLETAP: - mBtnToolTripleTap = rawEvent->value; - break; - case BTN_TOOL_QUADTAP: - mBtnToolQuadTap = rawEvent->value; - break; - } - } -} - -uint32_t TouchButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnStylus) { - result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY; - } - if (mBtnStylus2) { - result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY; - } - return result; -} - -int32_t TouchButtonAccumulator::getToolType() const { - if (mBtnToolMouse || mBtnToolLens) { - return AMOTION_EVENT_TOOL_TYPE_MOUSE; - } - if (mBtnToolRubber) { - return AMOTION_EVENT_TOOL_TYPE_ERASER; - } - if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { - return AMOTION_EVENT_TOOL_TYPE_FINGER; - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - -bool TouchButtonAccumulator::isToolActive() const { - return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber || mBtnToolBrush || - mBtnToolPencil || mBtnToolAirbrush || mBtnToolMouse || mBtnToolLens || - mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; -} - -bool TouchButtonAccumulator::isHovering() const { - return mHaveBtnTouch && !mBtnTouch; -} - -bool TouchButtonAccumulator::hasStylus() const { - return mHaveStylus; -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h deleted file mode 100644 index 65b6bdcc12..0000000000 --- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H -#define _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H - -#include <stdint.h> - -namespace android { - -class InputDevice; -struct RawEvent; - -/* Keeps track of the state of touch, stylus and tool buttons. */ -class TouchButtonAccumulator { -public: - TouchButtonAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - int32_t getToolType() const; - bool isToolActive() const; - bool isHovering() const; - bool hasStylus() const; - -private: - bool mHaveBtnTouch; - bool mHaveStylus; - - bool mBtnTouch; - bool mBtnStylus; - bool mBtnStylus2; - bool mBtnToolFinger; - bool mBtnToolPen; - bool mBtnToolRubber; - bool mBtnToolBrush; - bool mBtnToolPencil; - bool mBtnToolAirbrush; - bool mBtnToolMouse; - bool mBtnToolLens; - bool mBtnToolDoubleTap; - bool mBtnToolTripleTap; - bool mBtnToolQuadTap; - - void clearButtons(); -}; - -} // namespace android - -#endif // _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index c4f8626a98..9054316204 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -32,7 +32,4 @@ cc_test { "libinputflinger_base", "libinputservice", ], - header_libs: [ - "libinputreader_headers", - ], } diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index 7cc17a2215..4cddec50d0 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -22,6 +22,9 @@ #include <android/hardware/input/classifier/1.0/IInputClassifier.h> using namespace android::hardware::input; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::input::common::V1_0::Classification; namespace android { @@ -129,6 +132,49 @@ TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) { ASSERT_EQ(args, outArgs); } +TEST_F(InputClassifierTest, SetMotionClassifier_Enabled) { + mClassifier->setMotionClassifierEnabled(true); +} + +TEST_F(InputClassifierTest, SetMotionClassifier_Disabled) { + mClassifier->setMotionClassifierEnabled(false); +} + +/** + * Try to break it by calling setMotionClassifierEnabled multiple times. + */ +TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) { + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(false); + mClassifier->setMotionClassifierEnabled(false); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); +} + +/** + * A minimal implementation of IInputClassifier. + */ +struct TestHal : public android::hardware::input::classifier::V1_0::IInputClassifier { + Return<Classification> classify( + const android::hardware::input::common::V1_0::MotionEvent& event) override { + return Classification::NONE; + }; + Return<void> reset() override { return Void(); }; + Return<void> resetDevice(int32_t deviceId) override { return Void(); }; +}; + +/** + * An entity that will be subscribed to the HAL death. + */ +class TestDeathRecipient : public android::hardware::hidl_death_recipient { +public: + virtual void serviceDied(uint64_t cookie, + const wp<android::hidl::base::V1_0::IBase>& who) override{}; +}; + // --- MotionClassifierTest --- class MotionClassifierTest : public testing::Test { @@ -136,7 +182,14 @@ protected: std::unique_ptr<MotionClassifierInterface> mMotionClassifier; virtual void SetUp() override { - mMotionClassifier = std::make_unique<MotionClassifier>(); + mMotionClassifier = MotionClassifier::create(new TestDeathRecipient()); + if (mMotionClassifier == nullptr) { + // If the device running this test does not have IInputClassifier service, + // use the test HAL instead. + // Using 'new' to access non-public constructor + mMotionClassifier = + std::unique_ptr<MotionClassifier>(new MotionClassifier(new TestHal())); + } } }; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 551bee18e8..9fe6481ca0 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -14,16 +14,14 @@ * limitations under the License. */ -#include "../dispatcher/InputDispatcher.h" - -#include <InputDispatcherThread.h> +#include "../InputDispatcher.h" #include <binder/Binder.h> #include <gtest/gtest.h> #include <linux/input.h> -namespace android::inputdispatcher { +namespace android { // An arbitrary time value. static const nsecs_t ARBITRARY_TIME = 1234; @@ -1027,4 +1025,4 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, mFakePolicy->assertOnPointerDownEquals(nullptr); } -} // namespace android::inputdispatcher +} // namespace android diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index aeb4ad62a8..d35302885d 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -14,16 +14,8 @@ * limitations under the License. */ -#include <CursorInputMapper.h> -#include <InputDevice.h> -#include <InputMapper.h> -#include <InputReader.h> -#include <KeyboardInputMapper.h> -#include <MultiTouchInputMapper.h> -#include <SingleTouchInputMapper.h> -#include <SwitchInputMapper.h> -#include <TestInputListener.h> -#include <TouchInputMapper.h> +#include "../InputReader.h" +#include "TestInputListener.h" #include <gtest/gtest.h> #include <inttypes.h> diff --git a/services/nativeperms/.clang-format b/services/nativeperms/.clang-format new file mode 100644 index 0000000000..6006e6f4fd --- /dev/null +++ b/services/nativeperms/.clang-format @@ -0,0 +1,13 @@ +BasedOnStyle: Google +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +BinPackArguments: true +BinPackParameters: true +ColumnLimit: 80 +CommentPragmas: NOLINT:.* +ContinuationIndentWidth: 8 +DerivePointerAlignment: false +IndentWidth: 4 +PointerAlignment: Left +TabWidth: 4 diff --git a/services/inputflinger/reporter/Android.bp b/services/nativeperms/Android.bp index 5956fb0794..cbc7d665e3 100644 --- a/services/inputflinger/reporter/Android.bp +++ b/services/nativeperms/Android.bp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 The Android Open Source Project +// Copyright 2016 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,31 +11,24 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// -cc_library_headers { - name: "libinputreporter_headers", - export_include_dirs: ["."], -} - -cc_library_shared { - name: "libinputreporter", - defaults: ["inputflinger_defaults"], - +cc_binary { + name: "nativeperms", srcs: [ - "InputReporter.cpp", + "nativeperms.cpp", + "android/os/IPermissionController.aidl", + ], + cflags: [ + "-Wall", + "-Werror", ], - shared_libs: [ - "liblog", + "libbinder", + "libbrillo", + "libbrillo-binder", + "libchrome", "libutils", ], - - header_libs: [ - "libinputflinger_headers", - ], - - export_header_lib_headers: [ - "libinputflinger_headers", - ], + init_rc: ["nativeperms.rc"], } - diff --git a/services/nativeperms/android/os/IPermissionController.aidl b/services/nativeperms/android/os/IPermissionController.aidl new file mode 100644 index 0000000000..89db85ca0a --- /dev/null +++ b/services/nativeperms/android/os/IPermissionController.aidl @@ -0,0 +1,25 @@ +/* //device/java/android/android/os/IPowerManager.aidl +** +** Copyright 2007, 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.os; + +/** @hide */ +interface IPermissionController { + boolean checkPermission(String permission, int pid, int uid); + String[] getPackagesForUid(int uid); + boolean isRuntimePermission(String permission); +} diff --git a/services/nativeperms/android/os/README b/services/nativeperms/android/os/README new file mode 100644 index 0000000000..e4144995b0 --- /dev/null +++ b/services/nativeperms/android/os/README @@ -0,0 +1,4 @@ +IPermissionController.aidl in this directory is a verbatim copy of +https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/IPermissionController.aidl, +because some Brillo manifests do not currently include the frameworks/base repo. +TODO(jorgelo): Figure out a way to use the .aidl file in frameworks/base. diff --git a/services/nativeperms/nativeperms.cpp b/services/nativeperms/nativeperms.cpp new file mode 100644 index 0000000000..7f03bedb29 --- /dev/null +++ b/services/nativeperms/nativeperms.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <base/at_exit.h> +#include <base/logging.h> +#include <base/message_loop/message_loop.h> +#include <binder/IServiceManager.h> +#include <binder/Status.h> +#include <brillo/binder_watcher.h> +#include <brillo/message_loops/base_message_loop.h> +#include <brillo/syslog_logging.h> +#include <utils/String16.h> + +#include "android/os/BnPermissionController.h" + +namespace { +static android::String16 serviceName("permission"); +} + +namespace android { + +class PermissionService : public android::os::BnPermissionController { + public: + ::android::binder::Status checkPermission( + const ::android::String16& permission, int32_t pid, int32_t uid, + bool* _aidl_return) { + (void)permission; + (void)pid; + (void)uid; + *_aidl_return = true; + return binder::Status::ok(); + } + + ::android::binder::Status getPackagesForUid( + int32_t uid, ::std::vector<::android::String16>* _aidl_return) { + (void)uid; + // Brillo doesn't currently have installable packages. + if (_aidl_return) { + _aidl_return->clear(); + } + return binder::Status::ok(); + } + + ::android::binder::Status isRuntimePermission( + const ::android::String16& permission, bool* _aidl_return) { + (void)permission; + // Brillo doesn't currently have runtime permissions. + *_aidl_return = false; + return binder::Status::ok(); + } +}; + +} // namespace android + +int main() { + base::AtExitManager atExitManager; + brillo::InitLog(brillo::kLogToSyslog); + // Register the service with servicemanager. + android::status_t status = android::defaultServiceManager()->addService( + serviceName, new android::PermissionService()); + CHECK(status == android::OK) << "Failed to get IPermissionController " + "binder from servicemanager."; + + // Create a message loop. + base::MessageLoopForIO messageLoopForIo; + brillo::BaseMessageLoop messageLoop{&messageLoopForIo}; + + // Initialize a binder watcher. + brillo::BinderWatcher watcher(&messageLoop); + watcher.Init(); + + // Run the message loop. + messageLoop.Run(); +} diff --git a/services/nativeperms/nativeperms.rc b/services/nativeperms/nativeperms.rc new file mode 100644 index 0000000000..704c0a2acc --- /dev/null +++ b/services/nativeperms/nativeperms.rc @@ -0,0 +1,4 @@ +service nativeperms /system/bin/nativeperms + class main + user system + group system diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp index 73802dbc9f..0227164ef5 100644 --- a/services/schedulerservice/Android.bp +++ b/services/schedulerservice/Android.bp @@ -6,6 +6,8 @@ cc_library_shared { cflags: ["-Wall", "-Werror"], shared_libs: [ "libhidlbase", + "libhidltransport", + "libhwbinder", "libmediautils", "liblog", "libutils", diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index 1c9a4af72b..33a2747312 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -45,6 +45,8 @@ cc_library_shared { "libcrypto", "libbase", "libhidlbase", + "libhidltransport", + "libhwbinder", "libfmq", "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS index 90c233030e..81099e895c 100644 --- a/services/sensorservice/OWNERS +++ b/services/sensorservice/OWNERS @@ -1,3 +1,3 @@ arthuri@google.com bduddie@google.com -stange@google.com +bstack@google.com diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 14ed73deaf..090a0ce478 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -208,12 +208,6 @@ void SensorService::onFirstRef() { registerSensor(new RotationVectorSensor(), !needRotationVector, true); registerSensor(new OrientationSensor(), !needRotationVector, true); - bool needLinearAcceleration = - (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) != 0; - - registerSensor(new LinearAccelerationSensor(list, count), - !needLinearAcceleration, true); - // virtual debugging sensors are not for user registerSensor( new CorrectedGyroSensor(list, count), true, true); registerSensor( new GyroDriftSensor(), true, true); @@ -223,6 +217,11 @@ void SensorService::onFirstRef() { bool needGravitySensor = (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) != 0; registerSensor(new GravitySensor(list, count), !needGravitySensor, true); + bool needLinearAcceleration = + (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) != 0; + registerSensor(new LinearAccelerationSensor(list, count), + !needLinearAcceleration, true); + bool needGameRotationVector = (virtualSensorsNeeds & (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR)) != 0; registerSensor(new GameRotationVectorSensor(), !needGameRotationVector, true); diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp index d0c83d6002..02c13fa579 100644 --- a/services/sensorservice/hidl/Android.bp +++ b/services/sensorservice/hidl/Android.bp @@ -13,6 +13,8 @@ cc_library_shared { shared_libs: [ "libbase", "libhidlbase", + "libhidltransport", + "libhwbinder", "libutils", "libsensor", "android.frameworks.sensorservice@1.0", diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index cda982ac23..501d176401 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -43,6 +43,8 @@ cc_defaults { "libgui", "libhardware", "libhidlbase", + "libhidltransport", + "libhwbinder", "liblayers_proto", "liblog", "libnativewindow", @@ -83,6 +85,8 @@ cc_defaults { "android.hardware.graphics.composer@2.3", "android.hardware.power@1.3", "libhidlbase", + "libhidltransport", + "libhwbinder", ], } @@ -96,10 +100,6 @@ cc_defaults { lto: { thin: true, }, - // TODO(b/131771163): Fix broken fuzzer support with LTO. - sanitize: { - fuzzer: false, - }, } cc_library_headers { @@ -183,6 +183,9 @@ cc_defaults { cflags: [ "-DLOG_TAG=\"SurfaceFlinger\"", ], + whole_static_libs: [ + "libsigchain", + ], shared_libs: [ "android.frameworks.displayservice@1.0", "android.hardware.configstore-utils", @@ -193,6 +196,7 @@ cc_defaults { "libcutils", "libdisplayservicehidl", "libhidlbase", + "libhidltransport", "libinput", "liblayers_proto", "liblog", @@ -241,6 +245,8 @@ cc_library_shared { "android.hardware.configstore@1.1", "android.hardware.graphics.common@1.2", "libhidlbase", + "libhidltransport", + "libhwbinder", "libui", "libutils", "liblog", @@ -251,6 +257,8 @@ cc_library_shared { export_shared_lib_headers: [ "android.hardware.graphics.common@1.2", "libhidlbase", + "libhidltransport", + "libhwbinder", ], export_static_lib_headers: [ "SurfaceFlingerProperties", diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index cbb9d658e4..eb1bf66cd6 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -243,9 +243,8 @@ bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) { bool sidebandStreamChanged = true; if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) { // mSidebandStreamChanged was changed to false - mSidebandStream = mConsumer->getSidebandStream(); auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; - layerCompositionState.sidebandStream = mSidebandStream; + layerCompositionState.sidebandStream = mConsumer->getSidebandStream(); if (layerCompositionState.sidebandStream != nullptr) { setTransactionFlags(eTransactionNeeded); mFlinger->setTransactionFlags(eTraversalNeeded); @@ -462,6 +461,7 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); if (result != NO_ERROR) { ALOGE("[%s] Timed out waiting on callback", mName.string()); + break; } } @@ -496,6 +496,7 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); if (result != NO_ERROR) { ALOGE("[%s] Timed out waiting on callback", mName.string()); + break; } } diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 1c31ab9d7d..6f076ad11f 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -118,13 +118,6 @@ cc_test { // // You can either "make dist tests" before flashing, or set this // option to false temporarily. - - - // FIXME: ASAN build is broken for a while, but was not discovered - // since new PM silently suppressed ASAN. Temporarily turn off ASAN - // to unblock the compiler upgrade process. - // address: true, - // http://b/139747256 - address: false, + address: true, }, } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 5700d72cae..4a13bfb7ae 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -272,17 +272,13 @@ void DisplayDevice::setProjection(int orientation, scissor = displayBounds; } - uint32_t transformOrientation; - if (isPrimary()) { sPrimaryDisplayOrientation = displayStateOrientationToTransformOrientation(orientation); - transformOrientation = displayStateOrientationToTransformOrientation( - (orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1)); - } else { - transformOrientation = displayStateOrientationToTransformOrientation(orientation); } - getCompositionDisplay()->setProjection(globalTransform, transformOrientation, + getCompositionDisplay()->setProjection(globalTransform, + displayStateOrientationToTransformOrientation( + orientation), frame, viewport, scissor, needsFiltering); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3e6ddedf48..44f3eae1ea 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -153,6 +153,7 @@ void Layer::removeRemoteSyncPoints() { mRemoteSyncPoints.clear(); { + Mutex::Autolock pendingStateLock(mPendingStateMutex); for (State pendingState : mPendingStates) { pendingState.barrierLayer_legacy = nullptr; } @@ -906,7 +907,6 @@ uint32_t Layer::doTransaction(uint32_t flags) { // Commit the transaction commitTransaction(c); - mPendingStatesSnapshot = mPendingStates; mCurrentState.callbackHandles = {}; return flags; } @@ -1874,61 +1874,14 @@ void Layer::setInputInfo(const InputWindowInfo& info) { setTransactionFlags(eTransactionNeeded); } -void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) const { - ui::Transform transform = getTransform(); - - if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { - for (const auto& pendingState : mPendingStatesSnapshot) { - auto barrierLayer = pendingState.barrierLayer_legacy.promote(); - if (barrierLayer != nullptr) { - BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer(); - barrierLayerProto->set_id(barrierLayer->sequence); - barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy); - } - } - - auto buffer = mActiveBuffer; - if (buffer != nullptr) { - LayerProtoHelper::writeToProto(buffer, - [&]() { return layerInfo->mutable_active_buffer(); }); - LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform), - layerInfo->mutable_buffer_transform()); - } - layerInfo->set_invalidate(contentDirty); - layerInfo->set_is_protected(isProtected()); - layerInfo->set_dataspace( - dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace))); - layerInfo->set_queued_frames(getQueuedFrameCount()); - layerInfo->set_refresh_pending(isBufferLatched()); - layerInfo->set_curr_frame(mCurrentFrameNumber); - layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); - - layerInfo->set_corner_radius(getRoundedCornerState().radius); - LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform()); - LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), - [&]() { return layerInfo->mutable_position(); }); - LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); - LayerProtoHelper::writeToProto(visibleRegion, - [&]() { return layerInfo->mutable_visible_region(); }); - LayerProtoHelper::writeToProto(surfaceDamageRegion, - [&]() { return layerInfo->mutable_damage_region(); }); - } - - if (traceFlags & SurfaceTracing::TRACE_EXTRA) { - LayerProtoHelper::writeToProto(mSourceBounds, - [&]() { return layerInfo->mutable_source_bounds(); }); - LayerProtoHelper::writeToProto(mScreenBounds, - [&]() { return layerInfo->mutable_screen_bounds(); }); - } -} - -void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet, - uint32_t traceFlags) const { +void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, + uint32_t traceFlags) { const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren; const State& state = useDrawing ? mDrawingState : mCurrentState; ui::Transform requestedTransform = state.active_legacy.transform; + ui::Transform transform = getTransform(); if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { layerInfo->set_id(sequence); @@ -1948,10 +1901,17 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, [&]() { return layerInfo->mutable_transparent_region(); }); + LayerProtoHelper::writeToProto(visibleRegion, + [&]() { return layerInfo->mutable_visible_region(); }); + LayerProtoHelper::writeToProto(surfaceDamageRegion, + [&]() { return layerInfo->mutable_damage_region(); }); layerInfo->set_layer_stack(getLayerStack()); layerInfo->set_z(state.z); + LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), + [&]() { return layerInfo->mutable_position(); }); + LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() { return layerInfo->mutable_requested_position(); @@ -1962,9 +1922,15 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet LayerProtoHelper::writeToProto(state.crop_legacy, [&]() { return layerInfo->mutable_crop(); }); + layerInfo->set_corner_radius(getRoundedCornerState().radius); layerInfo->set_is_opaque(isOpaque(state)); + layerInfo->set_invalidate(contentDirty); + layerInfo->set_is_protected(isProtected()); + // XXX (b/79210409) mCurrentDataSpace is not protected + layerInfo->set_dataspace( + dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace))); layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat())); LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); }); @@ -1972,6 +1938,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet [&]() { return layerInfo->mutable_requested_color(); }); layerInfo->set_flags(state.flags); + LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform()); LayerProtoHelper::writeToProto(requestedTransform, layerInfo->mutable_requested_transform()); @@ -1988,6 +1955,29 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet } else { layerInfo->set_z_order_relative_of(-1); } + + auto buffer = mActiveBuffer; + if (buffer != nullptr) { + LayerProtoHelper::writeToProto(buffer, + [&]() { return layerInfo->mutable_active_buffer(); }); + LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform), + layerInfo->mutable_buffer_transform()); + } + + layerInfo->set_queued_frames(getQueuedFrameCount()); + layerInfo->set_refresh_pending(isBufferLatched()); + layerInfo->set_curr_frame(mCurrentFrameNumber); + layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); + + for (const auto& pendingState : mPendingStates) { + auto barrierLayer = pendingState.barrierLayer_legacy.promote(); + if (barrierLayer != nullptr) { + BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer(); + barrierLayerProto->set_id(barrierLayer->sequence); + barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy); + } + } + LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); } if (traceFlags & SurfaceTracing::TRACE_INPUT) { @@ -2000,19 +1990,23 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet for (const auto& entry : state.metadata.mMap) { (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend()); } + LayerProtoHelper::writeToProto(mEffectiveTransform, + layerInfo->mutable_effective_transform()); + LayerProtoHelper::writeToProto(mSourceBounds, + [&]() { return layerInfo->mutable_source_bounds(); }); + LayerProtoHelper::writeToProto(mScreenBounds, + [&]() { return layerInfo->mutable_screen_bounds(); }); } } -void Layer::writeToProtoCompositionState(LayerProto* layerInfo, - const sp<DisplayDevice>& displayDevice, - uint32_t traceFlags) const { +void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice, + uint32_t traceFlags) { auto outputLayer = findOutputLayerForDisplay(displayDevice); if (!outputLayer) { return; } - writeToProtoDrawingState(layerInfo, traceFlags); - writeToProtoCommonState(layerInfo, LayerVector::StateSet::Drawing, traceFlags); + writeToProto(layerInfo, LayerVector::StateSet::Drawing, traceFlags); const auto& compositionState = outputLayer->getState(); @@ -2030,12 +2024,26 @@ void Layer::writeToProtoCompositionState(LayerProto* layerInfo, static_cast<int32_t>(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType : Hwc2::IComposerClient::Composition::CLIENT); layerInfo->set_hwc_composition_type(compositionType); + + if (std::strcmp(getTypeId(), "BufferLayer") == 0 && + static_cast<BufferLayer*>(this)->isProtected()) { + layerInfo->set_is_protected(true); + } else { + layerInfo->set_is_protected(false); + } } bool Layer::isRemovedFromCurrentState() const { return mRemovedFromCurrentState; } +// Debug helper for b/137560795 +#define INT32_MIGHT_OVERFLOW(n) (((n) >= INT32_MAX / 2) || ((n) <= INT32_MIN / 2)) + +#define RECT_BOUNDS_INVALID(rect) \ + (INT32_MIGHT_OVERFLOW((rect).left) || INT32_MIGHT_OVERFLOW((rect).right) || \ + INT32_MIGHT_OVERFLOW((rect).bottom) || INT32_MIGHT_OVERFLOW((rect).top)) + InputWindowInfo Layer::fillInputInfo() { InputWindowInfo info = mDrawingState.inputInfo; @@ -2046,14 +2054,14 @@ InputWindowInfo Layer::fillInputInfo() { ui::Transform t = getTransform(); const float xScale = t.sx(); const float yScale = t.sy(); - int32_t xSurfaceInset = info.surfaceInset; - int32_t ySurfaceInset = info.surfaceInset; + float xSurfaceInset = info.surfaceInset; + float ySurfaceInset = info.surfaceInset; if (xScale != 1.0f || yScale != 1.0f) { - info.windowXScale *= (xScale != 0.0f) ? 1.0f / xScale : 0.0f; - info.windowYScale *= (yScale != 0.0f) ? 1.0f / yScale : 0.0f; + info.windowXScale *= 1.0f / xScale; + info.windowYScale *= 1.0f / yScale; info.touchableRegion.scaleSelf(xScale, yScale); - xSurfaceInset = std::round(xSurfaceInset * xScale); - ySurfaceInset = std::round(ySurfaceInset * yScale); + xSurfaceInset *= xScale; + ySurfaceInset *= yScale; } // Transform layer size to screen space and inset it by surface insets. @@ -2066,10 +2074,25 @@ InputWindowInfo Layer::fillInputInfo() { } layerBounds = t.transform(layerBounds); - // clamp inset to layer bounds - xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0; - ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0; + // debug check for b/137560795 + { + if (RECT_BOUNDS_INVALID(layerBounds)) { + ALOGE("layer %s bounds are invalid (%" PRIi32 ", %" PRIi32 ", %" PRIi32 ", %" PRIi32 + ")", + mName.c_str(), layerBounds.left, layerBounds.top, layerBounds.right, + layerBounds.bottom); + std::string out; + getTransform().dump(out, "Transform"); + ALOGE("%s", out.c_str()); + layerBounds.left = layerBounds.top = layerBounds.right = layerBounds.bottom = 0; + } + if (INT32_MIGHT_OVERFLOW(xSurfaceInset) || INT32_MIGHT_OVERFLOW(ySurfaceInset)) { + ALOGE("layer %s surface inset are invalid (%" PRIi32 ", %" PRIi32 ")", mName.c_str(), + int32_t(xSurfaceInset), int32_t(ySurfaceInset)); + xSurfaceInset = ySurfaceInset = 0; + } + } layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset); // Input coordinate should match the layer bounds. diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 3b4d8733c7..b46eb112e7 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -437,21 +437,11 @@ public: bool isRemovedFromCurrentState() const; - // 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 = SurfaceTracing::TRACE_ALL) const; - // Write states that are modified by the main thread. This includes drawing - // state as well as buffer data and composition data for layers on the specified - // display. This should be called in the main or tracing thread. - void writeToProtoCompositionState(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; - // 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. - void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + void writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, + uint32_t traceFlags = SurfaceTracing::TRACE_ALL); + + void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice, + uint32_t traceFlags = SurfaceTracing::TRACE_ALL); virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; } virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; } @@ -841,15 +831,13 @@ protected: bool mPrimaryDisplayOnly = false; - // These are only accessed by the main thread or the tracing thread. - State mDrawingState; - // Store a copy of the pending state so that the drawing thread can access the - // states without a lock. - Vector<State> mPendingStatesSnapshot; - - // these are protected by an external lock (mStateLock) + // these are protected by an external lock State mCurrentState; + State mDrawingState; std::atomic<uint32_t> mTransactionFlags{0}; + + // Accessed from main thread and binder threads + Mutex mPendingStateMutex; Vector<State> mPendingStates; // Timestamp history for UIAutomation. Thread safe. diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 07fdead310..80da154278 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -200,9 +200,10 @@ RegionSamplingThread::~RegionSamplingThread() { void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, const sp<IRegionSamplingListener>& listener) { - wp<Layer> stopLayer = stopLayerHandle != nullptr - ? static_cast<Layer::Handle*>(stopLayerHandle.get())->owner - : nullptr; + wp<Layer> stopLayer; + if (stopLayerHandle != nullptr && stopLayerHandle->localBinder() != nullptr) { + stopLayer = static_cast<Layer::Handle*>(stopLayerHandle.get())->owner; + } sp<IBinder> asBinder = IInterface::asBinder(listener); asBinder->linkToDeath(this); diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 8a2604f4a3..9fa2bbc96e 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -96,7 +96,6 @@ PhaseOffsets::PhaseOffsets() { highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; - mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index d7300583c3..d8137085dd 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -34,10 +34,9 @@ namespace scheduler { */ class RefreshRateConfigs { public: - // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest - // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance + // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs. - enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE }; + enum class RefreshRateType { DEFAULT, PERFORMANCE }; struct RefreshRate { // This config ID corresponds to the position of the config in the vector that is stored @@ -47,26 +46,57 @@ public: std::string name; // Refresh rate in frames per second, rounded to the nearest integer. uint32_t fps = 0; - // config Id (returned from HWC2::Display::Config::getId()) - hwc2_config_t id; + // Vsync period in nanoseconds. + nsecs_t vsyncPeriod; + // Hwc config Id (returned from HWC2::Display::Config::getId()) + hwc2_config_t hwcId; }; + // Returns true if this device is doing refresh rate switching. This won't change at runtime. + bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; } + + // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access + // from multiple threads. This can only be called if refreshRateSwitching() returns true. // TODO(b/122916473): Get this information from configs prepared by vendors, instead of // baking them in. - const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() const { - return mRefreshRates; + const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const { + LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported); + return mRefreshRateMap; } - std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) const { - const auto& refreshRate = mRefreshRates.find(type); - if (refreshRate != mRefreshRates.end()) { + + const RefreshRate& getRefreshRateFromType(RefreshRateType type) const { + if (!mRefreshRateSwitchingSupported) { + return getCurrentRefreshRate().second; + } else { + auto refreshRate = mRefreshRateMap.find(type); + LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end()); return refreshRate->second; } - return nullptr; } - RefreshRateType getRefreshRateType(hwc2_config_t id) const { - for (const auto& [type, refreshRate] : mRefreshRates) { - if (refreshRate->id == id) { + std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const { + int currentConfig = mCurrentConfig; + if (mRefreshRateSwitchingSupported) { + for (const auto& [type, refresh] : mRefreshRateMap) { + if (refresh.configId == currentConfig) { + return {type, refresh}; + } + } + LOG_ALWAYS_FATAL(); + } + return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]}; + } + + const RefreshRate& getRefreshRateFromConfigId(int configId) const { + LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size()); + return mRefreshRates[configId]; + } + + RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const { + if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT; + + for (const auto& [type, refreshRate] : mRefreshRateMap) { + if (refreshRate.hwcId == hwcId) { return type; } } @@ -74,64 +104,102 @@ public: return RefreshRateType::DEFAULT; } - void populate(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { - mRefreshRates.clear(); + void setCurrentConfig(int config) { + LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size()); + mCurrentConfig = config; + } - // This is the rate that HWC encapsulates right now when the device is in DOZE mode. - mRefreshRates.emplace(RefreshRateType::POWER_SAVING, - std::make_shared<RefreshRate>( - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, - HWC2_SCREEN_OFF_CONFIG_ID})); + struct InputConfig { + hwc2_config_t hwcId = 0; + nsecs_t vsyncPeriod = 0; + }; - if (configs.size() < 1) { - ALOGE("Device does not have valid configs. Config size is 0."); - return; + RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs, + int currentConfig) { + init(refreshRateSwitching, configs, currentConfig); + } + + RefreshRateConfigs(bool refreshRateSwitching, + const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs, + int currentConfig) { + std::vector<InputConfig> inputConfigs; + for (const auto& config : configs) { + inputConfigs.push_back({config->getId(), config->getVsyncPeriod()}); } + init(refreshRateSwitching, inputConfigs, currentConfig); + } + +private: + void init(bool refreshRateSwitching, const std::vector<InputConfig>& configs, + int currentConfig) { + mRefreshRateSwitchingSupported = refreshRateSwitching; + LOG_ALWAYS_FATAL_IF(configs.empty()); + LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size()); + mCurrentConfig = currentConfig; + + auto buildRefreshRate = [&](int configId) -> RefreshRate { + const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod; + const float fps = 1e9 / vsyncPeriod; + return {configId, base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps), + vsyncPeriod, configs[configId].hwcId}; + }; - // Create a map between config index and vsync period. This is all the info we need - // from the configs. - std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod; for (int i = 0; i < configs.size(); ++i) { - configIdToVsyncPeriod.emplace_back(i, configs.at(i)->getVsyncPeriod()); + mRefreshRates.push_back(buildRefreshRate(i)); } - std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(), - [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) { - return a.second > b.second; - }); + if (!mRefreshRateSwitchingSupported) return; - // When the configs are ordered by the resync rate. We assume that the first one is DEFAULT. - nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second; - if (vsyncPeriod != 0) { - const float fps = 1e9 / vsyncPeriod; - const int configId = configIdToVsyncPeriod[0].first; - mRefreshRates.emplace(RefreshRateType::DEFAULT, - std::make_shared<RefreshRate>( - RefreshRate{configId, base::StringPrintf("%2.ffps", fps), - static_cast<uint32_t>(fps), - configs.at(configId)->getId()})); - } + auto findDefaultAndPerfConfigs = [&]() -> std::optional<std::pair<int, int>> { + if (configs.size() < 2) { + return {}; + } - if (configs.size() < 2) { + std::vector<const RefreshRate*> sortedRefreshRates; + for (const auto& refreshRate : mRefreshRates) { + sortedRefreshRates.push_back(&refreshRate); + } + std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(), + [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) { + return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; + }); + + // When the configs are ordered by the resync rate, we assume that + // the first one is DEFAULT and the second one is PERFORMANCE, + // i.e. the higher rate. + if (sortedRefreshRates[0]->vsyncPeriod == 0 || + sortedRefreshRates[1]->vsyncPeriod == 0) { + return {}; + } + + return std::pair<int, int>(sortedRefreshRates[0]->configId, + sortedRefreshRates[1]->configId); + }; + + auto defaultAndPerfConfigs = findDefaultAndPerfConfigs(); + if (!defaultAndPerfConfigs) { + mRefreshRateSwitchingSupported = false; return; } - // When the configs are ordered by the resync rate. We assume that the second one is - // PERFORMANCE, eg. the higher rate. - vsyncPeriod = configIdToVsyncPeriod[1].second; - if (vsyncPeriod != 0) { - const float fps = 1e9 / vsyncPeriod; - const int configId = configIdToVsyncPeriod[1].first; - mRefreshRates.emplace(RefreshRateType::PERFORMANCE, - std::make_shared<RefreshRate>( - RefreshRate{configId, base::StringPrintf("%2.ffps", fps), - static_cast<uint32_t>(fps), - configs.at(configId)->getId()})); - } + mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first]; + mRefreshRateMap[RefreshRateType::PERFORMANCE] = + mRefreshRates[defaultAndPerfConfigs->second]; } -private: - std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates; + // Whether this device is doing refresh rate switching or not. This must not change after this + // object is initialized. + bool mRefreshRateSwitchingSupported; + // The list of refresh rates, indexed by display config ID. This must not change after this + // object is initialized. + std::vector<RefreshRate> mRefreshRates; + // The mapping of refresh rate type to RefreshRate. This must not change after this object is + // initialized. + std::map<RefreshRateType, RefreshRate> mRefreshRateMap; + // The ID of the current config. This will change at runtime. This is set by SurfaceFlinger on + // the main thread, and read by the Scheduler (and other objects) on other threads, so it's + // atomic. + std::atomic<int> mCurrentConfig; }; } // namespace scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 7e7c6307a4..947eb08d90 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -41,21 +41,18 @@ class RefreshRateStats { static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR; public: - RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats) - : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats) {} - - // Sets power mode. We only collect the information when the power mode is not - // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based - // on config mode. + RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats, + int currentConfigMode, int currentPowerMode) + : mRefreshRateConfigs(refreshRateConfigs), + mTimeStats(timeStats), + mCurrentConfigMode(currentConfigMode), + mCurrentPowerMode(currentPowerMode) {} + + // Sets power mode. void setPowerMode(int mode) { if (mCurrentPowerMode == mode) { return; } - // If power mode is normal, the time is going to be recorded under config modes. - if (mode == HWC_POWER_MODE_NORMAL) { - mCurrentPowerMode = mode; - return; - } flushTime(); mCurrentPowerMode = mode; } @@ -79,16 +76,15 @@ public: flushTime(); std::unordered_map<std::string, int64_t> totalTime; - for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { - int64_t totalTimeForConfig = 0; - if (!config) { - continue; - } - if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) { - totalTimeForConfig = mConfigModesTotalTime.at(config->configId); - } - totalTime[config->name] = totalTimeForConfig; + // Multiple configs may map to the same name, e.g. "60fps". Add the + // times for such configs together. + for (const auto& [config, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] = 0; + } + for (const auto& [config, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] += time; } + totalTime["ScreenOff"] = mScreenOffTime; return totalTime; } @@ -104,32 +100,26 @@ public: } private: - void flushTime() { - // Normal power mode is counted under different config modes. - if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) { - flushTimeForMode(mCurrentConfigMode); - } else { - flushTimeForMode(SCREEN_OFF_CONFIG_ID); - } - } - // Calculates the time that passed in ms between the last time we recorded time and the time // this method was called. - void flushTimeForMode(int mode) { + void flushTime() { nsecs_t currentTime = systemTime(); nsecs_t timeElapsed = currentTime - mPreviousRecordedTime; int64_t timeElapsedMs = ns2ms(timeElapsed); mPreviousRecordedTime = currentTime; - mConfigModesTotalTime[mode] += timeElapsedMs; - for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { - if (!config) { - continue; - } - if (config->configId == mode) { - mTimeStats.recordRefreshRate(config->fps, timeElapsed); + uint32_t fps = 0; + if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) { + // Normal power mode is counted under different config modes. + if (mConfigModesTotalTime.find(mCurrentConfigMode) == mConfigModesTotalTime.end()) { + mConfigModesTotalTime[mCurrentConfigMode] = 0; } + mConfigModesTotalTime[mCurrentConfigMode] += timeElapsedMs; + fps = mRefreshRateConfigs.getRefreshRateFromConfigId(mCurrentConfigMode).fps; + } else { + mScreenOffTime += timeElapsedMs; } + mTimeStats.recordRefreshRate(fps, timeElapsed); } // Formats the time in milliseconds into easy to read format. @@ -149,10 +139,11 @@ private: // Aggregate refresh rate statistics for telemetry. TimeStats& mTimeStats; - int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID; - int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF; + int mCurrentConfigMode; + int32_t mCurrentPowerMode; - std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime; + std::unordered_map<int /* config */, int64_t /* duration in ms */> mConfigModesTotalTime; + int64_t mScreenOffTime = 0; nsecs_t mPreviousRecordedTime = systemTime(); }; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 8da5612b5b..0b43378394 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -133,7 +133,6 @@ Scheduler::~Scheduler() { sp<Scheduler::ConnectionHandle> Scheduler::createConnection( const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync, - ResyncCallback resyncCallback, impl::EventThread::InterceptVSyncsCallback interceptCallback) { const int64_t id = sNextId++; ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id); @@ -143,8 +142,7 @@ sp<Scheduler::ConnectionHandle> Scheduler::createConnection( offsetThresholdForNextVsync, std::move(interceptCallback)); auto eventThreadConnection = - createConnectionInternal(eventThread.get(), std::move(resyncCallback), - ISurfaceComposer::eConfigChangedSuppress); + createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress); mConnections.emplace(id, std::make_unique<Connection>(new ConnectionHandle(id), eventThreadConnection, @@ -164,17 +162,15 @@ std::unique_ptr<EventThread> Scheduler::makeEventThread( } sp<EventThreadConnection> Scheduler::createConnectionInternal( - EventThread* eventThread, ResyncCallback&& resyncCallback, - ISurfaceComposer::ConfigChanged configChanged) { - return eventThread->createEventConnection(std::move(resyncCallback), configChanged); + EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) { + return eventThread->createEventConnection([&] { resync(); }, configChanged); } sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection( - const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback, + const sp<Scheduler::ConnectionHandle>& handle, ISurfaceComposer::ConfigChanged configChanged) { RETURN_VALUE_IF_INVALID(nullptr); - return createConnectionInternal(mConnections[handle->id]->thread.get(), - std::move(resyncCallback), configChanged); + return createConnectionInternal(mConnections[handle->id]->thread.get(), configChanged); } EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) { @@ -264,23 +260,15 @@ void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) { setVsyncPeriod(period); } -ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) { - std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState; - return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() { - if (const auto vsync = ptr.lock()) { - vsync->resync(getVsyncPeriod); - } - }; -} - -void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) { +void Scheduler::resync() { static constexpr nsecs_t kIgnoreDelay = ms2ns(750); const nsecs_t now = systemTime(); - const nsecs_t last = lastResyncTime.exchange(now); + const nsecs_t last = mLastResyncTime.exchange(now); if (now - last > kIgnoreDelay) { - scheduler.resyncToHardwareVsync(false, getVsyncPeriod()); + resyncToHardwareVsync(false, + mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod); } } @@ -338,15 +326,19 @@ void Scheduler::dumpPrimaryDispSync(std::string& result) const { std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer( std::string const& name, int windowType) { - RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER) - ? RefreshRateType::DEFAULT - : RefreshRateType::PERFORMANCE; - - const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType); - const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0; - - const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT); - const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0; + uint32_t defaultFps, performanceFps; + if (mRefreshRateConfigs.refreshRateSwitchingSupported()) { + defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps; + performanceFps = + mRefreshRateConfigs + .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER) + ? RefreshRateType::DEFAULT + : RefreshRateType::PERFORMANCE) + .fps; + } else { + defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps; + performanceFps = defaultFps; + } return mLayerHistory.createLayer(name, defaultFps, performanceFps); } @@ -398,17 +390,6 @@ void Scheduler::setChangeRefreshRateCallback( mChangeRefreshRateCallback = changeRefreshRateCallback; } -void Scheduler::setGetCurrentRefreshRateTypeCallback( - const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) { - std::lock_guard<std::mutex> lock(mCallbackLock); - mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback; -} - -void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) { - std::lock_guard<std::mutex> lock(mCallbackLock); - mGetVsyncPeriod = getVsyncPeriod; -} - void Scheduler::updateFrameSkipping(const int64_t skipCount) { ATRACE_INT("FrameSkipCount", skipCount); if (mSkipCount != skipCount) { @@ -460,14 +441,12 @@ void Scheduler::resetTimerCallback() { void Scheduler::resetKernelTimerCallback() { ATRACE_INT("ExpiredKernelIdleTimer", 0); - std::lock_guard<std::mutex> lock(mCallbackLock); - if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) { + const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); + if (refreshRate.first == RefreshRateType::PERFORMANCE) { // If we're not in performance mode then the kernel timer shouldn't do // anything, as the refresh rate during DPU power collapse will be the // same. - if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) { - resyncToHardwareVsync(true, mGetVsyncPeriod()); - } + resyncToHardwareVsync(true, refreshRate.second.vsyncPeriod); } } @@ -497,15 +476,13 @@ void Scheduler::expiredDisplayPowerTimerCallback() { } void Scheduler::expiredKernelTimerCallback() { - std::lock_guard<std::mutex> lock(mCallbackLock); ATRACE_INT("ExpiredKernelIdleTimer", 1); - if (mGetCurrentRefreshRateTypeCallback) { - if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) { - // Disable HW Vsync if the timer expired, as we don't need it - // enabled if we're not pushing frames, and if we're in PERFORMANCE - // mode then we'll need to re-update the DispSync model anyways. - disableHardwareVsync(false); - } + const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); + if (refreshRate.first != RefreshRateType::PERFORMANCE) { + // Disable HW Vsync if the timer expired, as we don't need it + // enabled if we're not pushing frames, and if we're in PERFORMANCE + // mode then we'll need to re-update the DispSync model anyways. + disableHardwareVsync(false); } } @@ -540,6 +517,10 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO } Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { + if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) { + return RefreshRateType::DEFAULT; + } + // HDR content is not supported on PERFORMANCE mode if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) { return RefreshRateType::DEFAULT; @@ -567,16 +548,12 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { } // Content detection is on, find the appropriate refresh rate with minimal error - auto begin = mRefreshRateConfigs.getRefreshRates().cbegin(); + auto begin = mRefreshRateConfigs.getRefreshRateMap().cbegin(); - // Skip POWER_SAVING config as it is not a real config - if (begin->first == RefreshRateType::POWER_SAVING) { - ++begin; - } - auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRates().cend(), + auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRateMap().cend(), [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool { - return std::abs(l.second->fps - static_cast<float>(rate)) < - std::abs(r.second->fps - static_cast<float>(rate)); + return std::abs(l.second.fps - static_cast<float>(rate)) < + std::abs(r.second.fps - static_cast<float>(rate)); }); RefreshRateType currRefreshRateType = iter->first; @@ -584,11 +561,11 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't // align well with both constexpr float MARGIN = 0.05f; - float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / + float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps / float(mContentRefreshRate); if (std::abs(std::round(ratio) - ratio) > MARGIN) { - while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { - ratio = iter->second->fps / float(mContentRefreshRate); + while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) { + ratio = iter->second.fps / float(mContentRefreshRate); if (std::abs(std::round(ratio) - ratio) <= MARGIN) { currRefreshRateType = iter->first; @@ -601,6 +578,11 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { return currRefreshRateType; } +Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() { + std::lock_guard<std::mutex> lock(mFeatureStateLock); + return mRefreshRateType; +} + void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) { std::lock_guard<std::mutex> lock(mCallbackLock); if (mChangeRefreshRateCallback) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 5d8bb4cd2f..4b21dadde9 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -49,9 +49,7 @@ public: } using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; - using GetCurrentRefreshRateTypeCallback = std::function<RefreshRateType()>; using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>; - using GetVsyncPeriod = std::function<nsecs_t()>; // Enum to indicate whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; @@ -81,16 +79,6 @@ public: const std::unique_ptr<EventThread> thread; }; - // Stores per-display state about VSYNC. - struct VsyncState { - explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {} - - void resync(const GetVsyncPeriod&); - - Scheduler& scheduler; - std::atomic<nsecs_t> lastResyncTime = 0; - }; - explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, const scheduler::RefreshRateConfigs& refreshRateConfig); @@ -98,12 +86,11 @@ public: /** Creates an EventThread connection. */ sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs, - nsecs_t offsetThresholdForNextVsync, ResyncCallback, + nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback); sp<IDisplayEventConnection> createDisplayEventConnection( - const sp<ConnectionHandle>& handle, ResyncCallback, - ISurfaceComposer::ConfigChanged configChanged); + const sp<ConnectionHandle>& handle, ISurfaceComposer::ConfigChanged configChanged); // Getter methods. EventThread* getEventThread(const sp<ConnectionHandle>& handle); @@ -143,8 +130,7 @@ public: // no-op. // The period is the vsync period from the current display configuration. void resyncToHardwareVsync(bool makeAvailable, nsecs_t period); - // Creates a callback for resyncing. - ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod); + void resync(); void setRefreshSkipCount(int count); // Passes a vsync sample to DispSync. periodFlushed will be true if // DispSync detected that the vsync period changed, and false otherwise. @@ -167,9 +153,6 @@ public: void updateFpsBasedOnContent(); // Callback that gets invoked when Scheduler wants to change the refresh rate. void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback); - void setGetCurrentRefreshRateTypeCallback( - const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateType); - void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod); // Returns whether idle timer is enabled or not bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; } @@ -189,6 +172,9 @@ public: // calls DispSync::dump() on primary disp sync void dumpPrimaryDispSync(std::string& result) const; + // Get the appropriate refresh type for current conditions. + RefreshRateType getPreferredRefreshRateType(); + protected: virtual std::unique_ptr<EventThread> makeEventThread( const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs, @@ -206,7 +192,7 @@ private: enum class DisplayPowerTimerState { EXPIRED, RESET }; // Creates a connection on the given EventThread and forwards the given callbacks. - sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&, + sp<EventThreadConnection> createConnectionInternal(EventThread*, ISurfaceComposer::ConfigChanged); nsecs_t calculateAverage() const; @@ -261,7 +247,8 @@ private: std::mutex mHWVsyncLock; bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock); bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock); - const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)}; + + std::atomic<nsecs_t> mLastResyncTime = 0; std::unique_ptr<DispSync> mPrimaryDispSync; std::unique_ptr<EventControlThread> mEventControlThread; @@ -297,9 +284,7 @@ private: std::unique_ptr<scheduler::IdleTimer> mDisplayPowerTimer; std::mutex mCallbackLock; - GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock); ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); - GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock); // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h index ac10f83ad9..f193553ea3 100644 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.h +++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h @@ -30,12 +30,6 @@ using namespace std::chrono_literals; // about layers. static constexpr size_t ARRAY_SIZE = 30; -// This number is used to have a place holder for when the screen is not NORMAL/ON. Currently -// the config is not visible to SF, and is completely maintained by HWC. However, we would -// still like to keep track of time when the device is in this config. -static constexpr int SCREEN_OFF_CONFIG_ID = -1; -static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff; - // This number is used when we try to determine how long do we keep layer information around // before we remove it. It is also used to determine how long the layer stays relevant. // This time period captures infrequent updates when playing YouTube video with static image, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 200da2e814..fd7f128411 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -540,9 +540,9 @@ void SurfaceFlinger::bootFinished() // wait patiently for the window manager death const String16 name("window"); - mWindowManager = defaultServiceManager()->getService(name); - if (mWindowManager != 0) { - mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); + sp<IBinder> window(defaultServiceManager()->getService(name)); + if (window != 0) { + window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); } sp<IBinder> input(defaultServiceManager()->getService( String16("inputflinger"))); @@ -569,14 +569,16 @@ void SurfaceFlinger::bootFinished() readPersistentProperties(); mBootStage = BootStage::FINISHED; - // set the refresh rate according to the policy - const auto& performanceRefreshRate = - mRefreshRateConfigs.getRefreshRate(RefreshRateType::PERFORMANCE); + if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { + // set the refresh rate according to the policy + const auto& performanceRefreshRate = + mRefreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE); - if (performanceRefreshRate && isDisplayConfigAllowed(performanceRefreshRate->configId)) { - setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); - } else { - setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); + if (isDisplayConfigAllowed(performanceRefreshRate.configId)) { + setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); + } else { + setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); + } } })); } @@ -619,32 +621,6 @@ void SurfaceFlinger::init() { ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset()); Mutex::Autolock _l(mStateLock); - // start the EventThread - mScheduler = - getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, - mRefreshRateConfigs); - auto resyncCallback = - mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); - - mAppConnectionHandle = - mScheduler->createConnection("app", mVsyncModulator.getOffsets().app, - mPhaseOffsets->getOffsetThresholdForNextVsync(), - resyncCallback, - impl::EventThread::InterceptVSyncsCallback()); - mSfConnectionHandle = - mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf, - mPhaseOffsets->getOffsetThresholdForNextVsync(), - resyncCallback, [this](nsecs_t timestamp) { - mInterceptor->saveVSyncEvent(timestamp); - }); - - mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); - mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), - mSfConnectionHandle.get()); - - mRegionSamplingThread = - new RegionSamplingThread(*this, *mScheduler, - RegionSamplingThread::EnvironmentTimingTunables()); // Get a RenderEngine for the given display / config (can't fail) int32_t renderEngineFeature = 0; @@ -715,37 +691,6 @@ void SurfaceFlinger::init() { ALOGE("Run StartPropertySetThread failed!"); } - mScheduler->setChangeRefreshRateCallback( - [this](RefreshRateType type, Scheduler::ConfigEvent event) { - Mutex::Autolock lock(mStateLock); - setRefreshRateTo(type, event); - }); - mScheduler->setGetCurrentRefreshRateTypeCallback([this] { - Mutex::Autolock lock(mStateLock); - const auto display = getDefaultDisplayDeviceLocked(); - if (!display) { - // If we don't have a default display the fallback to the default - // refresh rate type - return RefreshRateType::DEFAULT; - } - - const int configId = display->getActiveConfig(); - for (const auto& [type, refresh] : mRefreshRateConfigs.getRefreshRates()) { - if (refresh && refresh->configId == configId) { - return type; - } - } - // This should never happen, but just gracefully fallback to default. - return RefreshRateType::DEFAULT; - }); - mScheduler->setGetVsyncPeriodCallback([this] { - Mutex::Autolock lock(mStateLock); - return getVsyncPeriod(); - }); - - mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId())); - mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId())); - ALOGV("Done initializing"); } @@ -899,7 +844,8 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken, info.xdpi = xdpi; info.ydpi = ydpi; info.fps = 1e9 / hwConfig->getVsyncPeriod(); - const auto refreshRateType = mRefreshRateConfigs.getRefreshRateType(hwConfig->getId()); + const auto refreshRateType = + mRefreshRateConfigs->getRefreshRateTypeFromHwcConfigId(hwConfig->getId()); const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(refreshRateType); info.appVsyncOffset = offset.late.app; @@ -1001,7 +947,8 @@ void SurfaceFlinger::setActiveConfigInternal() { } std::lock_guard<std::mutex> lock(mActiveConfigLock); - mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId); + mRefreshRateConfigs->setCurrentConfig(mUpcomingActiveConfig.configId); + mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); display->setActiveConfig(mUpcomingActiveConfig.configId); @@ -1280,9 +1227,6 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { return; } - auto resyncCallback = - mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); - // TODO(b/128863962): Part of the Injector should be refactored, so that it // can be passed to Scheduler. if (enable) { @@ -1294,11 +1238,11 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { impl::EventThread::InterceptVSyncsCallback(), "injEventThread"); } - mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback)); + mEventQueue->setEventThread(mInjectorEventThread.get(), [&] { mScheduler->resync(); }); } else { ALOGV("VSync Injections disabled"); mEventQueue->setEventThread(mScheduler->getEventThread(mSfConnectionHandle), - std::move(resyncCallback)); + [&] { mScheduler->resync(); }); } mInjectVSyncs = enable; @@ -1409,16 +1353,10 @@ status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) { sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) { - auto resyncCallback = mScheduler->makeResyncCallback([this] { - Mutex::Autolock lock(mStateLock); - return getVsyncPeriod(); - }); - const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle; - return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback), - configChanged); + return mScheduler->createDisplayEventConnection(handle, configChanged); } // ---------------------------------------------------------------------------- @@ -1515,13 +1453,8 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - const auto& refreshRateConfig = mRefreshRateConfigs.getRefreshRate(refreshRate); - if (!refreshRateConfig) { - ALOGV("Skipping refresh rate change request for unsupported rate."); - return; - } - - const int desiredConfigId = refreshRateConfig->configId; + const auto& refreshRateConfig = mRefreshRateConfigs->getRefreshRateFromType(refreshRate); + const int desiredConfigId = refreshRateConfig.configId; if (!isDisplayConfigAllowed(desiredConfigId)) { ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); @@ -1851,12 +1784,6 @@ void SurfaceFlinger::handleMessageRefresh() { mVsyncModulator.onRefreshed(mHadClientComposition); mLayersWithQueuedFrames.clear(); - if (mVisibleRegionsDirty) { - mVisibleRegionsDirty = false; - if (mTracingEnabled) { - mTracing.notify("visibleRegionsDirty"); - } - } } @@ -1866,6 +1793,9 @@ bool SurfaceFlinger::handleMessageInvalidate() { if (mVisibleRegionsDirty) { computeLayerBounds(); + if (mTracingEnabled) { + mTracing.notify("visibleRegionsDirty"); + } } for (auto& layer : mLayersPendingRefresh) { @@ -2272,6 +2202,7 @@ void SurfaceFlinger::rebuildLayerStacks() { // rebuild the visible layer list per screen if (CC_UNLIKELY(mVisibleRegionsDirty)) { ATRACE_NAME("rebuildLayerStacks VR Dirty"); + mVisibleRegionsDirty = false; invalidateHwcGeometry(); for (const auto& pair : mDisplays) { @@ -2628,6 +2559,9 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { if (event.connection == HWC2::Connection::Connected) { if (!mPhysicalDisplayTokens.count(info->id)) { ALOGV("Creating display %s", to_string(info->id).c_str()); + if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { + initScheduler(info->id); + } mPhysicalDisplayTokens[info->id] = new BBinder(); DisplayDeviceState state; state.displayId = info->id; @@ -3028,7 +2962,7 @@ void SurfaceFlinger::updateInputFlinger() { setInputWindowsFinished(); } - executeInputWindowCommands(); + mInputWindowCommands.clear(); } void SurfaceFlinger::updateInputWindowInfo() { @@ -3052,19 +2986,6 @@ void SurfaceFlinger::commitInputWindowCommands() { mPendingInputWindowCommands.clear(); } -void SurfaceFlinger::executeInputWindowCommands() { - for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) { - if (transferTouchFocusCommand.fromToken != nullptr && - transferTouchFocusCommand.toToken != nullptr && - transferTouchFocusCommand.fromToken != transferTouchFocusCommand.toToken) { - mInputFlinger->transferTouchFocus(transferTouchFocusCommand.fromToken, - transferTouchFocusCommand.toToken); - } - } - - mInputWindowCommands.clear(); -} - void SurfaceFlinger::updateCursorAsync() { for (const auto& [token, display] : mDisplays) { @@ -3086,6 +3007,55 @@ void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) { layer->releasePendingBuffer(systemTime()); } +void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { + if (mScheduler) { + // In practice it's not allowed to hotplug in/out the primary display once it's been + // connected during startup, but some tests do it, so just warn and return. + ALOGW("Can't re-init scheduler"); + return; + } + + int currentConfig = getHwComposer().getActiveConfigIndex(primaryDisplayId); + mRefreshRateConfigs = + std::make_unique<scheduler::RefreshRateConfigs>(refresh_rate_switching(false), + getHwComposer().getConfigs( + primaryDisplayId), + currentConfig); + mRefreshRateStats = + std::make_unique<scheduler::RefreshRateStats>(*mRefreshRateConfigs, *mTimeStats, + currentConfig, HWC_POWER_MODE_OFF); + mRefreshRateStats->setConfigMode(currentConfig); + + // start the EventThread + mScheduler = + getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, + *mRefreshRateConfigs); + mAppConnectionHandle = + mScheduler->createConnection("app", mVsyncModulator.getOffsets().app, + mPhaseOffsets->getOffsetThresholdForNextVsync(), + impl::EventThread::InterceptVSyncsCallback()); + mSfConnectionHandle = + mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf, + mPhaseOffsets->getOffsetThresholdForNextVsync(), + [this](nsecs_t timestamp) { + mInterceptor->saveVSyncEvent(timestamp); + }); + + mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); + mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), + mSfConnectionHandle.get()); + + mRegionSamplingThread = + new RegionSamplingThread(*this, *mScheduler, + RegionSamplingThread::EnvironmentTimingTunables()); + + mScheduler->setChangeRefreshRateCallback( + [this](RefreshRateType type, Scheduler::ConfigEvent event) { + Mutex::Autolock lock(mStateLock); + setRefreshRateTo(type, event); + }); +} + void SurfaceFlinger::commitTransaction() { if (!mLayersPendingRemoval.isEmpty()) { @@ -4598,7 +4568,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int if (display->isPrimary()) { mTimeStats->setPowerMode(mode); - mRefreshRateStats.setPowerMode(mode); + mRefreshRateStats->setPowerMode(mode); mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL); } @@ -4671,22 +4641,18 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, if (const auto it = dumpers.find(flag); it != dumpers.end()) { (it->second)(args, asProto, result); - } else if (!asProto) { - dumpAllLocked(args, result); + } else { + if (asProto) { + LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current); + result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize()); + } else { + dumpAllLocked(args, result); + } } if (locked) { mStateLock.unlock(); } - - LayersProto layersProto = dumpProtoFromMainThread(); - if (asProto) { - result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize()); - } else { - auto layerTree = LayerProtoParser::generateLayerTree(layersProto); - result.append(LayerProtoParser::layerTreeToString(layerTree)); - result.append("\n"); - } } write(fd, result.c_str(), result.size()); return NO_ERROR; @@ -4770,15 +4736,14 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { mUseSmart90ForVideo ? "on" : "off"); StringAppendF(&result, "Allowed Display Configs: "); for (int32_t configId : mAllowedDisplayConfigs) { - for (auto refresh : mRefreshRateConfigs.getRefreshRates()) { - if (refresh.second && refresh.second->configId == configId) { - StringAppendF(&result, "%dHz, ", refresh.second->fps); - } - } + StringAppendF(&result, "%" PRIu32 " Hz, ", + mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps); } StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); mScheduler->dump(mAppConnectionHandle, result); + StringAppendF(&result, "+ Refresh rate switching: %s\n", + mRefreshRateConfigs->refreshRateSwitchingSupported() ? "on" : "off"); } void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const { @@ -4929,23 +4894,19 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { result.append("\n"); } -LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { +LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet, + uint32_t traceFlags) const { LayersProto layersProto; - mDrawingState.traverseInZOrder([&](Layer* layer) { + const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; + const State& state = useDrawing ? mDrawingState : mCurrentState; + state.traverseInZOrder([&](Layer* layer) { LayerProto* layerProto = layersProto.add_layers(); - layer->writeToProtoDrawingState(layerProto, traceFlags); - layer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags); + layer->writeToProto(layerProto, stateSet, traceFlags); }); return layersProto; } -LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) { - LayersProto layersProto; - postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); })); - return layersProto; -} - LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo( const sp<DisplayDevice>& displayDevice) const { LayersProto layersProto; @@ -4966,7 +4927,7 @@ LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo( mDrawingState.traverseInZOrder([&](Layer* layer) { if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) { LayerProto* layerProto = layersProto.add_layers(); - layer->writeToProtoCompositionState(layerProto, displayDevice); + layer->writeToProto(layerProto, displayDevice); } }); @@ -5031,6 +4992,13 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co colorizer.reset(result); { + LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current); + auto layerTree = LayerProtoParser::generateLayerTree(layersProto); + result.append(LayerProtoParser::layerTreeToString(layerTree)); + result.append("\n"); + } + + { StringAppendF(&result, "Composition layers\n"); mDrawingState.traverseInZOrder([&](Layer* layer) { auto compositionLayer = layer->getCompositionLayer(); @@ -5140,7 +5108,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("\nScheduler state:\n"); result.append(mScheduler->doDump() + "\n"); StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); - result.append(mRefreshRateStats.doDump() + "\n"); + result.append(mRefreshRateStats->doDump() + "\n"); result.append(mTimeStats->miniDump()); result.append("\n"); @@ -5611,7 +5579,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r case 1034: { // TODO(b/129297325): expose this via developer menu option n = data.readInt32(); - if (n && !mRefreshRateOverlay) { + if (n && !mRefreshRateOverlay && + mRefreshRateConfigs->refreshRateSwitchingSupported()) { RefreshRateType type; { std::lock_guard<std::mutex> lock(mActiveConfigLock); @@ -6210,15 +6179,28 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& d mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, display->getActiveConfig()); - // Set the highest allowed config by iterating backwards on available refresh rates - const auto& refreshRates = mRefreshRateConfigs.getRefreshRates(); - for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { - if (iter->second && isDisplayConfigAllowed(iter->second->configId)) { - ALOGV("switching to config %d", iter->second->configId); - setDesiredActiveConfig( - {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed}); - break; + if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { + const auto& type = mScheduler->getPreferredRefreshRateType(); + const auto& config = mRefreshRateConfigs->getRefreshRateFromType(type); + if (isDisplayConfigAllowed(config.configId)) { + ALOGV("switching to Scheduler preferred config %d", config.configId); + setDesiredActiveConfig({type, config.configId, Scheduler::ConfigEvent::Changed}); + } else { + // Set the highest allowed config by iterating backwards on available refresh rates + const auto& refreshRates = mRefreshRateConfigs->getRefreshRateMap(); + for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { + if (isDisplayConfigAllowed(iter->second.configId)) { + ALOGV("switching to allowed config %d", iter->second.configId); + setDesiredActiveConfig( + {iter->first, iter->second.configId, Scheduler::ConfigEvent::Changed}); + break; + } + } } + } else if (!isDisplayConfigAllowed(display->getActiveConfig())) { + ALOGV("switching to config %d", allowedConfigs[0]); + setDesiredActiveConfig( + {RefreshRateType::DEFAULT, allowedConfigs[0], Scheduler::ConfigEvent::Changed}); } } @@ -6235,7 +6217,7 @@ status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToke return NO_ERROR; } - postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS { + postMessageSync(new LambdaMessage([&]() { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set allowed display configs for invalid display token %p", @@ -6243,6 +6225,7 @@ status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToke } else if (display->isVirtual()) { ALOGW("Attempt to set allowed display configs for virtual display"); } else { + Mutex::Autolock lock(mStateLock); setAllowedDisplayConfigsInternal(display, allowedConfigs); } })); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 5778be6900..a22d6fc649 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -263,8 +263,7 @@ public: status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0); // post a synchronous message to the main thread - status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0) - EXCLUDES(mStateLock); + status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0); // force full composition on all displays void repaintEverything(); @@ -554,9 +553,9 @@ private: void updateInputFlinger(); void updateInputWindowInfo(); void commitInputWindowCommands() REQUIRES(mStateLock); - void executeInputWindowCommands(); void setInputWindowsFinished(); void updateCursorAsync(); + void initScheduler(DisplayId primaryDisplayId); /* handlePageFlip - latch a new buffer if available and compute the dirty * region. Returns whether a new buffer has been latched, i.e., whether it @@ -901,9 +900,8 @@ private: void dumpBufferingStats(std::string& result) const; void dumpDisplayIdentificationData(std::string& result) const; void dumpWideColorInfo(std::string& result) const; - LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; - LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) - EXCLUDES(mStateLock); + LayersProto dumpProtoInfo(LayerVector::StateSet stateSet, + uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock); LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const; @@ -1104,9 +1102,6 @@ private: // either AID_GRAPHICS or AID_SYSTEM. status_t CheckTransactCodeCredentials(uint32_t code); - // to linkToDeath - sp<IBinder> mWindowManager; - std::unique_ptr<dvr::VrFlinger> mVrFlinger; std::atomic<bool> mVrFlingerRequestsDisplay = false; static bool useVrFlinger; @@ -1138,8 +1133,8 @@ private: sp<Scheduler::ConnectionHandle> mAppConnectionHandle; sp<Scheduler::ConnectionHandle> mSfConnectionHandle; - scheduler::RefreshRateConfigs mRefreshRateConfigs; - scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats}; + std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; + std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats; // All configs are allowed if the set is empty. using DisplayConfigs = std::set<int32_t>; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 768074a6cd..b4716eb61e 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -226,6 +226,14 @@ int64_t color_space_agnostic_dataspace(Dataspace defaultValue) { return static_cast<int64_t>(defaultValue); } +bool refresh_rate_switching(bool defaultValue) { + auto temp = SurfaceFlingerProperties::refresh_rate_switching(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + int32_t set_idle_timer_ms(int32_t defaultValue) { auto temp = SurfaceFlingerProperties::set_idle_timer_ms(); if (temp.has_value()) { diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index 5f88322f71..e394ccab7b 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -73,6 +73,8 @@ int32_t wcg_composition_pixel_format( int64_t color_space_agnostic_dataspace( android::hardware::graphics::common::V1_2::Dataspace defaultValue); +bool refresh_rate_switching(bool defaultValue); + int32_t set_idle_timer_ms(int32_t defaultValue); int32_t set_touch_timer_ms(int32_t defaultValue); diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index 9053f2c7de..c4ab0668e7 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -162,7 +162,7 @@ LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { LayersTraceProto entry; entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); entry.set_where(where); - LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags)); + LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing, mTraceFlags)); entry.mutable_layers()->Swap(&layers); return entry; diff --git a/services/surfaceflinger/TimeStats/OWNERS b/services/surfaceflinger/TimeStats/OWNERS index 1441f91489..ac02d12fcd 100644 --- a/services/surfaceflinger/TimeStats/OWNERS +++ b/services/surfaceflinger/TimeStats/OWNERS @@ -1,2 +1 @@ -alecmouri@google.com -zzyiwei@google.com +zzyiwei@google.com
\ No newline at end of file diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp index d03cb7b22a..cb368b0886 100644 --- a/services/surfaceflinger/layerproto/Android.bp +++ b/services/surfaceflinger/layerproto/Android.bp @@ -43,7 +43,7 @@ java_library_static { type: "nano", }, srcs: ["*.proto"], - sdk_version: "core_platform", + no_framework_libs: true, target: { android: { jarjar_rules: "jarjar-rules.txt", diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 56ab4e3f33..000f21c545 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -15,7 +15,7 @@ module: "android.sysprop.SurfaceFlingerProperties" owner: Platform -# The following two propertiess define (respectively): +# The following two properties define (respectively): # # - The phase offset between hardware vsync and when apps are woken up by the # Choreographer callback @@ -36,7 +36,7 @@ owner: Platform prop { api_name: "vsync_event_phase_offset_ns" type: Long - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns" } @@ -44,7 +44,7 @@ prop { prop { api_name: "vsync_sf_event_phase_offset_ns" type: Long - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns" } @@ -53,7 +53,7 @@ prop { prop { api_name: "use_context_priority" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.use_context_priority" } @@ -62,7 +62,7 @@ prop { prop { api_name: "max_frame_buffer_acquired_buffers" type: Long - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" } @@ -80,7 +80,7 @@ prop { prop { api_name: "has_wide_color_display" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.has_wide_color_display" } @@ -90,7 +90,7 @@ prop { prop { api_name: "running_without_sync_framework" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.running_without_sync_framework" } @@ -108,7 +108,7 @@ prop { prop { api_name: "has_HDR_display" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.has_HDR_display" } @@ -117,7 +117,7 @@ prop { prop { api_name: "present_time_offset_from_vsync_ns" type: Long - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns" } @@ -129,7 +129,7 @@ prop { prop { api_name: "force_hwc_copy_for_virtual_displays" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" } @@ -139,7 +139,7 @@ prop { prop { api_name: "max_virtual_display_dimension" type: Long - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.max_virtual_display_dimension" } @@ -151,7 +151,7 @@ prop { prop { api_name: "use_vr_flinger" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.use_vr_flinger" } @@ -161,7 +161,7 @@ prop { prop { api_name: "start_graphics_allocator_service" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.start_graphics_allocator_service" } @@ -171,7 +171,7 @@ prop { api_name: "primary_display_orientation" type: Enum enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270" - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.primary_display_orientation" } @@ -182,7 +182,7 @@ prop { prop { api_name: "use_color_management" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.use_color_management" } @@ -209,7 +209,7 @@ prop { prop { api_name: "default_composition_dataspace" type: Long - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.default_composition_dataspace" } @@ -220,7 +220,7 @@ prop { prop { api_name: "default_composition_pixel_format" type: Integer - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.default_composition_pixel_format" } @@ -235,7 +235,7 @@ prop { prop { api_name: "wcg_composition_dataspace" type: Long - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.wcg_composition_dataspace" } @@ -246,7 +246,7 @@ prop { prop { api_name: "wcg_composition_pixel_format" type: Integer - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.wcg_composition_pixel_format" } @@ -272,7 +272,7 @@ prop { prop { api_name: "display_primary_red" type: DoubleList - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.display_primary_red" } @@ -280,7 +280,7 @@ prop { prop { api_name: "display_primary_green" type: DoubleList - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.display_primary_green" } @@ -288,7 +288,7 @@ prop { prop { api_name: "display_primary_blue" type: DoubleList - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.display_primary_blue" } @@ -296,18 +296,30 @@ prop { prop { api_name: "display_primary_white" type: DoubleList - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.display_primary_white" } +# refreshRateSwitching indicates whether SurfaceFlinger should use refresh rate +# switching on the device, e.g. to switch between 60 and 90 Hz. The settings +# below that are related to refresh rate switching will only have an effect if +# refresh_rate_switching is enabled. +prop { + api_name: "refresh_rate_switching" + type: Boolean + scope: System + access: Readonly + prop_name: "ro.surface_flinger.refresh_rate_switching" +} + # setIdleTimerMs indicates what is considered a timeout in milliseconds for Scheduler. This value is # used by the Scheduler to trigger inactivity callbacks that will switch the display to a lower # refresh rate. Setting this property to 0 means there is no timer. prop { api_name: "set_idle_timer_ms" type: Integer - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.set_idle_timer_ms" } @@ -318,7 +330,7 @@ prop { prop { api_name: "set_touch_timer_ms" type: Integer - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.set_touch_timer_ms" } @@ -340,7 +352,7 @@ prop { prop { api_name: "use_smart_90_for_video" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.use_smart_90_for_video" } @@ -348,7 +360,7 @@ prop { prop { api_name: "enable_protected_contents" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.protected_contents" } @@ -358,7 +370,7 @@ prop { prop { api_name: "support_kernel_idle_timer" type: Boolean - scope: Public + scope: System access: Readonly prop_name: "ro.surface_flinger.support_kernel_idle_timer" } diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt deleted file mode 100644 index b66e56ecc7..0000000000 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ /dev/null @@ -1,138 +0,0 @@ -props { - module: "android.sysprop.SurfaceFlingerProperties" - prop { - api_name: "color_space_agnostic_dataspace" - type: Long - prop_name: "ro.surface_flinger.color_space_agnostic_dataspace" - } - prop { - api_name: "default_composition_dataspace" - type: Long - prop_name: "ro.surface_flinger.default_composition_dataspace" - } - prop { - api_name: "default_composition_pixel_format" - type: Integer - prop_name: "ro.surface_flinger.default_composition_pixel_format" - } - prop { - api_name: "display_primary_blue" - type: DoubleList - prop_name: "ro.surface_flinger.display_primary_blue" - } - prop { - api_name: "display_primary_green" - type: DoubleList - prop_name: "ro.surface_flinger.display_primary_green" - } - prop { - api_name: "display_primary_red" - type: DoubleList - prop_name: "ro.surface_flinger.display_primary_red" - } - prop { - api_name: "display_primary_white" - type: DoubleList - prop_name: "ro.surface_flinger.display_primary_white" - } - prop { - api_name: "enable_protected_contents" - prop_name: "ro.surface_flinger.protected_contents" - } - prop { - api_name: "force_hwc_copy_for_virtual_displays" - prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" - } - prop { - api_name: "has_HDR_display" - prop_name: "ro.surface_flinger.has_HDR_display" - } - prop { - api_name: "has_wide_color_display" - prop_name: "ro.surface_flinger.has_wide_color_display" - } - prop { - api_name: "max_frame_buffer_acquired_buffers" - type: Long - prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" - } - prop { - api_name: "max_virtual_display_dimension" - type: Long - prop_name: "ro.surface_flinger.max_virtual_display_dimension" - } - prop { - api_name: "present_time_offset_from_vsync_ns" - type: Long - prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns" - } - prop { - api_name: "primary_display_orientation" - type: Enum - prop_name: "ro.surface_flinger.primary_display_orientation" - enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270" - } - prop { - api_name: "running_without_sync_framework" - prop_name: "ro.surface_flinger.running_without_sync_framework" - } - prop { - api_name: "set_display_power_timer_ms" - type: Integer - prop_name: "ro.surface_flinger.set_display_power_timer_ms" - } - prop { - api_name: "set_idle_timer_ms" - type: Integer - prop_name: "ro.surface_flinger.set_idle_timer_ms" - } - prop { - api_name: "set_touch_timer_ms" - type: Integer - prop_name: "ro.surface_flinger.set_touch_timer_ms" - } - prop { - api_name: "start_graphics_allocator_service" - prop_name: "ro.surface_flinger.start_graphics_allocator_service" - } - prop { - api_name: "support_kernel_idle_timer" - prop_name: "ro.surface_flinger.support_kernel_idle_timer" - } - prop { - api_name: "use_color_management" - prop_name: "ro.surface_flinger.use_color_management" - } - prop { - api_name: "use_context_priority" - prop_name: "ro.surface_flinger.use_context_priority" - } - prop { - api_name: "use_smart_90_for_video" - prop_name: "ro.surface_flinger.use_smart_90_for_video" - } - prop { - api_name: "use_vr_flinger" - prop_name: "ro.surface_flinger.use_vr_flinger" - } - prop { - api_name: "vsync_event_phase_offset_ns" - type: Long - prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns" - } - prop { - api_name: "vsync_sf_event_phase_offset_ns" - type: Long - prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns" - } - prop { - api_name: "wcg_composition_dataspace" - type: Long - prop_name: "ro.surface_flinger.wcg_composition_dataspace" - } - prop { - api_name: "wcg_composition_pixel_format" - type: Integer - prop_name: "ro.surface_flinger.wcg_composition_pixel_format" - } -} diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt deleted file mode 100644 index b66e56ecc7..0000000000 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt +++ /dev/null @@ -1,138 +0,0 @@ -props { - module: "android.sysprop.SurfaceFlingerProperties" - prop { - api_name: "color_space_agnostic_dataspace" - type: Long - prop_name: "ro.surface_flinger.color_space_agnostic_dataspace" - } - prop { - api_name: "default_composition_dataspace" - type: Long - prop_name: "ro.surface_flinger.default_composition_dataspace" - } - prop { - api_name: "default_composition_pixel_format" - type: Integer - prop_name: "ro.surface_flinger.default_composition_pixel_format" - } - prop { - api_name: "display_primary_blue" - type: DoubleList - prop_name: "ro.surface_flinger.display_primary_blue" - } - prop { - api_name: "display_primary_green" - type: DoubleList - prop_name: "ro.surface_flinger.display_primary_green" - } - prop { - api_name: "display_primary_red" - type: DoubleList - prop_name: "ro.surface_flinger.display_primary_red" - } - prop { - api_name: "display_primary_white" - type: DoubleList - prop_name: "ro.surface_flinger.display_primary_white" - } - prop { - api_name: "enable_protected_contents" - prop_name: "ro.surface_flinger.protected_contents" - } - prop { - api_name: "force_hwc_copy_for_virtual_displays" - prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" - } - prop { - api_name: "has_HDR_display" - prop_name: "ro.surface_flinger.has_HDR_display" - } - prop { - api_name: "has_wide_color_display" - prop_name: "ro.surface_flinger.has_wide_color_display" - } - prop { - api_name: "max_frame_buffer_acquired_buffers" - type: Long - prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" - } - prop { - api_name: "max_virtual_display_dimension" - type: Long - prop_name: "ro.surface_flinger.max_virtual_display_dimension" - } - prop { - api_name: "present_time_offset_from_vsync_ns" - type: Long - prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns" - } - prop { - api_name: "primary_display_orientation" - type: Enum - prop_name: "ro.surface_flinger.primary_display_orientation" - enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270" - } - prop { - api_name: "running_without_sync_framework" - prop_name: "ro.surface_flinger.running_without_sync_framework" - } - prop { - api_name: "set_display_power_timer_ms" - type: Integer - prop_name: "ro.surface_flinger.set_display_power_timer_ms" - } - prop { - api_name: "set_idle_timer_ms" - type: Integer - prop_name: "ro.surface_flinger.set_idle_timer_ms" - } - prop { - api_name: "set_touch_timer_ms" - type: Integer - prop_name: "ro.surface_flinger.set_touch_timer_ms" - } - prop { - api_name: "start_graphics_allocator_service" - prop_name: "ro.surface_flinger.start_graphics_allocator_service" - } - prop { - api_name: "support_kernel_idle_timer" - prop_name: "ro.surface_flinger.support_kernel_idle_timer" - } - prop { - api_name: "use_color_management" - prop_name: "ro.surface_flinger.use_color_management" - } - prop { - api_name: "use_context_priority" - prop_name: "ro.surface_flinger.use_context_priority" - } - prop { - api_name: "use_smart_90_for_video" - prop_name: "ro.surface_flinger.use_smart_90_for_video" - } - prop { - api_name: "use_vr_flinger" - prop_name: "ro.surface_flinger.use_vr_flinger" - } - prop { - api_name: "vsync_event_phase_offset_ns" - type: Long - prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns" - } - prop { - api_name: "vsync_sf_event_phase_offset_ns" - type: Long - prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns" - } - prop { - api_name: "wcg_composition_dataspace" - type: Long - prop_name: "ro.surface_flinger.wcg_composition_dataspace" - } - prop { - api_name: "wcg_composition_pixel_format" - type: Integer - prop_name: "ro.surface_flinger.wcg_composition_pixel_format" - } -} diff --git a/services/surfaceflinger/sysprop/api/current.txt b/services/surfaceflinger/sysprop/api/current.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/services/surfaceflinger/sysprop/api/current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/surfaceflinger/sysprop/api/removed.txt b/services/surfaceflinger/sysprop/api/removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/services/surfaceflinger/sysprop/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt new file mode 100644 index 0000000000..2e804c8a31 --- /dev/null +++ b/services/surfaceflinger/sysprop/api/system-current.txt @@ -0,0 +1,46 @@ +// Signature format: 2.0 +package android.sysprop { + + public final class SurfaceFlingerProperties { + method public static java.util.Optional<java.lang.Long> color_space_agnostic_dataspace(); + method public static java.util.Optional<java.lang.Long> default_composition_dataspace(); + method public static java.util.Optional<java.lang.Integer> default_composition_pixel_format(); + method public static java.util.List<java.lang.Double> display_primary_blue(); + method public static java.util.List<java.lang.Double> display_primary_green(); + method public static java.util.List<java.lang.Double> display_primary_red(); + method public static java.util.List<java.lang.Double> display_primary_white(); + method public static java.util.Optional<java.lang.Boolean> enable_protected_contents(); + method public static java.util.Optional<java.lang.Boolean> force_hwc_copy_for_virtual_displays(); + method public static java.util.Optional<java.lang.Boolean> has_HDR_display(); + method public static java.util.Optional<java.lang.Boolean> has_wide_color_display(); + method public static java.util.Optional<java.lang.Long> max_frame_buffer_acquired_buffers(); + method public static java.util.Optional<java.lang.Long> max_virtual_display_dimension(); + method public static java.util.Optional<java.lang.Long> present_time_offset_from_vsync_ns(); + method public static java.util.Optional<android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values> primary_display_orientation(); + method public static java.util.Optional<java.lang.Boolean> refresh_rate_switching(); + method public static java.util.Optional<java.lang.Boolean> running_without_sync_framework(); + method public static java.util.Optional<java.lang.Integer> set_display_power_timer_ms(); + method public static java.util.Optional<java.lang.Integer> set_idle_timer_ms(); + method public static java.util.Optional<java.lang.Integer> set_touch_timer_ms(); + method public static java.util.Optional<java.lang.Boolean> start_graphics_allocator_service(); + method public static java.util.Optional<java.lang.Boolean> support_kernel_idle_timer(); + method public static java.util.Optional<java.lang.Boolean> use_color_management(); + method public static java.util.Optional<java.lang.Boolean> use_context_priority(); + method public static java.util.Optional<java.lang.Boolean> use_smart_90_for_video(); + method public static java.util.Optional<java.lang.Boolean> use_vr_flinger(); + method public static java.util.Optional<java.lang.Long> vsync_event_phase_offset_ns(); + method public static java.util.Optional<java.lang.Long> vsync_sf_event_phase_offset_ns(); + method public static java.util.Optional<java.lang.Long> wcg_composition_dataspace(); + method public static java.util.Optional<java.lang.Integer> wcg_composition_pixel_format(); + } + + public enum SurfaceFlingerProperties.primary_display_orientation_values { + method public String getPropValue(); + enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_0; + enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_180; + enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_270; + enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_90; + } + +} + diff --git a/services/surfaceflinger/sysprop/api/system-removed.txt b/services/surfaceflinger/sysprop/api/system-removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/services/surfaceflinger/sysprop/api/system-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/surfaceflinger/sysprop/api/test-current.txt b/services/surfaceflinger/sysprop/api/test-current.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/services/surfaceflinger/sysprop/api/test-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/surfaceflinger/sysprop/api/test-removed.txt b/services/surfaceflinger/sysprop/api/test-removed.txt new file mode 100644 index 0000000000..d802177e24 --- /dev/null +++ b/services/surfaceflinger/sysprop/api/test-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp index 2feff4570e..a2c0611b1e 100644 --- a/services/surfaceflinger/tests/fakehwc/Android.bp +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -20,6 +20,8 @@ cc_test { "libgui", "libhardware", "libhidlbase", + "libhidltransport", + "libhwbinder", "liblayers_proto", "liblog", "libnativewindow", diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index a892a2abd0..f9e0b6413b 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -54,11 +54,10 @@ using namespace sftest; namespace { // Mock test helpers -using ::testing::_; -using ::testing::DoAll; using ::testing::Invoke; using ::testing::Return; using ::testing::SetArgPointee; +using ::testing::_; using Transaction = SurfaceComposerClient::Transaction; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4f8ed1ae1c..349dd3f2f1 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -125,7 +125,17 @@ public: } void setupScheduler() { - mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs()); + std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}}; + mFlinger.mutableRefreshRateConfigs() = + std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, + configs, + /*currentConfig=*/0); + mFlinger.mutableRefreshRateStats() = + std::make_unique<scheduler::RefreshRateStats>(*mFlinger.mutableRefreshRateConfigs(), + *mFlinger.mutableTimeStats(), + /*currentConfig=*/0, + /*powerMode=*/HWC_POWER_MODE_OFF); + mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs()); mScheduler->mutableEventControlThread().reset(mEventControlThread); mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync); EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_)); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 5f58e7dce9..f40996eecf 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -29,6 +29,7 @@ #include <ui/DebugUtils.h> #include "DisplayIdentificationTest.h" +#include "Scheduler/RefreshRateConfigs.h" #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -179,7 +180,16 @@ DisplayTransactionTest::~DisplayTransactionTest() { } void DisplayTransactionTest::setupScheduler() { - mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs()); + std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}}; + mFlinger.mutableRefreshRateConfigs() = + std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, + /*currentConfig=*/0); + mFlinger.mutableRefreshRateStats() = + std::make_unique<scheduler::RefreshRateStats>(*mFlinger.mutableRefreshRateConfigs(), + *mFlinger.mutableTimeStats(), + /*currentConfig=*/0, + /*powerMode=*/HWC_POWER_MODE_OFF); + mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs()); mScheduler->mutableEventControlThread().reset(mEventControlThread); mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 5067fe890b..f315a8a86c 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -23,7 +23,6 @@ #include "DisplayHardware/HWC2.h" #include "Scheduler/RefreshRateConfigs.h" -#include "mock/DisplayHardware/MockDisplay.h" using namespace std::chrono_literals; using testing::_; @@ -50,9 +49,8 @@ protected: ASSERT_EQ(left.configId, right.configId); ASSERT_EQ(left.name, right.name); ASSERT_EQ(left.fps, right.fps); + ASSERT_EQ(left.vsyncPeriod, right.vsyncPeriod); } - - RefreshRateConfigs mConfigs; }; RefreshRateConfigsTest::RefreshRateConfigsTest() { @@ -71,101 +69,39 @@ namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) { - std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; - mConfigs.populate(displayConfigs); - - // We always store a configuration for screen off. - const auto& rates = mConfigs.getRefreshRates(); - ASSERT_EQ(1, rates.size()); - const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); - ASSERT_NE(rates.end(), powerSavingRate); - ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); - ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT)); - - RefreshRate expectedConfig = - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID}; - assertRatesEqual(expectedConfig, *powerSavingRate->second); - - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedConfig, *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); - ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - - // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(1, mConfigs.getRefreshRates().size()); +TEST_F(RefreshRateConfigsTest, oneDeviceConfig_isRejected) { + std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60}}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs, + /*currentConfig=*/0); + ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported()); } -TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { - auto display = new Hwc2::mock::Display(); - std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; - auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); - config60.setVsyncPeriod(VSYNC_60); - displayConfigs.push_back(config60.build()); - mConfigs.populate(displayConfigs); +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { + std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60}, + {HWC2_CONFIG_ID_90, VSYNC_90}}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs, + /*currentConfig=*/0); - const auto& rates = mConfigs.getRefreshRates(); + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + const auto& rates = refreshRateConfigs->getRefreshRateMap(); ASSERT_EQ(2, rates.size()); - const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); - const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); - ASSERT_NE(rates.end(), powerSavingRate); - ASSERT_NE(rates.end(), defaultRate); - ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); - - RefreshRate expectedPowerSavingConfig = - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID}; - assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); - RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60}; - assertRatesEqual(expectedDefaultConfig, *defaultRate->second); - - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedPowerSavingConfig, - *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); - - // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(2, mConfigs.getRefreshRates().size()); -} - -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { - auto display = new Hwc2::mock::Display(); - std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; - auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); - config60.setVsyncPeriod(VSYNC_60); - displayConfigs.push_back(config60.build()); - auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); - config90.setVsyncPeriod(VSYNC_90); - displayConfigs.push_back(config90.build()); - mConfigs.populate(displayConfigs); - - const auto& rates = mConfigs.getRefreshRates(); - ASSERT_EQ(3, rates.size()); - const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE); - ASSERT_NE(rates.end(), powerSavingRate); ASSERT_NE(rates.end(), defaultRate); ASSERT_NE(rates.end(), performanceRate); - RefreshRate expectedPowerSavingConfig = - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID}; - assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); - RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60}; - assertRatesEqual(expectedDefaultConfig, *defaultRate->second); - RefreshRate expectedPerformanceConfig = - RefreshRate{CONFIG_ID_90, "90fps", 90, HWC2_CONFIG_ID_90}; - assertRatesEqual(expectedPerformanceConfig, *performanceRate->second); - - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedPowerSavingConfig, - *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); + RefreshRate expectedDefaultConfig = {CONFIG_ID_60, "60fps", 60, VSYNC_60, HWC2_CONFIG_ID_60}; + assertRatesEqual(expectedDefaultConfig, defaultRate->second); + RefreshRate expectedPerformanceConfig = {CONFIG_ID_90, "90fps", 90, VSYNC_90, + HWC2_CONFIG_ID_90}; + assertRatesEqual(expectedPerformanceConfig, performanceRate->second); + + assertRatesEqual(expectedDefaultConfig, + refreshRateConfigs->getRefreshRateFromType(RefreshRateType::DEFAULT)); assertRatesEqual(expectedPerformanceConfig, - *mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); + refreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE)); } } // namespace } // namespace scheduler diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index 411ec61770..cec0b32a6b 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -22,7 +22,6 @@ #include <thread> #include "Scheduler/RefreshRateStats.h" -#include "mock/DisplayHardware/MockDisplay.h" #include "mock/MockTimeStats.h" using namespace std::chrono_literals; @@ -42,9 +41,18 @@ protected: RefreshRateStatsTest(); ~RefreshRateStatsTest(); + void init(const std::vector<RefreshRateConfigs::InputConfig>& configs) { + mRefreshRateConfigs = std::make_unique<RefreshRateConfigs>( + /*refreshRateSwitching=*/true, configs, /*currentConfig=*/0); + mRefreshRateStats = + std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats, + /*currentConfig=*/0, + /*currentPowerMode=*/HWC_POWER_MODE_OFF); + } + mock::TimeStats mTimeStats; - RefreshRateConfigs mRefreshRateConfigs; - RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, mTimeStats}; + std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs; + std::unique_ptr<RefreshRateStats> mRefreshRateStats; }; RefreshRateStatsTest::RefreshRateStatsTest() { @@ -63,63 +71,46 @@ namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) { - std::vector<std::shared_ptr<const HWC2::Display::Config>> configs; - mRefreshRateConfigs.populate(configs); - - // There is one default config, so the refresh rates should have one item. - EXPECT_EQ(1, mRefreshRateStats.getTotalTimes().size()); -} - TEST_F(RefreshRateStatsTest, oneConfigTest) { - auto display = new Hwc2::mock::Display(); - - auto config = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); - config.setVsyncPeriod(VSYNC_90); - std::vector<std::shared_ptr<const HWC2::Display::Config>> configs; - configs.push_back(config.build()); - - mRefreshRateConfigs.populate(configs); + init({{CONFIG_ID_90, VSYNC_90}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes(); - EXPECT_EQ(2, times.size()); + std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes(); + ASSERT_EQ(1, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); - EXPECT_EQ(1u, times.count("90fps")); - EXPECT_EQ(0, times["90fps"]); // Setting up tests on mobile harness can be flaky with time passing, so testing for // exact time changes can result in flaxy numbers. To avoid that remember old // numbers to make sure the correct values are increasing in the next test. int screenOff = times["ScreenOff"]; - int ninety = times["90fps"]; // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(0, times["90fps"]); + EXPECT_EQ(0u, times.count("90fps")); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_LT(ninety, times["90fps"]); + ASSERT_EQ(1u, times.count("90fps")); + EXPECT_LT(0, times["90fps"]); - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); - ninety = mRefreshRateStats.getTotalTimes()["90fps"]; + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); + int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. EXPECT_LT(screenOff, times["ScreenOff"]); @@ -127,93 +118,75 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { } TEST_F(RefreshRateStatsTest, twoConfigsTest) { - auto display = new Hwc2::mock::Display(); - - auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); - config90.setVsyncPeriod(VSYNC_90); - std::vector<std::shared_ptr<const HWC2::Display::Config>> configs; - configs.push_back(config90.build()); - - auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); - config60.setVsyncPeriod(VSYNC_60); - configs.push_back(config60.build()); - - mRefreshRateConfigs.populate(configs); + init({{CONFIG_ID_90, VSYNC_90}, {CONFIG_ID_60, VSYNC_60}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes(); - EXPECT_EQ(3, times.size()); + std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes(); + ASSERT_EQ(1, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); - EXPECT_EQ(1u, times.count("60fps")); - EXPECT_EQ(0, times["60fps"]); - EXPECT_EQ(1u, times.count("90fps")); - EXPECT_EQ(0, times["90fps"]); // Setting up tests on mobile harness can be flaky with time passing, so testing for // exact time changes can result in flaxy numbers. To avoid that remember old // numbers to make sure the correct values are increasing in the next test. int screenOff = times["ScreenOff"]; - int sixty = times["60fps"]; - int ninety = times["90fps"]; // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(sixty, times["60fps"]); - EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(sixty, times["60fps"]); - EXPECT_LT(ninety, times["90fps"]); + ASSERT_EQ(1u, times.count("90fps")); + EXPECT_LT(0, times["90fps"]); // When power mode is normal, time for configs updates. - mRefreshRateStats.setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats.getTotalTimes()["90fps"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_60); + int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - EXPECT_LT(sixty, times["60fps"]); + ASSERT_EQ(1u, times.count("60fps")); + EXPECT_LT(0, times["60fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats.getTotalTimes()["60fps"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + int sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_LT(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats.getTotalTimes()["90fps"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_60); + ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_LT(sixty, times["60fps"]); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats.getTotalTimes()["60fps"]; + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_60); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_60); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 740115ea32..571fdfd9fc 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -3,13 +3,13 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> - #include <log/log.h> #include <mutex> #include "Scheduler/EventControlThread.h" #include "Scheduler/EventThread.h" +#include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/Scheduler.h" #include "mock/MockEventThread.h" @@ -34,7 +34,7 @@ protected: MOCK_METHOD0(requestNextVsync, void()); }; - scheduler::RefreshRateConfigs mRefreshRateConfigs; + std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; /** * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else @@ -73,9 +73,14 @@ SchedulerTest::SchedulerTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}}; + mRefreshRateConfigs = + std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, + /*currentConfig=*/0); + std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>(); mEventThread = eventThread.get(); - mScheduler = std::make_unique<MockScheduler>(mRefreshRateConfigs, std::move(eventThread)); + mScheduler = std::make_unique<MockScheduler>(*mRefreshRateConfigs, std::move(eventThread)); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); mEventThreadConnection = new MockEventThreadConnection(mEventThread); @@ -85,7 +90,7 @@ SchedulerTest::SchedulerTest() { EXPECT_CALL(*mEventThread, createEventConnection(_, _)) .WillRepeatedly(Return(mEventThreadConnection)); - mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(), + mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, impl::EventThread::InterceptVSyncsCallback()); EXPECT_TRUE(mConnectionHandle != nullptr); } @@ -107,7 +112,7 @@ TEST_F(SchedulerTest, testNullPtr) { sp<IDisplayEventConnection> returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(), + mScheduler->createDisplayEventConnection(nullptr, ISurfaceComposer:: eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); @@ -130,7 +135,7 @@ TEST_F(SchedulerTest, invalidConnectionHandle) { sp<IDisplayEventConnection> returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(), + mScheduler->createDisplayEventConnection(connectionHandle, ISurfaceComposer:: eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); @@ -161,7 +166,7 @@ TEST_F(SchedulerTest, validConnectionHandle) { sp<IDisplayEventConnection> returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(), + mScheduler->createDisplayEventConnection(mConnectionHandle, ISurfaceComposer:: eConfigChangedSuppress)); EXPECT_TRUE(returnedValue != nullptr); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 64d34ee102..1c1b0201d9 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -32,11 +32,11 @@ #include "Layer.h" #include "NativeWindowSurface.h" #include "Scheduler/MessageQueue.h" +#include "Scheduler/RefreshRateConfigs.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" #include "SurfaceFlingerFactory.h" #include "SurfaceInterceptor.h" - #include "TimeStats/TimeStats.h" namespace android { @@ -342,6 +342,8 @@ public: auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; } auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; } auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; } + auto& mutableRefreshRateStats() { return mFlinger->mRefreshRateStats; } + auto& mutableTimeStats() { return mFlinger->mTimeStats; } ~TestableSurfaceFlinger() { // All these pointer and container clears help ensure that GMock does diff --git a/services/surfaceflinger/version-script32.txt b/services/surfaceflinger/version-script32.txt new file mode 100644 index 0000000000..2340785c42 --- /dev/null +++ b/services/surfaceflinger/version-script32.txt @@ -0,0 +1,12 @@ +{ +global: + EnsureFrontOfChain; + AddSpecialSignalHandlerFn; + RemoveSpecialSignalHandlerFn; + bsd_signal; + sigaction; + signal; + sigprocmask; +local: + *; +}; diff --git a/services/surfaceflinger/version-script64.txt b/services/surfaceflinger/version-script64.txt new file mode 100644 index 0000000000..acf36309ea --- /dev/null +++ b/services/surfaceflinger/version-script64.txt @@ -0,0 +1,11 @@ +{ +global: + EnsureFrontOfChain; + AddSpecialSignalHandlerFn; + RemoveSpecialSignalHandlerFn; + sigaction; + signal; + sigprocmask; +local: + *; +}; diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index c202b5c07c..4c34b938c8 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -1,151 +1,180 @@ cc_library_shared { - name: "libvr_hwc-hal", - - srcs: [ - "impl/vr_hwc.cpp", - "impl/vr_composer_client.cpp", - ], - - static_libs: [ - "libbroadcastring", - "libdisplay", - ], - - shared_libs: [ - "android.frameworks.vr.composer@1.0", - "android.hardware.graphics.composer@2.1", - "android.hardware.graphics.mapper@2.0", - "android.hardware.graphics.mapper@3.0", - "libbase", - "libbufferhubqueue", - "libbinder", - "libcutils", - "libfmq", - "libhardware", - "libhidlbase", - "liblog", - "libsync", - "libui", - "libutils", - "libpdx_default_transport", - ], - - header_libs: [ - "android.hardware.graphics.composer@2.1-command-buffer", - "android.hardware.graphics.composer@2.1-hal", - ], - - export_header_lib_headers: [ - "android.hardware.graphics.composer@2.1-hal", - ], - - export_static_lib_headers: [ - "libdisplay", - ], - - export_shared_lib_headers: [ - "android.frameworks.vr.composer@1.0", - "android.hardware.graphics.composer@2.1", - ], - - export_include_dirs: ["."], - - cflags: [ - "-DLOG_TAG=\"vr_hwc\"", - "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", - "-Wall", - "-Werror", - "-Wno-error=unused-private-field", - // Warnings in vr_hwc.cpp to be fixed after sync of goog/master. - "-Wno-sign-compare", - "-Wno-unused-parameter", - ], + name: "libvr_hwc-hal", + srcs: [ + "impl/vr_hwc.cpp", + "impl/vr_composer_client.cpp", + ], + + static_libs: [ + "libbroadcastring", + "libdisplay", + ], + + shared_libs: [ + "android.frameworks.vr.composer@1.0", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "libbase", + "libbufferhubqueue", + "libbinder", + "libcutils", + "libfmq", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libsync", + "libui", + "libutils", + "libpdx_default_transport", + ], + + header_libs: [ + "android.hardware.graphics.composer@2.1-command-buffer", + "android.hardware.graphics.composer@2.1-hal", + ], + + export_header_lib_headers: [ + "android.hardware.graphics.composer@2.1-hal", + ], + + export_static_lib_headers: [ + "libdisplay", + ], + + export_shared_lib_headers: [ + "android.frameworks.vr.composer@1.0", + "android.hardware.graphics.composer@2.1", + ], + + export_include_dirs: ["."], + + cflags: [ + "-DLOG_TAG=\"vr_hwc\"", + "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", + "-Wall", + "-Werror", + "-Wno-error=unused-private-field", + // Warnings in vr_hwc.cpp to be fixed after sync of goog/master. + "-Wno-sign-compare", + "-Wno-unused-parameter", + ], + +} + +cc_library_static { + name: "libvr_hwc-binder", + srcs: [ + "aidl/android/dvr/IVrComposer.aidl", + "aidl/android/dvr/IVrComposerCallback.aidl", + "aidl/android/dvr/parcelable_composer_frame.cpp", + "aidl/android/dvr/parcelable_composer_layer.cpp", + "aidl/android/dvr/parcelable_unique_fd.cpp", + ], + aidl: { + include_dirs: ["frameworks/native/services/vr/hardware_composer/aidl"], + export_aidl_headers: true, + }, + export_include_dirs: ["aidl"], + + cflags: [ + "-Wall", + "-Werror", + ], + + shared_libs: [ + "libbinder", + "libui", + "libutils", + "libvr_hwc-hal", + ], } cc_library_static { - name: "libvr_hwc-impl", - srcs: [ - "vr_composer.cpp", - ], - static_libs: [ - "libvr_hwc-binder", - ], - shared_libs: [ - "libbase", - "libbinder", - "liblog", - "libui", - "libutils", - "libvr_hwc-hal", - ], - export_shared_lib_headers: [ - "libvr_hwc-hal", - ], - cflags: [ - "-DLOG_TAG=\"vr_hwc\"", - "-Wall", - "-Werror", - ], + name: "libvr_hwc-impl", + srcs: [ + "vr_composer.cpp", + ], + static_libs: [ + "libvr_hwc-binder", + ], + shared_libs: [ + "libbase", + "libbinder", + "liblog", + "libui", + "libutils", + "libvr_hwc-hal", + ], + export_shared_lib_headers: [ + "libvr_hwc-hal", + ], + cflags: [ + "-DLOG_TAG=\"vr_hwc\"", + "-Wall", + "-Werror", + ], } cc_binary { - name: "vr_hwc", - vintf_fragments: ["manifest_vr_hwc.xml"], - srcs: [ - "vr_hardware_composer_service.cpp", - ], - static_libs: [ - "libvr_hwc-impl", - // NOTE: This needs to be included after the *-impl lib otherwise the - // symbols in the *-binder library get optimized out. - "libvr_hwc-binder", - ], - shared_libs: [ - "android.frameworks.vr.composer@1.0", - "android.hardware.graphics.composer@2.1", - "libbase", - "libbinder", - "liblog", - "libhardware", - "libhidlbase", - "libui", - "libutils", - "libvr_hwc-hal", - ], - cflags: [ - "-DLOG_TAG=\"vr_hwc\"", - "-Wall", - "-Werror", - ], - init_rc: [ - "vr_hwc.rc", - ], + name: "vr_hwc", + vintf_fragments: ["manifest_vr_hwc.xml"], + srcs: [ + "vr_hardware_composer_service.cpp" + ], + static_libs: [ + "libvr_hwc-impl", + // NOTE: This needs to be included after the *-impl lib otherwise the + // symbols in the *-binder library get optimized out. + "libvr_hwc-binder", + ], + shared_libs: [ + "android.frameworks.vr.composer@1.0", + "android.hardware.graphics.composer@2.1", + "libbase", + "libbinder", + "liblog", + "libhardware", + "libhidlbase", + "libui", + "libutils", + "libvr_hwc-hal", + ], + cflags: [ + "-DLOG_TAG=\"vr_hwc\"", + "-Wall", + "-Werror", + ], + init_rc: [ + "vr_hwc.rc", + ], } cc_test { - name: "vr_hwc_test", - gtest: true, - srcs: ["tests/vr_composer_test.cpp"], - static_libs: [ - "libgtest", - "libvr_hwc-impl", - // NOTE: This needs to be included after the *-impl lib otherwise the - // symbols in the *-binder library get optimized out. - "libvr_hwc-binder", - ], - cflags: [ - "-Wall", - "-Werror", - // warnings in vr_composer_test.cpp to be fixed after merge of goog/master - "-Wno-sign-compare", - "-Wno-unused-parameter", - ], - shared_libs: [ - "libbase", - "libbinder", - "liblog", - "libui", - "libutils", - ], + name: "vr_hwc_test", + gtest: true, + srcs: ["tests/vr_composer_test.cpp"], + static_libs: [ + "libgtest", + "libvr_hwc-impl", + // NOTE: This needs to be included after the *-impl lib otherwise the + // symbols in the *-binder library get optimized out. + "libvr_hwc-binder", + ], + cflags: [ + "-Wall", + "-Werror", + // warnings in vr_composer_test.cpp to be fixed after merge of goog/master + "-Wno-sign-compare", + "-Wno-unused-parameter", + ], + shared_libs: [ + "libbase", + "libbinder", + "liblog", + "libui", + "libutils", + ], } diff --git a/services/vr/hardware_composer/aidl/Android.bp b/services/vr/hardware_composer/aidl/Android.bp deleted file mode 100644 index a1d5392071..0000000000 --- a/services/vr/hardware_composer/aidl/Android.bp +++ /dev/null @@ -1,27 +0,0 @@ -cc_library_static { - name: "libvr_hwc-binder", - srcs: [ - "android/dvr/IVrComposer.aidl", - "android/dvr/IVrComposerCallback.aidl", - "android/dvr/parcelable_composer_frame.cpp", - "android/dvr/parcelable_composer_layer.cpp", - "android/dvr/parcelable_unique_fd.cpp", - ], - aidl: { - local_include_dirs: ["."], - export_aidl_headers: true, - }, - export_include_dirs: ["."], - - cflags: [ - "-Wall", - "-Werror", - ], - - shared_libs: [ - "libbinder", - "libui", - "libutils", - "libvr_hwc-hal", - ], -} diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp index dcaa663160..131a306c08 100644 --- a/services/vr/virtual_touchpad/Android.bp +++ b/services/vr/virtual_touchpad/Android.bp @@ -62,7 +62,7 @@ cc_test { service_src = [ "main.cpp", "VirtualTouchpadService.cpp", - ":virtualtouchpad_aidl", + "aidl/android/dvr/IVirtualTouchpadService.aidl", ] service_static_libs = [ @@ -99,7 +99,7 @@ cc_binary { client_src = [ "VirtualTouchpadClient.cpp", "DvrVirtualTouchpadClient.cpp", - ":virtualtouchpad_aidl", + "aidl/android/dvr/IVirtualTouchpadService.aidl", ] client_shared_libs = [ @@ -122,9 +122,3 @@ cc_library { name: "libvirtualtouchpadclient", export_include_dirs: ["include"], } - -filegroup { - name: "virtualtouchpad_aidl", - srcs: ["aidl/android/dvr/IVirtualTouchpadService.aidl"], - path: "aidl", -} diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 4d6b2be301..993b751747 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -41,13 +41,11 @@ cc_library_shared { "-DVK_NO_PROTOTYPES", "-fvisibility=hidden", "-fstrict-aliasing", - "-Wextra", + "-Weverything", "-Werror", "-Wno-padded", - "-Wno-sign-compare", "-Wno-switch-enum", - "-Wno-unused-variable", - "-Wno-unused-function", + "-Wno-undef", // Have clang emit complete debug_info. "-fstandalone-debug", @@ -89,6 +87,7 @@ cc_library_shared { "libbase", "libdl_android", "libhidlbase", + "libhidltransport", "liblog", "libui", "libgraphicsenv", diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp index 3d56656896..c3b5523b9e 100644 --- a/vulkan/libvulkan/api.cpp +++ b/vulkan/libvulkan/api.cpp @@ -124,7 +124,7 @@ class OverrideLayerNames { }; void AddImplicitLayers() { - if (!is_instance_ || !driver::Debuggable()) + if (!is_instance_) return; GetLayersFromSettings(); @@ -370,7 +370,8 @@ class OverrideExtensionNames { private: bool EnableDebugCallback() const { - return (is_instance_ && driver::Debuggable() && + return (is_instance_ && + android::GraphicsEnv::getInstance().isDebuggable() && property_get_bool("debug.vulkan.enable_callback", false)); } @@ -519,11 +520,7 @@ LayerChain::LayerChain(bool is_instance, get_device_proc_addr_(nullptr), driver_extensions_(nullptr), driver_extension_count_(0) { - // advertise the loader supported core Vulkan API version at vulkan::api - for (uint32_t i = driver::ProcHook::EXTENSION_CORE_1_0; - i != driver::ProcHook::EXTENSION_COUNT; ++i) { - enabled_extensions_.set(i); - } + enabled_extensions_.set(driver::ProcHook::EXTENSION_CORE); } LayerChain::~LayerChain() { diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl index a5a0405f2d..bdd3573b11 100644 --- a/vulkan/libvulkan/code-generator.tmpl +++ b/vulkan/libvulkan/code-generator.tmpl @@ -765,19 +765,6 @@ VK_KHR_bind_memory2 {{end}} - -{{/* ------------------------------------------------------------------------------- - Emits the ProcHook enum for core Vulkan API verions. ------------------------------------------------------------------------------- -*/}} -{{define "driver.GetProcHookEnum"}} - {{if GetAnnotation $ "vulkan1_1"}}ProcHook::EXTENSION_CORE_1_1 - {{else}}ProcHook::EXTENSION_CORE_1_0 - {{end}} -{{end}} - - {{/* ------------------------------------------------------------------------------ Emits true if a function needs a ProcHook stub. @@ -791,8 +778,6 @@ VK_KHR_bind_memory2 {{if $ext}} {{if not (Macro "IsExtensionInternal" $ext)}}true{{end}} {{end}} - - {{if GetAnnotation $ "vulkan1_1"}}true{{end}} {{end}} {{end}} @@ -816,8 +801,7 @@ VK_KHR_bind_memory2 {{TrimPrefix "VK_" $e}}, {{end}} ¶ - EXTENSION_CORE_1_0, - EXTENSION_CORE_1_1, + EXTENSION_CORE, // valid bit EXTENSION_COUNT, EXTENSION_UNKNOWN, }; @@ -854,21 +838,14 @@ VK_KHR_bind_memory2 {{AssertType $ "Function"}} {{if (Macro "driver.NeedProcHookStub" $)}} - {{$ext_name := Strings ("")}} - {{$ext_hook := Strings ("")}} {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - {{$ext_name = index $ext.Arguments 0}} - {{$ext_hook = Strings ("ProcHook::") (Macro "BaseName" $ext)}} - {{else}} - {{$ext_name = Strings ("VK_VERSION_1_0")}} - {{$ext_hook = (Macro "driver.GetProcHookEnum" $)}} - {{end}} + {{$ext_name := index $ext.Arguments 0}} {{$base := (Macro "BaseName" $)}} VKAPI_ATTR {{Node "Type" $.Return}} checked{{$base}}({{Macro "Parameters" $}}) { {{$p0 := index $.CallParameters 0}} + {{$ext_hook := Strings ("ProcHook::") (Macro "BaseName" $ext)}} if (GetData({{$p0.Name}}).hook_extensions[{{$ext_hook}}]) { {{if not (IsVoid $.Return.Type)}}return §{{end}} @@ -901,7 +878,7 @@ VK_KHR_bind_memory2 { "{{$.Name}}", ProcHook::GLOBAL, - {{Macro "driver.GetProcHookEnum" $}}, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>({{$base}}), nullptr, }, @@ -934,7 +911,7 @@ VK_KHR_bind_memory2 nullptr, {{end}} {{else}} - {{Macro "driver.GetProcHookEnum" $}}, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>({{$base}}), nullptr, {{end}} @@ -957,23 +934,18 @@ VK_KHR_bind_memory2 ProcHook::DEVICE, {{$ext := GetAnnotation $ "extension"}} - {{if or $ext (GetAnnotation $ "vulkan1_1")}} - {{if $ext}} - ProcHook::{{Macro "BaseName" $ext}}, - {{if Macro "IsExtensionInternal" $ext}} - nullptr, - nullptr, - {{else}} - reinterpret_cast<PFN_vkVoidFunction>({{$base}}), - reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}), - {{end}} + {{if $ext}} + ProcHook::{{Macro "BaseName" $ext}}, + + {{if (Macro "IsExtensionInternal" $ext)}} + nullptr, + nullptr, {{else}} - {{Macro "driver.GetProcHookEnum" $}}, reinterpret_cast<PFN_vkVoidFunction>({{$base}}), reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}), {{end}} {{else}} - {{Macro "driver.GetProcHookEnum" $}}, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>({{$base}}), nullptr, {{end}} diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 74773517ae..8ea09805ae 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -24,10 +24,7 @@ #include <dlfcn.h> #include <algorithm> #include <array> -#include <climits> #include <new> -#include <sstream> -#include <string> #include <log/log.h> @@ -107,7 +104,6 @@ class CreateInfoWrapper { VkResult Validate(); void DowngradeApiVersion(); - void UpgradeDeviceCoreApiVersion(uint32_t api_version); const std::bitset<ProcHook::EXTENSION_COUNT>& GetHookExtensions() const; const std::bitset<ProcHook::EXTENSION_COUNT>& GetHalExtensions() const; @@ -156,12 +152,15 @@ class CreateInfoWrapper { Hal Hal::hal_; void* LoadLibrary(const android_dlextinfo& dlextinfo, - const std::string_view subname) { + const char* subname, + int subname_len) { ATRACE_CALL(); - std::stringstream ss; - ss << "vulkan." << subname << ".so"; - return android_dlopen_ext(ss.str().c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo); + const char kLibFormat[] = "vulkan.%*s.so"; + char* name = static_cast<char*>( + alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len))); + sprintf(name, kLibFormat, subname_len, subname); + return android_dlopen_ext(name, RTLD_LOCAL | RTLD_NOW, &dlextinfo); } const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{ @@ -181,9 +180,8 @@ int LoadDriver(android_namespace_t* library_namespace, char prop[PROPERTY_VALUE_MAX]; for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { int prop_len = property_get(key, prop, nullptr); - if (prop_len > 0 && prop_len <= UINT_MAX) { - std::string_view lib_name(prop, static_cast<unsigned int>(prop_len)); - so = LoadLibrary(dlextinfo, lib_name); + if (prop_len > 0) { + so = LoadLibrary(dlextinfo, prop, prop_len); if (so) break; } @@ -335,12 +333,8 @@ CreateInfoWrapper::CreateInfoWrapper(const VkInstanceCreateInfo& create_info, physical_dev_(VK_NULL_HANDLE), instance_info_(create_info), extension_filter_() { - // instance core versions need to match the loader api version - for (uint32_t i = ProcHook::EXTENSION_CORE_1_0; - i != ProcHook::EXTENSION_COUNT; ++i) { - hook_extensions_.set(i); - hal_extensions_.set(i); - } + hook_extensions_.set(ProcHook::EXTENSION_CORE); + hal_extensions_.set(ProcHook::EXTENSION_CORE); } CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev, @@ -351,9 +345,8 @@ CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev, physical_dev_(physical_dev), dev_info_(create_info), extension_filter_() { - // initialize with baseline core API version - hook_extensions_.set(ProcHook::EXTENSION_CORE_1_0); - hal_extensions_.set(ProcHook::EXTENSION_CORE_1_0); + hook_extensions_.set(ProcHook::EXTENSION_CORE); + hal_extensions_.set(ProcHook::EXTENSION_CORE); } CreateInfoWrapper::~CreateInfoWrapper() { @@ -552,8 +545,7 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::ANDROID_external_memory_android_hardware_buffer: case ProcHook::ANDROID_native_buffer: case ProcHook::GOOGLE_display_timing: - case ProcHook::EXTENSION_CORE_1_0: - case ProcHook::EXTENSION_CORE_1_1: + case ProcHook::EXTENSION_CORE: case ProcHook::EXTENSION_COUNT: // Device and meta extensions. If we ever get here it's a bug in // our code. But enumerating them lets us avoid having a default @@ -601,8 +593,7 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::EXT_debug_report: case ProcHook::EXT_swapchain_colorspace: case ProcHook::ANDROID_native_buffer: - case ProcHook::EXTENSION_CORE_1_0: - case ProcHook::EXTENSION_CORE_1_1: + case ProcHook::EXTENSION_CORE: case ProcHook::EXTENSION_COUNT: // Instance and meta extensions. If we ever get here it's a bug // in our code. But enumerating them lets us avoid having a @@ -650,28 +641,6 @@ void CreateInfoWrapper::DowngradeApiVersion() { } } -void CreateInfoWrapper::UpgradeDeviceCoreApiVersion(uint32_t api_version) { - ALOG_ASSERT(!is_instance_, "Device only API called by instance wrapper."); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wold-style-cast" - api_version ^= VK_VERSION_PATCH(api_version); -#pragma clang diagnostic pop - // cap the API version to the loader supported highest version - if (api_version > VK_API_VERSION_1_1) - api_version = VK_API_VERSION_1_1; - switch (api_version) { - case VK_API_VERSION_1_1: - hook_extensions_.set(ProcHook::EXTENSION_CORE_1_1); - hal_extensions_.set(ProcHook::EXTENSION_CORE_1_1); - [[clang::fallthrough]]; - case VK_API_VERSION_1_0: - break; - default: - ALOGD("Unknown upgrade API version[%u]", api_version); - break; - } -} - VKAPI_ATTR void* DefaultAllocate(void*, size_t size, size_t alignment, @@ -755,10 +724,6 @@ void FreeDeviceData(DeviceData* data, const VkAllocationCallbacks& allocator) { } // anonymous namespace -bool Debuggable() { - return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0); -} - bool OpenHAL() { return Hal::Open(); } @@ -807,7 +772,7 @@ PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) { : nullptr; break; case ProcHook::DEVICE: - proc = (hook->extension == ProcHook::EXTENSION_CORE_1_0) + proc = (hook->extension == ProcHook::EXTENSION_CORE) ? hook->proc : hook->checked_proc; break; @@ -1155,13 +1120,6 @@ VkResult CreateDevice(VkPhysicalDevice physicalDevice, if (!data) return VK_ERROR_OUT_OF_HOST_MEMORY; - VkPhysicalDeviceProperties properties; - ATRACE_BEGIN("driver.GetPhysicalDeviceProperties"); - instance_data.driver.GetPhysicalDeviceProperties(physicalDevice, - &properties); - ATRACE_END(); - - wrapper.UpgradeDeviceCoreApiVersion(properties.apiVersion); data->hook_extensions |= wrapper.GetHookExtensions(); // call into the driver @@ -1206,6 +1164,12 @@ VkResult CreateDevice(VkPhysicalDevice physicalDevice, return VK_ERROR_INCOMPATIBLE_DRIVER; } + VkPhysicalDeviceProperties properties; + ATRACE_BEGIN("driver.GetPhysicalDeviceProperties"); + instance_data.driver.GetPhysicalDeviceProperties(physicalDevice, + &properties); + ATRACE_END(); + if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) { // Log that the app is hitting software Vulkan implementation android::GraphicsEnv::getInstance().setTargetStats( diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h index 047a27adc9..075a15b31a 100644 --- a/vulkan/libvulkan/driver.h +++ b/vulkan/libvulkan/driver.h @@ -67,7 +67,9 @@ struct InstanceData { : opaque_api_data(), allocator(alloc), driver(), - get_device_proc_addr(nullptr) {} + get_device_proc_addr(nullptr) { + hook_extensions.set(ProcHook::EXTENSION_CORE); + } api::InstanceData opaque_api_data; @@ -87,7 +89,9 @@ struct DeviceData { : opaque_api_data(), allocator(alloc), debug_report_callbacks(debug_report_callbacks_), - driver() {} + driver() { + hook_extensions.set(ProcHook::EXTENSION_CORE); + } api::DeviceData opaque_api_data; @@ -101,7 +105,6 @@ struct DeviceData { uint32_t driver_version; }; -bool Debuggable(); bool OpenHAL(); const VkAllocationCallbacks& GetDefaultAllocator(); diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index aa31735eef..574c3273d0 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -31,23 +31,6 @@ namespace { // clang-format off -VKAPI_ATTR VkResult checkedBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { - if (GetData(device).hook_extensions[ProcHook::EXTENSION_CORE_1_1]) { - return BindImageMemory2(device, bindInfoCount, pBindInfos); - } else { - Logger(device).Err(device, "VK_VERSION_1_0 not enabled. vkBindImageMemory2 not executed."); - return VK_SUCCESS; - } -} - -VKAPI_ATTR void checkedGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) { - if (GetData(device).hook_extensions[ProcHook::EXTENSION_CORE_1_1]) { - GetDeviceQueue2(device, pQueueInfo, pQueue); - } else { - Logger(device).Err(device, "VK_VERSION_1_0 not enabled. vkGetDeviceQueue2 not executed."); - } -} - VKAPI_ATTR VkResult checkedCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) { return CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); @@ -191,16 +174,16 @@ const ProcHook g_proc_hooks[] = { { "vkAllocateCommandBuffers", ProcHook::DEVICE, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers), nullptr, }, { "vkBindImageMemory2", ProcHook::DEVICE, - ProcHook::EXTENSION_CORE_1_1, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2), - reinterpret_cast<PFN_vkVoidFunction>(checkedBindImageMemory2), + nullptr, }, { "vkBindImageMemory2KHR", @@ -226,14 +209,14 @@ const ProcHook g_proc_hooks[] = { { "vkCreateDevice", ProcHook::INSTANCE, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(CreateDevice), nullptr, }, { "vkCreateInstance", ProcHook::GLOBAL, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(CreateInstance), nullptr, }, @@ -261,14 +244,14 @@ const ProcHook g_proc_hooks[] = { { "vkDestroyDevice", ProcHook::DEVICE, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice), nullptr, }, { "vkDestroyInstance", ProcHook::INSTANCE, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance), nullptr, }, @@ -289,28 +272,28 @@ const ProcHook g_proc_hooks[] = { { "vkEnumerateDeviceExtensionProperties", ProcHook::INSTANCE, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties), nullptr, }, { "vkEnumerateInstanceExtensionProperties", ProcHook::GLOBAL, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties), nullptr, }, { "vkEnumeratePhysicalDeviceGroups", ProcHook::INSTANCE, - ProcHook::EXTENSION_CORE_1_1, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroups), nullptr, }, { "vkEnumeratePhysicalDevices", ProcHook::INSTANCE, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices), nullptr, }, @@ -331,28 +314,28 @@ const ProcHook g_proc_hooks[] = { { "vkGetDeviceProcAddr", ProcHook::DEVICE, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr), nullptr, }, { "vkGetDeviceQueue", ProcHook::DEVICE, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue), nullptr, }, { "vkGetDeviceQueue2", ProcHook::DEVICE, - ProcHook::EXTENSION_CORE_1_1, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2), - reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceQueue2), + nullptr, }, { "vkGetInstanceProcAddr", ProcHook::INSTANCE, - ProcHook::EXTENSION_CORE_1_0, + ProcHook::EXTENSION_CORE, reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr), nullptr, }, diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 831efb7026..3faf6c0e32 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -48,8 +48,7 @@ struct ProcHook { ANDROID_external_memory_android_hardware_buffer, KHR_bind_memory2, - EXTENSION_CORE_1_0, - EXTENSION_CORE_1_1, + EXTENSION_CORE, // valid bit EXTENSION_COUNT, EXTENSION_UNKNOWN, }; diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp index dd917393d1..691f3b0f52 100644 --- a/vulkan/libvulkan/layers_extensions.cpp +++ b/vulkan/libvulkan/layers_extensions.cpp @@ -24,7 +24,6 @@ #include <string.h> #include <sys/prctl.h> -#include <memory> #include <mutex> #include <string> #include <vector> @@ -102,7 +101,9 @@ class LayerLibrary { bool EnumerateLayers(size_t library_idx, std::vector<Layer>& instance_layers) const; - void* GetGPA(const Layer& layer, const std::string_view gpa_name) const; + void* GetGPA(const Layer& layer, + const char* gpa_name, + size_t gpa_name_len) const; const std::string GetFilename() { return filename_; } @@ -225,10 +226,17 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx, } // get layer properties - auto properties = std::make_unique<VkLayerProperties[]>(num_instance_layers + num_device_layers); + VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca( + (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties))); + result = enumerate_instance_layers(&num_instance_layers, properties); + if (result != VK_SUCCESS) { + ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d", + path_.c_str(), result); + return false; + } if (num_device_layers > 0) { result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, - properties.get() + num_instance_layers); + properties + num_instance_layers); if (result != VK_SUCCESS) { ALOGE( "vkEnumerateDeviceLayerProperties failed for library '%s': %d", @@ -313,11 +321,21 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx, return true; } -void* LayerLibrary::GetGPA(const Layer& layer, const std::string_view gpa_name) const { - std::string layer_name { layer.properties.layerName }; - if (void* gpa = GetTrampoline((layer_name.append(gpa_name).c_str()))) - return gpa; - return GetTrampoline((std::string {"vk"}.append(gpa_name)).c_str()); +void* LayerLibrary::GetGPA(const Layer& layer, + const char* gpa_name, + size_t gpa_name_len) const { + void* gpa; + size_t layer_name_len = + std::max(size_t{2}, strlen(layer.properties.layerName)); + char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1)); + strcpy(name, layer.properties.layerName); + strcpy(name + layer_name_len, gpa_name); + if (!(gpa = GetTrampoline(name))) { + strcpy(name, "vk"); + strcpy(name + 2, gpa_name); + gpa = GetTrampoline(name); + } + return gpa; } // ---------------------------------------------------------------------------- @@ -370,8 +388,9 @@ void ForEachFileInZip(const std::string& zipname, return; } std::string prefix(dir_in_zip + "/"); + const ZipString prefix_str(prefix.c_str()); void* iter_cookie = nullptr; - if ((err = StartIteration(zip, &iter_cookie, prefix, "")) != 0) { + if ((err = StartIteration(zip, &iter_cookie, &prefix_str, nullptr)) != 0) { ALOGE("failed to iterate entries in apk '%s': %d", zipname.c_str(), err); CloseArchive(zip); @@ -380,9 +399,11 @@ void ForEachFileInZip(const std::string& zipname, ALOGD("searching for layers in '%s!/%s'", zipname.c_str(), dir_in_zip.c_str()); ZipEntry entry; - std::string name; + ZipString name; while (Next(iter_cookie, &entry, &name) == 0) { - std::string filename(name.substr(prefix.length())); + std::string filename( + reinterpret_cast<const char*>(name.name) + prefix.length(), + name.name_length - prefix.length()); // only enumerate direct entries of the directory, not subdirectories if (filename.find('/') != filename.npos) continue; @@ -452,9 +473,10 @@ const VkExtensionProperties* FindExtension( } void* GetLayerGetProcAddr(const Layer& layer, - const std::string_view gpa_name) { + const char* gpa_name, + size_t gpa_name_len) { const LayerLibrary& library = g_layer_libraries[layer.library_idx]; - return library.GetGPA(layer, gpa_name); + return library.GetGPA(layer, gpa_name, gpa_name_len); } } // anonymous namespace @@ -462,8 +484,7 @@ void* GetLayerGetProcAddr(const Layer& layer, void DiscoverLayers() { ATRACE_CALL(); - if (property_get_bool("ro.debuggable", false) && - prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { + if (android::GraphicsEnv::getInstance().isDebuggable()) { DiscoverLayersInPathList(kSystemLayerLibraryDir); } if (!android::GraphicsEnv::getInstance().getLayerPaths().empty()) @@ -537,13 +558,13 @@ LayerRef::LayerRef(LayerRef&& other) noexcept : layer_(other.layer_) { PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const { return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>( - GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr")) + GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19)) : nullptr; } PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const { return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>( - GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr")) + GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17)) : nullptr; } diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index fbf6d0d233..a8949d36f4 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -718,6 +718,8 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, + {VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, + {VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, }; const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); uint32_t total_num_formats = kNumFormats; @@ -1278,7 +1280,6 @@ VkResult CreateSwapchainKHR(VkDevice device, VkImageCreateInfo image_create = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = &image_native_buffer, - .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, .imageType = VK_IMAGE_TYPE_2D, .format = create_info->imageFormat, .extent = {0, 0, 1}, @@ -1287,6 +1288,7 @@ VkResult CreateSwapchainKHR(VkDevice device, .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_OPTIMAL, .usage = create_info->imageUsage, + .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, .sharingMode = create_info->imageSharingMode, .queueFamilyIndexCount = create_info->queueFamilyIndexCount, .pQueueFamilyIndices = create_info->pQueueFamilyIndices, @@ -1379,7 +1381,7 @@ void DestroySwapchainKHR(VkDevice device, bool active = swapchain->surface.swapchain_handle == swapchain_handle; ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr; - if (window && swapchain->frame_timestamps_enabled) { + if (swapchain->frame_timestamps_enabled) { native_window_enable_frame_timestamps(window, false); } for (uint32_t i = 0; i < swapchain->num_images; i++) diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp index ba025046fa..dedf419dc3 100644 --- a/vulkan/nulldrv/Android.bp +++ b/vulkan/nulldrv/Android.bp @@ -23,11 +23,18 @@ cc_library_shared { "-fvisibility=hidden", "-fstrict-aliasing", "-DLOG_TAG=\"vknulldrv\"", - "-Wextra", + "-Weverything", "-Werror", + "-Wno-padded", + "-Wno-undef", + "-Wno-zero-length-array", "-DLOG_NDEBUG=0", ], + cppflags: [ + "-Wno-c++98-compat-pedantic", + "-Wno-c99-extensions", + ], srcs: [ "null_driver.cpp", diff --git a/vulkan/tools/Android.bp b/vulkan/tools/Android.bp index 91d64fe1c9..2514094a15 100644 --- a/vulkan/tools/Android.bp +++ b/vulkan/tools/Android.bp @@ -22,8 +22,16 @@ cc_binary { "-DLOG_TAG=\"vkinfo\"", - "-Wextra", + "-Weverything", "-Werror", + "-Wno-padded", + "-Wno-undef", + "-Wno-switch-enum", + ], + cppflags: [ + "-Wno-c++98-compat-pedantic", + "-Wno-c99-extensions", + "-Wno-old-style-cast", ], srcs: ["vkinfo.cpp"], diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp index f9e4916722..89bc926aa6 100644 --- a/vulkan/tools/vkinfo.cpp +++ b/vulkan/tools/vkinfo.cpp @@ -195,10 +195,10 @@ void GatherGpuInfo(VkPhysicalDevice gpu, .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queue_create_info, - .enabledLayerCount = (options.validate) ? num_layers : 0, - .ppEnabledLayerNames = kValidationLayers, .enabledExtensionCount = num_extensions, .ppEnabledExtensionNames = extensions, + .enabledLayerCount = (options.validate) ? num_layers : 0, + .ppEnabledLayerNames = kValidationLayers, .pEnabledFeatures = &info.features, }; result = vkCreateDevice(gpu, &create_info, nullptr, &device); @@ -272,10 +272,10 @@ void GatherInfo(VulkanInfo* info, const Options& options) { const VkInstanceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &application_info, - .enabledLayerCount = (options.validate) ? num_layers : 0, - .ppEnabledLayerNames = kValidationLayers, .enabledExtensionCount = num_extensions, .ppEnabledExtensionNames = extensions, + .enabledLayerCount = (options.validate) ? num_layers : 0, + .ppEnabledLayerNames = kValidationLayers, }; VkInstance instance; result = vkCreateInstance(&create_info, nullptr, &instance); |