diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp index b850390d93483ef8f7825ca41380891193b35e7a..bb84a1807094d6db1b5f57dd84ed7e1cf4439b87 100644 --- a/cmds/atrace/Android.bp +++ b/cmds/atrace/Android.bp @@ -18,8 +18,6 @@ cc_binary { "libcutils", "libz", "libbase", - ], - static_libs: [ "libpdx_default_transport", ], diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 5d21f6a5596f712a5f323acb26724f96738e83b4..2561e0acd76f8f39dd4a151c11664a56bd5adc68 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -127,6 +127,7 @@ static const TracingCategory k_categories[] = { { OPT, "events/sched/sched_waking/enable" }, { OPT, "events/sched/sched_blocked_reason/enable" }, { OPT, "events/sched/sched_cpu_hotplug/enable" }, + { OPT, "events/sched/sched_pi_setprio/enable" }, { OPT, "events/cgroup/enable" }, } }, { "irq", "IRQ Events", 0, { @@ -187,7 +188,10 @@ static const TracingCategory k_categories[] = { { REQ, "events/cpufreq_interactive/enable" }, } }, { "sync", "Synchronization", 0, { - { REQ, "events/sync/enable" }, + // before linux kernel 4.9 + { OPT, "events/sync/enable" }, + // starting in linux kernel 4.9 + { OPT, "events/fence/enable" }, } }, { "workq", "Kernel Workqueues", 0, { { REQ, "events/workqueue/enable" }, diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 406f90990f3a7f88d22a3a304d13ea19f0e93217..579cfaf57d098175257aed07cd2cb1d63e2e28cf 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -1,6 +1,6 @@ ## Permissions to allow system-wide tracing to the kernel trace buffer. ## -on post-fs +on late-init # Allow writing to the kernel trace log. chmod 0222 /sys/kernel/debug/tracing/trace_marker @@ -29,6 +29,8 @@ on post-fs chmod 0666 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable chmod 0666 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable + chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_pi_setprio/enable + chmod 0666 /sys/kernel/tracing/events/sched/sched_pi_setprio/enable chmod 0666 /sys/kernel/debug/tracing/events/cgroup/enable chmod 0666 /sys/kernel/tracing/events/cgroup/enable chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable @@ -119,6 +121,12 @@ on post-fs chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable + # graphics + chmod 0666 /sys/kernel/tracing/events/sde/enable + chmod 0666 /sys/kernel/debug/tracing/events/sde/enable + chmod 0666 /sys/kernel/tracing/events/mdss/enable + chmod 0666 /sys/kernel/debug/tracing/events/mdss/enable + # Tracing disabled by default write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0 diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp index 022d3dd6bad0d843c33d3e4dff6d61dddc8df272..423853175bf909df3277e15f67acfdfd220a4214 100644 --- a/cmds/cmd/cmd.cpp +++ b/cmds/cmd/cmd.cpp @@ -61,7 +61,8 @@ class MyShellCallback : public BnShellCallback public: bool mActive = true; - virtual int openOutputFile(const String16& path, const String16& seLinuxContext) { + virtual int openFile(const String16& path, const String16& seLinuxContext, + const String16& mode) { String8 path8(path); char cwd[256]; getcwd(cwd, 256); @@ -71,7 +72,32 @@ public: aerr << "Open attempt after active for: " << fullPath << endl; return -EPERM; } - int fd = open(fullPath.string(), O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG); +#if DEBUG + ALOGD("openFile: %s, full=%s", path8.string(), fullPath.string()); +#endif + int flags = 0; + bool checkRead = false; + bool checkWrite = false; + if (mode == String16("w")) { + flags = O_WRONLY|O_CREAT|O_TRUNC; + checkWrite = true; + } else if (mode == String16("w+")) { + flags = O_RDWR|O_CREAT|O_TRUNC; + checkRead = checkWrite = true; + } else if (mode == String16("r")) { + flags = O_RDONLY; + checkRead = true; + } else if (mode == String16("r+")) { + flags = O_RDWR; + checkRead = checkWrite = true; + } else { + aerr << "Invalid mode requested: " << mode.string() << endl; + return -EINVAL; + } + int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG); +#if DEBUG + ALOGD("openFile: fd=%d", fd); +#endif if (fd < 0) { return fd; } @@ -80,14 +106,33 @@ public: security_context_t tmp = NULL; getfilecon(fullPath.string(), &tmp); Unique_SecurityContext context(tmp); - int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(), - "file", "write", NULL); - if (accessGranted != 0) { - close(fd); - aerr << "System server has no access to file context " << context.get() - << " (from path " << fullPath.string() << ", context " - << seLinuxContext8.string() << ")" << endl; - return -EPERM; + if (checkWrite) { + int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(), + "file", "write", NULL); + if (accessGranted != 0) { +#if DEBUG + ALOGD("openFile: failed selinux write check!"); +#endif + close(fd); + aerr << "System server has no access to write file context " << context.get() + << " (from path " << fullPath.string() << ", context " + << seLinuxContext8.string() << ")" << endl; + return -EPERM; + } + } + if (checkRead) { + int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(), + "file", "read", NULL); + if (accessGranted != 0) { +#if DEBUG + ALOGD("openFile: failed selinux read check!"); +#endif + close(fd); + aerr << "System server has no access to read file context " << context.get() + << " (from path " << fullPath.string() << ", context " + << seLinuxContext8.string() << ")" << endl; + return -EPERM; + } } } return fd; @@ -122,15 +167,11 @@ int main(int argc, char* const argv[]) { signal(SIGPIPE, SIG_IGN); sp proc = ProcessState::self(); - // setThreadPoolMaxThreadCount(0) actually tells the kernel it's - // not allowed to spawn any additional threads, but we still spawn - // a binder thread from userspace when we call startThreadPool(). - // This is safe because we only have 2 callbacks, neither of which - // block. - // See b/36066697 for rationale - proc->setThreadPoolMaxThreadCount(0); proc->startThreadPool(); +#if DEBUG + ALOGD("cmd: starting"); +#endif sp sm = defaultServiceManager(); fflush(stdout); if (sm == NULL) { diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index ce3a6aad7a8424549e71ecead76e551a48ea70f0..b04543bd400715a72e8a430f19c254b16923f23a 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -14,7 +14,7 @@ // limitations under the License. cc_defaults { - name: "dumpstate_defaults", + name: "dumpstate_cflag_defaults", cflags: [ "-Wall", "-Werror", @@ -26,7 +26,7 @@ cc_defaults { cc_library_shared { name: "libdumpstateutil", - defaults: ["dumpstate_defaults"], + defaults: ["dumpstate_cflag_defaults"], vendor_available: true, vndk: { enabled: true, @@ -47,7 +47,7 @@ cc_library_shared { cc_library_shared { name: "libdumpstateaidl", - defaults: ["dumpstate_defaults"], + defaults: ["dumpstate_cflag_defaults"], shared_libs: [ "libbinder", "libutils", @@ -63,9 +63,9 @@ cc_library_shared { ], } -cc_binary { - name: "dumpstate", - defaults: ["dumpstate_defaults"], +cc_defaults { + name: "dumpstate_defaults", + defaults: ["dumpstate_cflag_defaults"], shared_libs: [ "android.hardware.dumpstate@1.0", "libziparchive", @@ -76,16 +76,29 @@ cc_binary { "libdebuggerd_client", "libdumpstateaidl", "libdumpstateutil", + "libdumputils", "libhidlbase", "libhidltransport", "liblog", "libutils", ], srcs: [ - "DumpstateInternal.cpp", + "DumpstateSectionReporter.cpp", "DumpstateService.cpp", "utils.cpp", + ], + static_libs: [ + "libdumpsys", + "libserviceutils" + ], +} + +cc_binary { + name: "dumpstate", + defaults: ["dumpstate_defaults"], + srcs: [ "dumpstate.cpp", + "main.cpp", ], init_rc: ["dumpstate.rc"], } @@ -93,24 +106,18 @@ cc_binary { cc_test { name: "dumpstate_test", defaults: ["dumpstate_defaults"], - shared_libs: [ - "libziparchive", - "libbase", - "libbinder", - "libcutils", - "libdebuggerd_client", - "libdumpstateaidl", - "libdumpstateutil", - "libhidlbase", - "libhidltransport", - "liblog", - "libutils", - ], srcs: [ - "DumpstateInternal.cpp", - "DumpstateService.cpp", - "utils.cpp", "tests/dumpstate_test.cpp", ], static_libs: ["libgmock"], } + +cc_test { + name: "dumpstate_smoke_test", + defaults: ["dumpstate_defaults"], + srcs: [ + "dumpstate.cpp", + "tests/dumpstate_smoke_test.cpp", + ], + static_libs: ["libgmock"], +} diff --git a/cmds/dumpstate/DumpstateSectionReporter.cpp b/cmds/dumpstate/DumpstateSectionReporter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f814bde26d44ac4036b5c486bae3240f4e150244 --- /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 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::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 0000000000000000000000000000000000000000..e971de84c5e47e5839be85db371ce61f7d0e0e41 --- /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 +#include + +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 listener, + bool sendReport); + + ~DumpstateSectionReporter(); + + void setStatus(status_t status) { + status_ = status; + } + + void setSize(int size) { + size_ = size; + } + + private: + std::string title_; + android::sp listener_; + bool sendReport_; + status_t status_; + int size_; + std::chrono::time_point 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 efe0466d07740e0b6e4e5ff667018a2305f2d9c6..49a78e751bf0818bb6002976f1ad57b75ded277a 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -52,6 +52,7 @@ status_t DumpstateService::Start() { binder::Status DumpstateService::setListener(const std::string& name, const sp& listener, + bool getSectionDetails, sp* returned_token) { *returned_token = nullptr; if (name.empty()) { @@ -70,6 +71,7 @@ binder::Status DumpstateService::setListener(const std::string& name, ds_.listener_name_ = name; ds_.listener_ = listener; + ds_.report_section_ = getSectionDetails; *returned_token = new DumpstateToken(); return binder::Status::ok(); diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h index 4352d3dacfa00be523a1313933fe0126fddbbaef..7bca24ae33c26964ccfd945613f8de6310d3bb8a 100644 --- a/cmds/dumpstate/DumpstateService.h +++ b/cmds/dumpstate/DumpstateService.h @@ -38,6 +38,7 @@ class DumpstateService : public BinderService, public BnDumpst status_t dump(int fd, const Vector& args) override; binder::Status setListener(const std::string& name, const sp& listener, + bool getSectionDetails, sp* returned_token) override; private: diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index ede4254a9b6f00ade305fb192d8ebed1cf4aa5c3..85eb464104600111cc3a0a52ea17d0c123b31d3d 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -43,7 +43,7 @@ namespace { static constexpr const char* kSuPath = "/system/xbin/su"; -static bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) { +static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) { sigset_t child_mask, old_mask; sigemptyset(&child_mask); sigaddset(&child_mask, SIGCHLD); @@ -54,10 +54,11 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) { } timespec ts; - ts.tv_sec = timeout_seconds; - ts.tv_nsec = 0; + ts.tv_sec = MSEC_TO_SEC(timeout_ms); + ts.tv_nsec = (timeout_ms % 1000) * 1000000; int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts)); int saved_errno = errno; + // Set the signals back the way they were. if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) { printf("*** sigprocmask failed: %s\n", strerror(errno)); @@ -91,7 +92,7 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) { CommandOptions CommandOptions::DEFAULT = CommandOptions::WithTimeout(10).Build(); CommandOptions CommandOptions::AS_ROOT = CommandOptions::WithTimeout(10).AsRoot().Build(); -CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(int64_t timeout) : values(timeout) { +CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(int64_t timeout_ms) : values(timeout_ms) { } CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Always() { @@ -130,8 +131,8 @@ CommandOptions CommandOptions::CommandOptionsBuilder::Build() { return CommandOptions(values); } -CommandOptions::CommandOptionsValues::CommandOptionsValues(int64_t timeout) - : timeout_(timeout), +CommandOptions::CommandOptionsValues::CommandOptionsValues(int64_t timeout_ms) + : timeout_ms_(timeout_ms), always_(false), account_mode_(DONT_DROP_ROOT), output_mode_(NORMAL_OUTPUT), @@ -142,7 +143,11 @@ CommandOptions::CommandOptions(const CommandOptionsValues& values) : values(valu } int64_t CommandOptions::Timeout() const { - return values.timeout_; + return MSEC_TO_SEC(values.timeout_ms_); +} + +int64_t CommandOptions::TimeoutInMs() const { + return values.timeout_ms_; } bool CommandOptions::Always() const { @@ -161,8 +166,12 @@ std::string CommandOptions::LoggingMessage() const { return values.logging_message_; } -CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(int64_t timeout) { - return CommandOptions::CommandOptionsBuilder(timeout); +CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(int64_t timeout_sec) { + return CommandOptions::CommandOptionsBuilder(SEC_TO_MSEC(timeout_sec)); +} + +CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeoutInMs(int64_t timeout_ms) { + return CommandOptions::CommandOptionsBuilder(timeout_ms); } std::string PropertiesHelper::build_type_ = ""; @@ -314,7 +323,7 @@ int RunCommandToFd(int fd, const std::string& title, const std::vector(elapsed) / NANOS_PER_SEC, pid); } kill(pid, SIGTERM); - if (!waitpid_with_timeout(pid, 5, nullptr)) { + if (!waitpid_with_timeout(pid, 5000, nullptr)) { kill(pid, SIGKILL); - if (!waitpid_with_timeout(pid, 5, nullptr)) { + if (!waitpid_with_timeout(pid, 5000, nullptr)) { if (!silent) dprintf(fd, "could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid); diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h index 698ceffcc40e9ae28069d66a8c48705bbc461b31..8342099821a9282f37ebbbf97d16044345e0df81 100644 --- a/cmds/dumpstate/DumpstateUtil.h +++ b/cmds/dumpstate/DumpstateUtil.h @@ -19,6 +19,16 @@ #include #include +/* + * Converts seconds to milliseconds. + */ +#define SEC_TO_MSEC(second) (second * 1000) + +/* + * Converts milliseconds to seconds. + */ +#define MSEC_TO_SEC(millisecond) (millisecond / 1000) + namespace android { namespace os { namespace dumpstate { @@ -66,9 +76,9 @@ class CommandOptions { private: class CommandOptionsValues { private: - CommandOptionsValues(int64_t timeout); + CommandOptionsValues(int64_t timeout_ms); - int64_t timeout_; + int64_t timeout_ms_; bool always_; PrivilegeMode account_mode_; OutputMode output_mode_; @@ -102,13 +112,15 @@ class CommandOptions { CommandOptions Build(); private: - CommandOptionsBuilder(int64_t timeout); + CommandOptionsBuilder(int64_t timeout_ms); CommandOptionsValues values; friend class CommandOptions; }; - /** Gets the command timeout, in seconds. */ + /** Gets the command timeout in seconds. */ int64_t Timeout() const; + /** Gets the command timeout in milliseconds. */ + int64_t TimeoutInMs() const; /* Checks whether the command should always be run, even on dry-run mode. */ bool Always() const; /** Gets the PrivilegeMode of the command. */ @@ -118,8 +130,11 @@ class CommandOptions { /** Gets the logging message header, it any. */ std::string LoggingMessage() const; - /** Creates a builder with the requied timeout. */ - static CommandOptionsBuilder WithTimeout(int64_t timeout); + /** Creates a builder with the requied timeout in seconds. */ + static CommandOptionsBuilder WithTimeout(int64_t timeout_sec); + + /** Creates a builder with the requied timeout in milliseconds. */ + static CommandOptionsBuilder WithTimeoutInMs(int64_t timeout_ms); // Common options. static CommandOptions DEFAULT; diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl index 4becccfc6d4b61967cd3ee56d149747cfd3046eb..9b11b960c58d3b279de879472d4a550627fd5c6b 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl @@ -30,6 +30,9 @@ interface IDumpstate { * * Returns a token used to monitor dumpstate death, or `nullptr` if the listener was already * set (the listener behaves like a Highlander: There Can be Only One). + * Set {@code getSectionDetails} to true in order to receive callbacks with per section + * progress details */ - IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener); + IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener, + boolean getSectionDetails); } diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl index 32717f4f87ee011c0f8ba50fda662bc98329ce2e..030d69d16e82c9c3614ddab60b8b0756efbc8947 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl @@ -24,4 +24,16 @@ package android.os; interface IDumpstateListener { 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/bugreport-format.md b/cmds/dumpstate/bugreport-format.md index b995b808c183ed821259e60b08ee812a368714a4..39e70d131b1d1705e6ece8654972375c4fd4815a 100644 --- a/cmds/dumpstate/bugreport-format.md +++ b/cmds/dumpstate/bugreport-format.md @@ -56,8 +56,37 @@ files upon the end user’s request: - `description.txt`: whose value is a multi-line, detailed description of the problem. ## Android O versions -On _Android O (OhMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made: -- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-1`). +On _Android O (Oreo)_, the following changes were made: +- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-split-anr`). + +## Version 2.0 (Android P) +On _Android P_, the following changes were made: +- Framework services are dumped by priority. Supported priorities can be specified + when registering the service. If a service does not specify its priority, its + assumed to be NORMAL. + Supported priorities: + - CRITICAL - services that must dump first, and fast (under 100ms). Ex: cpuinfo. + - HIGH - services that also must dump first, but can take longer (under 250ms) + to dump. Ex: meminfo. + - NORMAL - services that have no rush to dump and can take a long time (under 10s). + + Format changes: + - Two additional dumpsys sections are generated. The two new sections can be + identified by their HEADER `DUMPSYS CRITICAL` and `DUMPSYS HIGH`. + - Services in the new sections will have a new header containing the + priority. + `DUMP OF SERVICE CRITICAL ` and + `DUMP OF SERVICE HIGH `. + For example, cpuinfo will now move to `DUMPSYS CRITICAL` and will have a + header `DUMP OF SERVICE CRITICAL CPUINFO`. + +- Bug report will contain proto dumps from all supporting services. Support can be + specified when registering framework services. + Format changes: + - All protos will be generated into separate files per service, per priority. The files + will be stored in `proto/(_CRITICAL|_HIGH|).proto` + +- ANR trace feature has been pushed to version `3.0-dev-split-anr` ## Intermediate versions During development, the versions will be suffixed with _-devX_ or diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index d94c649b117dbe589dee0dbd7a8c5c911c6aa997..2b6241566cb134223fdb4541c06ce51208e2fa9d 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -25,41 +25,68 @@ #include #include #include +#include #include #include #include #include #include #include + +#include +#include +#include #include #include #include #include +#include #include #include #include +#include #include #include #include #include +#include #include #include +#include +#include #include #include #include - +#include +#include #include "DumpstateInternal.h" +#include "DumpstateSectionReporter.h" #include "DumpstateService.h" #include "dumpstate.h" using ::android::hardware::dumpstate::V1_0::IDumpstateDevice; +using ::std::literals::chrono_literals::operator""ms; +using ::std::literals::chrono_literals::operator""s; // TODO: remove once moved to namespace +using android::defaultServiceManager; +using android::Dumpsys; +using android::INVALID_OPERATION; +using android::IServiceManager; +using android::OK; +using android::sp; +using android::status_t; +using android::String16; +using android::String8; +using android::TIMED_OUT; +using android::UNKNOWN_ERROR; +using android::Vector; using android::os::dumpstate::CommandOptions; using android::os::dumpstate::DumpFileToFd; -using android::os::dumpstate::PropertiesHelper; +using android::os::dumpstate::DumpstateSectionReporter; using android::os::dumpstate::GetPidByName; +using android::os::dumpstate::PropertiesHelper; /* read before root is shed */ static char cmdline_buf[16384] = "(unknown)"; @@ -82,6 +109,7 @@ void add_mountinfo(); #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur" #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref" #define WLUTIL "/vendor/xbin/wlutil" +#define WMTRACE_DATA_DIR "/data/misc/wmtrace" // TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. @@ -100,8 +128,8 @@ static int RunCommand(const std::string& title, const std::vector& } static void RunDumpsys(const std::string& title, const std::vector& dumpsysArgs, const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS, - long dumpsysTimeout = 0) { - return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeout); + long dumpsysTimeoutMs = 0) { + return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs); } static int DumpFile(const std::string& title, const std::string& path) { return ds.DumpFile(title, path); @@ -112,14 +140,14 @@ static const std::string ZIP_ROOT_DIR = "FS"; // Must be hardcoded because dumpstate HAL implementation need SELinux access to it static const std::string kDumpstateBoardPath = "/bugreports/"; +static const std::string kProtoPath = "proto/"; +static const std::string kProtoExt = ".proto"; static const std::string kDumpstateBoardFiles[] = { "dumpstate_board.txt", "dumpstate_board.bin" }; static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles); -static const std::string kLsHalDebugPath = "/bugreports/dumpstate_lshal.txt"; - static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options"; static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id"; static constexpr char PROPERTY_VERSION[] = "dumpstate.version"; @@ -214,7 +242,7 @@ static bool AddDumps(const std::vector::const_iterator start, } if (ds.IsZipping() && add_to_zip) { - if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) { + if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) { MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str()); } } else { @@ -644,12 +672,18 @@ static int dump_stat_from_fd(const char *title __unused, const char *path, int f return 0; } -/* timeout in ms */ -static unsigned long logcat_timeout(const char *name) { - log_id_t id = android_name_to_log_id(name); - unsigned long property_size = __android_logger_get_buffer_size(id); - /* Engineering margin is ten-fold our guess */ - return 10 * (property_size + worst_write_perf) / worst_write_perf; +static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000; + +/* timeout in ms to read a list of buffers */ +static unsigned long logcat_timeout(const std::vector& buffers) { + unsigned long timeout_ms = 0; + for (const auto& buffer : buffers) { + log_id_t id = android_name_to_log_id(buffer.c_str()); + unsigned long property_size = __android_logger_get_buffer_size(id); + /* Engineering margin is ten-fold our guess */ + timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf; + } + return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS; } void Dumpstate::PrintHeader() const { @@ -678,7 +712,9 @@ void Dumpstate::PrintHeader() const { printf("Kernel: "); DumpFileToFd(STDOUT_FILENO, "", "/proc/version"); printf("Command line: %s\n", strtok(cmdline_buf, "\n")); - ds.RunCommand("UPTIME", {"uptime"}, CommandOptions::DEFAULT); + printf("Uptime: "); + RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"}, + CommandOptions::WithTimeout(1).Always().Build()); printf("Bugreport format version: %s\n", version_.c_str()); printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_, PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str()); @@ -693,11 +729,12 @@ static const std::set PROBLEMATIC_FILE_EXTENSIONS = { ".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh" }; -bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) { +status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd, + std::chrono::milliseconds timeout = 0ms) { if (!IsZipping()) { MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n", entry_name.c_str()); - return false; + return INVALID_OPERATION; } std::string valid_name = entry_name; @@ -719,32 +756,55 @@ bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) { if (err != 0) { MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(), ZipWriter::ErrorCodeString(err)); - return false; + return UNKNOWN_ERROR; } + auto start = std::chrono::steady_clock::now(); + auto end = start + timeout; + struct pollfd pfd = {fd, POLLIN}; std::vector buffer(65536); while (1) { + if (timeout.count() > 0) { + // lambda to recalculate the timeout. + auto time_left_ms = [end]() { + auto now = std::chrono::steady_clock::now(); + auto diff = std::chrono::duration_cast(end - now); + return std::max(diff.count(), 0LL); + }; + + int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms())); + if (rc < 0) { + MYLOGE("Error in poll while adding from fd to zip entry %s:%s", entry_name.c_str(), + strerror(errno)); + return -errno; + } else if (rc == 0) { + MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms", + entry_name.c_str(), strerror(errno), timeout.count()); + return TIMED_OUT; + } + } + ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size())); if (bytes_read == 0) { break; } else if (bytes_read == -1) { MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno)); - return false; + return -errno; } err = zip_writer_->WriteBytes(buffer.data(), bytes_read); if (err) { MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err)); - return false; + return UNKNOWN_ERROR; } } err = zip_writer_->FinishEntry(); if (err != 0) { MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err)); - return false; + return UNKNOWN_ERROR; } - return true; + return OK; } bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) { @@ -755,12 +815,12 @@ bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& en return false; } - return AddZipEntryFromFd(entry_name, fd.get()); + return (AddZipEntryFromFd(entry_name, fd.get()) == OK); } /* adds a file to the existing zipped bugreport */ static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) { - return ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) ? 0 : 1; + return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1; } void Dumpstate::AddDir(const std::string& dir, bool recursive) { @@ -816,41 +876,43 @@ static void DoKmsg() { } } +static void DoKernelLogcat() { + unsigned long timeout_ms = logcat_timeout({"kernel"}); + RunCommand( + "KERNEL LOG", + {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); +} + static void DoLogcat() { - unsigned long timeout; + unsigned long timeout_ms; // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags"); // calculate timeout - timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash"); - if (timeout < 20000) { - timeout = 20000; - } + timeout_ms = logcat_timeout({"main", "system", "crash"}); RunCommand("SYSTEM LOG", - {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", - "-d", "*:v"}, - CommandOptions::WithTimeout(timeout / 1000).Build()); - timeout = logcat_timeout("events"); - if (timeout < 20000) { - timeout = 20000; - } - RunCommand("EVENT LOG", - {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", - "-d", "*:v"}, - CommandOptions::WithTimeout(timeout / 1000).Build()); - timeout = logcat_timeout("radio"); - if (timeout < 20000) { - timeout = 20000; - } - RunCommand("RADIO LOG", - {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", - "-d", "*:v"}, - CommandOptions::WithTimeout(timeout / 1000).Build()); + {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); + timeout_ms = logcat_timeout({"events"}); + RunCommand( + "EVENT LOG", + {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, + 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()); + timeout_ms = logcat_timeout({"radio"}); + RunCommand( + "RADIO LOG", + {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"}); /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */ - RunCommand("LAST LOGCAT", - {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-v", "uid", - "-d", "*:v"}); + RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", + "-v", "uid", "-d", "*:v"}); } static void DumpIpTablesAsRoot() { @@ -968,11 +1030,191 @@ static void DumpIpAddrAndRules() { RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"}); } +static void RunDumpsysTextByPriority(const std::string& title, int priority, + std::chrono::milliseconds timeout, + std::chrono::milliseconds service_timeout) { + auto start = std::chrono::steady_clock::now(); + sp sm = defaultServiceManager(); + Dumpsys dumpsys(sm.get()); + Vector args; + Dumpsys::setServiceArgs(args, /* asProto = */ false, priority); + Vector services = dumpsys.listServices(priority, /* supports_proto = */ false); + for (const String16& service : services) { + 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(service, args); + if (status == OK) { + dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority); + std::chrono::duration 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::steady_clock::now() - start); + if (elapsed_duration > timeout) { + MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(), + elapsed_duration.count()); + break; + } + } +} + +static void RunDumpsysText(const std::string& title, int priority, + std::chrono::milliseconds timeout, + std::chrono::milliseconds service_timeout) { + DurationReporter duration_reporter(title); + dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str()); + fsync(STDOUT_FILENO); + RunDumpsysTextByPriority(title, priority, timeout, service_timeout); +} + +/* Dump all services registered with Normal or Default priority. */ +static void RunDumpsysTextNormalPriority(const std::string& title, + std::chrono::milliseconds timeout, + std::chrono::milliseconds service_timeout) { + DurationReporter duration_reporter(title); + dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str()); + fsync(STDOUT_FILENO); + RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout, + service_timeout); + RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout, + service_timeout); +} + +static void RunDumpsysProto(const std::string& title, int priority, + std::chrono::milliseconds timeout, + std::chrono::milliseconds service_timeout) { + if (!ds.IsZipping()) { + MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str()); + return; + } + sp sm = defaultServiceManager(); + Dumpsys dumpsys(sm.get()); + Vector args; + Dumpsys::setServiceArgs(args, /* asProto = */ true, priority); + DurationReporter duration_reporter(title); + + auto start = std::chrono::steady_clock::now(); + Vector services = dumpsys.listServices(priority, /* supports_proto = */ true); + for (const String16& service : services) { + std::string path(kProtoPath); + path.append(String8(service).c_str()); + if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) { + path.append("_CRITICAL"); + } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) { + path.append("_HIGH"); + } + path.append(kProtoExt); + 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); + dumpsys.stopDumpThread(dumpTerminated); + } + 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::steady_clock::now() - start); + if (elapsed_duration > timeout) { + MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(), + elapsed_duration.count()); + break; + } + } +} + +// Runs dumpsys on services that must dump first and and will take less than 100ms to dump. +static void RunDumpsysCritical() { + RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, + /* timeout= */ 5s, /* service_timeout= */ 500ms); + RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, + /* timeout= */ 5s, /* service_timeout= */ 500ms); +} + +// Runs dumpsys on services that must dump first but can take up to 250ms to dump. +static void RunDumpsysHigh() { + // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both + // high priority. Reduce timeout once they are able to dump in a shorter time or + // moved to a parallel task. + RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH, + /* timeout= */ 90s, /* service_timeout= */ 30s); + RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH, + /* timeout= */ 5s, /* service_timeout= */ 1s); +} + +// Runs dumpsys on services that must dump but can take up to 10s to dump. +static void RunDumpsysNormal() { + RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s); + RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, + /* timeout= */ 90s, /* service_timeout= */ 10s); +} + +static void DumpHals() { + using android::hidl::manager::V1_0::IServiceManager; + using android::hardware::defaultServiceManager; + + sp sm = defaultServiceManager(); + if (sm == nullptr) { + MYLOGE("Could not retrieve hwservicemanager to dump hals.\n"); + return; + } + + auto ret = sm->list([&](const auto& interfaces) { + for (const std::string& interface : interfaces) { + std::string cleanName = interface; + std::replace_if(cleanName.begin(), + cleanName.end(), + [](char c) { + return !isalnum(c) && + std::string("@-_:.").find(c) == std::string::npos; + }, '_'); + const std::string path = kDumpstateBoardPath + "lshal_debug_" + cleanName; + + { + 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 additional hal information.\n", path.c_str()); + continue; + } + RunCommandToFd(fd, + "", + {"lshal", "debug", "-E", interface}, + CommandOptions::WithTimeout(2).AsRootIfAvailable().Build()); + + bool empty = 0 == lseek(fd, 0, SEEK_END); + if (!empty) { + ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path); + } + } + + unlink(path.c_str()); + } + }); + + if (!ret.isOk()) { + MYLOGE("Could not list hals from hwservicemanager.\n"); + } +} + static void dumpstate() { DurationReporter duration_reporter("DUMPSTATE"); dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); - /* TODO: Remove duplicate uptime call when tools use it from header */ RunCommand("UPTIME", {"uptime"}); DumpBlockStatFiles(); dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd"); @@ -993,22 +1235,14 @@ static void dumpstate() { DumpFile("KERNEL SYNC", "/d/sync"); RunCommand("PROCESSES AND THREADS", - {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"}); + {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"}); RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT); if (ds.IsZipping()) { - RunCommand( - "HARDWARE HALS", - {"lshal", std::string("--debug=") + kLsHalDebugPath}, - CommandOptions::WithTimeout(10).AsRootIfAvailable().Build()); - - ds.AddZipEntry("lshal-debug.txt", kLsHalDebugPath); - - unlink(kLsHalDebugPath.c_str()); + RunCommand("HARDWARE HALS", {"lshal"}, CommandOptions::WithTimeout(2).AsRootIfAvailable().Build()); + DumpHals(); } else { - RunCommand( - "HARDWARE HALS", {"lshal", "--debug"}, - CommandOptions::WithTimeout(10).AsRootIfAvailable().Build()); + RunCommand("HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::WithTimeout(10).AsRootIfAvailable().Build()); } RunCommand("PRINTENV", {"printenv"}); @@ -1020,7 +1254,12 @@ static void dumpstate() { RunCommand("LSMOD", {"lsmod"}); } - do_dmesg(); + if (__android_logger_property_get_bool( + "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) { + DoKernelLogcat(); + } else { + do_dmesg(); + } RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT); for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES"); @@ -1059,15 +1298,11 @@ static void dumpstate() { RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"}); RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"}); - RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"}, - CommandOptions::WithTimeout(10).Build()); + RunDumpsysHigh(); RunCommand("SYSTEM PROPERTIES", {"getprop"}); - RunCommand("VOLD DUMP", {"vdc", "dump"}); - RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"}); - - RunCommand("STORAGED TASKIOINFO", {"storaged", "-u"}, CommandOptions::WithTimeout(10).Build()); + RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"}); RunCommand("FILESYSTEMS & FREE SPACE", {"df"}); @@ -1080,6 +1315,11 @@ static void dumpstate() { DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats"); DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state"); + /* Add window and surface trace files. */ + if (!PropertiesHelper::IsUserBuild()) { + ds.AddDir(WMTRACE_DATA_DIR, false); + } + ds.DumpstateBoard(); /* Migrate the ril_dumpstate to a device specific dumpstate? */ @@ -1100,8 +1340,7 @@ static void dumpstate() { printf("== Android Framework Services\n"); printf("========================================================\n"); - RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(), - 10); + RunDumpsysNormal(); printf("========================================================\n"); printf("== Checkins\n"); @@ -1118,19 +1357,40 @@ static void dumpstate() { printf("== Running Application Activities\n"); printf("========================================================\n"); - RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}); + // The following dumpsys internally collects output from running apps, so it can take a long + // time. So let's extend the timeout. + + const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build(); + + RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS); + + printf("========================================================\n"); + printf("== Running Application Services (platform)\n"); + printf("========================================================\n"); + + RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform"}, + DUMPSYS_COMPONENTS_OPTIONS); printf("========================================================\n"); - printf("== Running Application Services\n"); + printf("== Running Application Services (non-platform)\n"); printf("========================================================\n"); - RunDumpsys("APP SERVICES", {"activity", "service", "all"}); + RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"}, + DUMPSYS_COMPONENTS_OPTIONS); printf("========================================================\n"); - printf("== Running Application Providers\n"); + printf("== Running Application Providers (platform)\n"); printf("========================================================\n"); - RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"}); + RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"}, + DUMPSYS_COMPONENTS_OPTIONS); + + printf("========================================================\n"); + printf("== Running Application Providers (non-platform)\n"); + printf("========================================================\n"); + + RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"}, + DUMPSYS_COMPONENTS_OPTIONS); printf("========================================================\n"); printf("== Dropbox crashes\n"); @@ -1147,10 +1407,8 @@ static void dumpstate() { printf("========================================================\n"); } -// This method collects dumpsys for telephony debugging only -static void DumpstateTelephonyOnly() { - DurationReporter duration_reporter("DUMPSTATE"); - +// This method collects common dumpsys for telephony and wifi +static void DumpstateRadioCommon() { DumpIpTablesAsRoot(); if (!DropRootUser()) { @@ -1166,6 +1424,14 @@ static void DumpstateTelephonyOnly() { RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"}, CommandOptions::WithTimeout(10).Build()); +} + +// This method collects dumpsys for telephony debugging only +static void DumpstateTelephonyOnly() { + DurationReporter duration_reporter("DUMPSTATE"); + const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build(); + + DumpstateRadioCommon(); RunCommand("SYSTEM PROPERTIES", {"getprop"}); @@ -1173,8 +1439,14 @@ static void DumpstateTelephonyOnly() { printf("== Android Framework Services\n"); printf("========================================================\n"); - RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10); - RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10); + RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); + RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); + RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); + RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); printf("========================================================\n"); printf("== Running Application Services\n"); @@ -1182,6 +1454,33 @@ static void DumpstateTelephonyOnly() { RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"}); + printf("========================================================\n"); + printf("== Running Application Services (non-platform)\n"); + printf("========================================================\n"); + + RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"}, + DUMPSYS_COMPONENTS_OPTIONS); + + printf("========================================================\n"); + printf("== dumpstate: done (id %d)\n", ds.id_); + printf("========================================================\n"); +} + +// This method collects dumpsys for wifi debugging only +static void DumpstateWifiOnly() { + DurationReporter duration_reporter("DUMPSTATE"); + + DumpstateRadioCommon(); + + printf("========================================================\n"); + printf("== Android Framework Services\n"); + printf("========================================================\n"); + + RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); + RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); + printf("========================================================\n"); printf("== dumpstate: done (id %d)\n", ds.id_); printf("========================================================\n"); @@ -1193,77 +1492,112 @@ void Dumpstate::DumpstateBoard() { printf("== Board\n"); printf("========================================================\n"); - ::android::sp dumpstate_device(IDumpstateDevice::getService()); - if (dumpstate_device == nullptr) { - MYLOGE("No IDumpstateDevice implementation\n"); - return; - } - if (!IsZipping()) { MYLOGD("Not dumping board info because it's not a zipped bugreport\n"); return; } - std::string path[NUM_OF_DUMPS]; - android::base::unique_fd fd[NUM_OF_DUMPS]; - int numFds = 0; - + std::vector paths; + std::vector>> remover; for (int i = 0; i < NUM_OF_DUMPS; i++) { - path[i] = kDumpstateBoardPath + kDumpstateBoardFiles[i]; - MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path[i].c_str()); - - fd[i] = android::base::unique_fd( - TEMP_FAILURE_RETRY(open(path[i].c_str(), - O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))); - if (fd[i] < 0) { - MYLOGE("Could not open file %s: %s\n", path[i].c_str(), strerror(errno)); - return; - } else { - numFds++; - } + paths.emplace_back(kDumpstateBoardPath + kDumpstateBoardFiles[i]); + remover.emplace_back(android::base::make_scope_guard(std::bind( + [](std::string path) { + if (remove(path.c_str()) != 0 && errno != ENOENT) { + MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno)); + } + }, + paths[i]))); } - native_handle_t *handle = native_handle_create(numFds, 0); + sp dumpstate_device(IDumpstateDevice::getService()); + if (dumpstate_device == nullptr) { + MYLOGE("No IDumpstateDevice implementation\n"); + return; + } + + using ScopedNativeHandle = + std::unique_ptr>; + ScopedNativeHandle handle(native_handle_create(static_cast(paths.size()), 0), + [](native_handle_t* handle) { + native_handle_close(handle); + native_handle_delete(handle); + }); if (handle == nullptr) { MYLOGE("Could not create native_handle\n"); return; } - for (int i = 0; i < numFds; i++) { - handle->data[i] = fd[i].release(); - } + for (size_t i = 0; i < paths.size(); i++) { + MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str()); - // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call. - android::hardware::Return status = dumpstate_device->dumpstateBoard(handle); - if (!status.isOk()) { - MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str()); - native_handle_close(handle); - native_handle_delete(handle); - return; + android::base::unique_fd fd(TEMP_FAILURE_RETRY( + open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))); + if (fd < 0) { + MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno)); + return; + } + handle.get()->data[i] = fd.release(); + } + + // Given that bugreport is required to diagnose failures, it's better to + // set an arbitrary amount of timeout for IDumpstateDevice than to block the + // rest of bugreport. In the timeout case, we will kill dumpstate board HAL + // and grab whatever dumped + std::packaged_task + dumpstate_task([paths, dumpstate_device, &handle]() -> bool { + android::hardware::Return status = dumpstate_device->dumpstateBoard(handle.get()); + if (!status.isOk()) { + MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str()); + return false; + } + return true; + }); + + auto result = dumpstate_task.get_future(); + std::thread(std::move(dumpstate_task)).detach(); + + constexpr size_t timeout_sec = 30; + if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) { + MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec); + if (!android::base::SetProperty("ctl.interface_restart", + android::base::StringPrintf("%s/default", + IDumpstateDevice::descriptor))) { + MYLOGE("Couldn't restart dumpstate HAL\n"); + } + } + // Wait some time for init to kill dumpstate vendor HAL + constexpr size_t killing_timeout_sec = 10; + if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) { + MYLOGE("killing dumpstateBoard timed out after %zus, continue and " + "there might be racing in content\n", killing_timeout_sec); } - for (int i = 0; i < numFds; i++) { + auto file_sizes = std::make_unique(paths.size()); + for (size_t i = 0; i < paths.size(); i++) { struct stat s; - if (fstat(handle->data[i], &s) == -1) { - MYLOGE("Failed to fstat %s: %d\n", kDumpstateBoardFiles[i].c_str(), errno); - } else if (s.st_size > 0) { - AddZipEntry(kDumpstateBoardFiles[i], path[i]); - } else { - MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str()); + if (fstat(handle.get()->data[i], &s) == -1) { + MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(), + strerror(errno)); + file_sizes[i] = -1; + continue; } + file_sizes[i] = s.st_size; } - printf("*** See dumpstate-board.txt entry ***\n"); - - native_handle_close(handle); - native_handle_delete(handle); - - for (int i = 0; i < numFds; i++) { - if (remove(path[i].c_str()) != 0) { - MYLOGE("Could not remove(%s): %s\n", path[i].c_str(), strerror(errno)); + for (size_t i = 0; i < paths.size(); i++) { + if (file_sizes[i] == -1) { + continue; } + if (file_sizes[i] == 0) { + MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str()); + continue; + } + AddZipEntry(kDumpstateBoardFiles[i], paths[i]); } + + printf("*** See dumpstate-board.txt entry ***\n"); } static void ShowUsageAndExit(int exitCode = 1) { @@ -1294,20 +1628,8 @@ static void ExitOnInvalidArgs() { ShowUsageAndExit(); } -static void sig_handler(int) { - _exit(EXIT_FAILURE); -} - static void register_sig_handler() { - struct sigaction sa; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = sig_handler; - sigaction(SIGPIPE, &sa, NULL); // broken pipe - sigaction(SIGSEGV, &sa, NULL); // segment fault - sigaction(SIGINT, &sa, NULL); // ctrl-c - sigaction(SIGTERM, &sa, NULL); // killed - sigaction(SIGQUIT, &sa, NULL); // quit + signal(SIGPIPE, SIG_IGN); } bool Dumpstate::FinishZipFile() { @@ -1419,7 +1741,8 @@ static void Vibrate(int duration_ms) { // clang-format on } -int main(int argc, char *argv[]) { +/** Main entry point for dumpstate. */ +int run_main(int argc, char* argv[]) { int do_add_date = 0; int do_zip_file = 0; int do_vibrate = 1; @@ -1432,6 +1755,9 @@ int main(int argc, char *argv[]) { bool show_header_only = false; bool do_start_service = false; bool telephony_only = false; + bool wifi_only = false; + int dup_stdout_fd; + int dup_stderr_fd; /* set as high priority, and protect from OOM killer */ setpriority(PRIO_PROCESS, 0, -20); @@ -1500,8 +1826,12 @@ int main(int argc, char *argv[]) { } else if (ds.extra_options_ == "bugreportwear") { do_start_service = true; ds.update_progress_ = true; + do_zip_file = 1; } else if (ds.extra_options_ == "bugreporttelephony") { telephony_only = true; + } else if (ds.extra_options_ == "bugreportwifi") { + wifi_only = true; + do_zip_file = 1; } else { MYLOGE("Unknown extra option: %s\n", ds.extra_options_.c_str()); } @@ -1620,6 +1950,8 @@ int main(int argc, char *argv[]) { if (telephony_only) { ds.base_name_ += "-telephony"; + } else if (wifi_only) { + ds.base_name_ += "-wifi"; } if (do_fb) { @@ -1701,11 +2033,13 @@ int main(int argc, char *argv[]) { } if (is_redirecting) { + TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr))); redirect_to_file(stderr, const_cast(ds.log_path_.c_str())); if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", ds.log_path_.c_str(), strerror(errno)); } + TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout))); /* TODO: rather than generating a text file now and zipping it later, it would be more efficient to redirect stdout to the zip entry directly, but the libziparchive doesn't support that option yet. */ @@ -1727,6 +2061,8 @@ int main(int argc, char *argv[]) { if (telephony_only) { DumpstateTelephonyOnly(); ds.DumpstateBoard(); + } else if (wifi_only) { + DumpstateWifiOnly(); } else { // Dumps systrace right away, otherwise it will be filled with unnecessary events. // First try to dump anrd trace if the daemon is running. Otherwise, dump @@ -1737,10 +2073,7 @@ int main(int argc, char *argv[]) { // Invoking the following dumpsys calls before dump_traces() to try and // keep the system stats as close to its initial state as possible. - RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"}, - CommandOptions::WithTimeout(90).DropRoot().Build()); - RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"}, - CommandOptions::WithTimeout(10).DropRoot().Build()); + RunDumpsysCritical(); // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed. dump_raft(); @@ -1771,6 +2104,9 @@ int main(int argc, char *argv[]) { RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build()); + // Run iotop as root to show top 100 IO threads + RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"}); + if (!DropRootUser()) { return -1; } @@ -1780,7 +2116,7 @@ int main(int argc, char *argv[]) { /* close output if needed */ if (is_redirecting) { - fclose(stdout); + TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout))); } /* rename or zip the (now complete) .tmp file to its final location */ @@ -1913,7 +2249,7 @@ int main(int argc, char *argv[]) { MYLOGI("done (id %d)\n", ds.id_); if (is_redirecting) { - fclose(stderr); + TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr))); } if (use_control_socket && ds.control_socket_fd_ != -1) { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 69b0a5e014ae2c8656151e67faaa563ba49c3373..b220013f1774efdae30ac8f9a610d42d67ed0372 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -146,13 +146,13 @@ class Progress { * * See bugreport-format.md for more info. */ -static std::string VERSION_CURRENT = "1.0"; +static std::string VERSION_CURRENT = "2.0"; /* * Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version - * will be bumped to 2.0-dev-1. + * will be bumped to 3.0. */ -static std::string VERSION_SPLIT_ANR = "2.0-dev-1"; +static std::string VERSION_SPLIT_ANR = "3.0-dev-split-anr"; /* * "Alias" for the current version. @@ -205,19 +205,19 @@ class Dumpstate { /* * Runs `dumpsys` with the given arguments, automatically setting its timeout - * (`-t` argument) + * (`-T` argument) * according to the command options. * * |title| description of the command printed on `stdout` (or empty to skip * description). * |dumpsys_args| `dumpsys` arguments (except `-t`). * |options| optional argument defining the command's behavior. - * |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -t` (otherwise it uses the + * |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -T` (otherwise it uses the * timeout from `options`) */ void RunDumpsys(const std::string& title, const std::vector& dumpsys_args, const android::os::dumpstate::CommandOptions& options = DEFAULT_DUMPSYS, - long dumpsys_timeout = 0); + long dumpsys_timeout_ms = 0); /* * Prints the contents of a file. @@ -235,8 +235,14 @@ class Dumpstate { /* * Adds a new entry to the existing zip file. + * + * |entry_name| destination path of the new entry. + * |fd| file descriptor to read from. + * |timeout| timeout to terminate the read if not completed. Set + * value of 0s (default) to disable timeout. */ - bool AddZipEntryFromFd(const std::string& entry_name, int fd); + android::status_t AddZipEntryFromFd(const std::string& entry_name, int fd, + std::chrono::milliseconds timeout); /* * Adds a text entry entry to the existing zip file. @@ -281,6 +287,9 @@ class Dumpstate { /* Gets the path of a bugreport file with the given suffix. */ std::string GetPath(const std::string& suffix) const; + /* Returns true if the current version supports priority dump feature. */ + bool CurrentVersionSupportsPriorityDumps() const; + // TODO: initialize fields on constructor // dumpstate id - unique after each device reboot. @@ -347,9 +356,10 @@ class Dumpstate { // Pointer to the zip structure. std::unique_ptr zip_writer_; - // Binder object listing to progress. + // Binder object listening to progress. android::sp listener_; std::string listener_name_; + bool report_section_; // Notification title and description std::string notification_title; @@ -445,6 +455,9 @@ void dump_emmc_ecsd(const char *ext_csd_path); /** Gets command-line arguments. */ void format_args(int argc, const char *argv[], std::string *args); +/** Main entry point for dumpstate. */ +int run_main(int argc, char* argv[]); + #ifdef __cplusplus } #endif diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/cmds/dumpstate/main.cpp similarity index 72% rename from vulkan/libvulkan/vulkan_loader_data.cpp rename to cmds/dumpstate/main.cpp index 0eda0af59a1f55fb3cb1aa7a1312b3af11ff1724..78aad1137b649fbf590176924f0fc7adb80fad3c 100644 --- a/vulkan/libvulkan/vulkan_loader_data.cpp +++ b/cmds/dumpstate/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015 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,11 +14,8 @@ * limitations under the License. */ -#include +#include "dumpstate.h" -using namespace vulkan; - -LoaderData& LoaderData::GetInstance() { - static LoaderData loader_data = {}; - return loader_data; +int main(int argc, char* argv[]) { + return run_main(argc, argv); } diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..61a5ef5b7dd9f29cf78974ecd0eb92159a3ebf48 --- /dev/null +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -0,0 +1,286 @@ +/* + * 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 +#include + +#include +#include + +#include +#include +#include + +#include "dumpstate.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +namespace android { +namespace os { +namespace dumpstate { + +using ::testing::Test; +using ::std::literals::chrono_literals::operator""s; + +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. + */ +class DumpstateListener : public IDumpstateListener { + public: + int outFd_, max_progress_; + std::shared_ptr> sections_; + DumpstateListener(int fd, std::shared_ptr> sections) + : outFd_(fd), max_progress_(5000), sections_(sections) { + } + binder::Status onProgressUpdated(int32_t progress) override { + dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_); + return binder::Status::ok(); + } + binder::Status onMaxProgressUpdated(int32_t max_progress) override { + 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 { + sections_->push_back({name, status, size_bytes, duration_ms}); + return binder::Status::ok(); + } + IBinder* onAsBinder() override { + return nullptr; + } +}; + +/** + * Generates bug report and provide access to the bug report file and other info for other tests. + * Since bug report generation is slow, the bugreport is only generated once. + */ +class ZippedBugreportGenerationTest : public Test { + public: + static std::shared_ptr> sections; + static Dumpstate& ds; + static std::chrono::milliseconds duration; + static void SetUpTestCase() { + property_set("dumpstate.options", "bugreportplus"); + // clang-format off + char* argv[] = { + (char*)"dumpstate", + (char*)"-d", + (char*)"-z", + (char*)"-B", + (char*)"-o", + (char*)dirname(android::base::GetExecutablePath().c_str()) + }; + // clang-format on + sp listener(new DumpstateListener(dup(fileno(stdout)), sections)); + ds.listener_ = listener; + ds.listener_name_ = "Smokey"; + ds.report_section_ = true; + auto start = std::chrono::steady_clock::now(); + run_main(ARRAY_SIZE(argv), argv); + auto end = std::chrono::steady_clock::now(); + duration = std::chrono::duration_cast(end - start); + } + + static const char* getZipFilePath() { + return ds.GetPath(".zip").c_str(); + } +}; +std::shared_ptr> ZippedBugreportGenerationTest::sections = + std::make_shared>(); +Dumpstate& ZippedBugreportGenerationTest::ds = Dumpstate::GetInstance(); +std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s; + +TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) { + EXPECT_EQ(access(getZipFilePath(), F_OK), 0); +} + +TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) { + struct stat st; + EXPECT_EQ(stat(getZipFilePath(), &st), 0); + EXPECT_GE(st.st_size, 3000000 /* 3MB */); + EXPECT_LE(st.st_size, 30000000 /* 30MB */); +} + +TEST_F(ZippedBugreportGenerationTest, TakesBetween30And150Seconds) { + EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time " + << duration.count() << " s."; + EXPECT_LE(duration, 150s) << "Expected completion in less than 150s. Actual time " + << duration.count() << " s."; +} + +/** + * Run tests on contents of zipped bug report. + */ +class ZippedBugReportContentsTest : public Test { + public: + ZipArchiveHandle handle; + void SetUp() { + ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath(), &handle), 0); + } + void TearDown() { + CloseArchive(handle); + } + + void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) { + ZipEntry 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 mainEntryLoc; + // contains main entry name file + EXPECT_EQ(FindEntry(handle, ZipString("main_entry.txt"), &mainEntryLoc), 0); + + char* buf = new char[mainEntryLoc.uncompressed_length]; + ExtractToMemory(handle, &mainEntryLoc, (uint8_t*)buf, mainEntryLoc.uncompressed_length); + delete[] buf; + + // contains main entry file + FileExists(buf, 1000000U, 50000000U); +} + +TEST_F(ZippedBugReportContentsTest, ContainsVersion) { + ZipEntry entry; + // contains main entry name file + 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); + buf[entry.uncompressed_length] = 0; + EXPECT_STREQ(buf, ZippedBugreportGenerationTest::ds.version_.c_str()); + delete[] buf; +} + +TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) { + FileExists("dumpstate_board.bin", 1000000U, 80000000U); + FileExists("dumpstate_board.txt", 100000U, 1000000U); +} + +// Spot check on some files pulled from the file system +TEST_F(ZippedBugReportContentsTest, ContainsSomeFileSystemFiles) { + // FS/proc/*/mountinfo size > 0 + FileExists("FS/proc/1/mountinfo", 0U, 100000U); + + // FS/data/misc/profiles/cur/0/*/primary.prof size > 0 + FileExists("FS/data/misc/profiles/cur/0/com.android.phone/primary.prof", 0U, 100000U); +} + +/** + * Runs tests on section data generated by dumpstate and captured by DumpstateListener. + */ +class BugreportSectionTest : public Test { + public: + int numMatches(const std::string& substring) { + int matches = 0; + for (auto const& section : *ZippedBugreportGenerationTest::sections) { + if (section.name.find(substring) != std::string::npos) { + matches++; + } + } + 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); + return; + } + } + FAIL() << sectionName << " not found."; + } +}; + +// 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("DUMPSYS CRITICAL"); + EXPECT_GE(numSections, 3); +} + +TEST_F(BugreportSectionTest, Atleast2HighDumpsysSectionsGenerated) { + int numSections = numMatches("DUMPSYS HIGH"); + EXPECT_GE(numSections, 2); +} + +TEST_F(BugreportSectionTest, Atleast50NormalDumpsysSectionsGenerated) { + 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("DUMPSYS CRITICAL - SurfaceFlinger", /* bytes= */ 10000); +} + +TEST_F(BugreportSectionTest, ActivitySectionsGenerated) { + SectionExists("DUMPSYS CRITICAL - activity", /* bytes= */ 5000); + SectionExists("DUMPSYS - activity", /* bytes= */ 10000); +} + +TEST_F(BugreportSectionTest, CpuinfoSectionGenerated) { + SectionExists("DUMPSYS CRITICAL - cpuinfo", /* bytes= */ 1000); +} + +TEST_F(BugreportSectionTest, WindowSectionGenerated) { + SectionExists("DUMPSYS CRITICAL - window", /* bytes= */ 20000); +} + +TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) { + SectionExists("DUMPSYS HIGH - connectivity", /* bytes= */ 5000); + SectionExists("DUMPSYS - connectivity", /* bytes= */ 5000); +} + +TEST_F(BugreportSectionTest, MeminfoSectionGenerated) { + SectionExists("DUMPSYS HIGH - meminfo", /* bytes= */ 100000); +} + +TEST_F(BugreportSectionTest, BatteryStatsSectionGenerated) { + SectionExists("DUMPSYS - batterystats", /* bytes= */ 1000); +} + +TEST_F(BugreportSectionTest, WifiSectionGenerated) { + SectionExists("DUMPSYS - wifi", /* bytes= */ 100000); +} + +} // namespace dumpstate +} // namespace os +} // namespace android diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 92b0c0d8bc7abef61b44b62124c3dbfd768359c9..838b385b1b6b97c7ff73936f8cb6e2f715a9c910 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -58,6 +58,8 @@ class DumpstateListenerMock : public IDumpstateListener { public: 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*()); @@ -601,27 +603,43 @@ class DumpstateServiceTest : public DumpstateBaseTest { TEST_F(DumpstateServiceTest, SetListenerNoName) { sp listener(new DumpstateListenerMock()); sp token; - EXPECT_TRUE(dss.setListener("", listener, &token).isOk()); + EXPECT_TRUE(dss.setListener("", listener, /* getSectionDetails = */ false, &token).isOk()); ASSERT_THAT(token, IsNull()); } TEST_F(DumpstateServiceTest, SetListenerNoPointer) { sp token; - EXPECT_TRUE(dss.setListener("whatever", nullptr, &token).isOk()); + EXPECT_TRUE( + dss.setListener("whatever", nullptr, /* getSectionDetails = */ false, &token).isOk()); ASSERT_THAT(token, IsNull()); } TEST_F(DumpstateServiceTest, SetListenerTwice) { sp listener(new DumpstateListenerMock()); sp token; - EXPECT_TRUE(dss.setListener("whatever", listener, &token).isOk()); + EXPECT_TRUE( + dss.setListener("whatever", listener, /* getSectionDetails = */ false, &token).isOk()); ASSERT_THAT(token, NotNull()); EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever")); + EXPECT_FALSE(Dumpstate::GetInstance().report_section_); token.clear(); - EXPECT_TRUE(dss.setListener("whatsoever", listener, &token).isOk()); + EXPECT_TRUE( + dss.setListener("whatsoever", listener, /* getSectionDetails = */ false, &token).isOk()); ASSERT_THAT(token, IsNull()); EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever")); + EXPECT_FALSE(Dumpstate::GetInstance().report_section_); +} + +TEST_F(DumpstateServiceTest, SetListenerWithSectionDetails) { + sp listener(new DumpstateListenerMock()); + sp token; + Dumpstate::GetInstance().listener_ = nullptr; + EXPECT_TRUE( + dss.setListener("whatever", listener, /* getSectionDetails = */ true, &token).isOk()); + ASSERT_THAT(token, NotNull()); + EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever")); + EXPECT_TRUE(Dumpstate::GetInstance().report_section_); } class ProgressTest : public DumpstateBaseTest { @@ -1001,7 +1019,7 @@ TEST_F(DumpstateUtilTest, RunCommandCrashes) { err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code")); } -TEST_F(DumpstateUtilTest, RunCommandTimesout) { +TEST_F(DumpstateUtilTest, RunCommandTimesoutWithSec) { CreateFd("RunCommandTimesout.txt"); EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"}, CommandOptions::WithTimeout(1).Build())); @@ -1011,6 +1029,17 @@ TEST_F(DumpstateUtilTest, RunCommandTimesout) { " --sleep 2' timed out after 1")); } +TEST_F(DumpstateUtilTest, RunCommandTimesoutWithMsec) { + CreateFd("RunCommandTimesout.txt"); + EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"}, + CommandOptions::WithTimeoutInMs(1000).Build())); + EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand + + " --sleep 2' timed out after 1")); + EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand + + " --sleep 2' timed out after 1")); +} + + TEST_F(DumpstateUtilTest, RunCommandIsKilled) { CreateFd("RunCommandIsKilled.txt"); CaptureStderr(); diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp index 6b808e36ad322f9a829ff41b0f65a8031a4d1df3..9beff989dfb240823064cf8c0dfc661ee6908409 100644 --- a/cmds/dumpstate/utils.cpp +++ b/cmds/dumpstate/utils.cpp @@ -48,10 +48,10 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -76,36 +76,6 @@ static int RunCommand(const std::string& title, const std::vector& return ds.RunCommand(title, full_command, options); } -/* list of native processes to include in the native dumps */ -// This matches the /proc/pid/exe link instead of /proc/pid/cmdline. -static const char* native_processes_to_dump[] = { - "/system/bin/audioserver", - "/system/bin/cameraserver", - "/system/bin/drmserver", - "/system/bin/mediadrmserver", - "/system/bin/mediaextractor", // media.extractor - "/system/bin/mediametrics", // media.metrics - "/system/bin/mediaserver", - "/system/bin/sdcard", - "/system/bin/statsd", - "/system/bin/surfaceflinger", - "/system/bin/vehicle_network_service", - "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec - NULL, -}; - -/* list of hal interface to dump containing process during native dumps */ -static const char* hal_interfaces_to_dump[] { - "android.hardware.audio@2.0::IDevicesFactory", - "android.hardware.bluetooth@1.0::IBluetoothHci", - "android.hardware.camera.provider@2.4::ICameraProvider", - "android.hardware.graphics.composer@2.1::IComposer", - "android.hardware.media.omx@1.0::IOmx", - "android.hardware.sensors@1.0::ISensors", - "android.hardware.vr@1.0::IVr", - NULL, -}; - // Reasonable value for max stats. static const int STATS_MAX_N_RUNS = 1000; static const long STATS_MAX_AVERAGE = 100000; @@ -217,10 +187,10 @@ int32_t Progress::Get() const { return progress_; } -bool Progress::Inc(int32_t delta) { +bool Progress::Inc(int32_t delta_sec) { bool changed = false; - if (delta >= 0) { - progress_ += delta; + if (delta_sec >= 0) { + progress_ += delta_sec; if (progress_ > max_) { int32_t old_max = max_; max_ = floor((float)progress_ * growth_factor_); @@ -721,9 +691,9 @@ int Dumpstate::RunCommand(const std::string& title, const std::vector& dumpsys_args, - const CommandOptions& options, long dumpsysTimeout) { - long timeout = dumpsysTimeout > 0 ? dumpsysTimeout : options.Timeout(); - std::vector dumpsys = {"/system/bin/dumpsys", "-t", std::to_string(timeout)}; + const CommandOptions& options, long dumpsysTimeoutMs) { + long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs(); + std::vector dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)}; dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end()); RunCommand(title, dumpsys, options); } @@ -809,71 +779,11 @@ void redirect_to_existing_file(FILE *redirect, char *path) { _redirect_to_file(redirect, path, O_APPEND); } -static bool should_dump_hal_interface(const char* interface) { - for (const char** i = hal_interfaces_to_dump; *i; i++) { - if (!strcmp(*i, interface)) { - return true; - } - } - return false; -} - -static bool should_dump_native_traces(const char* path) { - for (const char** p = native_processes_to_dump; *p; p++) { - if (!strcmp(*p, path)) { - return true; - } - } - return false; -} - -std::set get_interesting_hal_pids() { - using android::hidl::manager::V1_0::IServiceManager; - using android::sp; - using android::hardware::Return; - - sp manager = IServiceManager::getService(); - std::set pids; - - Return ret = manager->debugDump([&](auto& hals) { - for (const auto &info : hals) { - if (info.pid == static_cast(IServiceManager::PidConstant::NO_PID)) { - continue; - } - - if (!should_dump_hal_interface(info.interfaceName.c_str())) { - continue; - } - - pids.insert(info.pid); - } - }); - - if (!ret.isOk()) { - MYLOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str()); - } - - return pids; // whether it was okay or not -} - -static bool IsZygote(int pid) { - static const std::string kZygotePrefix = "zygote"; - - std::string cmdline; - if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid), - &cmdline)) { - return true; - } - - return (cmdline.find(kZygotePrefix) == 0); -} - // Dump Dalvik and native stack traces, return the trace file location (nullptr if none). const char* dump_traces() { DurationReporter duration_reporter("DUMP TRACES"); const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX"; - const size_t buf_size = temp_file_pattern.length() + 1; std::unique_ptr file_name_buf(new char[buf_size]); memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size); @@ -996,14 +906,14 @@ void dump_route_tables() { } // TODO: make this function thread safe if sections are generated in parallel. -void Dumpstate::UpdateProgress(int32_t delta) { +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); + bool max_changed = progress_->Inc(delta_sec); // ...but only notifiy listeners when necessary. if (!update_progress_) return; diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp index 34769644d5fcca17883ecb8597c3a63018e2aaba..f68b862f249251108587d149e5a2d2f345eae3ea 100644 --- a/cmds/dumpsys/Android.bp +++ b/cmds/dumpsys/Android.bp @@ -17,6 +17,10 @@ cc_defaults { "libbinder", ], + static_libs: [ + "libserviceutils", + ], + clang: true, } diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index 32277499a6e0f2675929ce434186d9a274518883..5412d4df7b7e7041d253851fd295e86bff53c588 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -42,9 +43,11 @@ #include "dumpsys.h" using namespace android; -using android::base::StringPrintf; -using android::base::unique_fd; -using android::base::WriteFully; +using ::android::base::StringAppendF; +using ::android::base::StringPrintf; +using ::android::base::unique_fd; +using ::android::base::WriteFully; +using ::android::base::WriteStringToFd; static int sort_func(const String16* lhs, const String16* rhs) { @@ -53,13 +56,19 @@ static int sort_func(const String16* lhs, const String16* rhs) static void usage() { fprintf(stderr, - "usage: dumpsys\n" + "usage: dumpsys\n" " To dump all services.\n" "or:\n" - " dumpsys [-t TIMEOUT] [--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: TIMEOUT to use in seconds instead of default 10 seconds\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" + " --proto: filter services that support dumping data in proto format. Dumps" + " will be in proto format.\n" + " --priority LEVEL: filter services based on specified priority\n" + " LEVEL must be one of CRITICAL | HIGH | NORMAL\n" " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n" " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n"); } @@ -73,18 +82,51 @@ static bool IsSkipped(const Vector& skipped, const String16& service) return false; } +static bool ConvertPriorityTypeToBitmask(const String16& type, int& bitmask) { + if (type == PriorityDumper::PRIORITY_ARG_CRITICAL) { + bitmask = IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL; + return true; + } + if (type == PriorityDumper::PRIORITY_ARG_HIGH) { + bitmask = IServiceManager::DUMP_FLAG_PRIORITY_HIGH; + return true; + } + if (type == PriorityDumper::PRIORITY_ARG_NORMAL) { + bitmask = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL; + return true; + } + return false; +} + +String16 ConvertBitmaskToPriorityType(int bitmask) { + if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) { + return String16(PriorityDumper::PRIORITY_ARG_CRITICAL); + } + if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) { + return String16(PriorityDumper::PRIORITY_ARG_HIGH); + } + if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) { + return String16(PriorityDumper::PRIORITY_ARG_NORMAL); + } + return String16(""); +} + int Dumpsys::main(int argc, char* const argv[]) { Vector services; Vector args; + String16 priorityType; Vector skippedServices; + Vector protoServices; bool showListOnly = false; bool skipServices = false; - int timeoutArg = 10; - static struct option longOptions[] = { - {"skip", no_argument, 0, 0 }, - {"help", no_argument, 0, 0 }, - { 0, 0, 0, 0 } - }; + bool asProto = false; + int timeoutArgMs = 10000; + int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL; + static struct option longOptions[] = {{"priority", required_argument, 0, 0}, + {"proto", no_argument, 0, 0}, + {"skip", no_argument, 0, 0}, + {"help", no_argument, 0, 0}, + {0, 0, 0, 0}}; // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but // happens on test cases). @@ -93,7 +135,7 @@ int Dumpsys::main(int argc, char* const argv[]) { int c; int optionIndex = 0; - c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex); + c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex); if (c == -1) { break; @@ -103,18 +145,39 @@ int Dumpsys::main(int argc, char* const argv[]) { case 0: if (!strcmp(longOptions[optionIndex].name, "skip")) { skipServices = true; + } else if (!strcmp(longOptions[optionIndex].name, "proto")) { + asProto = true; } else if (!strcmp(longOptions[optionIndex].name, "help")) { usage(); return 0; + } else if (!strcmp(longOptions[optionIndex].name, "priority")) { + priorityType = String16(String8(optarg)); + if (!ConvertPriorityTypeToBitmask(priorityType, priorityFlags)) { + fprintf(stderr, "\n"); + usage(); + return -1; + } } break; case 't': { - char *endptr; - timeoutArg = strtol(optarg, &endptr, 10); - if (*endptr != '\0' || timeoutArg <= 0) { - fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg); + char* endptr; + timeoutArgMs = strtol(optarg, &endptr, 10); + timeoutArgMs = timeoutArgMs * 1000; + if (*endptr != '\0' || timeoutArgMs <= 0) { + fprintf(stderr, "Error: invalid timeout(seconds) number: '%s'\n", optarg); + return -1; + } + } + break; + + case 'T': + { + char* endptr; + timeoutArgMs = strtol(optarg, &endptr, 10); + if (*endptr != '\0' || timeoutArgMs <= 0) { + fprintf(stderr, "Error: invalid timeout(milliseconds) number: '%s'\n", optarg); return -1; } } @@ -150,14 +213,11 @@ int Dumpsys::main(int argc, char* const argv[]) { } if (services.empty() || showListOnly) { - // gets all services - services = sm_->listServices(); - services.sort(sort_func); - args.add(String16("-a")); + services = listServices(priorityFlags, asProto); + setServiceArgs(args, asProto, priorityFlags); } const size_t N = services.size(); - if (N > 1) { // first print a list of the current services aout << "Currently running services:" << endl; @@ -177,125 +237,214 @@ int Dumpsys::main(int argc, char* const argv[]) { } for (size_t i = 0; i < N; i++) { - const String16& service_name = std::move(services[i]); - if (IsSkipped(skippedServices, service_name)) continue; - - sp service = sm_->checkService(service_name); - if (service != nullptr) { - int sfd[2]; + const String16& serviceName = services[i]; + if (IsSkipped(skippedServices, serviceName)) continue; - if (pipe(sfd) != 0) { - aerr << "Failed to create pipe to dump service info for " << service_name - << ": " << strerror(errno) << endl; - continue; + if (startDumpThread(serviceName, args) == OK) { + bool addSeparator = (N > 1); + if (addSeparator) { + writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags); } + std::chrono::duration elapsedDuration; + size_t bytesWritten = 0; + status_t status = + writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(timeoutArgMs), + asProto, elapsedDuration, bytesWritten); - unique_fd local_end(sfd[0]); - unique_fd remote_end(sfd[1]); - sfd[0] = sfd[1] = -1; + if (status == TIMED_OUT) { + aout << endl + << "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs + << "ms) EXPIRED ***" << endl + << endl; + } - if (N > 1) { - aout << "------------------------------------------------------------" - "-------------------" << endl; - aout << "DUMP OF SERVICE " << service_name << ":" << endl; + if (addSeparator) { + writeDumpFooter(STDOUT_FILENO, serviceName, elapsedDuration); } + bool dumpComplete = (status == OK); + stopDumpThread(dumpComplete); + } + } - // dump blocks until completion, so spawn a thread.. - std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable { - int err = service->dump(remote_end.get(), args); + return 0; +} - // 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(); +Vector Dumpsys::listServices(int priorityFilterFlags, bool filterByProto) const { + Vector services = sm_->listServices(priorityFilterFlags); + services.sort(sort_func); + if (filterByProto) { + Vector protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO); + protoServices.sort(sort_func); + Vector intersection; + std::set_intersection(services.begin(), services.end(), protoServices.begin(), + protoServices.end(), std::back_inserter(intersection)); + services = std::move(intersection); + } + return services; +} - if (err != 0) { - aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name - << endl; - } - }); - - auto timeout = std::chrono::seconds(timeoutArg); - auto start = std::chrono::steady_clock::now(); - auto end = start + timeout; - - struct pollfd pfd = { - .fd = local_end.get(), - .events = POLLIN - }; - - bool timed_out = false; - bool error = false; - while (true) { - // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout. - auto time_left_ms = [end]() { - auto now = std::chrono::steady_clock::now(); - auto diff = std::chrono::duration_cast(end - now); - return std::max(diff.count(), 0ll); - }; - - int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms())); - if (rc < 0) { - aerr << "Error in poll while dumping service " << service_name << " : " - << strerror(errno) << endl; - error = true; - break; - } else if (rc == 0) { - timed_out = true; - break; - } +void Dumpsys::setServiceArgs(Vector& args, bool asProto, int priorityFlags) { + // Add proto flag if dumping service as proto. + if (asProto) { + args.insertAt(String16(PriorityDumper::PROTO_ARG), 0); + } - char buf[4096]; - rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf))); - if (rc < 0) { - aerr << "Failed to read while dumping service " << service_name << ": " - << strerror(errno) << endl; - error = true; - break; - } else if (rc == 0) { - // EOF. - break; - } + // Add -a (dump all) flag if dumping all services, dumping normal services or + // services not explicitly registered to a priority bucket (default services). + if ((priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) || + (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) || + (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT)) { + args.insertAt(String16("-a"), 0); + } - if (!WriteFully(STDOUT_FILENO, buf, rc)) { - aerr << "Failed to write while dumping service " << service_name << ": " - << strerror(errno) << endl; - error = true; - break; - } - } + // Add priority flags when dumping services registered to a specific priority bucket. + if ((priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) || + (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) || + (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL)) { + String16 priorityType = ConvertBitmaskToPriorityType(priorityFlags); + args.insertAt(String16(PriorityDumper::PRIORITY_ARG), 0); + args.insertAt(priorityType, 1); + } +} - if (timed_out) { - aout << endl - << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArg - << "s) EXPIRED ***" << endl - << endl; - } +status_t Dumpsys::startDumpThread(const String16& serviceName, const Vector& args) { + sp service = sm_->checkService(serviceName); + if (service == nullptr) { + aerr << "Can't find service: " << serviceName << endl; + return NAME_NOT_FOUND; + } - if (timed_out || error) { - dump_thread.detach(); - } else { - dump_thread.join(); - } + int sfd[2]; + if (pipe(sfd) != 0) { + aerr << "Failed to create pipe to dump service info for " << serviceName << ": " + << strerror(errno) << endl; + return -errno; + } - if (N > 1) { - std::chrono::duration elapsed_seconds = - std::chrono::steady_clock::now() - start; - aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str() - << "was the duration of dumpsys " << service_name; - - using std::chrono::system_clock; - const auto finish = system_clock::to_time_t(system_clock::now()); - std::tm finish_tm; - localtime_r(&finish, &finish_tm); - aout << ", ending at: " << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S") - << endl; - } - } else { - aerr << "Can't find service: " << service_name << endl; + redirectFd_ = unique_fd(sfd[0]); + unique_fd remote_end(sfd[1]); + sfd[0] = sfd[1] = -1; + + // dump blocks until completion, so spawn a thread.. + activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable { + int err = service->dump(remote_end.get(), args); + + // 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 != 0) { + aerr << "Error dumping service info: (" << strerror(err) << ") " + << serviceName << endl; } + }); + return OK; +} + +void Dumpsys::stopDumpThread(bool dumpComplete) { + if (dumpComplete) { + activeThread_.join(); + } else { + activeThread_.detach(); } + /* close read end of the dump output redirection pipe */ + redirectFd_.reset(); +} - return 0; +void Dumpsys::writeDumpHeader(int fd, const String16& serviceName, int priorityFlags) const { + std::string msg( + "----------------------------------------" + "---------------------------------------\n"); + if (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL || + priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL || + priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) { + StringAppendF(&msg, "DUMP OF SERVICE %s:\n", String8(serviceName).c_str()); + } else { + String16 priorityType = ConvertBitmaskToPriorityType(priorityFlags); + StringAppendF(&msg, "DUMP OF SERVICE %s %s:\n", String8(priorityType).c_str(), + String8(serviceName).c_str()); + } + WriteStringToFd(msg, fd); +} + +status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout, + bool asProto, std::chrono::duration& elapsedDuration, + size_t& bytesWritten) const { + status_t status = OK; + size_t totalBytes = 0; + auto start = std::chrono::steady_clock::now(); + auto end = start + timeout; + + int serviceDumpFd = redirectFd_.get(); + if (serviceDumpFd == -1) { + return INVALID_OPERATION; + } + + struct pollfd pfd = {.fd = serviceDumpFd, .events = POLLIN}; + + while (true) { + // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout. + auto time_left_ms = [end]() { + auto now = std::chrono::steady_clock::now(); + auto diff = std::chrono::duration_cast(end - now); + return std::max(diff.count(), 0ll); + }; + + int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms())); + if (rc < 0) { + aerr << "Error in poll while dumping service " << serviceName << " : " + << strerror(errno) << endl; + status = -errno; + break; + } else if (rc == 0) { + status = TIMED_OUT; + break; + } + + char buf[4096]; + rc = TEMP_FAILURE_RETRY(read(redirectFd_.get(), buf, sizeof(buf))); + if (rc < 0) { + aerr << "Failed to read while dumping service " << serviceName << ": " + << strerror(errno) << endl; + status = -errno; + break; + } else if (rc == 0) { + // EOF. + break; + } + + if (!WriteFully(fd, buf, rc)) { + aerr << "Failed to write while dumping service " << serviceName << ": " + << strerror(errno) << endl; + status = -errno; + break; + } + totalBytes += rc; + } + + if ((status == TIMED_OUT) && (!asProto)) { + std::string msg = StringPrintf("\n*** SERVICE '%s' DUMP TIMEOUT (%llums) EXPIRED ***\n\n", + String8(serviceName).string(), timeout.count()); + WriteStringToFd(msg, fd); + } + + elapsedDuration = std::chrono::steady_clock::now() - start; + bytesWritten = totalBytes; + return status; +} + +void Dumpsys::writeDumpFooter(int fd, const String16& serviceName, + const std::chrono::duration& elapsedDuration) const { + using std::chrono::system_clock; + const auto finish = system_clock::to_time_t(system_clock::now()); + std::tm finish_tm; + localtime_r(&finish, &finish_tm); + std::stringstream oss; + oss << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S"); + std::string msg = + StringPrintf("--------- %.3fs was the duration of dumpsys %s, ending at: %s\n", + elapsedDuration.count(), String8(serviceName).string(), oss.str().c_str()); + WriteStringToFd(msg, fd); } diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h index 2534dded131b95bc4b5d689bb6825180a5e5b525..84f3b0236e02baa10b10707be325a0ccaf52e469 100644 --- a/cmds/dumpsys/dumpsys.h +++ b/cmds/dumpsys/dumpsys.h @@ -17,6 +17,9 @@ #ifndef FRAMEWORK_NATIVE_CMD_DUMPSYS_H_ #define FRAMEWORK_NATIVE_CMD_DUMPSYS_H_ +#include + +#include #include namespace android { @@ -25,10 +28,97 @@ class Dumpsys { public: Dumpsys(android::IServiceManager* sm) : sm_(sm) { } + /** + * Main entry point into dumpsys. + */ int main(int argc, char* const argv[]); + /** + * Returns a list of services. + * @param priorityFlags filter services by specified priorities + * @param supportsProto filter services that support proto dumps + * @return list of services + */ + Vector listServices(int priorityFlags, bool supportsProto) const; + + /** + * Modifies @{code args} to add additional arguments to indicate if the service + * must dump as proto or dump to a certian priority bucket. + * @param args initial list of arguments to pass to service dump method. + * @param asProto dump service as proto by passing an additional --proto arg + * @param priorityFlags indicates priority of dump by passing additional priority args + * to the service + */ + static void setServiceArgs(Vector& args, bool asProto, int priorityFlags); + + /** + * 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 + * stopDumpThread}. + * @param serviceName + * @param args list of arguments to pass to service dump method. + * @return {@code OK} thread is started successfully. + * {@code NAME_NOT_FOUND} service could not be found. + * {@code != OK} error + */ + status_t startDumpThread(const String16& serviceName, const Vector& args); + + /** + * Writes a section header to a file descriptor. + * @param fd file descriptor to write data + * @param serviceName + * @param priorityFlags dump priority specified + */ + void writeDumpHeader(int fd, const String16& serviceName, int priorityFlags) const; + + /** + * Redirects service dump to a file descriptor. This requires + * {@code startDumpThread} to be called successfully otherwise the function will + * return {@code INVALID_OPERATION}. + * @param fd file descriptor to write data + * @param serviceName + * @param timeout timeout to terminate the dump if not completed + * @param asProto used to supresses additional output to the fd such as timeout + * error messages + * @param elapsedDuration returns elapsed time in seconds + * @param bytesWritten returns number of bytes written + * @return {@code OK} if successful + * {@code TIMED_OUT} dump timed out + * {@code INVALID_OPERATION} invalid state + * {@code != OK} error + */ + status_t writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout, + bool asProto, std::chrono::duration& elapsedDuration, + size_t& bytesWritten) const; + + /** + * Writes a section footer to a file descriptor with duration info. + * @param fd file descriptor to write data + * @param serviceName + * @param elapsedDuration duration of dump + */ + void writeDumpFooter(int fd, const String16& serviceName, + const std::chrono::duration& elapsedDuration) const; + + /** + * Terminates dump thread. + * @param dumpComplete If {@code true}, indicates the dump was successfully completed and + * tries to join the thread. Otherwise thread is detached. + */ + void stopDumpThread(bool dumpComplete); + + /** + * Returns file descriptor of the pipe used to dump service data. This assumes + * {@code startDumpThread} was called successfully. + */ + int getDumpFd() const { + return redirectFd_.get(); + } + private: android::IServiceManager* sm_; + std::thread activeThread_; + mutable android::base::unique_fd redirectFd_; }; } diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp index 39fcb8063141f2467c7a029fc1724513e38a1916..e182b9d287c4b5ce051b4fbf04ece9ffeddf2a5e 100644 --- a/cmds/dumpsys/tests/Android.bp +++ b/cmds/dumpsys/tests/Android.bp @@ -15,6 +15,7 @@ cc_test { static_libs: [ "libdumpsys", "libgmock", + "libserviceutils", ], clang: true, diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index 16fefe64ba3d5a52a2c27b19c98d15b828efcda9..502935259a8af49f94910c486097596767cf55e7 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -50,8 +51,8 @@ class ServiceManagerMock : public IServiceManager { public: MOCK_CONST_METHOD1(getService, sp(const String16&)); MOCK_CONST_METHOD1(checkService, sp(const String16&)); - MOCK_METHOD3(addService, status_t(const String16&, const sp&, bool)); - MOCK_METHOD0(listServices, Vector()); + MOCK_METHOD4(addService, status_t(const String16&, const sp&, bool, int)); + MOCK_METHOD1(listServices, Vector(int)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); @@ -131,7 +132,16 @@ class DumpsysTest : public Test { for (auto& service : services) { services16.add(String16(service.c_str())); } - EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16)); + EXPECT_CALL(sm_, listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL)) + .WillRepeatedly(Return(services16)); + } + + void ExpectListServicesWithPriority(std::vector services, int dumpFlags) { + Vector services16; + for (auto& service : services) { + services16.add(String16(service.c_str())); + } + EXPECT_CALL(sm_, listServices(dumpFlags)).WillRepeatedly(Return(services16)); } sp ExpectCheckService(const char* name, bool running = true) { @@ -178,8 +188,27 @@ class DumpsysTest : public Test { EXPECT_THAT(status, Eq(0)); } + void CallSingleService(const String16& serviceName, Vector& args, int priorityFlags, + bool supportsProto, std::chrono::duration& elapsedDuration, + size_t& bytesWritten) { + CaptureStdout(); + CaptureStderr(); + dump_.setServiceArgs(args, supportsProto, priorityFlags); + 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); + EXPECT_THAT(status, Eq(0)); + dump_.stopDumpThread(/* dumpCompleted = */ true); + stdout_ = GetCapturedStdout(); + stderr_ = GetCapturedStderr(); + } + void AssertRunningServices(const std::vector& services) { - std::string expected("Currently running services:\n"); + std::string expected; + if (services.size() > 1) { + expected.append("Currently running services:\n"); + } for (const std::string& service : services) { expected.append(" ").append(service).append("\n"); } @@ -196,6 +225,15 @@ class DumpsysTest : public Test { void AssertDumped(const std::string& service, const std::string& dump) { EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump)); + EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: ")); + } + + void AssertDumpedWithPriority(const std::string& service, const std::string& dump, + const char16_t* priorityType) { + std::string priority = String8(priorityType).c_str(); + EXPECT_THAT(stdout_, + HasSubstr("DUMP OF SERVICE " + priority + " " + service + ":\n" + dump)); + EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: ")); } void AssertNotDumped(const std::string& dump) { @@ -236,6 +274,39 @@ TEST_F(DumpsysTest, ListRunningServices) { AssertNotDumped({"Valet"}); } +// Tests 'dumpsys -l --priority HIGH' +TEST_F(DumpsysTest, ListAllServicesWithPriority) { + ExpectListServicesWithPriority({"Locksmith", "Valet"}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH); + ExpectCheckService("Locksmith"); + ExpectCheckService("Valet"); + + CallMain({"-l", "--priority", "HIGH"}); + + AssertRunningServices({"Locksmith", "Valet"}); +} + +// Tests 'dumpsys -l --priority HIGH' with and empty list +TEST_F(DumpsysTest, ListEmptyServicesWithPriority) { + ExpectListServicesWithPriority({}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH); + + CallMain({"-l", "--priority", "HIGH"}); + + AssertRunningServices({}); +} + +// Tests 'dumpsys -l --proto' +TEST_F(DumpsysTest, ListAllServicesWithProto) { + ExpectListServicesWithPriority({"Locksmith", "Valet", "Car"}, + IServiceManager::DUMP_FLAG_PRIORITY_ALL); + ExpectListServicesWithPriority({"Valet", "Car"}, IServiceManager::DUMP_FLAG_PROTO); + ExpectCheckService("Car"); + ExpectCheckService("Valet"); + + CallMain({"-l", "--proto"}); + + AssertRunningServices({"Car", "Valet"}); +} + // Tests 'dumpsys service_name' on a service is running TEST_F(DumpsysTest, DumpRunningService) { ExpectDump("Valet", "Here's your car"); @@ -246,12 +317,25 @@ TEST_F(DumpsysTest, DumpRunningService) { } // Tests 'dumpsys -t 1 service_name' on a service that times out after 2s -TEST_F(DumpsysTest, DumpRunningServiceTimeout) { +TEST_F(DumpsysTest, DumpRunningServiceTimeoutInSec) { sp binder_mock = ExpectDumpAndHang("Valet", 2, "Here's your car"); CallMain({"-t", "1", "Valet"}); - AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1s) EXPIRED"); + AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1000ms) EXPIRED"); + AssertNotDumped("Here's your car"); + + // TODO(b/65056227): BinderMock is not destructed because thread is detached on dumpsys.cpp + Mock::AllowLeak(binder_mock.get()); +} + +// Tests 'dumpsys -T 500 service_name' on a service that times out after 2s +TEST_F(DumpsysTest, DumpRunningServiceTimeoutInMs) { + sp binder_mock = ExpectDumpAndHang("Valet", 2, "Here's your car"); + + CallMain({"-T", "500", "Valet"}); + + AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (500ms) EXPIRED"); AssertNotDumped("Here's your car"); // TODO(b/65056227): BinderMock is not destructed because thread is detached on dumpsys.cpp @@ -267,6 +351,65 @@ TEST_F(DumpsysTest, DumpWithArgsRunningService) { AssertOutput("I DO!"); } +// Tests dumpsys passes the -a flag when called on all services +TEST_F(DumpsysTest, PassAllFlagsToServices) { + ExpectListServices({"Locksmith", "Valet"}); + ExpectCheckService("Locksmith"); + ExpectCheckService("Valet"); + ExpectDumpWithArgs("Locksmith", {"-a"}, "dumped1"); + ExpectDumpWithArgs("Valet", {"-a"}, "dumped2"); + + CallMain({"-T", "500"}); + + AssertDumped("Locksmith", "dumped1"); + AssertDumped("Valet", "dumped2"); +} + +// Tests dumpsys passes the -a flag when called on NORMAL priority services +TEST_F(DumpsysTest, PassAllFlagsToNormalServices) { + ExpectListServicesWithPriority({"Locksmith", "Valet"}, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL); + ExpectCheckService("Locksmith"); + ExpectCheckService("Valet"); + ExpectDumpWithArgs("Locksmith", {"-a", "--dump-priority", "NORMAL"}, "dump1"); + ExpectDumpWithArgs("Valet", {"-a", "--dump-priority", "NORMAL"}, "dump2"); + + CallMain({"--priority", "NORMAL"}); + + AssertDumped("Locksmith", "dump1"); + AssertDumped("Valet", "dump2"); +} + +// Tests dumpsys passes only priority flags when called on CRITICAL priority services +TEST_F(DumpsysTest, PassPriorityFlagsToCriticalServices) { + ExpectListServicesWithPriority({"Locksmith", "Valet"}, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL); + ExpectCheckService("Locksmith"); + ExpectCheckService("Valet"); + ExpectDumpWithArgs("Locksmith", {"--dump-priority", "CRITICAL"}, "dump1"); + ExpectDumpWithArgs("Valet", {"--dump-priority", "CRITICAL"}, "dump2"); + + CallMain({"--priority", "CRITICAL"}); + + AssertDumpedWithPriority("Locksmith", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL); + AssertDumpedWithPriority("Valet", "dump2", PriorityDumper::PRIORITY_ARG_CRITICAL); +} + +// Tests dumpsys passes only priority flags when called on HIGH priority services +TEST_F(DumpsysTest, PassPriorityFlagsToHighServices) { + ExpectListServicesWithPriority({"Locksmith", "Valet"}, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH); + ExpectCheckService("Locksmith"); + ExpectCheckService("Valet"); + ExpectDumpWithArgs("Locksmith", {"--dump-priority", "HIGH"}, "dump1"); + ExpectDumpWithArgs("Valet", {"--dump-priority", "HIGH"}, "dump2"); + + CallMain({"--priority", "HIGH"}); + + AssertDumpedWithPriority("Locksmith", "dump1", PriorityDumper::PRIORITY_ARG_HIGH); + AssertDumpedWithPriority("Valet", "dump2", PriorityDumper::PRIORITY_ARG_HIGH); +} + // Tests 'dumpsys' with no arguments TEST_F(DumpsysTest, DumpMultipleServices) { ExpectListServices({"running1", "stopped2", "running3"}); @@ -300,3 +443,124 @@ TEST_F(DumpsysTest, DumpWithSkip) { AssertNotDumped("dump3"); AssertNotDumped("dump5"); } + +// Tests 'dumpsys --skip skipped3 skipped5 --priority CRITICAL', which should skip these services +TEST_F(DumpsysTest, DumpWithSkipAndPriority) { + ExpectListServicesWithPriority({"running1", "stopped2", "skipped3", "running4", "skipped5"}, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL); + ExpectDump("running1", "dump1"); + ExpectCheckService("stopped2", false); + ExpectDump("skipped3", "dump3"); + ExpectDump("running4", "dump4"); + ExpectDump("skipped5", "dump5"); + + CallMain({"--priority", "CRITICAL", "--skip", "skipped3", "skipped5"}); + + AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"}); + AssertDumpedWithPriority("running1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL); + AssertDumpedWithPriority("running4", "dump4", PriorityDumper::PRIORITY_ARG_CRITICAL); + AssertStopped("stopped2"); + AssertNotDumped("dump3"); + AssertNotDumped("dump5"); +} + +// Tests 'dumpsys --priority CRITICAL' +TEST_F(DumpsysTest, DumpWithPriorityCritical) { + ExpectListServicesWithPriority({"runningcritical1", "runningcritical2"}, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL); + ExpectDump("runningcritical1", "dump1"); + ExpectDump("runningcritical2", "dump2"); + + CallMain({"--priority", "CRITICAL"}); + + AssertRunningServices({"runningcritical1", "runningcritical2"}); + AssertDumpedWithPriority("runningcritical1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL); + AssertDumpedWithPriority("runningcritical2", "dump2", PriorityDumper::PRIORITY_ARG_CRITICAL); +} + +// Tests 'dumpsys --priority HIGH' +TEST_F(DumpsysTest, DumpWithPriorityHigh) { + ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"}, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH); + ExpectDump("runninghigh1", "dump1"); + ExpectDump("runninghigh2", "dump2"); + + CallMain({"--priority", "HIGH"}); + + AssertRunningServices({"runninghigh1", "runninghigh2"}); + AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH); + AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH); +} + +// Tests 'dumpsys --priority NORMAL' +TEST_F(DumpsysTest, DumpWithPriorityNormal) { + ExpectListServicesWithPriority({"runningnormal1", "runningnormal2"}, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL); + ExpectDump("runningnormal1", "dump1"); + ExpectDump("runningnormal2", "dump2"); + + CallMain({"--priority", "NORMAL"}); + + AssertRunningServices({"runningnormal1", "runningnormal2"}); + AssertDumped("runningnormal1", "dump1"); + AssertDumped("runningnormal2", "dump2"); +} + +// Tests 'dumpsys --proto' +TEST_F(DumpsysTest, DumpWithProto) { + ExpectListServicesWithPriority({"run8", "run1", "run2", "run5"}, + IServiceManager::DUMP_FLAG_PRIORITY_ALL); + ExpectListServicesWithPriority({"run3", "run2", "run4", "run8"}, + IServiceManager::DUMP_FLAG_PROTO); + ExpectDump("run2", "dump1"); + ExpectDump("run8", "dump2"); + + CallMain({"--proto"}); + + AssertRunningServices({"run2", "run8"}); + AssertDumped("run2", "dump1"); + AssertDumped("run8", "dump2"); +} + +// Tests 'dumpsys --priority HIGH --proto' +TEST_F(DumpsysTest, DumpWithPriorityHighAndProto) { + ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"}, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH); + ExpectListServicesWithPriority({"runninghigh1", "runninghigh2", "runninghigh3"}, + IServiceManager::DUMP_FLAG_PROTO); + + ExpectDump("runninghigh1", "dump1"); + ExpectDump("runninghigh2", "dump2"); + + CallMain({"--priority", "HIGH", "--proto"}); + + AssertRunningServices({"runninghigh1", "runninghigh2"}); + AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH); + AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH); +} + +TEST_F(DumpsysTest, GetBytesWritten) { + const char* serviceName = "service2"; + const char* dumpContents = "dump1"; + ExpectDump(serviceName, dumpContents); + + String16 service(serviceName); + Vector args; + std::chrono::duration elapsedDuration; + size_t bytesWritten; + + CallSingleService(service, args, IServiceManager::DUMP_FLAG_PRIORITY_ALL, + /* as_proto = */ false, elapsedDuration, bytesWritten); + + AssertOutput(dumpContents); + EXPECT_THAT(bytesWritten, Eq(strlen(dumpContents))); +} + +TEST_F(DumpsysTest, WriteDumpWithoutThreadStart) { + std::chrono::duration elapsedDuration; + size_t bytesWritten; + status_t status = + 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/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp index dfc3e581fdffc7eb6246fc629137edef95915507..d5b3372f96b7119537b731ab97b6e4f729275ca8 100644 --- a/cmds/flatland/GLHelper.cpp +++ b/cmds/flatland/GLHelper.cpp @@ -269,24 +269,10 @@ bool GLHelper::createWindowSurface(uint32_t w, uint32_t h, return false; } - SurfaceComposerClient::openGlobalTransaction(); - err = sc->setLayer(0x7FFFFFFF); - if (err != NO_ERROR) { - fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err); - return false; - } - err = sc->setMatrix(scale, 0.0f, 0.0f, scale); - if (err != NO_ERROR) { - fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err); - return false; - } - - err = sc->show(); - if (err != NO_ERROR) { - fprintf(stderr, "SurfaceComposer::show error: %#x\n", err); - return false; - } - SurfaceComposerClient::closeGlobalTransaction(); + SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF) + .setMatrix(sc, scale, 0.0f, 0.0f, scale) + .show(sc) + .apply(); sp anw = sc->getSurface(); EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 1d8b52c6c96542bf0a3a3ba4f29fecfd56300cea..860a68b2733590b16bb66d779c02c08ae93cb633 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -18,17 +18,21 @@ #define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER +#include #include -#include #include #include +#include +#include #include #include #include #include #include -#include +#include +#include #include +#include #include #include #include @@ -41,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +77,7 @@ namespace installd { static constexpr const char* kCpPath = "/system/bin/cp"; static constexpr const char* kXattrDefault = "user.default"; +static constexpr const char* kPropHasReserved = "vold.has_reserved"; static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M @@ -83,6 +89,10 @@ static constexpr const char *kIdMapPath = "/system/bin/idmap"; static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/"; static constexpr const char* IDMAP_SUFFIX = "@idmap"; +// fsverity assumes the page size is always 4096. If not, the feature can not be +// enabled. +static constexpr int kVerityPageSize = 4096; +static constexpr size_t kSha256Size = 32; static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode"; // NOTE: keep in sync with Installer @@ -162,6 +172,35 @@ binder::Status checkArgumentPackageName(const std::string& packageName) { } } +binder::Status checkArgumentPath(const std::string& path) { + if (path.empty()) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing path"); + } + if (path[0] != '/') { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Path %s is relative", path.c_str())); + } + if ((path + '/').find("/../") != std::string::npos) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Path %s is shady", path.c_str())); + } + for (const char& c : path) { + if (c == '\0' || c == '\n') { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Path %s is malformed", path.c_str())); + } + } + return ok(); +} + +binder::Status checkArgumentPath(const std::unique_ptr& path) { + if (path) { + return checkArgumentPath(*path); + } else { + return ok(); + } +} + #define ENFORCE_UID(uid) { \ binder::Status status = checkUid((uid)); \ if (!status.isOk()) { \ @@ -184,6 +223,19 @@ binder::Status checkArgumentPackageName(const std::string& packageName) { } \ } +#define CHECK_ARGUMENT_PATH(path) { \ + binder::Status status = checkArgumentPath((path)); \ + if (!status.isOk()) { \ + return status; \ + } \ +} + +#define ASSERT_PAGE_SIZE_4K() { \ + if (getpagesize() != kVerityPageSize) { \ + return error("FSVerity only supports 4K pages"); \ + } \ +} + } // namespace status_t InstalldNativeService::start() { @@ -304,8 +356,11 @@ static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t ui * Ensure that we have a hard-limit quota to protect against abusive apps; * they should never use more than 90% of blocks or 50% of inodes. */ -static int prepare_app_quota(const std::unique_ptr& uuid, const std::string& device, - uid_t uid) { +static int prepare_app_quota(const std::unique_ptr& uuid ATTRIBUTE_UNUSED, + const std::string& device, uid_t uid) { + // Skip when reserved blocks are protecting us against abusive apps + if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0; + // Skip when device no quotas present if (device.empty()) return 0; struct dqblk dq; @@ -1122,6 +1177,7 @@ binder::Status InstalldNativeService::freeCache(const std::unique_ptr lock(mLock); char dex_path[PKG_PATH_MAX]; @@ -1381,6 +1437,9 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr lock(mLock); *_aidl_return = dump_profiles(uid, packageName, profileName, codePath); @@ -1893,9 +1953,12 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t const std::unique_ptr& compilationReason) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); + CHECK_ARGUMENT_PATH(apkPath); if (packageName && *packageName != "*") { CHECK_ARGUMENT_PACKAGE_NAME(*packageName); } + CHECK_ARGUMENT_PATH(outputPath); + CHECK_ARGUMENT_PATH(dexMetadataPath); std::lock_guard lock(mLock); const char* apk_path = apkPath.c_str(); @@ -1936,33 +1999,13 @@ binder::Status InstalldNativeService::markBootComplete(const std::string& instru return ok(); } -void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid, - struct stat* statbuf) -{ - while (path[basepos] != 0) { - if (path[basepos] == '/') { - path[basepos] = 0; - if (lstat(path, statbuf) < 0) { - ALOGV("Making directory: %s\n", path); - if (mkdir(path, mode) == 0) { - chown(path, uid, gid); - } else { - ALOGW("Unable to make directory %s: %s\n", path, strerror(errno)); - } - } - path[basepos] = '/'; - basepos++; - } - basepos++; - } -} - binder::Status InstalldNativeService::linkNativeLibraryDirectory( const std::unique_ptr& uuid, const std::string& packageName, const std::string& nativeLibPath32, int32_t userId) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); + CHECK_ARGUMENT_PATH(nativeLibPath32); std::lock_guard lock(mLock); const char* uuid_ = uuid ? uuid->c_str() : nullptr; @@ -2130,6 +2173,8 @@ static int flatten_path(const char *prefix, const char *suffix, binder::Status InstalldNativeService::idmap(const std::string& targetApkPath, const std::string& overlayApkPath, int32_t uid) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(targetApkPath); + CHECK_ARGUMENT_PATH(overlayApkPath); std::lock_guard lock(mLock); const char* target_apk = targetApkPath.c_str(); @@ -2215,6 +2260,10 @@ fail: } binder::Status InstalldNativeService::removeIdmap(const std::string& overlayApkPath) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(overlayApkPath); + std::lock_guard lock(mLock); + const char* overlay_apk = overlayApkPath.c_str(); char idmap_path[PATH_MAX]; @@ -2265,6 +2314,7 @@ binder::Status InstalldNativeService::restoreconAppData(const std::unique_ptr lock(mLock); const char* oat_dir = oatDir.c_str(); @@ -2289,6 +2339,7 @@ binder::Status InstalldNativeService::createOatDir(const std::string& oatDir, binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(packageDir); std::lock_guard lock(mLock); if (validate_apk_path(packageDir.c_str())) { @@ -2303,6 +2354,8 @@ binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir binder::Status InstalldNativeService::linkFile(const std::string& relativePath, const std::string& fromBase, const std::string& toBase) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(fromBase); + CHECK_ARGUMENT_PATH(toBase); std::lock_guard lock(mLock); const char* relative_path = relativePath.c_str(); @@ -2331,6 +2384,8 @@ binder::Status InstalldNativeService::linkFile(const std::string& relativePath, binder::Status InstalldNativeService::moveAb(const std::string& apkPath, const std::string& instructionSet, const std::string& outputPath) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(apkPath); + CHECK_ARGUMENT_PATH(outputPath); std::lock_guard lock(mLock); const char* apk_path = apkPath.c_str(); @@ -2344,6 +2399,8 @@ binder::Status InstalldNativeService::moveAb(const std::string& apkPath, binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath, const std::string& instructionSet, const std::unique_ptr& outputPath) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(apkPath); + CHECK_ARGUMENT_PATH(outputPath); std::lock_guard lock(mLock); const char* apk_path = apkPath.c_str(); @@ -2354,15 +2411,140 @@ binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath, return res ? ok() : error(); } -binder::Status InstalldNativeService::installApkVerity(const std::string& /*filePath*/, - const ::android::base::unique_fd& /*verityInput*/) { +// This kernel feature is experimental. +// TODO: remove local definition once upstreamed +#ifndef FS_IOC_ENABLE_VERITY + +#define FS_IOC_ENABLE_VERITY _IO('f', 133) +#define FS_IOC_SET_VERITY_MEASUREMENT _IOW('f', 134, struct fsverity_measurement) + +#define FS_VERITY_ALG_SHA256 1 + +struct fsverity_measurement { + __u16 digest_algorithm; + __u16 digest_size; + __u32 reserved1; + __u64 reserved2[3]; + __u8 digest[]; +}; + +#endif + +binder::Status InstalldNativeService::installApkVerity(const std::string& filePath, + const ::android::base::unique_fd& verityInputAshmem, int32_t contentSize) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(filePath); + std::lock_guard lock(mLock); + + if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) { + return ok(); + } +#ifndef NDEBUG + ASSERT_PAGE_SIZE_4K(); +#endif + // TODO: also check fsverity support in the current file system if compiled with DEBUG. + // TODO: change ashmem to some temporary file to support huge apk. + if (!ashmem_valid(verityInputAshmem.get())) { + return error("FD is not an ashmem"); + } + + // 1. Seek to the next page boundary beyond the end of the file. + ::android::base::unique_fd wfd(open(filePath.c_str(), O_WRONLY)); + if (wfd.get() < 0) { + return error("Failed to open " + filePath); + } + struct stat st; + if (fstat(wfd.get(), &st) < 0) { + return error("Failed to stat " + filePath); + } + // fsverity starts from the block boundary. + off_t padding = kVerityPageSize - st.st_size % kVerityPageSize; + if (padding == kVerityPageSize) { + padding = 0; + } + if (lseek(wfd.get(), st.st_size + padding, SEEK_SET) < 0) { + return error("Failed to lseek " + filePath); + } + + // 2. Write everything in the ashmem to the file. Note that allocated + // ashmem size is multiple of page size, which is different from the + // actual content size. + int shmSize = ashmem_get_size_region(verityInputAshmem.get()); + if (shmSize < 0) { + return error("Failed to get ashmem size: " + std::to_string(shmSize)); + } + if (contentSize < 0) { + return error("Invalid content size: " + std::to_string(contentSize)); + } + if (contentSize > shmSize) { + return error("Content size overflow: " + std::to_string(contentSize) + " > " + + std::to_string(shmSize)); + } + auto data = std::unique_ptr>( + mmap(NULL, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0), + [contentSize] (void* ptr) { + if (ptr != MAP_FAILED) { + munmap(ptr, contentSize); + } + }); + + if (data.get() == MAP_FAILED) { + return error("Failed to mmap the ashmem"); + } + char* cursor = reinterpret_cast(data.get()); + int remaining = contentSize; + while (remaining > 0) { + int ret = TEMP_FAILURE_RETRY(write(wfd.get(), cursor, remaining)); + if (ret < 0) { + return error("Failed to write to " + filePath + " (" + std::to_string(remaining) + + + "/" + std::to_string(contentSize) + ")"); + } + cursor += ret; + remaining -= ret; + } + wfd.reset(); + + // 3. Enable fsverity (needs readonly fd. Once it's done, the file becomes immutable. + ::android::base::unique_fd rfd(open(filePath.c_str(), O_RDONLY)); + if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) { + return error("Failed to enable fsverity on " + filePath); + } + return ok(); +} + +binder::Status InstalldNativeService::assertFsverityRootHashMatches(const std::string& filePath, + const std::vector& expectedHash) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(filePath); + std::lock_guard lock(mLock); + if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) { return ok(); } - // TODO: Append verity to filePath then issue ioctl to enable - // it and hide the tree. See b/30972906. - return error("not implemented yet"); + // TODO: also check fsverity support in the current file system if compiled with DEBUG. + if (expectedHash.size() != kSha256Size) { + return error("verity hash size should be " + std::to_string(kSha256Size) + " but is " + + std::to_string(expectedHash.size())); + } + + ::android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY)); + if (fd.get() < 0) { + return error("Failed to open " + filePath + ": " + strerror(errno)); + } + + unsigned int buffer_size = sizeof(fsverity_measurement) + kSha256Size; + std::vector buffer(buffer_size, 0); + + fsverity_measurement* config = reinterpret_cast(buffer.data()); + config->digest_algorithm = FS_VERITY_ALG_SHA256; + config->digest_size = kSha256Size; + memcpy(config->digest, expectedHash.data(), kSha256Size); + if (ioctl(fd.get(), FS_IOC_SET_VERITY_MEASUREMENT, config) < 0) { + // This includes an expected failure case with no FSVerity setup. It normally happens when + // the apk does not contains the Merkle tree root hash. + return error("Failed to measure fsverity on " + filePath + ": " + strerror(errno)); + } + return ok(); // hashes match } binder::Status InstalldNativeService::reconcileSecondaryDexFile( @@ -2372,8 +2554,9 @@ binder::Status InstalldNativeService::reconcileSecondaryDexFile( ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(volumeUuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); - + CHECK_ARGUMENT_PATH(dexPath); std::lock_guard lock(mLock); + bool result = android::installd::reconcile_secondary_dex_file( dexPath, packageName, uid, isas, volumeUuid, storage_flag, _aidl_return); return result ? ok() : error(); @@ -2386,6 +2569,7 @@ binder::Status InstalldNativeService::hashSecondaryDexFile( ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(volumeUuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); + CHECK_ARGUMENT_PATH(dexPath); // mLock is not taken here since we will never modify the file system. // If a file is modified just as we are reading it this may result in an @@ -2431,14 +2615,18 @@ binder::Status InstalldNativeService::invalidateMounts() { mQuotaReverseMounts[target] = source; // ext4 only enables DQUOT_USAGE_ENABLED by default, so we - // need to kick it again to enable DQUOT_LIMITS_ENABLED. - if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0 - && errno != EBUSY) { - PLOG(ERROR) << "Failed to enable USRQUOTA on " << source; - } - if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0 - && errno != EBUSY) { - PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source; + // need to kick it again to enable DQUOT_LIMITS_ENABLED. We + // only need hard limits enabled when we're not being protected + // by reserved blocks. + if (!android::base::GetBoolProperty(kPropHasReserved, false)) { + if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, + nullptr) != 0 && errno != EBUSY) { + PLOG(ERROR) << "Failed to enable USRQUOTA on " << source; + } + if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, + nullptr) != 0 && errno != EBUSY) { + PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source; + } } } } @@ -2478,6 +2666,7 @@ binder::Status InstalldNativeService::prepareAppProfile(const std::string& packa const std::unique_ptr& dexMetadata, bool* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_PACKAGE_NAME(packageName); + CHECK_ARGUMENT_PATH(codePath); std::lock_guard lock(mLock); *_aidl_return = prepare_app_profile(packageName, userId, appId, profileName, codePath, diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 1648603b52e45d22e00ac7a6bc5f8bc5717fe1a4..cebd3f90d334adb41663fda6d63677fd587ddf15 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -123,7 +123,9 @@ public: binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet, const std::unique_ptr& outputPath); binder::Status installApkVerity(const std::string& filePath, - const ::android::base::unique_fd& verityInput); + const ::android::base::unique_fd& verityInput, int32_t contentSize); + binder::Status assertFsverityRootHashMatches(const std::string& filePath, + const std::vector& expectedHash); binder::Status reconcileSecondaryDexFile(const std::string& dexPath, const std::string& packageName, int32_t uid, const std::vector& isa, const std::unique_ptr& volumeUuid, int32_t storage_flag, bool* _aidl_return); diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 432751feda067556b12e9a25bef235b0d97ba0d7..91e20b75ae4adcaedd931d089516a69339339a12 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -85,7 +85,9 @@ interface IInstalld { @utf8InCpp String outputPath); void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath); - void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput); + void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput, + int contentSize); + void assertFsverityRootHashMatches(@utf8InCpp String filePath, in byte[] expectedHash); boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName, int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid, diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index a19ce0958cdfdc8978d8f7c671fe9ba1cd8c5fe5..fa23d3a93efeadab9a683dc6097fd8b375f2e2ca 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -309,7 +309,9 @@ static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vd // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat. const char* dex2oat_bin = "/system/bin/dex2oat"; constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd"; - if (is_debug_runtime() || (background_job_compile && is_debuggable_build())) { + // Do not use dex2oatd for release candidates (give dex2oat more soak time). + bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL"; + if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) { if (access(kDex2oatDebugPath, X_OK) == 0) { dex2oat_bin = kDex2oatDebugPath; } diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 4c75eb51e1bae8a9ad17997d70af235386b1ff13..96d8c47a8a6f10734fd2aa03b221c9a96288d817 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -549,6 +549,7 @@ private: CHECK(EndsWith(path, "/")); path = path + "oat"; if (access(path.c_str(), F_OK) == 0) { + LOG(INFO) << "Skipping A/B OTA preopt of already preopted package " << apk_path; return true; } } @@ -560,7 +561,7 @@ private: // this tool will wipe the OTA artifact cache and try again (for robustness after // a failed OTA with remaining cache artifacts). if (access(apk_path, F_OK) != 0) { - LOG(WARNING) << "Skipping preopt of non-existing package " << apk_path; + LOG(WARNING) << "Skipping A/B OTA preopt of non-existing package " << apk_path; return true; } diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index bbff6fb0d7093961e7f399353bad6eb45b237f3e..bcdd03efad16e5933345bb625b43ba8996518e63 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -33,7 +33,7 @@ #define TEST_APP_PRIVATE_DIR "/data/app-private/" #define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/" #define TEST_ASEC_DIR "/mnt/asec/" -#define TEST_EXPAND_DIR "/mnt/expand/" +#define TEST_EXPAND_DIR "/mnt/expand/00000000-0000-0000-0000-000000000000/" #define TEST_SYSTEM_DIR1 "/system/app/" #define TEST_SYSTEM_DIR2 "/vendor/app/" @@ -116,6 +116,41 @@ TEST_F(UtilsTest, IsValidApkPath_Internal) { << bad_path5 << " should be rejected as a invalid path"; } +TEST_F(UtilsTest, IsValidApkPath_TopDir) { + EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example")); + EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example")); + EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example")); + EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example")); +} + +TEST_F(UtilsTest, IsValidApkPath_TopFile) { + EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example/base.apk")); + EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example/base.apk")); + EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example/base.apk")); + EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example/base.apk")); +} + +TEST_F(UtilsTest, IsValidApkPath_OatDir) { + EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat")); + EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat")); + EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat")); + EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat")); +} + +TEST_F(UtilsTest, IsValidApkPath_OatDirDir) { + EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64")); + EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64")); + EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64")); + EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64")); +} + +TEST_F(UtilsTest, IsValidApkPath_OatDirDirFile) { + EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64/base.odex")); + EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64/base.odex")); + EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64/base.odex")); + EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64/base.odex")); +} + TEST_F(UtilsTest, IsValidApkPath_Private) { // Internal directories const char *private1 = TEST_APP_PRIVATE_DIR "example.apk"; diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index a8c32ed2a5af1fccd9e29c28098ca429ec5a8558..1ff45e4845846c7d59c455233dec4ecc369d8c08 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -855,21 +855,25 @@ bool validate_secondary_dex_path(const std::string& pkgname, const std::string& * that path. Returns -1 when an invalid path is encountered and 0 when a valid path * is encountered. */ -static int validate_apk_path_internal(const char *path, int maxSubdirs) { - std::string path_ = path; - if (validate_path(android_app_dir, path_, maxSubdirs) == 0) { - return 0; - } else if (validate_path(android_app_private_dir, path_, maxSubdirs) == 0) { +static int validate_apk_path_internal(const std::string& path, int maxSubdirs) { + if (validate_path(android_app_dir, path, maxSubdirs) == 0) { return 0; - } else if (validate_path(android_app_ephemeral_dir, path_, maxSubdirs) == 0) { + } else if (validate_path(android_app_private_dir, path, maxSubdirs) == 0) { return 0; - } else if (validate_path(android_asec_dir, path_, maxSubdirs) == 0) { + } else if (validate_path(android_app_ephemeral_dir, path, maxSubdirs) == 0) { return 0; - } else if (validate_path(android_mnt_expand_dir, path_, std::max(maxSubdirs, 2)) == 0) { + } else if (validate_path(android_asec_dir, path, maxSubdirs) == 0) { return 0; - } else { - return -1; + } else if (android::base::StartsWith(path, android_mnt_expand_dir)) { + // Rewrite the path as if it were on internal storage, and test that + size_t end = path.find('/', android_mnt_expand_dir.size() + 1); + if (end != std::string::npos) { + auto modified = path; + modified.replace(0, end + 1, android_data_dir); + return validate_apk_path_internal(modified, maxSubdirs); + } } + return -1; } int validate_apk_path(const char* path) { diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index b74073cb291c30822f2bc2f13c48060598678360..5829c4fd14c42b83899ca93d801f9192bb6da937 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -36,7 +36,7 @@ #define BYPASS_QUOTA 0 #define BYPASS_SDCARDFS 0 -#define APPLY_HARD_QUOTAS 1 +#define APPLY_HARD_QUOTAS 0 namespace android { namespace installd { diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index c0e1a35e20d13abe9f4aa35cf6215b1edfaf93df..92e915181b9825b8d66587e3c5a2ca32efe467f1 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -576,7 +576,7 @@ Status ListCommand::fetchAllLibraries(const sp &manager) { using namespace ::android::hidl::manager::V1_0; using namespace ::android::hidl::base::V1_0; using std::literals::chrono_literals::operator""s; - auto ret = timeoutIPC(2s, manager, &IServiceManager::debugDump, [&] (const auto &infos) { + auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [&] (const auto &infos) { std::map entries; for (const auto &info : infos) { std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" + diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index 31cd0cb5ac6a96ef48c0e7c31e71214bff6e1f96..6b340a8d3aaf4a432b177e015a5b411f50fa0a71 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -138,6 +138,7 @@ struct svcinfo uint32_t handle; struct binder_death death; int allow_isolated; + uint32_t dumpsys_priority; size_t len; uint16_t name[0]; }; @@ -198,11 +199,8 @@ uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid) 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, - pid_t spid) -{ +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) { struct svcinfo *si; //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, @@ -239,6 +237,7 @@ int do_add_service(struct binder_state *bs, 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; } @@ -259,6 +258,7 @@ int svcmgr_handler(struct binder_state *bs, uint32_t handle; uint32_t strict_policy; int allow_isolated; + uint32_t dumpsys_priority; //ALOGI("target=%p code=%d pid=%d uid=%d\n", // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); @@ -317,13 +317,15 @@ int svcmgr_handler(struct binder_state *bs, } handle = bio_get_ref(msg); allow_isolated = bio_get_uint32(msg) ? 1 : 0; - if (do_add_service(bs, s, len, handle, txn->sender_euid, - allow_isolated, txn->sender_pid)) + dumpsys_priority = bio_get_uint32(msg); + if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, + txn->sender_pid)) 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, txn->sender_euid)) { ALOGE("list_service() uid=%d - PERMISSION DENIED\n", @@ -331,8 +333,15 @@ int svcmgr_handler(struct binder_state *bs, return -1; } si = svclist; - while ((n-- > 0) && si) + // 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; diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 2b5389b8dc95aa12e550ff289f5b59ab414da781..4140f4088834cbc9dc0ea09f5b6052fa294cd25f 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -24,9 +24,9 @@ #include #include +#include #include #include -#include #include #include @@ -338,27 +338,29 @@ status_t Replayer::dispatchEvent(int index) { status_t Replayer::doTransaction(const Transaction& t, const std::shared_ptr& event) { ALOGV("Started Transaction"); - SurfaceComposerClient::openGlobalTransaction(); + SurfaceComposerClient::Transaction liveTransaction; status_t status = NO_ERROR; - status = doSurfaceTransaction(t.surface_change()); - doDisplayTransaction(t.display_change()); + status = doSurfaceTransaction(liveTransaction, t.surface_change()); + doDisplayTransaction(liveTransaction, t.display_change()); if (t.animation()) { - SurfaceComposerClient::setAnimationTransaction(); + liveTransaction.setAnimationTransaction(); } event->readyToExecute(); - SurfaceComposerClient::closeGlobalTransaction(t.synchronous()); + liveTransaction.apply(t.synchronous()); ALOGV("Ended Transaction"); return status; } -status_t Replayer::doSurfaceTransaction(const SurfaceChanges& surfaceChanges) { +status_t Replayer::doSurfaceTransaction( + SurfaceComposerClient::Transaction& transaction, + const SurfaceChanges& surfaceChanges) { status_t status = NO_ERROR; for (const SurfaceChange& change : surfaceChanges) { @@ -369,62 +371,66 @@ status_t Replayer::doSurfaceTransaction(const SurfaceChanges& surfaceChanges) { switch (change.SurfaceChange_case()) { case SurfaceChange::SurfaceChangeCase::kPosition: - status = setPosition(change.id(), change.position()); + setPosition(transaction, change.id(), change.position()); break; case SurfaceChange::SurfaceChangeCase::kSize: - status = setSize(change.id(), change.size()); + setSize(transaction, change.id(), change.size()); break; case SurfaceChange::SurfaceChangeCase::kAlpha: - status = setAlpha(change.id(), change.alpha()); + setAlpha(transaction, change.id(), change.alpha()); break; case SurfaceChange::SurfaceChangeCase::kLayer: - status = setLayer(change.id(), change.layer()); + setLayer(transaction, change.id(), change.layer()); break; case SurfaceChange::SurfaceChangeCase::kCrop: - status = setCrop(change.id(), change.crop()); + setCrop(transaction, change.id(), change.crop()); break; case SurfaceChange::SurfaceChangeCase::kMatrix: - status = setMatrix(change.id(), change.matrix()); + setMatrix(transaction, change.id(), change.matrix()); break; case SurfaceChange::SurfaceChangeCase::kFinalCrop: - status = setFinalCrop(change.id(), change.final_crop()); + setFinalCrop(transaction, change.id(), change.final_crop()); break; case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode: - status = setOverrideScalingMode(change.id(), change.override_scaling_mode()); + setOverrideScalingMode(transaction, change.id(), + change.override_scaling_mode()); break; case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint: - status = setTransparentRegionHint(change.id(), change.transparent_region_hint()); + setTransparentRegionHint(transaction, change.id(), + change.transparent_region_hint()); break; case SurfaceChange::SurfaceChangeCase::kLayerStack: - status = setLayerStack(change.id(), change.layer_stack()); + setLayerStack(transaction, change.id(), change.layer_stack()); break; case SurfaceChange::SurfaceChangeCase::kHiddenFlag: - status = setHiddenFlag(change.id(), change.hidden_flag()); + setHiddenFlag(transaction, change.id(), change.hidden_flag()); break; case SurfaceChange::SurfaceChangeCase::kOpaqueFlag: - status = setOpaqueFlag(change.id(), change.opaque_flag()); + setOpaqueFlag(transaction, change.id(), change.opaque_flag()); break; case SurfaceChange::SurfaceChangeCase::kSecureFlag: - status = setSecureFlag(change.id(), change.secure_flag()); + setSecureFlag(transaction, change.id(), change.secure_flag()); break; case SurfaceChange::SurfaceChangeCase::kDeferredTransaction: waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock); - status = setDeferredTransaction(change.id(), change.deferred_transaction()); + setDeferredTransaction(transaction, change.id(), + change.deferred_transaction()); break; default: - status = NO_ERROR; + status = 1; break; } if (status != NO_ERROR) { - ALOGE("SET TRANSACTION FAILED"); + ALOGE("Unknown Transaction Code"); return status; } } return status; } -void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) { +void Replayer::doDisplayTransaction(SurfaceComposerClient::Transaction& t, + const DisplayChanges& displayChanges) { for (const DisplayChange& change : displayChanges) { ALOGV("Doing display transaction"); std::unique_lock lock(mDisplayLock); @@ -434,16 +440,16 @@ void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) { switch (change.DisplayChange_case()) { case DisplayChange::DisplayChangeCase::kSurface: - setDisplaySurface(change.id(), change.surface()); + setDisplaySurface(t, change.id(), change.surface()); break; case DisplayChange::DisplayChangeCase::kLayerStack: - setDisplayLayerStack(change.id(), change.layer_stack()); + setDisplayLayerStack(t, change.id(), change.layer_stack()); break; case DisplayChange::DisplayChangeCase::kSize: - setDisplaySize(change.id(), change.size()); + setDisplaySize(t, change.id(), change.size()); break; case DisplayChange::DisplayChangeCase::kProjection: - setDisplayProjection(change.id(), change.projection()); + setDisplayProjection(t, change.id(), change.projection()); break; default: break; @@ -451,57 +457,66 @@ void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) { } } -status_t Replayer::setPosition(layer_id id, const PositionChange& pc) { +void Replayer::setPosition(SurfaceComposerClient::Transaction& t, + layer_id id, const PositionChange& pc) { ALOGV("Layer %d: Setting Position -- x=%f, y=%f", id, pc.x(), pc.y()); - return mLayers[id]->setPosition(pc.x(), pc.y()); + t.setPosition(mLayers[id], pc.x(), pc.y()); } -status_t Replayer::setSize(layer_id id, const SizeChange& sc) { +void Replayer::setSize(SurfaceComposerClient::Transaction& t, + layer_id id, const SizeChange& sc) { ALOGV("Layer %d: Setting Size -- w=%u, h=%u", id, sc.w(), sc.h()); - return mLayers[id]->setSize(sc.w(), sc.h()); + t.setSize(mLayers[id], sc.w(), sc.h()); } -status_t Replayer::setLayer(layer_id id, const LayerChange& lc) { +void Replayer::setLayer(SurfaceComposerClient::Transaction& t, + layer_id id, const LayerChange& lc) { ALOGV("Layer %d: Setting Layer -- layer=%d", id, lc.layer()); - return mLayers[id]->setLayer(lc.layer()); + t.setLayer(mLayers[id], lc.layer()); } -status_t Replayer::setAlpha(layer_id id, const AlphaChange& ac) { +void Replayer::setAlpha(SurfaceComposerClient::Transaction& t, + layer_id id, const AlphaChange& ac) { ALOGV("Layer %d: Setting Alpha -- alpha=%f", id, ac.alpha()); - return mLayers[id]->setAlpha(ac.alpha()); + t.setAlpha(mLayers[id], ac.alpha()); } -status_t Replayer::setCrop(layer_id id, const CropChange& cc) { +void Replayer::setCrop(SurfaceComposerClient::Transaction& t, + layer_id id, const CropChange& cc) { ALOGV("Layer %d: Setting Crop -- left=%d, top=%d, right=%d, bottom=%d", id, cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(), cc.rectangle().bottom()); Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(), cc.rectangle().bottom()); - return mLayers[id]->setCrop(r); + t.setCrop(mLayers[id], r); } -status_t Replayer::setFinalCrop(layer_id id, const FinalCropChange& fcc) { +void Replayer::setFinalCrop(SurfaceComposerClient::Transaction& t, + layer_id id, const FinalCropChange& fcc) { ALOGV("Layer %d: Setting Final Crop -- left=%d, top=%d, right=%d, bottom=%d", id, fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(), fcc.rectangle().bottom()); Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(), fcc.rectangle().bottom()); - return mLayers[id]->setFinalCrop(r); + t.setFinalCrop(mLayers[id], r); } -status_t Replayer::setMatrix(layer_id id, const MatrixChange& mc) { +void Replayer::setMatrix(SurfaceComposerClient::Transaction& t, + layer_id id, const MatrixChange& mc) { ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy()); - return mLayers[id]->setMatrix(mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy()); + t.setMatrix(mLayers[id], mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy()); } -status_t Replayer::setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc) { +void Replayer::setOverrideScalingMode(SurfaceComposerClient::Transaction& t, + layer_id id, const OverrideScalingModeChange& osmc) { ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode()); - return mLayers[id]->setOverrideScalingMode(osmc.override_scaling_mode()); + t.setOverrideScalingMode(mLayers[id], osmc.override_scaling_mode()); } -status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trhc) { +void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t, + layer_id id, const TransparentRegionHintChange& trhc) { ALOGV("Setting Transparent Region Hint"); Region re = Region(); @@ -510,71 +525,80 @@ status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegion re.merge(rect); } - return mLayers[id]->setTransparentRegionHint(re); + t.setTransparentRegionHint(mLayers[id], re); } -status_t Replayer::setLayerStack(layer_id id, const LayerStackChange& lsc) { +void Replayer::setLayerStack(SurfaceComposerClient::Transaction& t, + layer_id id, const LayerStackChange& lsc) { ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack()); - return mLayers[id]->setLayerStack(lsc.layer_stack()); + t.setLayerStack(mLayers[id], lsc.layer_stack()); } -status_t Replayer::setHiddenFlag(layer_id id, const HiddenFlagChange& hfc) { +void Replayer::setHiddenFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const HiddenFlagChange& hfc) { ALOGV("Layer %d: Setting Hidden Flag -- hidden_flag=%d", id, hfc.hidden_flag()); layer_id flag = hfc.hidden_flag() ? layer_state_t::eLayerHidden : 0; - return mLayers[id]->setFlags(flag, layer_state_t::eLayerHidden); + t.setFlags(mLayers[id], flag, layer_state_t::eLayerHidden); } -status_t Replayer::setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc) { +void Replayer::setOpaqueFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const OpaqueFlagChange& ofc) { ALOGV("Layer %d: Setting Opaque Flag -- opaque_flag=%d", id, ofc.opaque_flag()); layer_id flag = ofc.opaque_flag() ? layer_state_t::eLayerOpaque : 0; - return mLayers[id]->setFlags(flag, layer_state_t::eLayerOpaque); + t.setFlags(mLayers[id], flag, layer_state_t::eLayerOpaque); } -status_t Replayer::setSecureFlag(layer_id id, const SecureFlagChange& sfc) { +void Replayer::setSecureFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const SecureFlagChange& sfc) { ALOGV("Layer %d: Setting Secure Flag -- secure_flag=%d", id, sfc.secure_flag()); layer_id flag = sfc.secure_flag() ? layer_state_t::eLayerSecure : 0; - return mLayers[id]->setFlags(flag, layer_state_t::eLayerSecure); + t.setFlags(mLayers[id], flag, layer_state_t::eLayerSecure); } -status_t Replayer::setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc) { +void Replayer::setDeferredTransaction(SurfaceComposerClient::Transaction& t, + layer_id id, const DeferredTransactionChange& dtc) { ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, " "frame_number=%llu", id, dtc.layer_id(), dtc.frame_number()); if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) { ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id()); - return BAD_VALUE; + return; } auto handle = mLayers[dtc.layer_id()]->getHandle(); - return mLayers[id]->deferTransactionUntil(handle, dtc.frame_number()); + t.deferTransactionUntil(mLayers[id], handle, dtc.frame_number()); } -void Replayer::setDisplaySurface(display_id id, const DispSurfaceChange& /*dsc*/) { +void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t, + display_id id, const DispSurfaceChange& /*dsc*/) { sp outProducer; sp outConsumer; BufferQueue::createBufferQueue(&outProducer, &outConsumer); - SurfaceComposerClient::setDisplaySurface(mDisplays[id], outProducer); + t.setDisplaySurface(mDisplays[id], outProducer); } -void Replayer::setDisplayLayerStack(display_id id, const LayerStackChange& lsc) { - SurfaceComposerClient::setDisplayLayerStack(mDisplays[id], lsc.layer_stack()); +void Replayer::setDisplayLayerStack(SurfaceComposerClient::Transaction& t, + display_id id, const LayerStackChange& lsc) { + t.setDisplayLayerStack(mDisplays[id], lsc.layer_stack()); } -void Replayer::setDisplaySize(display_id id, const SizeChange& sc) { - SurfaceComposerClient::setDisplaySize(mDisplays[id], sc.w(), sc.h()); +void Replayer::setDisplaySize(SurfaceComposerClient::Transaction& t, + display_id id, const SizeChange& sc) { + t.setDisplaySize(mDisplays[id], sc.w(), sc.h()); } -void Replayer::setDisplayProjection(display_id id, const ProjectionChange& pc) { +void Replayer::setDisplayProjection(SurfaceComposerClient::Transaction& t, + display_id id, const ProjectionChange& pc) { Rect viewport = Rect(pc.viewport().left(), pc.viewport().top(), pc.viewport().right(), pc.viewport().bottom()); Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom()); - SurfaceComposerClient::setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame); + t.setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame); } status_t Replayer::createSurfaceControl( diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h index f36c9fd4a47958b231ea5c4de2a43955d2caf5d1..295403eace76608253458194154064facac965b8 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -77,28 +77,48 @@ class Replayer { void deleteDisplay(const DisplayDeletion& delete_, const std::shared_ptr& event); void updatePowerMode(const PowerModeUpdate& update, const std::shared_ptr& event); - status_t doSurfaceTransaction(const SurfaceChanges& surfaceChange); - void doDisplayTransaction(const DisplayChanges& displayChange); - - status_t setPosition(layer_id id, const PositionChange& pc); - status_t setSize(layer_id id, const SizeChange& sc); - status_t setAlpha(layer_id id, const AlphaChange& ac); - status_t setLayer(layer_id id, const LayerChange& lc); - status_t setCrop(layer_id id, const CropChange& cc); - status_t setFinalCrop(layer_id id, const FinalCropChange& fcc); - status_t setMatrix(layer_id id, const MatrixChange& mc); - status_t setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc); - status_t setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trgc); - status_t setLayerStack(layer_id id, const LayerStackChange& lsc); - status_t setHiddenFlag(layer_id id, const HiddenFlagChange& hfc); - status_t setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc); - status_t setSecureFlag(layer_id id, const SecureFlagChange& sfc); - status_t setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc); - - void setDisplaySurface(display_id id, const DispSurfaceChange& dsc); - void setDisplayLayerStack(display_id id, const LayerStackChange& lsc); - void setDisplaySize(display_id id, const SizeChange& sc); - void setDisplayProjection(display_id id, const ProjectionChange& pc); + status_t doSurfaceTransaction(SurfaceComposerClient::Transaction& transaction, + const SurfaceChanges& surfaceChange); + void doDisplayTransaction(SurfaceComposerClient::Transaction& transaction, + const DisplayChanges& displayChange); + + void setPosition(SurfaceComposerClient::Transaction& t, + layer_id id, const PositionChange& pc); + void setSize(SurfaceComposerClient::Transaction& t, + layer_id id, const SizeChange& sc); + void setAlpha(SurfaceComposerClient::Transaction& t, + layer_id id, const AlphaChange& ac); + void setLayer(SurfaceComposerClient::Transaction& t, + layer_id id, const LayerChange& lc); + void setCrop(SurfaceComposerClient::Transaction& t, + layer_id id, const CropChange& cc); + void setFinalCrop(SurfaceComposerClient::Transaction& t, + layer_id id, const FinalCropChange& fcc); + void setMatrix(SurfaceComposerClient::Transaction& t, + layer_id id, const MatrixChange& mc); + void setOverrideScalingMode(SurfaceComposerClient::Transaction& t, + layer_id id, const OverrideScalingModeChange& osmc); + void setTransparentRegionHint(SurfaceComposerClient::Transaction& t, + layer_id id, const TransparentRegionHintChange& trgc); + void setLayerStack(SurfaceComposerClient::Transaction& t, + layer_id id, const LayerStackChange& lsc); + void setHiddenFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const HiddenFlagChange& hfc); + void setOpaqueFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const OpaqueFlagChange& ofc); + void setSecureFlag(SurfaceComposerClient::Transaction& t, + layer_id id, const SecureFlagChange& sfc); + void setDeferredTransaction(SurfaceComposerClient::Transaction& t, + layer_id id, const DeferredTransactionChange& dtc); + + void setDisplaySurface(SurfaceComposerClient::Transaction& t, + display_id id, const DispSurfaceChange& dsc); + void setDisplayLayerStack(SurfaceComposerClient::Transaction& t, + display_id id, const LayerStackChange& lsc); + void setDisplaySize(SurfaceComposerClient::Transaction& t, + display_id id, const SizeChange& sc); + void setDisplayProjection(SurfaceComposerClient::Transaction& t, + display_id id, const ProjectionChange& pc); void doDeleteSurfaceControls(); void waitUntilTimestamp(int64_t timestamp); diff --git a/data/etc/android.hardware.camera.ar.xml b/data/etc/android.hardware.camera.ar.xml new file mode 100644 index 0000000000000000000000000000000000000000..2fc3280b6dc194bc6c7e4a30d8760d25772ebdde --- /dev/null +++ b/data/etc/android.hardware.camera.ar.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/data/etc/android.hardware.sensor.assist.xml b/data/etc/android.hardware.sensor.assist.xml new file mode 100644 index 0000000000000000000000000000000000000000..c7f9d5601625f60e659945bdabc34151e49aba9b --- /dev/null +++ b/data/etc/android.hardware.sensor.assist.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/data/etc/android.hardware.strongbox_keystore.xml b/data/etc/android.hardware.strongbox_keystore.xml new file mode 100644 index 0000000000000000000000000000000000000000..2a0ec3780c8c41356d8ff35877dd70b848daadfc --- /dev/null +++ b/data/etc/android.hardware.strongbox_keystore.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/data/etc/android.hardware.vulkan.version-1_1.xml b/data/etc/android.hardware.vulkan.version-1_1.xml new file mode 100644 index 0000000000000000000000000000000000000000..9704e0f5da9a9a260ea30debf6532dc5f9d8af05 --- /dev/null +++ b/data/etc/android.hardware.vulkan.version-1_1.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/data/etc/android.hardware.wifi.rtt.xml b/data/etc/android.hardware.wifi.rtt.xml new file mode 100644 index 0000000000000000000000000000000000000000..60529ea1aec7703caf98e63d51b39c1d586e8ddb --- /dev/null +++ b/data/etc/android.hardware.wifi.rtt.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/data/etc/android.software.device_id_attestation.xml b/data/etc/android.software.device_id_attestation.xml new file mode 100644 index 0000000000000000000000000000000000000000..4e637ca98b9e5d7f3aa73168b5b97c28b3fbebda --- /dev/null +++ b/data/etc/android.software.device_id_attestation.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/data/etc/aosp_excluded_hardware.xml b/data/etc/aosp_excluded_hardware.xml new file mode 100644 index 0000000000000000000000000000000000000000..013f278f340790d818bde963410c20840e302bb7 --- /dev/null +++ b/data/etc/aosp_excluded_hardware.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml new file mode 100644 index 0000000000000000000000000000000000000000..8b5a46187f9fc6511d7e6a5ef566056fea79d400 --- /dev/null +++ b/data/etc/go_handheld_core_hardware.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml index ec7be53bfc40584bd76ebd7e6a382d75f4f0939b..060a3346c8d9c9460b62599fe6ea498f7d8f3b2e 100644 --- a/data/etc/handheld_core_hardware.xml +++ b/data/etc/handheld_core_hardware.xml @@ -14,9 +14,9 @@ limitations under the License. --> - - + - - diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml index d7c3730f5be8da5665878d0ef16c1c0fff84c2d1..e2ab71a853f0ef55b37ea766d0131cfd35b22d73 100644 --- a/data/etc/wearable_core_hardware.xml +++ b/data/etc/wearable_core_hardware.xml @@ -36,9 +36,6 @@ - - - diff --git a/docs/Doxyfile b/docs/Doxyfile index bb0ca3251f40901ee1722b7bab44efb1f2bbb85e..efa639d2e77aa0d87d83add3f19c8399e30461fd 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -677,7 +677,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../include/android ../../av/include/ndk ../../av/include/camera/ndk +INPUT = ../include/android ../../av/media/ndk/include ../../av/camera/ndk/include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -1580,20 +1580,20 @@ PERLMOD_MAKEVAR_PREFIX = # evaluate all C-preprocessor directives found in the sources and include # files. -ENABLE_PREPROCESSING = NO +ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. @@ -1621,7 +1621,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = +PREDEFINED = __attribute__(x)= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png index a02fd893b286cdc7a36584f84194d6e8b567f657..f739fa2bc204d8a1e42518d6965eb22d1f8097aa 100644 Binary files a/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png and b/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png differ diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png index c309ac5ea887eb36bc8bc1082d418a81fc1b5200..4b45e3aa9cc7ab20e962370eba644a061d8fa578 100644 Binary files a/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png and b/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png differ diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png index 414fad49a919e07e185a5530dfff3979f8ca23a9..748d1a29626e3425008c2a5829b457fae74dd745 100644 Binary files a/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png and b/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png differ diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png index c147a8729f171818230fbe19e3315c21faf6e39f..6e436baa3b58ae0fc1f5ccf7aedf2657c88b8f39 100644 Binary files a/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png and b/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png differ diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png index 4ce2125f3c911c10b2e92094087154b7694715e1..9776874bb0191c6e2274973b36703f48d58f8ebe 100644 Binary files a/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png and b/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png differ diff --git a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h new file mode 100644 index 0000000000000000000000000000000000000000..b32c92eb88d68f13317edad21f1711d103044fa6 --- /dev/null +++ b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h @@ -0,0 +1,46 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_IARC_VIDEO_BRIDGE_H +#define ANDROID_IARC_VIDEO_BRIDGE_H + +#include +#include +#include + +namespace android { + +class IArcVideoBridge : public IInterface { +public: + DECLARE_META_INTERFACE(ArcVideoBridge); + + // Returns MojoBootstrapResult for creating mojo ipc channel of + // VideoAcceleratorFactory. + virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() = 0; + + // Get the version of the remote VideoHost on Chromium side. + virtual int32_t hostVersion() = 0; +}; + +class BnArcVideoBridge : public BnInterface { +public: + virtual status_t onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); +}; + +}; // namespace android + +#endif // ANDROID_IARC_VIDEO_BRIDGE_H diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h index 67f4511e6525ad1e8e8880b61bdbab14b8b528f8..4de314dca4d72ccf8bbf5b1135ee7ae6982c4e03 100644 --- a/headers/media_plugin/media/cas/CasAPI.h +++ b/headers/media_plugin/media/cas/CasAPI.h @@ -63,7 +63,7 @@ struct CasFactory { // Construct a new instance of a CasPlugin given a CA_system_id virtual status_t createPlugin( int32_t CA_system_id, - uint64_t appData, + void *appData, CasPluginCallback callback, CasPlugin **plugin) = 0; diff --git a/headers/media_plugin/media/cas/DescramblerAPI.h b/headers/media_plugin/media/cas/DescramblerAPI.h index 0a519525e022dea58760eb1bae69863a0d31a285..033c8ce7f9aa518b94fe2a53f0dbdf17887c6671 100644 --- a/headers/media_plugin/media/cas/DescramblerAPI.h +++ b/headers/media_plugin/media/cas/DescramblerAPI.h @@ -48,6 +48,10 @@ struct DescramblerPlugin { kScrambling_Reserved = 1, kScrambling_EvenKey = 2, kScrambling_OddKey = 3, + kScrambling_Mask_Key = 0x3, + + // Hint that the descrambling request is for a PES header only + kScrambling_Flag_PesHeader = (1 << 31), }; struct SubSample { diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h index 985d919220cc6e1b437c17fe7ed996c33acb6ee4..c44a1f61529d5a4dc25e4180e4903d9af13e4c4c 100644 --- a/headers/media_plugin/media/drm/DrmAPI.h +++ b/headers/media_plugin/media/drm/DrmAPI.h @@ -102,7 +102,9 @@ namespace android { kKeyRequestType_Unknown, kKeyRequestType_Initial, kKeyRequestType_Renewal, - kKeyRequestType_Release + kKeyRequestType_Release, + kKeyRequestType_None, + kKeyRequestType_Update, }; // Enumerate KeyStatusTypes which indicate the state of a key @@ -123,6 +125,48 @@ namespace android { KeyStatusType mType; }; + // Enumerate HDCP output protection levels + enum HdcpLevel { + // Failure to access HDCP level, an error occurred + kHdcpLevelUnknown, + // HDCP is not supported on this device, content is unprotected + kHdcpNone, + // HDCP version 1.0 + kHdcpV1, + // HDCP version 2.0 Type 1. + kHdcpV2, + // HDCP version 2.1 Type 1. + kHdcpV2_1, + // HDCP version 2.2 Type 1. + kHdcpV2_2, + // No digital output, implicitly secure + kHdcpNoOutput = 0x7fff + }; + + // SecurityLevel indicates the level of robustness of the DRM + // implementation on the device + enum SecurityLevel { + // Failure to access security level, an error occurred + kSecurityLevelUnknown, + // The maximum security level of the device. This is the default when + // a session is opened if no security level is specified + kSecurityLevelMax, + // Software-based whitebox crypto + kSecurityLevelSwSecureCrypto, + // Software-based whitebox crypto and an obfuscated decoder + kSecurityLevelSwSecureDecode, + // DRM key management and crypto operations are performed within a + // hardware backed trusted execution environment + kSecurityLevelHwSecureCrypto, + // DRM key management, crypto operations and decoding of content + // are performed within a hardware backed trusted execution environment + kSecurityLevelHwSecureDecode, + // DRM key management, crypto operations, decoding of content and all + // handling of the media (compressed and uncompressed) is handled within + // a hardware backed trusted execution environment. + kSecurityLevelHwSecureAll + }; + DrmPlugin() {} virtual ~DrmPlugin() {} diff --git a/headers/media_plugin/media/openmax/OMX_Audio.h b/headers/media_plugin/media/openmax/OMX_Audio.h index 9c0296bf55538bc3b1dc3de219ac312874d0994d..f8a36bd43232327ce453f0bdbb2a1d9bd26ca258 100644 --- a/headers/media_plugin/media/openmax/OMX_Audio.h +++ b/headers/media_plugin/media/openmax/OMX_Audio.h @@ -263,6 +263,7 @@ typedef enum OMX_AUDIO_AACPROFILETYPE{ OMX_AUDIO_AACObjectLD = 23, /**< AAC Low Delay object (Error Resilient) */ OMX_AUDIO_AACObjectHE_PS = 29, /**< AAC High Efficiency with Parametric Stereo coding (HE-AAC v2, object type PS) */ OMX_AUDIO_AACObjectELD = 39, /** AAC Enhanced Low Delay. NOTE: Pending Khronos standardization **/ + OMX_AUDIO_AACObjectXHE = 42, /** extended High Efficiency AAC. NOTE: Pending Khronos standardization */ OMX_AUDIO_AACObjectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_AUDIO_AACObjectVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_AUDIO_AACObjectMax = 0x7FFFFFFF diff --git a/headers/media_plugin/media/openmax/OMX_AudioExt.h b/headers/media_plugin/media/openmax/OMX_AudioExt.h index 05c223212e3f40cbccab6b1902f915467ecb33c0..8409553697a618803834b16c041f9e32d5786bb6 100644 --- a/headers/media_plugin/media/openmax/OMX_AudioExt.h +++ b/headers/media_plugin/media/openmax/OMX_AudioExt.h @@ -82,6 +82,7 @@ typedef struct OMX_AUDIO_PARAM_ANDROID_OPUSTYPE { limit the audio signal. Use 0 to let encoder decide */ } OMX_AUDIO_PARAM_ANDROID_OPUSTYPE; +/** deprecated. use OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE */ typedef struct OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE { OMX_U32 nSize; /**< size of the structure in bytes */ OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ @@ -94,6 +95,19 @@ typedef struct OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE { OMX_S32 nPCMLimiterEnable; /**< Signal level limiting, 0 for disable, 1 for enable, -1 if unspecified */ } OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE; +typedef struct OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE { + OMX_U32 nSize; /**< size of the structure in bytes */ + OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ + OMX_S32 nMaxOutputChannels; /**< Maximum channel count to be output, -1 if unspecified, 0 if downmixing disabled */ + OMX_S32 nDrcCut; /**< The DRC attenuation factor, between 0 and 127, -1 if unspecified */ + OMX_S32 nDrcBoost; /**< The DRC amplification factor, between 0 and 127, -1 if unspecified */ + OMX_S32 nHeavyCompression; /**< 0 for light compression, 1 for heavy compression, -1 if unspecified */ + OMX_S32 nTargetReferenceLevel; /**< Target reference level, between 0 and 127, -1 if unspecified */ + OMX_S32 nEncodedTargetLevel; /**< Target reference level assumed at the encoder, between 0 and 127, -1 if unspecified */ + OMX_S32 nPCMLimiterEnable; /**< Signal level limiting, 0 for disable, 1 for enable, -1 if unspecified */ + OMX_S32 nDrcEffectType; /**< MPEG-D DRC effect type, between -1 and 6, -2 if unspecified */ +} OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE; + typedef struct OMX_AUDIO_PARAM_ANDROID_PROFILETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; diff --git a/headers/media_plugin/media/openmax/OMX_IVCommon.h b/headers/media_plugin/media/openmax/OMX_IVCommon.h index f9b6f4b0fd279a370a455ffa7e3a6a7bea65ab9e..f83114b0400ef195bfc6ac8f3357d68c26465005 100644 --- a/headers/media_plugin/media/openmax/OMX_IVCommon.h +++ b/headers/media_plugin/media/openmax/OMX_IVCommon.h @@ -165,6 +165,14 @@ typedef enum OMX_COLOR_FORMATTYPE { * format for it. */ OMX_COLOR_FormatYUV420Flexible = 0x7F420888, + // 10-bit or 12-bit YUV format, LSB-justified (0's on higher bits) + OMX_COLOR_FormatYUV420Planar16 = 0x7F42016B, + + // Packed 10-bit YUV444 representation that includes 2 bits of alpha. Each pixel is + // 32-bit. Bits 0-9 contain the U sample, bits 10-19 contain the Y sample, + // bits 20-29 contain the V sample, and bits 30-31 contain the alpha value. + OMX_COLOR_FormatYUV444Y410 = 0x7F444AAA, + OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100, OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00, OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03, diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h index 5a029d0a4bf31e66917457a1daaac43fbc5cb2a8..716d9599799c34f240ec4d70c91b8a20f1b2bf42 100644 --- a/headers/media_plugin/media/openmax/OMX_IndexExt.h +++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h @@ -63,6 +63,7 @@ typedef enum OMX_INDEXEXTTYPE { OMX_IndexParamAudioAndroidAacPresentation, /**< reference: OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE */ OMX_IndexParamAudioAndroidEac3, /**< reference: OMX_AUDIO_PARAM_ANDROID_EAC3TYPE */ OMX_IndexParamAudioProfileQuerySupported, /**< reference: OMX_AUDIO_PARAM_ANDROID_PROFILETYPE */ + OMX_IndexParamAudioAndroidAacDrcPresentation, /**< reference: OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE */ OMX_IndexExtAudioEndUnused, /* Image parameters and configurations */ @@ -85,6 +86,7 @@ typedef enum OMX_INDEXEXTTYPE { OMX_IndexParamMaxFrameDurationForBitrateControl,/**< reference: OMX_PARAM_U32TYPE */ OMX_IndexParamVideoVp9, /**< reference: OMX_VIDEO_PARAM_VP9TYPE */ OMX_IndexParamVideoAndroidVp9Encoder, /**< reference: OMX_VIDEO_PARAM_ANDROID_VP9ENCODERTYPE */ + OMX_IndexParamVideoAndroidImageGrid, /**< reference: OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE */ OMX_IndexExtVideoEndUnused, /* Image & Video common configurations */ diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h index 76efac9b3ea928c4c4111f8d7321b697337386f6..9fd2fd2d65782a426121e37a57cb3a3d074ab6b6 100644 --- a/headers/media_plugin/media/openmax/OMX_Video.h +++ b/headers/media_plugin/media/openmax/OMX_Video.h @@ -89,6 +89,7 @@ typedef enum OMX_VIDEO_CODINGTYPE { OMX_VIDEO_CodingVP9, /**< Google VP9 */ OMX_VIDEO_CodingHEVC, /**< ITU H.265/HEVC */ OMX_VIDEO_CodingDolbyVision,/**< Dolby Vision */ + OMX_VIDEO_CodingImageHEIC, /**< HEIF image encoded with HEVC */ 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 @@ -240,6 +241,7 @@ typedef enum OMX_VIDEO_CONTROLRATETYPE { OMX_Video_ControlRateConstant, OMX_Video_ControlRateVariableSkipFrames, OMX_Video_ControlRateConstantSkipFrames, + OMX_Video_ControlRateConstantQuality, OMX_Video_ControlRateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_Video_ControlRateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_Video_ControlRateMax = 0x7FFFFFFF @@ -254,14 +256,20 @@ typedef enum OMX_VIDEO_CONTROLRATETYPE { * nVersion : OMX spec version info * nPortIndex : Port that this struct applies to * eControlRate : Control rate type enum - * nTargetBitrate : Target bitrate to encode with + * nTargetBitrate : Target bitrate to encode with (used when eControlRate is + * not OMX_Video_ControlRateConstantQuality) + * nQualityFactor : Quality to encode with (used when eControlRate is + * OMX_Video_ControlRateConstantQuality only) */ typedef struct OMX_VIDEO_PARAM_BITRATETYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_U32 nPortIndex; OMX_VIDEO_CONTROLRATETYPE eControlRate; - OMX_U32 nTargetBitrate; + union { + OMX_U32 nTargetBitrate; + OMX_U32 nQualityFactor; + }; } OMX_VIDEO_PARAM_BITRATETYPE; diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h index c1025643efcc9a5e4702ba7c4c563c3a133cb4d9..bbf157b88959774cb69c3c8c836974937e4d7588 100644 --- a/headers/media_plugin/media/openmax/OMX_VideoExt.h +++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h @@ -213,6 +213,7 @@ typedef enum OMX_VIDEO_HEVCPROFILETYPE { OMX_VIDEO_HEVCProfileUnknown = 0x0, OMX_VIDEO_HEVCProfileMain = 0x1, OMX_VIDEO_HEVCProfileMain10 = 0x2, + OMX_VIDEO_HEVCProfileMainStill = 0x4, // Main10 profile with HDR SEI support. OMX_VIDEO_HEVCProfileMain10HDR10 = 0x1000, OMX_VIDEO_HEVCProfileMax = 0x7FFFFFFF @@ -421,6 +422,49 @@ typedef struct OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE { OMX_U32 nBitrateRatios[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS]; } OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE; +/** + * Android specific param for specifying image grid layout information for image encoding + * use cases, corresponding to index OMX_IndexParamVideoAndroidImageGrid. + * + * OMX_VIDEO_CodingImageHEIC encoders must handle this param type. When this param is set + * on the component with bEnabled set to true, nTileWidth, nTileHeight, nGridRows, + * nGridCols indicates the desired grid config by the client. The component can use this + * as a heuristic, and is free to choose any suitable grid configs. The client shall + * always get the actual from the component after the param is set. Encoder will receive + * each input image in full, and shall encode it into tiles in row-major, top-row first, + * left-to-right order, and send each encoded tile in a separate output buffer. All output + * buffers for the same input buffer shall carry the same timestamp as the input buffer. + * If the input buffer is marked EOS, the EOS should only appear on the last output buffer + * for that input buffer. + * + * OMX_VIDEO_CodingHEVC encoders might also receive this param when it's used for image + * encoding, although in this case the param only serves as a hint. The encoder will + * receive the input image tiles in row-major, top-row first, left-to-right order. + * The grid config can be used for quality control, or optimizations. + * + * If this param is not set, the component shall assume that grid option is disabled. + * + * nSize : Size of the structure in bytes + * nVersion : OMX specification version information + * nPortIndex : Port that this structure applies to (output port for encoders) + * bEnabled : Whether grid is enabled. If true, the other parameters + * specifies the grid config; otherwise they shall be ignored. + * nTileWidth : Width of each tile. + * nTileHeight : Height of each tile. + * nGridRows : Number of rows in the grid. + * nGridCols : Number of cols in the grid. + */ +typedef struct OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE { + OMX_U32 nSize; + OMX_VERSIONTYPE nVersion; + OMX_U32 nPortIndex; + OMX_BOOL bEnabled; + OMX_U32 nTileWidth; + OMX_U32 nTileHeight; + OMX_U32 nGridRows; + OMX_U32 nGridCols; +} OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE; + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h index 60208701b69f24da2fd7d911ceed8946791abaae..7c4be24dbdbc3b24cf5a4efc24510a36220e198f 100644 --- a/include/android/hardware_buffer_jni.h +++ b/include/android/hardware_buffer_jni.h @@ -31,9 +31,11 @@ __BEGIN_DECLS /** * Return the AHardwareBuffer associated with a Java HardwareBuffer object, - * for interacting with it through native code. This acquires a reference - * on the AHardwareBuffer that is returned; be sure to use - * AHardwareBuffer_release() when done with it so that it doesn't leak. + * for interacting with it through native code. This method does not acquire any + * additional reference to the AHardwareBuffer 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. */ AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env, jobject hardwareBufferObj); diff --git a/include/android/keycodes.h b/include/android/keycodes.h index 2164d6163e1646c22825e364cad4f3c47638effd..59d67f35f24d231be7999174867774c2c62453e4 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -767,7 +767,9 @@ enum { /** fingerprint navigation key, right. */ AKEYCODE_SYSTEM_NAVIGATION_RIGHT = 283, /** all apps */ - AKEYCODE_ALL_APPS = 284 + AKEYCODE_ALL_APPS = 284, + /** refresh key */ + AKEYCODE_REFRESH = 285 // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/include/android/sensor.h b/include/android/sensor.h index 029db0a2fea82fb0df263a5ae6f5a0efc4349aef..191777cee5bb35dead226c6e43c6e8cd3f81bc30 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -288,7 +288,7 @@ enum { * A sensor event. */ -/* NOTE: Must match hardware/sensors.h */ +/* NOTE: changes to these structs have to be backward compatible */ typedef struct ASensorVector { union { float v[3]; @@ -350,7 +350,7 @@ typedef struct { }; } AAdditionalInfoEvent; -/* NOTE: Must match hardware/sensors.h */ +/* NOTE: changes to this struct has to be backward compatible */ typedef struct ASensorEvent { int32_t version; /* sizeof(struct ASensorEvent) */ int32_t sensor; diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h new file mode 100644 index 0000000000000000000000000000000000000000..56b334216692f4724f90435151cefd2bdd7e053f --- /dev/null +++ b/include/android/surface_texture.h @@ -0,0 +1,162 @@ +/* + * 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. + */ + +/** + * @addtogroup SurfaceTexture + * @{ + */ + +/** + * @file surface_texture.h + */ + +#ifndef ANDROID_NATIVE_SURFACE_TEXTURE_H +#define ANDROID_NATIVE_SURFACE_TEXTURE_H + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +#include + +#include + +__BEGIN_DECLS + +struct ASurfaceTexture; + +/** + * {@link ASurfaceTexture} is an opaque type to manage SurfaceTexture from native code + * + * {@link ASurfaceTexture} can be obtained from an android.graphics.SurfaceTexture object using + * ASurfaceTexture_fromSurfaceTexture(). + */ +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. + * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() + */ +void ASurfaceTexture_release(ASurfaceTexture* st); + +/** + * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture. + * This is equivalent to Java's: Surface sur = new Surface(surfaceTexture); + * + * \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 + * returned if \st is null or if it's not an instance of android.graphics.SurfaceTexture + */ +ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st); + +/** + * Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread. A + * new OpenGL ES texture object is created and populated with the SurfaceTexture image frame + * that was current at the time of the last call to {@link #detachFromGLContext}. This new + * texture is bound to the GL_TEXTURE_EXTERNAL_OES texture target. + * + * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES + * contexts. Note, however, that the image contents are only accessible from one OpenGL ES + * context at a time. + * + * \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. + * \return 0 on success, negative posix error code otherwise (see ) + */ +int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName); + +/** + * Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object. + * This call must be made with the OpenGL ES context current on the calling thread. The OpenGL + * ES texture object will be deleted as a result of this call. After calling this method all + * calls to {@link #updateTexImage} will fail until a successful call to {@link #attachToGLContext} + * is made. + * + * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES + * contexts. Note, however, that the image contents are only accessible from one OpenGL ES + * context at a time. + * + * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() + * \return 0 on success, negative posix error code otherwise (see ) + */ +int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st); + +/** + * Update the texture image to the most recent frame from the image stream. This may only be + * 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. + * + * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() + * \return 0 on success, negative posix error code otherwise (see ) + */ +int ASurfaceTexture_updateTexImage(ASurfaceTexture* st); + +/** + * Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by + * the most recent call to updateTexImage. + * + * This transform matrix maps 2D homogeneous texture coordinates of the form (s, t, 0, 1) with s + * and t in the inclusive range [0, 1] to the texture coordinate that should be used to sample + * that location from the texture. Sampling the texture outside of the range of this transform + * is undefined. + * + * The matrix is stored in column-major order so that it may be passed directly to OpenGL ES via + * the glLoadMatrixf or glUniformMatrix4fv functions. + * + * \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. + */ +void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]); + +/** + * Retrieve the timestamp associated with the texture image set by the most recent call to + * updateTexImage. + * + * This timestamp is in nanoseconds, and is normally monotonically increasing. The timestamp + * should be unaffected by time-of-day adjustments, and for a camera should be strictly + * monotonic but for a MediaPlayer may be reset when the position is set. The + * specific meaning and zero point of the timestamp depends on the source providing images to + * the SurfaceTexture. Unless otherwise specified by the image source, timestamps cannot + * generally be compared across SurfaceTexture instances, or across multiple program + * invocations. It is mostly useful for determining time offsets between subsequent frames. + * + * For EGL/Vulkan producers, this timestamp is the desired present time set with the + * EGL_ANDROID_presentation_time or VK_GOOGLE_display_timing extensions + * + * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() + */ +int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st); + +__END_DECLS + +#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_H */ diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h new file mode 100644 index 0000000000000000000000000000000000000000..b0e1edd5909e1f1082d567c5fe4f769633d969f1 --- /dev/null +++ b/include/android/surface_texture_jni.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/** + * @addtogroup SurfaceTexture + * @{ + */ + +/** + * @file surface_texture_jni.h + */ + +#ifndef ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H +#define ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H + +#include + +#include + +__BEGIN_DECLS + +/** + * Get a reference to the native ASurfaceTexture from the corresponding java object. + * + * The caller must keep a reference to the Java SurfaceTexture during the lifetime of the returned + * ASurfaceTexture. Failing to do so could result in the ASurfaceTexture to stop functioning + * properly once the Java object gets finalized. + * However, this will not result in program termination. + * + * \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); + +__END_DECLS + +#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H */ diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h index 067dc5cf2200375a72c76dbfb4d037558c13c6b0..d279bbd0457780a8f4e0c7bb058aa85627bdda2f 100644 --- a/include/audiomanager/IAudioManager.h +++ b/include/audiomanager/IAudioManager.h @@ -32,90 +32,10 @@ public: // These transaction IDs must be kept in sync with the method order from // IAudioService.aidl. enum { - // transaction IDs for the unsupported methods are commented out - /* - ADJUSTSUGGESTEDSTREAMVOLUME = IBinder::FIRST_CALL_TRANSACTION, - ADJUSTSTREAMVOLUME = IBinder::FIRST_CALL_TRANSACTION + 1, - SETSTREAMVOLUME = IBinder::FIRST_CALL_TRANSACTION + 2, - ISSTREAMMUTE = IBinder::FIRST_CALL_TRANSACTION + 3, - FORCEREMOTESUBMIXFULLVOLUME = IBinder::FIRST_CALL_TRANSACTION + 4, - ISMASTERMUTE = IBinder::FIRST_CALL_TRANSACTION + 5, - SETMASTERMUTE = IBinder::FIRST_CALL_TRANSACTION + 6, - GETSTREAMVOLUME = IBinder::FIRST_CALL_TRANSACTION + 7, - GETSTREAMMINVOLUME = IBinder::FIRST_CALL_TRANSACTION + 8, - GETSTREAMMAXVOLUME = IBinder::FIRST_CALL_TRANSACTION + 9, - GETLASTAUDIBLESTREAMVOLUME = IBinder::FIRST_CALL_TRANSACTION + 10, - SETMICROPHONEMUTE = IBinder::FIRST_CALL_TRANSACTION + 11, - SETRINGERMODEEXTERNAL = IBinder::FIRST_CALL_TRANSACTION + 12, - SETRINGERMODEINTERNAL = IBinder::FIRST_CALL_TRANSACTION + 13, - GETRINGERMODEEXTERNAL = IBinder::FIRST_CALL_TRANSACTION + 14, - GETRINGERMODEINTERNAL = IBinder::FIRST_CALL_TRANSACTION + 15, - ISVALIDRINGERMODE = IBinder::FIRST_CALL_TRANSACTION + 16, - SETVIBRATESETTING = IBinder::FIRST_CALL_TRANSACTION + 17, - GETVIBRATESETTING = IBinder::FIRST_CALL_TRANSACTION + 18, - SHOULDVIBRATE = IBinder::FIRST_CALL_TRANSACTION + 19, - SETMODE = IBinder::FIRST_CALL_TRANSACTION + 20, - GETMODE = IBinder::FIRST_CALL_TRANSACTION + 21, - PLAYSOUNDEFFECT = IBinder::FIRST_CALL_TRANSACTION + 22, - PLAYSOUNDEFFECTVOLUME = IBinder::FIRST_CALL_TRANSACTION + 23, - LOADSOUNDEFFECTS = IBinder::FIRST_CALL_TRANSACTION + 24, - UNLOADSOUNDEFFECTS = IBinder::FIRST_CALL_TRANSACTION + 25, - RELOADAUDIOSETTINGS = IBinder::FIRST_CALL_TRANSACTION + 26, - AVRCPSUPPORTSABSOLUTEVOLUME = IBinder::FIRST_CALL_TRANSACTION + 27, - SETSPEAKERPHONEON = IBinder::FIRST_CALL_TRANSACTION + 28, - ISSPEAKERPHONEON = IBinder::FIRST_CALL_TRANSACTION + 29, - SETBLUETOOTHSCOON = IBinder::FIRST_CALL_TRANSACTION + 30, - ISBLUETOOTHSCOON = IBinder::FIRST_CALL_TRANSACTION + 31, - SETBLUETOOTHA2DPON = IBinder::FIRST_CALL_TRANSACTION + 32, - ISBLUETOOTHA2DPON = IBinder::FIRST_CALL_TRANSACTION + 33, - REQUESTAUDIOFOCUS = IBinder::FIRST_CALL_TRANSACTION + 34, - ABANDONAUDIOFOCUS = IBinder::FIRST_CALL_TRANSACTION + 35, - UNREGISTERAUDIOFOCUSCLIENT = IBinder::FIRST_CALL_TRANSACTION + 36, - GETCURRENTAUDIOFOCUS = IBinder::FIRST_CALL_TRANSACTION + 37, - STARTBLUETOOTHSCO = IBinder::FIRST_CALL_TRANSACTION + 38, - STARTBLUETOOTHSCOVIRTUALCALL = IBinder::FIRST_CALL_TRANSACTION + 39, - STOPBLUETOOTHSCO = IBinder::FIRST_CALL_TRANSACTION + 40, - FORCEVOLUMECONTROLSTREAM = IBinder::FIRST_CALL_TRANSACTION + 41, - SETRINGTONEPLAYER = IBinder::FIRST_CALL_TRANSACTION + 42, - GETRINGTONEPLAYER = IBinder::FIRST_CALL_TRANSACTION + 43, - GETUISOUNDSSTREAMTYPE = IBinder::FIRST_CALL_TRANSACTION + 44, - SETWIREDDEVICECONNECTIONSTATE = IBinder::FIRST_CALL_TRANSACTION + 45, - SETBLUETOOTHA2DPDEVICECONNECTIONSTATE = IBinder::FIRST_CALL_TRANSACTION + 46, - HANDLEBLUETOOTHA2DPDEVICECONFIGCHANGE = IBinder::FIRST_CALL_TRANSACTION + 47, - STARTWATCHINGROUTES = IBinder::FIRST_CALL_TRANSACTION + 48, - ISCAMERASOUNDFORCED = IBinder::FIRST_CALL_TRANSACTION + 49, - SETVOLUMECONTROLLER = IBinder::FIRST_CALL_TRANSACTION + 50, - NOTIFYVOLUMECONTROLLERVISIBLE = IBinder::FIRST_CALL_TRANSACTION + 51, - ISSTREAMAFFECTEDBYRINGERMODE = IBinder::FIRST_CALL_TRANSACTION + 52, - ISSTREAMAFFECTEDBYMUTE = IBinder::FIRST_CALL_TRANSACTION + 53, - DISABLESAFEMEDIAVOLUME = IBinder::FIRST_CALL_TRANSACTION + 54, - SETHDMISYSTEMAUDIOSUPPORTED = IBinder::FIRST_CALL_TRANSACTION + 55, - ISHDMISYSTEMAUDIOSUPPORTED = IBinder::FIRST_CALL_TRANSACTION + 56, - REGISTERAUDIOPOLICY = IBinder::FIRST_CALL_TRANSACTION + 57, - UNREGISTERAUDIOPOLICYASYNC = IBinder::FIRST_CALL_TRANSACTION + 58, - SETFOCUSPROPERTIESFORPOLICY = IBinder::FIRST_CALL_TRANSACTION + 59, - SETVOLUMEPOLICY = IBinder::FIRST_CALL_TRANSACTION + 60, - REGISTERRECORDINGCALLBACK = IBinder::FIRST_CALL_TRANSACTION + 61, - UNREGISTERRECORDINGCALLBACK = IBinder::FIRST_CALL_TRANSACTION + 62, - GETACTIVERECORDINGCONFIGURATIONS = IBinder::FIRST_CALL_TRANSACTION + 63, - REGISTERPLAYBACKCALLBACK = IBinder::FIRST_CALL_TRANSACTION + 64, - UNREGISTERPLAYBACKCALLBACK = IBinder::FIRST_CALL_TRANSACTION + 65, - GETACTIVEPLAYBACKCONFIGURATIONS = IBinder::FIRST_CALL_TRANSACTION + 66, - */ - - TRACK_PLAYER = IBinder::FIRST_CALL_TRANSACTION + 67, - PLAYER_ATTRIBUTES = IBinder::FIRST_CALL_TRANSACTION + 68, - PLAYER_EVENT = IBinder::FIRST_CALL_TRANSACTION + 69, - RELEASE_PLAYER = IBinder::FIRST_CALL_TRANSACTION + 70, - - /* - DISABLE_RINGTONE_SYNC = IBinder::FIRST_CALL_TRANSACTION + 71, - GET_FOCUS_RAMP_TIME_MS = IBinder::FIRST_CALL_TRANSACTION + 72, - DISPATCH_FOCUS_CHANGE = IBinder::FIRST_CALL_TRANSACTION + 73, - PLAYER_HAS_OP_PLAY_AUDIO = IBinder::FIRST_CALL_TRANSACTION + 74, - SET_BLUETOOTH_A2DP_DEVICE_CONNECTION_STATE_SUPPRESS_NOISY_INTENT - = IBinder::FIRST_CALL_TRANSACTION + 75, - */ + TRACK_PLAYER = IBinder::FIRST_CALL_TRANSACTION, + PLAYER_ATTRIBUTES = IBinder::FIRST_CALL_TRANSACTION + 1, + PLAYER_EVENT = IBinder::FIRST_CALL_TRANSACTION + 2, + RELEASE_PLAYER = IBinder::FIRST_CALL_TRANSACTION + 3, }; DECLARE_META_INTERFACE(AudioManager) diff --git a/include/audiomanager/IPlayer.h b/include/audiomanager/IPlayer.h deleted file mode 100644 index de5c1c7b64c8328de66c167056683fb3699082cd..0000000000000000000000000000000000000000 --- a/include/audiomanager/IPlayer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_IPLAYER_H -#define ANDROID_IPLAYER_H - -#include -#include - -#include -#include -#include -#include - -namespace android { - -// ---------------------------------------------------------------------------- - -class IPlayer : public IInterface -{ -public: - DECLARE_META_INTERFACE(Player); - - virtual void start() = 0; - - virtual void pause() = 0; - - virtual void stop() = 0; - - virtual void setVolume(float vol) = 0; - - virtual void setPan(float pan) = 0; - - virtual void setStartDelayMs(int delayMs) = 0; - - virtual void applyVolumeShaper( - const sp& configuration, - const sp& operation) = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnPlayer : public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IPLAYER_H diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index c282cf0b2227922cafb3cb7048c8871b45f36ba9..4b33a96adf2ffcffd748adffdc2061325678870a 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -324,6 +324,7 @@ static const InputEventLabel KEYCODES[] = { DEFINE_KEYCODE(SYSTEM_NAVIGATION_LEFT), DEFINE_KEYCODE(SYSTEM_NAVIGATION_RIGHT), DEFINE_KEYCODE(ALL_APPS), + DEFINE_KEYCODE(REFRESH), { NULL, 0 } }; diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index ea1d2aa41fee39038f5e37e90e5fc0e10846dd08..1ea2c2cc0762be347be70024c7836ffa290f3946 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -142,16 +141,16 @@ protected: virtual ~InputChannel(); public: - InputChannel(const String8& name, int fd); + InputChannel(const std::string& name, int fd); /* Creates a pair of input channels. * * Returns OK on success. */ - static status_t openInputChannelPair(const String8& name, + static status_t openInputChannelPair(const std::string& name, sp& outServerChannel, sp& outClientChannel); - inline String8 getName() const { return mName; } + inline std::string getName() const { return mName; } inline int getFd() const { return mFd; } /* Sends a message to the other endpoint. @@ -183,7 +182,7 @@ public: sp dup() const; private: - String8 mName; + std::string mName; int mFd; }; diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index 79359277c70374ecab17487bc47fc71147966857..33d2757ec891b613abbe662e04edd71bbc5da052 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -51,6 +51,9 @@ public: KEYBOARD_TYPE_PREDICTIVE = 2, KEYBOARD_TYPE_ALPHA = 3, KEYBOARD_TYPE_FULL = 4, + /** + * Deprecated. Set 'keyboard.specialFunction' to '1' in the device's IDC file instead. + */ KEYBOARD_TYPE_SPECIAL_FUNCTION = 5, KEYBOARD_TYPE_OVERLAY = 6, }; diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 795f575a2e377ddcd16dcbaf33e2dbd7acfc56f0..ffa1614b55bff77525f7507d69fc88997f4b5d79 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -264,6 +264,40 @@ private: Movement mMovements[HISTORY_SIZE]; }; +class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { +public: + ImpulseVelocityTrackerStrategy(); + virtual ~ImpulseVelocityTrackerStrategy(); + + virtual void clear(); + virtual void clearPointers(BitSet32 idBits); + virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, + const VelocityTracker::Position* positions); + virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; + +private: + // Sample horizon. + // We don't use too much history by default since we want to react to quick + // changes in direction. + static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms + + // Number of samples to keep. + static constexpr size_t HISTORY_SIZE = 20; + + struct Movement { + nsecs_t eventTime; + BitSet32 idBits; + VelocityTracker::Position positions[MAX_POINTERS]; + + inline const VelocityTracker::Position& getPosition(uint32_t id) const { + return positions[idBits.getIndexOfBit(id)]; + } + }; + + size_t mIndex; + Movement mMovements[HISTORY_SIZE]; +}; + } // namespace android #endif // _LIBINPUT_VELOCITY_TRACKER_H diff --git a/include/layerproto b/include/layerproto new file mode 120000 index 0000000000000000000000000000000000000000..ef21a4eb8ef4002cd597b3219908bad2742053b1 --- /dev/null +++ b/include/layerproto @@ -0,0 +1 @@ +../services/surfaceflinger/layerproto/include/layerproto/ \ No newline at end of file diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h index 80741c04420e2180f1b2edea00f5189e890da4c9..b36728e9342c8d2d925d6271b7254cd2bfe69b81 100644 --- a/libs/arect/include/android/rect.h +++ b/libs/arect/include/android/rect.h @@ -33,23 +33,26 @@ extern "C" { #endif /** - * {@link ARect} is a struct that represents a rectangular window area. + * Rectangular window area. * - * It is used with {@link - * ANativeActivityCallbacks::onContentRectChanged} event callback and - * ANativeWindow_lock() function. + * This is the NDK equivalent of the android.graphics.Rect class in Java. It is + * used with {@link ANativeActivityCallbacks::onContentRectChanged} event + * callback and the ANativeWindow_lock() function. + * + * In a valid ARect, left <= right and top <= bottom. ARect with left=0, top=10, + * right=1, bottom=11 contains only one pixel at x=0, y=10. */ typedef struct ARect { #ifdef __cplusplus typedef int32_t value_type; #endif - /** left position */ + /// Minimum X coordinate of the rectangle. int32_t left; - /** top position */ + /// Minimum Y coordinate of the rectangle. int32_t top; - /** left position */ + /// Maximum X coordinate of the rectangle. int32_t right; - /** bottom position */ + /// Maximum Y coordinate of the rectangle. int32_t bottom; } ARect; diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2728f354080158c3871ea8e11c9b23f722669d46 --- /dev/null +++ b/libs/binder/ActivityManager.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +#include + +namespace android { + +ActivityManager::ActivityManager() +{ +} + +sp ActivityManager::getService() +{ + std::lock_guard scoped_lock(mLock); + int64_t startTime = 0; + sp service = mService; + while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) { + sp binder = defaultServiceManager()->checkService(String16("activity")); + if (binder == NULL) { + // Wait for the activity service to come back... + if (startTime == 0) { + startTime = uptimeMillis(); + ALOGI("Waiting for activity service"); + } else if ((uptimeMillis() - startTime) > 1000000) { + ALOGW("Waiting too long for activity service, giving up"); + service = NULL; + break; + } + usleep(25000); + } else { + service = interface_cast(binder); + mService = service; + } + } + return service; +} + +int ActivityManager::openContentUri(const String16& stringUri) +{ + sp service = getService(); + return service != NULL ? service->openContentUri(stringUri) : -1; +} + +void ActivityManager::registerUidObserver(const sp& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage) +{ + sp service = getService(); + if (service != NULL) { + service->registerUidObserver(observer, event, cutpoint, callingPackage); + } +} + +void ActivityManager::unregisterUidObserver(const sp& observer) +{ + sp service = getService(); + if (service != NULL) { + service->unregisterUidObserver(observer); + } +} + +bool ActivityManager::isUidActive(const uid_t uid, const String16& callingPackage) +{ + sp service = getService(); + if (service != NULL) { + return service->isUidActive(uid, callingPackage); + } + return false; +} + +status_t ActivityManager::linkToDeath(const sp& recipient) { + sp service = getService(); + if (service != NULL) { + return IInterface::asBinder(service)->linkToDeath(recipient); + } + return INVALID_OPERATION; +} + +status_t ActivityManager::unlinkToDeath(const sp& recipient) { + sp service = getService(); + if (service != NULL) { + return IInterface::asBinder(service)->unlinkToDeath(recipient); + } + return INVALID_OPERATION; +} + +}; // namespace android diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index d4db8c81b4aa29e060653ca1ea2022ec9e99f9ff..b8d6c78f6a9d863c289d23816363e1a7019d82c7 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -39,6 +39,7 @@ cc_library { double_loadable: true, srcs: [ + "ActivityManager.cpp", "AppOpsManager.cpp", "Binder.cpp", "BpBinder.cpp", @@ -57,11 +58,13 @@ cc_library { "IResultReceiver.cpp", "IServiceManager.cpp", "IShellCallback.cpp", + "IUidObserver.cpp", "MemoryBase.cpp", "MemoryDealer.cpp", "MemoryHeapBase.cpp", "Parcel.cpp", "PermissionCache.cpp", + "PermissionController.cpp", "PersistableBundle.cpp", "ProcessInfoService.cpp", "ProcessState.cpp", @@ -73,6 +76,28 @@ cc_library { ":libbinder_aidl", ], + target: { + vendor: { + 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", + ], + }, + }, + aidl: { export_aidl_headers: true, }, diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 4a9b9a760810811f1e171669b89e40c3cd2f514d..a494e223920b7a39dd41564dc5abd3d0eaf944be 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -100,11 +100,12 @@ int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPa : APP_OPS_MANAGER_UNAVAILABLE_MODE; } -int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) { +int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, + bool startIfModeDefault) { sp service = getService(); return service != nullptr - ? service->startOperation(getToken(service), op, uid, callingPackage) - : APP_OPS_MANAGER_UNAVAILABLE_MODE; + ? service->startOperation(getToken(service), op, uid, callingPackage, + startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE; } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) { diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 49ff46033c1d5731cab148f930dcebc62dde37a6..734212626a146a51e442e1a45175821c8ce3d316 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -32,6 +33,23 @@ namespace android { // --------------------------------------------------------------------------- +Mutex BpBinder::sTrackingLock; +std::unordered_map BpBinder::sTrackingMap; +int BpBinder::sNumTrackedUids = 0; +std::atomic_bool BpBinder::sCountByUidEnabled(false); +binder_proxy_limit_callback BpBinder::sLimitCallback; +bool BpBinder::sBinderProxyThrottleCreate = false; + +// Arbitrarily high value that probably distinguishes a bad behaving app +uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500; +// Another arbitrary value a binder count needs to drop below before another callback will be called +uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000; + +enum { + LIMIT_REACHED_MASK = 0x80000000, // A flag denoting that the limit has been reached + COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value +}; + BpBinder::ObjectManager::ObjectManager() { } @@ -87,16 +105,47 @@ void BpBinder::ObjectManager::kill() // --------------------------------------------------------------------------- -BpBinder::BpBinder(int32_t handle) + +BpBinder* BpBinder::create(int32_t handle) { + int32_t trackedUid = -1; + if (sCountByUidEnabled) { + trackedUid = IPCThreadState::self()->getCallingUid(); + AutoMutex _l(sTrackingLock); + uint32_t trackedValue = sTrackingMap[trackedUid]; + if (CC_UNLIKELY(trackedValue & LIMIT_REACHED_MASK)) { + if (sBinderProxyThrottleCreate) { + return nullptr; + } + } else { + if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) { + ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)", + getuid(), trackedUid, trackedValue); + sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK; + if (sLimitCallback) sLimitCallback(trackedUid); + if (sBinderProxyThrottleCreate) { + ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy" + " count drops below %d", + trackedUid, getuid(), sBinderProxyCountLowWatermark); + return nullptr; + } + } + } + sTrackingMap[trackedUid]++; + } + return new BpBinder(handle, trackedUid); +} + +BpBinder::BpBinder(int32_t handle, int32_t trackedUid) : mHandle(handle) , mAlive(1) , mObitsSent(0) , mObituaries(nullptr) + , mTrackedUid(trackedUid) { ALOGV("Creating BpBinder %p handle %d\n", this, mHandle); extendObjectLifetime(OBJECT_LIFETIME_WEAK); - IPCThreadState::self()->incWeakHandle(handle); + IPCThreadState::self()->incWeakHandle(handle, this); } bool BpBinder::isDescriptorCached() const { @@ -315,6 +364,26 @@ BpBinder::~BpBinder() IPCThreadState* ipc = IPCThreadState::self(); + if (mTrackedUid >= 0) { + AutoMutex _l(sTrackingLock); + uint32_t trackedValue = sTrackingMap[mTrackedUid]; + if (CC_UNLIKELY((trackedValue & COUNTING_VALUE_MASK) == 0)) { + ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle); + } else { + if (CC_UNLIKELY( + (trackedValue & LIMIT_REACHED_MASK) && + ((trackedValue & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark) + )) { + ALOGI("Limit reached bit reset for uid %d (fewer than %d proxies from uid %d held)", + getuid(), mTrackedUid, sBinderProxyCountLowWatermark); + sTrackingMap[mTrackedUid] &= ~LIMIT_REACHED_MASK; + } + if (--sTrackingMap[mTrackedUid] == 0) { + sTrackingMap.erase(mTrackedUid); + } + } + } + mLock.lock(); Vector* obits = mObituaries; if(obits != nullptr) { @@ -340,7 +409,7 @@ void BpBinder::onFirstRef() { ALOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle); IPCThreadState* ipc = IPCThreadState::self(); - if (ipc) ipc->incStrongHandle(mHandle); + if (ipc) ipc->incStrongHandle(mHandle, this); } void BpBinder::onLastStrongRef(const void* /*id*/) @@ -360,6 +429,42 @@ bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false; } +uint32_t BpBinder::getBinderProxyCount(uint32_t uid) +{ + AutoMutex _l(sTrackingLock); + auto it = sTrackingMap.find(uid); + if (it != sTrackingMap.end()) { + return it->second & COUNTING_VALUE_MASK; + } + return 0; +} + +void BpBinder::getCountByUid(Vector& uids, Vector& counts) +{ + AutoMutex _l(sTrackingLock); + uids.setCapacity(sTrackingMap.size()); + counts.setCapacity(sTrackingMap.size()); + for (const auto& it : sTrackingMap) { + uids.push_back(it.first); + counts.push_back(it.second & COUNTING_VALUE_MASK); + } +} + +void BpBinder::enableCountByUid() { sCountByUidEnabled.store(true); } +void BpBinder::disableCountByUid() { sCountByUidEnabled.store(false); } +void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); } + +void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) { + AutoMutex _l(sTrackingLock); + sLimitCallback = cb; +} + +void BpBinder::setBinderProxyCountWatermarks(int high, int low) { + AutoMutex _l(sTrackingLock); + sBinderProxyCountHighWatermark = high; + sBinderProxyCountLowWatermark = low; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index 50a8b28aae9c18c751f0fea4ab0267a2f543117b..428db4d579bdd7dc86154ae0cc7129ce55ea9da6 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -56,6 +56,40 @@ public: } return fd; } + + virtual void registerUidObserver(const sp& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeStrongBinder(IInterface::asBinder(observer)); + data.writeInt32(event); + data.writeInt32(cutpoint); + data.writeString16(callingPackage); + remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply); + } + + virtual void unregisterUidObserver(const sp& observer) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeStrongBinder(IInterface::asBinder(observer)); + remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply); + } + + virtual bool isUidActive(const uid_t uid, const String16& callingPackage) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeInt32(uid); + data.writeString16(callingPackage); + remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return false; + return reply.readInt32() == 1; + } }; // ------------------------------------------------------------------------------------ diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index c38568c40fa62b4036e397d75b121e13afce0aea..068664b418ce714a23393b59976240675ce7a7c3 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -61,13 +61,14 @@ public: } virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName) { + const String16& packageName, bool startIfModeDefault) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); + data.writeInt32(startIfModeDefault ? 1 : 0); remote()->transact(START_OPERATION_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; @@ -159,7 +160,8 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - int32_t res = startOperation(token, code, uid, packageName); + bool startIfModeDefault = data.readInt32() == 1; + int32_t res = startOperation(token, code, uid, packageName, startIfModeDefault); reply->writeNoException(); reply->writeInt32(res); return NO_ERROR; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 33ec65f10e2c1c9dc21735b5b52d97f46f31fe36..b2217b53336d05e71914c93266f0ea821d88ba0a 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -409,6 +409,15 @@ void IPCThreadState::flushCommands() if (mProcess->mDriverFD <= 0) return; talkWithDriver(false); + // The flush could have caused post-write refcount decrements to have + // been executed, which in turn could result in BC_RELEASE/BC_DECREFS + // being queued in mOut. So flush again, if we need to. + if (mOut.dataSize() > 0) { + talkWithDriver(false); + } + if (mOut.dataSize() > 0) { + ALOGW("mOut.dataSize() > 0 after flushCommands()"); + } } void IPCThreadState::blockUntilThreadAvailable() @@ -501,6 +510,21 @@ void IPCThreadState::processPendingDerefs() } } +void IPCThreadState::processPostWriteDerefs() +{ + for (size_t i = 0; i < mPostWriteWeakDerefs.size(); i++) { + RefBase::weakref_type* refs = mPostWriteWeakDerefs[i]; + refs->decWeak(mProcess.get()); + } + mPostWriteWeakDerefs.clear(); + + for (size_t i = 0; i < mPostWriteStrongDerefs.size(); i++) { + RefBase* obj = mPostWriteStrongDerefs[i]; + obj->decStrong(mProcess.get()); + } + mPostWriteStrongDerefs.clear(); +} + void IPCThreadState::joinThreadPool(bool isMain) { LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid()); @@ -627,11 +651,14 @@ status_t IPCThreadState::transact(int32_t handle, return err; } -void IPCThreadState::incStrongHandle(int32_t handle) +void IPCThreadState::incStrongHandle(int32_t handle, BpBinder *proxy) { LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle); mOut.writeInt32(BC_ACQUIRE); mOut.writeInt32(handle); + // Create a temp reference until the driver has handled this command. + proxy->incStrong(mProcess.get()); + mPostWriteStrongDerefs.push(proxy); } void IPCThreadState::decStrongHandle(int32_t handle) @@ -641,11 +668,14 @@ void IPCThreadState::decStrongHandle(int32_t handle) mOut.writeInt32(handle); } -void IPCThreadState::incWeakHandle(int32_t handle) +void IPCThreadState::incWeakHandle(int32_t handle, BpBinder *proxy) { LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle); mOut.writeInt32(BC_INCREFS); mOut.writeInt32(handle); + // Create a temp reference until the driver has handled this command. + proxy->getWeakRefs()->incWeak(mProcess.get()); + mPostWriteWeakDerefs.push(proxy->getWeakRefs()); } void IPCThreadState::decWeakHandle(int32_t handle) @@ -897,8 +927,10 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) if (bwr.write_consumed > 0) { if (bwr.write_consumed < mOut.dataSize()) mOut.remove(0, bwr.write_consumed); - else + else { mOut.setDataSize(0); + processPostWriteDerefs(); + } } if (bwr.read_consumed > 0) { mIn.setDataSize(bwr.read_consumed); diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp index 674bddf2183243181e6782a4f1ab9341907680e2..89ebc6c1aad8340218f4e7f59211a23e0dc0c8d4 100644 --- a/libs/binder/IPermissionController.cpp +++ b/libs/binder/IPermissionController.cpp @@ -49,6 +49,19 @@ public: return reply.readInt32() != 0; } + virtual int32_t noteOp(const String16& op, int32_t uid, const String16& packageName) + { + Parcel data, reply; + data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); + data.writeString16(op); + data.writeInt32(uid); + data.writeString16(packageName); + remote()->transact(NOTE_OP_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return 2; // MODE_ERRORED + return reply.readInt32(); + } + virtual void getPackagesForUid(const uid_t uid, Vector& packages) { Parcel data, reply; @@ -78,6 +91,18 @@ public: if (reply.readExceptionCode() != 0) return false; return reply.readInt32() != 0; } + + virtual int getPackageUid(const String16& package, int flags) + { + Parcel data, reply; + data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); + data.writeString16(package); + data.writeInt32(flags); + remote()->transact(GET_PACKAGE_UID_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return false; + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController"); @@ -99,6 +124,17 @@ status_t BnPermissionController::onTransact( return NO_ERROR; } break; + case NOTE_OP_TRANSACTION: { + CHECK_INTERFACE(IPermissionController, data, reply); + String16 op = data.readString16(); + int32_t uid = data.readInt32(); + String16 packageName = data.readString16(); + int32_t res = noteOp(op, uid, packageName); + reply->writeNoException(); + reply->writeInt32(res); + return NO_ERROR; + } break; + case GET_PACKAGES_FOR_UID_TRANSACTION: { CHECK_INTERFACE(IPermissionController, data, reply); int32_t uid = data.readInt32(); @@ -122,6 +158,16 @@ status_t BnPermissionController::onTransact( return NO_ERROR; } break; + case GET_PACKAGE_UID_TRANSACTION: { + CHECK_INTERFACE(IPermissionController, data, reply); + String16 package = data.readString16(); + int flags = data.readInt32(); + const int uid = getPackageUid(package, flags); + reply->writeNoException(); + reply->writeInt32(uid); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 001dc9e6cd2931fa1a3a2f929d1656e2d82474f9..17e098c541e4311219759eaf43aff932355f05e1 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -20,7 +20,11 @@ #include #include +#ifndef __ANDROID_VNDK__ +#include +#endif #include +#include #include #include #include @@ -48,6 +52,9 @@ sp defaultServiceManager() return gDefaultServiceManager; } +#ifndef __ANDROID_VNDK__ +// IPermissionController is not accessible to vendors + bool checkCallingPermission(const String16& permission) { return checkCallingPermission(permission, nullptr, nullptr); @@ -122,6 +129,8 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid) } } +#endif //__ANDROID_VNDK__ + // ---------------------------------------------------------------------- class BpServiceManager : public BpInterface @@ -134,20 +143,35 @@ public: virtual sp getService(const String16& name) const { - unsigned n; - for (n = 0; n < 5; n++){ - if (n > 0) { - if (!strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder")) { - ALOGI("Waiting for vendor service %s...", String8(name).string()); - CallStack stack(LOG_TAG); - } else { - ALOGI("Waiting for service %s...", String8(name).string()); - } - sleep(1); + sp 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; + if (!gSystemBootCompleted) { + char bootCompleted[PROPERTY_VALUE_MAX]; + property_get("sys.boot_completed", bootCompleted, "0"); + gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false; + } + // retry interval in millisecond. + const long sleepTime = gSystemBootCompleted ? 1000 : 100; + + int n = 0; + while (uptimeMillis() < timeout) { + n++; + if (isVendorService) { + ALOGI("Waiting for vendor service %s...", String8(name).string()); + CallStack stack(LOG_TAG); + } else if (n%10 == 0) { + ALOGI("Waiting for service %s...", String8(name).string()); } + usleep(1000*sleepTime); + sp svc = checkService(name); if (svc != nullptr) return svc; } + ALOGW("Service %s didn't start. Returning NULL", String8(name).string()); return nullptr; } @@ -161,19 +185,18 @@ public: } virtual status_t addService(const String16& name, const sp& service, - bool allowIsolated) - { + 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; } - virtual Vector listServices() - { + virtual Vector listServices(int dumpsysPriority) { Vector res; int n = 0; @@ -181,6 +204,7 @@ public: 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; diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp index 4568a426cdb8d357118013ab9bf014d5fa759056..dd4a65ee84e2c6e10ffb173a01320c8538d79e23 100644 --- a/libs/binder/IShellCallback.cpp +++ b/libs/binder/IShellCallback.cpp @@ -39,11 +39,13 @@ public: { } - virtual int openOutputFile(const String16& path, const String16& seLinuxContext) { + virtual int openFile(const String16& path, const String16& seLinuxContext, + const String16& mode) { Parcel data, reply; data.writeInterfaceToken(IShellCallback::getInterfaceDescriptor()); data.writeString16(path); data.writeString16(seLinuxContext); + data.writeString16(mode); remote()->transact(OP_OPEN_OUTPUT_FILE, data, &reply, 0); reply.readExceptionCode(); int fd = reply.readParcelFileDescriptor(); @@ -64,7 +66,8 @@ status_t BnShellCallback::onTransact( CHECK_INTERFACE(IShellCallback, data, reply); String16 path(data.readString16()); String16 seLinuxContext(data.readString16()); - int fd = openOutputFile(path, seLinuxContext); + String16 mode(data.readString16()); + int fd = openFile(path, seLinuxContext, mode); if (reply != nullptr) { reply->writeNoException(); if (fd >= 0) { diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..697e948a6dfa7339b1ec04a5a0556d75b37c7708 --- /dev/null +++ b/libs/binder/IUidObserver.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +namespace android { + +// ------------------------------------------------------------------------------------ + +class BpUidObserver : public BpInterface +{ +public: + explicit BpUidObserver(const sp& impl) + : BpInterface(impl) + { + } + + virtual void onUidGone(uid_t uid, bool disabled) + { + Parcel data, reply; + data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); + data.writeInt32((int32_t) uid); + data.writeInt32(disabled ? 1 : 0); + remote()->transact(ON_UID_GONE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void onUidActive(uid_t uid) + { + Parcel data, reply; + data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); + data.writeInt32((int32_t) uid); + remote()->transact(ON_UID_ACTIVE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void onUidIdle(uid_t uid, bool disabled) + { + Parcel data, reply; + data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); + data.writeInt32((int32_t) uid); + data.writeInt32(disabled ? 1 : 0); + remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +// ---------------------------------------------------------------------- + +IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver"); + +// ---------------------------------------------------------------------- + +status_t BnUidObserver::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case ON_UID_GONE_TRANSACTION: { + CHECK_INTERFACE(IUidObserver, data, reply); + uid_t uid = data.readInt32(); + bool disabled = data.readInt32() == 1; + onUidGone(uid, disabled); + return NO_ERROR; + } break; + + case ON_UID_ACTIVE_TRANSACTION: { + CHECK_INTERFACE(IUidObserver, data, reply); + uid_t uid = data.readInt32(); + onUidActive(uid); + return NO_ERROR; + } break; + + case ON_UID_IDLE_TRANSACTION: { + CHECK_INTERFACE(IUidObserver, data, reply); + uid_t uid = data.readInt32(); + bool disabled = data.readInt32() == 1; + onUidIdle(uid, disabled); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 03aef1791c4ab0fa11566a1a68c14600652bf784..eb8188b3ca8648c4b65d5fc1dcf5047aa27842a8 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -433,6 +433,7 @@ void Parcel::setDataPosition(size_t pos) const mDataPos = pos; mNextObjectHint = 0; + mObjectsSorted = false; } status_t Parcel::setDataCapacity(size_t size) @@ -1276,7 +1277,7 @@ status_t Parcel::write(const FlattenableHelperInterface& val) if (err) return err; // payload - void* const buf = this->writeInplace(pad_size(len)); + void* const buf = this->writeInplace(len); if (buf == nullptr) return BAD_VALUE; @@ -1469,6 +1470,59 @@ 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 + if (mObjectsSorted || mObjectsSize <= 1) { +data_sorted: + // Expect to check only against the next object + if (mNextObjectHint < mObjectsSize && upperBound > mObjects[mNextObjectHint]) { + // For some reason the current read position is greater than the next object + // hint. Iterate until we find the right object + size_t nextObject = mNextObjectHint; + do { + if (mDataPos < mObjects[nextObject] + sizeof(flat_binder_object)) { + // Requested info overlaps with an object + ALOGE("Attempt to read from protected data in Parcel %p", this); + return PERMISSION_DENIED; + } + nextObject++; + } while (nextObject < mObjectsSize && upperBound > mObjects[nextObject]); + mNextObjectHint = nextObject; + } + return NO_ERROR; + } + // Quickly determine if mObjects is sorted. + binder_size_t* currObj = mObjects + mObjectsSize - 1; + binder_size_t* prevObj = currObj; + while (currObj > mObjects) { + prevObj--; + if(*prevObj > *currObj) { + goto data_unsorted; + } + currObj--; + } + mObjectsSorted = true; + goto data_sorted; + +data_unsorted: + // Insertion Sort mObjects + // Great for mostly sorted lists. If randomly sorted or reverse ordered mObjects become common, + // switch to std::sort(mObjects, mObjects + mObjectsSize); + for (binder_size_t* iter0 = mObjects + 1; iter0 < mObjects + mObjectsSize; iter0++) { + binder_size_t temp = *iter0; + binder_size_t* iter1 = iter0 - 1; + while (iter1 >= mObjects && *iter1 > temp) { + *(iter1 + 1) = *iter1; + iter1--; + } + *(iter1 + 1) = temp; + } + mNextObjectHint = 0; + mObjectsSorted = true; + goto data_sorted; +} + status_t Parcel::read(void* outData, size_t len) const { if (len > INT32_MAX) { @@ -1479,6 +1533,15 @@ status_t Parcel::read(void* outData, size_t len) const if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize && len <= pad_size(len)) { + if (mObjectsSize > 0) { + status_t err = validateReadData(mDataPos + pad_size(len)); + if(err != NO_ERROR) { + // Still increment the data position by the expected length + mDataPos += pad_size(len); + ALOGV("read Setting data pos of %p to %zu", this, mDataPos); + return err; + } + } memcpy(outData, mData+mDataPos, len); mDataPos += pad_size(len); ALOGV("read Setting data pos of %p to %zu", this, mDataPos); @@ -1497,6 +1560,16 @@ const void* Parcel::readInplace(size_t len) const if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize && len <= pad_size(len)) { + if (mObjectsSize > 0) { + status_t err = validateReadData(mDataPos + pad_size(len)); + if(err != NO_ERROR) { + // Still increment the data position by the expected length + mDataPos += pad_size(len); + ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos); + return nullptr; + } + } + const void* data = mData+mDataPos; mDataPos += pad_size(len); ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos); @@ -1510,6 +1583,15 @@ status_t Parcel::readAligned(T *pArg) const { COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(T)) <= mDataSize) { + if (mObjectsSize > 0) { + status_t err = validateReadData(mDataPos + sizeof(T)); + if(err != NO_ERROR) { + // Still increment the data position by the expected length + mDataPos += sizeof(T); + return err; + } + } + const void* data = mData+mDataPos; mDataPos += sizeof(T); *pArg = *reinterpret_cast(data); @@ -2366,6 +2448,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, mObjects = const_cast(objects); mObjectsSize = mObjectsCapacity = objectsCount; mNextObjectHint = 0; + mObjectsSorted = false; mOwner = relFunc; mOwnerCookie = relCookie; for (size_t i = 0; i < mObjectsSize; i++) { @@ -2524,6 +2607,7 @@ status_t Parcel::restartWrite(size_t desired) mObjects = nullptr; mObjectsSize = mObjectsCapacity = 0; mNextObjectHint = 0; + mObjectsSorted = false; mHasFds = false; mFdsKnown = true; mAllowFds = true; @@ -2610,6 +2694,7 @@ status_t Parcel::continueWrite(size_t desired) mDataCapacity = desired; mObjectsSize = mObjectsCapacity = objectsSize; mNextObjectHint = 0; + mObjectsSorted = false; } else if (mData) { if (objectsSize < mObjectsSize) { @@ -2631,6 +2716,7 @@ status_t Parcel::continueWrite(size_t desired) } mObjectsSize = objectsSize; mNextObjectHint = 0; + mObjectsSorted = false; } // We own the data, so we can just do a realloc(). @@ -2703,6 +2789,7 @@ void Parcel::initState() mObjectsSize = 0; mObjectsCapacity = 0; mNextObjectHint = 0; + mObjectsSorted = false; mHasFds = false; mFdsKnown = true; mAllowFds = true; diff --git a/libs/binder/PermissionController.cpp b/libs/binder/PermissionController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96df33c9cfd440f3b95ccfe14ba24dffd420aff0 --- /dev/null +++ b/libs/binder/PermissionController.cpp @@ -0,0 +1,88 @@ +/* + * 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 +#include +#include +#include + +#include + +namespace android { + +PermissionController::PermissionController() +{ +} + +sp PermissionController::getService() +{ + std::lock_guard scoped_lock(mLock); + int64_t startTime = 0; + sp service = mService; + while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) { + sp binder = defaultServiceManager()->checkService(String16("permission")); + if (binder == nullptr) { + // Wait for the activity service to come back... + if (startTime == 0) { + startTime = uptimeMillis(); + ALOGI("Waiting for permission service"); + } else if ((uptimeMillis() - startTime) > 10000) { + ALOGW("Waiting too long for permission service, giving up"); + service = NULL; + break; + } + sleep(1); + } else { + service = interface_cast(binder); + mService = service; + } + } + return service; +} + +bool PermissionController::checkPermission(const String16& permission, int32_t pid, int32_t uid) +{ + sp service = getService(); + return service != NULL ? service->checkPermission(permission, pid, uid) : false; +} + +int32_t PermissionController::noteOp(const String16& op, int32_t uid, const String16& packageName) +{ + sp service = getService(); + return service != NULL ? service->noteOp(op, uid, packageName) : MODE_ERRORED; +} + +void PermissionController::getPackagesForUid(const uid_t uid, Vector &packages) +{ + sp service = getService(); + if (service != nullptr) { + service->getPackagesForUid(uid, packages); + } +} + +bool PermissionController::isRuntimePermission(const String16& permission) +{ + sp service = getService(); + return service != nullptr ? service->isRuntimePermission(permission) : false; +} + +int PermissionController::getPackageUid(const String16& package, int flags) +{ + sp service = getService(); + return service != nullptr ? service->getPackageUid(package, flags) : -1; +} + +}; // namespace android diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp index d617b5a179cff4d20060fb284bcef65ef110ffc4..c0aec0a979b60b0e05d846df3e3413d7b8337f26 100644 --- a/libs/binder/PersistableBundle.cpp +++ b/libs/binder/PersistableBundle.cpp @@ -39,8 +39,9 @@ using std::vector; using namespace ::android::binder; enum { - // Keep in sync with BUNDLE_MAGIC in frameworks/base/core/java/android/os/BaseBundle.java. + // Keep them in sync with BUNDLE_MAGIC* in frameworks/base/core/java/android/os/BaseBundle.java. BUNDLE_MAGIC = 0x4C444E42, + BUNDLE_MAGIC_NATIVE = 0x4C444E44, }; namespace { @@ -99,7 +100,7 @@ status_t PersistableBundle::writeToParcel(Parcel* parcel) const { size_t length_pos = parcel->dataPosition(); RETURN_IF_FAILED(parcel->writeInt32(1)); // dummy, will hold length - RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC)); + RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC_NATIVE)); size_t start_pos = parcel->dataPosition(); RETURN_IF_FAILED(writeToParcelInner(parcel)); @@ -392,7 +393,7 @@ status_t PersistableBundle::readFromParcelInner(const Parcel* parcel, size_t len int32_t magic; RETURN_IF_FAILED(parcel->readInt32(&magic)); - if (magic != BUNDLE_MAGIC) { + if (magic != BUNDLE_MAGIC && magic != BUNDLE_MAGIC_NATIVE) { ALOGE("Bad magic number for PersistableBundle: 0x%08x", magic); return BAD_VALUE; } diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 6e7c427b12971883c6a694af7623423c67a4240e..3e871f87f9df4180a311bcc73b602f0d62f5a449 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -282,7 +282,7 @@ sp ProcessState::getStrongProxyForHandle(int32_t handle) return nullptr; } - b = new BpBinder(handle); + b = BpBinder::create(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; @@ -316,7 +316,7 @@ wp ProcessState::getWeakProxyForHandle(int32_t handle) // arriving from the driver. IBinder* b = e->binder; if (b == nullptr || !e->refs->attemptIncWeak(this)) { - b = new BpBinder(handle); + b = BpBinder::create(handle); result = b; e->binder = b; if (b) e->refs = b->getWeakRefs(); diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp index c3ba5a23c5301e886e8cb5136378d0677b1ca10d..bd0e6f9a116790249685851bf2c1c14f6a837b06 100644 --- a/libs/binder/Static.cpp +++ b/libs/binder/Static.cpp @@ -72,13 +72,16 @@ TextOutput& aerr(gStderrTextOutput); // ------------ ProcessState.cpp -Mutex gProcessMutex; +Mutex& gProcessMutex = *new Mutex; sp gProcess; // ------------ IServiceManager.cpp Mutex gDefaultServiceManagerLock; sp gDefaultServiceManager; +#ifndef __ANDROID_VNDK__ sp gPermissionController; +#endif +bool gSystemBootCompleted = false; } // namespace android diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp index 006f7f94e9b45af3ba44326bcd55c080a18152a2..a9d50555497aae0ace93f1c2b0df12467e5f48cf 100644 --- a/libs/binder/Status.cpp +++ b/libs/binder/Status.cpp @@ -102,6 +102,15 @@ status_t Status::readFromParcel(const Parcel& parcel) { } mMessage = String8(message); + // Skip over the remote stack trace data + int32_t remote_stack_trace_header_size; + status = parcel.readInt32(&remote_stack_trace_header_size); + if (status != OK) { + setFromStatusT(status); + return status; + } + parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size); + if (mException == EX_SERVICE_SPECIFIC) { status = parcel.readInt32(&mErrorCode); } else if (mException == EX_PARCELABLE) { @@ -137,6 +146,7 @@ status_t Status::writeToParcel(Parcel* parcel) const { return status; } status = parcel->writeString16(String16(mMessage)); + status = parcel->writeInt32(0); // Empty remote stack trace header if (mException == EX_SERVICE_SPECIFIC) { status = parcel->writeInt32(mErrorCode); } else if (mException == EX_PARCELABLE) { diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 3264666a218d4968a84908d626a94b605b69d8eb..5b66b923e70111fbb86d4ca77244f825752f62b2 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -52,6 +52,6 @@ interface IPackageManagerNative { * Unknown or unknowable versions are returned as 0. */ - int getVersionCodeForPackage(in String packageName); + long getVersionCodeForPackage(in String packageName); } diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h new file mode 100644 index 0000000000000000000000000000000000000000..b8db09145f14ba99f9adeb6f6ceb0dc4755ece7c --- /dev/null +++ b/libs/binder/include/binder/ActivityManager.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ACTIVITY_MANAGER_H +#define ANDROID_ACTIVITY_MANAGER_H + +#ifndef __ANDROID_VNDK__ + +#include + +#include + +// --------------------------------------------------------------------------- +namespace android { + +class ActivityManager +{ +public: + + enum { + // Flag for registerUidObserver: report uid gone + UID_OBSERVER_GONE = 1<<1, + // Flag for registerUidObserver: report uid has become idle + UID_OBSERVER_IDLE = 1<<2, + // Flag for registerUidObserver: report uid has become active + UID_OBSERVER_ACTIVE = 1<<3 + }; + + enum { + // Not a real process state + PROCESS_STATE_UNKNOWN = -1 + }; + + ActivityManager(); + + int openContentUri(const String16& stringUri); + void registerUidObserver(const sp& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage); + void unregisterUidObserver(const sp& observer); + bool isUidActive(const uid_t uid, const String16& callingPackage); + + status_t linkToDeath(const sp& recipient); + status_t unlinkToDeath(const sp& recipient); + +private: + Mutex mLock; + sp mService; + sp getService(); +}; + + +}; // namespace android +// --------------------------------------------------------------------------- +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + +#endif // ANDROID_ACTIVITY_MANAGER_H diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 4212776e891baa1f5ad63ec63218012432690a24..c5b57c7edfbc9a5085c5f2c049f231f1ada65dd5 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -17,6 +17,8 @@ #ifndef ANDROID_APP_OPS_MANAGER_H #define ANDROID_APP_OPS_MANAGER_H +#ifndef __ANDROID_VNDK__ + #include #include @@ -99,7 +101,8 @@ public: int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); - int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage); + int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, + bool startIfModeDefault); void finishOp(int32_t op, int32_t uid, const String16& callingPackage); void startWatchingMode(int32_t op, const String16& packageName, const sp& callback); @@ -116,4 +119,8 @@ private: }; // namespace android // --------------------------------------------------------------------------- +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_APP_OPS_MANAGER_H diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h index ef703bda904b9e59d3f2f947562e89c98d0642ac..9230e89cdf40913dce7d3206ee9ce7969686a41c 100644 --- a/libs/binder/include/binder/BinderService.h +++ b/libs/binder/include/binder/BinderService.h @@ -34,15 +34,17 @@ template class BinderService { public: - static status_t publish(bool allowIsolated = false) { + static status_t publish(bool allowIsolated = false, + int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) { sp sm(defaultServiceManager()); - return sm->addService( - String16(SERVICE::getServiceName()), - new SERVICE(), allowIsolated); + return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated, + dumpFlags); } - static void publishAndJoinThreadPool(bool allowIsolated = false) { - publish(allowIsolated); + static void publishAndJoinThreadPool( + bool allowIsolated = false, + int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) { + publish(allowIsolated, dumpFlags); joinThreadPool(); } diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 7ef93aa390414fe240d566ef74b979f67b0f2437..8bd297bcfbdabece7174c2ecaefdf6d3865392f3 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -19,15 +19,20 @@ #include #include +#include #include +#include + // --------------------------------------------------------------------------- namespace android { +using binder_proxy_limit_callback = void(*)(int); + class BpBinder : public IBinder { public: - BpBinder(int32_t handle); + static BpBinder* create(int32_t handle); inline int32_t handle() const { return mHandle; } @@ -61,6 +66,14 @@ public: status_t setConstantData(const void* data, size_t size); void sendObituary(); + static uint32_t getBinderProxyCount(uint32_t uid); + static void getCountByUid(Vector& uids, Vector& counts); + static void enableCountByUid(); + static void disableCountByUid(); + static void setCountByUidEnabled(bool enable); + static void setLimitCallback(binder_proxy_limit_callback cb); + static void setBinderProxyCountWatermarks(int high, int low); + class ObjectManager { public: @@ -91,6 +104,7 @@ public: }; protected: + BpBinder(int32_t handle,int32_t trackedUid); virtual ~BpBinder(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); @@ -115,6 +129,16 @@ private: ObjectManager mObjects; Parcel* mConstantData; mutable String16 mDescriptorCache; + int32_t mTrackedUid; + + static Mutex sTrackingLock; + static std::unordered_map sTrackingMap; + static int sNumTrackedUids; + static std::atomic_bool sCountByUidEnabled; + static binder_proxy_limit_callback sLimitCallback; + static uint32_t sBinderProxyCountHighWatermark; + static uint32_t sBinderProxyCountLowWatermark; + static bool sBinderProxyThrottleCreate; }; }; // namespace android diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h index 5ad218035ab097a12a0741a8d77ec63f4ca2e90d..f34969be51040c0d92fa98084b92088356d878e9 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include/binder/IActivityManager.h @@ -17,7 +17,10 @@ #ifndef ANDROID_IACTIVITY_MANAGER_H #define ANDROID_IACTIVITY_MANAGER_H +#ifndef __ANDROID_VNDK__ + #include +#include namespace android { @@ -28,10 +31,19 @@ class IActivityManager : public IInterface public: DECLARE_META_INTERFACE(ActivityManager) - virtual int openContentUri(const String16& /* stringUri */) = 0; + virtual int openContentUri(const String16& stringUri) = 0; + virtual void registerUidObserver(const sp& observer, + const int32_t event, + const int32_t cutpoint, + const String16& callingPackage) = 0; + virtual void unregisterUidObserver(const sp& observer) = 0; + virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0; enum { - OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + REGISTER_UID_OBSERVER_TRANSACTION, + UNREGISTER_UID_OBSERVER_TRANSACTION, + IS_UID_ACTIVE_TRANSACTION }; }; @@ -39,4 +51,8 @@ public: }; // namespace android -#endif // ANDROID_IACTIVITY_MANAGER_H \ No newline at end of file +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + +#endif // ANDROID_IACTIVITY_MANAGER_H diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h index b62e9e264d9ea88484ae6b64218862bb2624ef47..e5b12a9720c4f0d92b5e8d40372ab16a3d93305b 100644 --- a/libs/binder/include/binder/IAppOpsCallback.h +++ b/libs/binder/include/binder/IAppOpsCallback.h @@ -18,6 +18,8 @@ #ifndef ANDROID_IAPP_OPS_CALLBACK_H #define ANDROID_IAPP_OPS_CALLBACK_H +#ifndef __ANDROID_VNDK__ + #include namespace android { @@ -51,5 +53,9 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IAPP_OPS_CALLBACK_H diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index dc1804597518da9054dd791e0f8d2517599bbd80..f0c5e1743d9c37439b33630b646e33b4d9ecee9e 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -18,6 +18,8 @@ #ifndef ANDROID_IAPP_OPS_SERVICE_H #define ANDROID_IAPP_OPS_SERVICE_H +#ifndef __ANDROID_VNDK__ + #include #include @@ -33,7 +35,7 @@ public: virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName) = 0; + const String16& packageName, bool startIfModeDefault) = 0; virtual void finishOperation(const sp& token, int32_t code, int32_t uid, const String16& packageName) = 0; virtual void startWatchingMode(int32_t op, const String16& packageName, @@ -75,4 +77,8 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IAPP_OPS_SERVICE_H diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h index e15d6f07e9b1af1ba737a4a75f26217fb241a47e..59e806c177cbf887b5cfeae2a1d89b03f928801d 100644 --- a/libs/binder/include/binder/IBatteryStats.h +++ b/libs/binder/include/binder/IBatteryStats.h @@ -17,6 +17,8 @@ #ifndef ANDROID_IBATTERYSTATS_H #define ANDROID_IBATTERYSTATS_H +#ifndef __ANDROID_VNDK__ + #include namespace android { @@ -76,4 +78,8 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IBATTERYSTATS_H diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h index b21047fc49d8e655e589344e9be107fc3506ce20..213ee63ea84d81d1dc00af575baf53e46aa6deec 100644 --- a/libs/binder/include/binder/IMediaResourceMonitor.h +++ b/libs/binder/include/binder/IMediaResourceMonitor.h @@ -17,6 +17,8 @@ #ifndef ANDROID_I_MEDIA_RESOURCE_MONITOR_H #define ANDROID_I_MEDIA_RESOURCE_MONITOR_H +#ifndef __ANDROID_VNDK__ + #include namespace android { @@ -52,4 +54,8 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_I_MEDIA_RESOURCE_MONITOR_H diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 245607e74e4f4ce399d59dfc66cff38e24201d0b..c1d9a9a8f772f1fa6383c90e451b79f00b968deb 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -64,9 +64,9 @@ public: uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - void incStrongHandle(int32_t handle); + void incStrongHandle(int32_t handle, BpBinder *proxy); void decStrongHandle(int32_t handle); - void incWeakHandle(int32_t handle); + void incWeakHandle(int32_t handle, BpBinder *proxy); void decWeakHandle(int32_t handle); status_t attemptIncStrongHandle(int32_t handle); static void expungeHandle(int32_t handle, IBinder* binder); @@ -106,6 +106,7 @@ private: status_t getAndExecuteCommand(); status_t executeCommand(int32_t command); void processPendingDerefs(); + void processPostWriteDerefs(); void clearCaller(); @@ -118,7 +119,8 @@ private: const sp mProcess; Vector mPendingStrongDerefs; Vector mPendingWeakDerefs; - + Vector mPostWriteStrongDerefs; + Vector mPostWriteWeakDerefs; Parcel mIn; Parcel mOut; status_t mLastError; diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h index 25f34313f0af54ce9637aba4da18e009c68642ac..3ec459fc32029b498f7fa5089873b75481aec383 100644 --- a/libs/binder/include/binder/IPermissionController.h +++ b/libs/binder/include/binder/IPermissionController.h @@ -18,6 +18,8 @@ #ifndef ANDROID_IPERMISSION_CONTROLLER_H #define ANDROID_IPERMISSION_CONTROLLER_H +#ifndef __ANDROID_VNDK__ + #include #include @@ -32,14 +34,20 @@ public: virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0; + virtual int32_t noteOp(const String16& op, int32_t uid, const String16& packageName) = 0; + virtual void getPackagesForUid(const uid_t uid, Vector &packages) = 0; virtual bool isRuntimePermission(const String16& permission) = 0; + virtual int getPackageUid(const String16& package, int flags) = 0; + enum { CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, - GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1, - IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2 + NOTE_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1, + GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2, + IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 3, + GET_PACKAGE_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 4 }; }; @@ -58,5 +66,9 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IPERMISSION_CONTROLLER_H diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include/binder/IProcessInfoService.h index 2669f9193df5063bb863dbd2b63b4cd89c7e194b..033c1453632d4f05b28e8873597495a4f88ffbc2 100644 --- a/libs/binder/include/binder/IProcessInfoService.h +++ b/libs/binder/include/binder/IProcessInfoService.h @@ -17,6 +17,8 @@ #ifndef ANDROID_I_PROCESS_INFO_SERVICE_H #define ANDROID_I_PROCESS_INFO_SERVICE_H +#ifndef __ANDROID_VNDK__ + #include namespace android { @@ -46,4 +48,8 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_I_PROCESS_INFO_SERVICE_H diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 3b23f81e43d69072f2bc5a6c5329cd8bccf15277..197026d5d6dfa652c1fe17bc14a326af050ca454 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -19,7 +19,6 @@ #define ANDROID_ISERVICE_MANAGER_H #include -#include #include #include @@ -31,6 +30,22 @@ class IServiceManager : public IInterface { public: DECLARE_META_INTERFACE(ServiceManager) + /** + * Must match values in IServiceManager.java + */ + /* Allows services to dump sections according to priorities. */ + static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0; + static const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1; + static 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. + */ + static const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3; + static const int DUMP_FLAG_PRIORITY_ALL = DUMP_FLAG_PRIORITY_CRITICAL | + DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT; + static const int DUMP_FLAG_PROTO = 1 << 4; /** * Retrieve an existing service, blocking for a few seconds @@ -46,14 +61,14 @@ public: /** * Register a service. */ - virtual status_t addService( const String16& name, - const sp& service, - bool allowIsolated = false) = 0; + virtual status_t addService(const String16& name, const sp& service, + bool allowIsolated = false, + int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0; /** * Return list of all existing services. */ - virtual Vector listServices() = 0; + virtual Vector listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0; enum { GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h index fda9ee6ba74ba77c163d15fdbcee3c8eeec79908..b47e9951831e447c57b3ea02c387baf80afefcb1 100644 --- a/libs/binder/include/binder/IShellCallback.h +++ b/libs/binder/include/binder/IShellCallback.h @@ -29,7 +29,8 @@ class IShellCallback : public IInterface public: DECLARE_META_INTERFACE(ShellCallback); - virtual int openOutputFile(const String16& path, const String16& seLinuxContext) = 0; + virtual int openFile(const String16& path, const String16& seLinuxContext, + const String16& mode) = 0; enum { OP_OPEN_OUTPUT_FILE = IBinder::FIRST_CALL_TRANSACTION diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h new file mode 100644 index 0000000000000000000000000000000000000000..d81789e399231835722bfae120d8b2b3c906930f --- /dev/null +++ b/libs/binder/include/binder/IUidObserver.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +#ifndef ANDROID_IUID_OBSERVER_H +#define ANDROID_IUID_OBSERVER_H + +#ifndef __ANDROID_VNDK__ + +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class IUidObserver : public IInterface +{ +public: + DECLARE_META_INTERFACE(UidObserver) + + virtual void onUidGone(uid_t uid, bool disabled) = 0; + virtual void onUidActive(uid_t uid) = 0; + virtual void onUidIdle(uid_t uid, bool disabled) = 0; + + enum { + ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + ON_UID_ACTIVE_TRANSACTION, + ON_UID_IDLE_TRANSACTION + }; +}; + +// ---------------------------------------------------------------------- + +class BnUidObserver : public BnInterface +{ +public: + virtual status_t onTransact(uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + +#endif // ANDROID_IUID_OBSERVER_H diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h index 96ebaac43778cf8a0601e97faa20538a9fd237bc..dd5bc3aafd95c665e4699f67756d8b52b7fa9ac0 100644 --- a/libs/binder/include/binder/IpPrefix.h +++ b/libs/binder/include/binder/IpPrefix.h @@ -17,6 +17,8 @@ #ifndef ANDROID_IP_PREFIX_H #define ANDROID_IP_PREFIX_H +#ifndef __ANDROID_VNDK__ + #include #include @@ -85,4 +87,8 @@ private: } // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_IP_PREFIX_H diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 5d36526cb3382647be84f66f182eb1f6f36179bd..dede78f61ead37dff9c33cf0a0f430020d6a1197 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -417,6 +417,7 @@ private: void freeDataNoInit(); void initState(); void scanForFds() const; + status_t validateReadData(size_t len) const; template status_t readAligned(T *pArg) const; @@ -463,6 +464,7 @@ private: size_t mObjectsSize; size_t mObjectsCapacity; mutable size_t mNextObjectHint; + mutable bool mObjectsSorted; mutable bool mFdsKnown; mutable bool mHasFds; diff --git a/libs/binder/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h index bcdf0c291434edeb76fd67e7c1a043f933f83935..95eabff7ac3efd4f519617a05653d88e4074306d 100644 --- a/libs/binder/include/binder/PermissionCache.h +++ b/libs/binder/include/binder/PermissionCache.h @@ -17,6 +17,8 @@ #ifndef BINDER_PERMISSION_H #define BINDER_PERMISSION_H +#ifndef __ANDROID_VNDK__ + #include #include @@ -77,4 +79,8 @@ public: // --------------------------------------------------------------------------- }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif /* BINDER_PERMISSION_H */ diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h new file mode 100644 index 0000000000000000000000000000000000000000..d81f5142bcd9660f98c2c046a12b411d5ef50e7e --- /dev/null +++ b/libs/binder/include/binder/PermissionController.h @@ -0,0 +1,69 @@ +/* + * 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_PERMISSION_CONTROLLER_H +#define ANDROID_PERMISSION_CONTROLLER_H + +#ifndef __ANDROID_VNDK__ + +#include + +#include + +// --------------------------------------------------------------------------- +namespace android { + +class PermissionController +{ +public: + + enum { + MATCH_SYSTEM_ONLY = 1<<16, + MATCH_UNINSTALLED_PACKAGES = 1<<13, + MATCH_FACTORY_ONLY = 1<<21, + MATCH_INSTANT = 1<<23 + }; + + enum { + MODE_ALLOWED = 0, + MODE_IGNORED = 1, + MODE_ERRORED = 2, + MODE_DEFAULT = 3, + }; + + PermissionController(); + + bool checkPermission(const String16& permission, int32_t pid, int32_t uid); + int32_t noteOp(const String16& op, int32_t uid, const String16& packageName); + void getPackagesForUid(const uid_t uid, Vector& packages); + bool isRuntimePermission(const String16& permission); + int getPackageUid(const String16& package, int flags); + +private: + Mutex mLock; + sp mService; + + sp getService(); +}; + + +}; // namespace android +// --------------------------------------------------------------------------- +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + +#endif // ANDROID_PERMISSION_CONTROLLER_H diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include/binder/ProcessInfoService.h index 0da61ee3cbc01f219a462532bf212a5d1a5d300e..a03aae98eeb182672997605d1fe37b73f944582b 100644 --- a/libs/binder/include/binder/ProcessInfoService.h +++ b/libs/binder/include/binder/ProcessInfoService.h @@ -17,6 +17,8 @@ #ifndef ANDROID_PROCESS_INFO_SERVICE_H #define ANDROID_PROCESS_INFO_SERVICE_H +#ifndef __ANDROID_VNDK__ + #include #include #include @@ -78,5 +80,9 @@ public: }; // namespace android +#else // __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif // __ANDROID_VNDK__ + #endif // ANDROID_PROCESS_INFO_SERVICE_H diff --git a/libs/binder/include/private/binder/Static.h b/libs/binder/include/private/binder/Static.h index 3d10456a8d6d610706415fc81c3d823dec45875c..171be7791eb9a15012f31c41e6bf99d5bb7dba99 100644 --- a/libs/binder/include/private/binder/Static.h +++ b/libs/binder/include/private/binder/Static.h @@ -21,7 +21,9 @@ #include #include +#ifndef __ANDROID_VNDK__ #include +#endif #include namespace android { @@ -30,12 +32,15 @@ namespace android { extern Vector gTextBuffers; // For ProcessState.cpp -extern Mutex gProcessMutex; +extern Mutex& gProcessMutex; extern sp gProcess; // For IServiceManager.cpp extern Mutex gDefaultServiceManagerLock; extern sp gDefaultServiceManager; +#ifndef __ANDROID_VNDK__ extern sp gPermissionController; +#endif +extern bool gSystemBootCompleted; } // namespace android diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp index da7fc39a8f7bc365228e8cc23082f2446009ee32..b7909972ffbc66b861608004a64bda577796cbf6 100644 --- a/libs/binder/tests/binderThroughputTest.cpp +++ b/libs/binder/tests/binderThroughputTest.cpp @@ -215,7 +215,7 @@ void worker_fx(int num, int target = cs_pair ? num % server_count : rand() % workers.size(); int sz = payload_size; - while (sz > sizeof(uint32_t)) { + while (sz >= sizeof(uint32_t)) { data.writeInt32(0); sz -= sizeof(uint32_t); } @@ -381,6 +381,7 @@ int main(int argc, char *argv[]) // No need to run training round in this case. if (atoi(argv[i+1]) > 0) { max_time_bucket = strtoull(argv[i+1], (char **)nullptr, 10) * 1000; + time_per_bucket = max_time_bucket / num_buckets; i++; } else { cout << "Max latency -m must be positive." << endl; diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..3412e14f17f24d73e236e83949e5c94fbcd8d4db --- /dev/null +++ b/libs/dumputils/Android.bp @@ -0,0 +1,34 @@ +// 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. + +cc_library { + name: "libdumputils", + + shared_libs: [ + "libbase", + "libbinder", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + + srcs: ["dump_utils.cpp"], + + cflags: ["-Wall", "-Werror"], + + export_include_dirs: [ + "include", + ], +} diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b2f842a448cc496acf1ff531a8421fe22c2eb9a --- /dev/null +++ b/libs/dumputils/dump_utils.cpp @@ -0,0 +1,114 @@ +/* + * 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 + +#include +#include +#include +#include +#include + +/* list of native processes to include in the native dumps */ +// This matches the /proc/pid/exe link instead of /proc/pid/cmdline. +static const char* native_processes_to_dump[] = { + "/system/bin/audioserver", + "/system/bin/cameraserver", + "/system/bin/drmserver", + "/system/bin/mediadrmserver", + "/system/bin/mediaextractor", // media.extractor + "/system/bin/mediametrics", // media.metrics + "/system/bin/mediaserver", + "/system/bin/sdcard", + "/system/bin/statsd", + "/system/bin/surfaceflinger", + "/system/bin/vehicle_network_service", + "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec + NULL, +}; + +/* list of hal interface to dump containing process during native dumps */ +static const char* hal_interfaces_to_dump[] { + "android.hardware.audio@2.0::IDevicesFactory", + "android.hardware.audio@4.0::IDevicesFactory", + "android.hardware.bluetooth@1.0::IBluetoothHci", + "android.hardware.camera.provider@2.4::ICameraProvider", + "android.hardware.drm@1.0::IDrmFactory", + "android.hardware.graphics.composer@2.1::IComposer", + "android.hardware.media.omx@1.0::IOmx", + "android.hardware.media.omx@1.0::IOmxStore", + "android.hardware.sensors@1.0::ISensors", + "android.hardware.vr@1.0::IVr", + NULL, +}; + +bool should_dump_hal_interface(const char* interface) { + for (const char** i = hal_interfaces_to_dump; *i; i++) { + if (!strcmp(*i, interface)) { + return true; + } + } + return false; +} + +bool should_dump_native_traces(const char* path) { + for (const char** p = native_processes_to_dump; *p; p++) { + if (!strcmp(*p, path)) { + return true; + } + } + return false; +} + +std::set get_interesting_hal_pids() { + using android::hidl::manager::V1_0::IServiceManager; + using android::sp; + using android::hardware::Return; + + sp manager = IServiceManager::getService(); + std::set pids; + + Return ret = manager->debugDump([&](auto& hals) { + for (const auto &info : hals) { + if (info.pid == static_cast(IServiceManager::PidConstant::NO_PID)) { + continue; + } + + if (!should_dump_hal_interface(info.interfaceName.c_str())) { + continue; + } + + pids.insert(info.pid); + } + }); + + if (!ret.isOk()) { + ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str()); + } + + return pids; // whether it was okay or not +} + +bool IsZygote(int pid) { + static const std::string kZygotePrefix = "zygote"; + + std::string cmdline; + if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid), + &cmdline)) { + return true; + } + + return (cmdline.find(kZygotePrefix) == 0); +} diff --git a/libs/dumputils/include/dumputils/dump_utils.h b/libs/dumputils/include/dumputils/dump_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..25f712733ae7bfc65d713089f549e92d3dd10042 --- /dev/null +++ b/libs/dumputils/include/dumputils/dump_utils.h @@ -0,0 +1,28 @@ +/** + * 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. + */ + +#ifndef DUMPUTILS_H_ +#define DUMPUTILS_H_ + +#include + +bool should_dump_native_traces(const char* path); + +std::set get_interesting_hal_pids(); + +bool IsZygote(int pid); + +#endif // DUMPUTILS_H_ diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index 9f995380bdfa28c05333851f3fd4a6fc433980ca..4da30e9980686fbc01ea389cd93ec9b87b340930 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -22,7 +22,6 @@ cc_library_shared { cflags: ["-Wall", "-Werror"], shared_libs: [ - "libnativeloader", "liblog", ], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 39b5829fafff32e54651228638230a9c9c728610..961f1011e0ee261aafb4865e4b61e31cbddcc5d9 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -20,12 +20,23 @@ #include +#include #include -#include // TODO(b/37049319) Get this from a header once one exists extern "C" { android_namespace_t* android_get_exported_namespace(const char*); + android_namespace_t* android_create_namespace(const char* name, + const char* ld_library_path, + const char* default_library_path, + uint64_t type, + const char* permitted_when_isolated_path, + android_namespace_t* parent); + + enum { + ANDROID_NAMESPACE_TYPE_ISOLATED = 1, + ANDROID_NAMESPACE_TYPE_SHARED = 2, + }; } namespace android { @@ -45,6 +56,32 @@ void GraphicsEnv::setDriverPath(const std::string path) { mDriverPath = path; } +void GraphicsEnv::setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths) { + if (mLayerPaths.empty()) { + mLayerPaths = layerPaths; + mAppNamespace = appNamespace; + } else { + ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'", + layerPaths.c_str(), appNamespace); + } +} + +android_namespace_t* GraphicsEnv::getAppNamespace() { + return mAppNamespace; +} + +const std::string GraphicsEnv::getLayerPaths(){ + return mLayerPaths; +} + +const std::string GraphicsEnv::getDebugLayers() { + return mDebugLayers; +} + +void GraphicsEnv::setDebugLayers(const std::string layers) { + mDebugLayers = layers; +} + android_namespace_t* GraphicsEnv::getDriverNamespace() { static std::once_flag once; std::call_once(once, [this]() { diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 781707694a7693d8260d8d6381f4d81e1e505bde..213580c20b895aa3972c3184d195e68d00335e8d 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -35,10 +35,20 @@ public: void setDriverPath(const std::string path); android_namespace_t* getDriverNamespace(); + void setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths); + android_namespace_t* getAppNamespace(); + const std::string getLayerPaths(); + + void setDebugLayers(const std::string layers); + const std::string getDebugLayers(); + private: GraphicsEnv() = default; std::string mDriverPath; + std::string mDebugLayers; + std::string mLayerPaths; android_namespace_t* mDriverNamespace = nullptr; + android_namespace_t* mAppNamespace = nullptr; }; } // namespace android diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 02d29a3e691c1914cd7d30e4b4b8b5a17227d817..b29c1d51579776e0772b8f19c32caf47e1c9df2c 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -19,7 +19,7 @@ cc_library_headers { cc_library_shared { name: "libgui", - vendor_available: true, + vendor_available: false, vndk: { enabled: true, }, @@ -63,6 +63,12 @@ cc_library_shared { // Allow documentation warnings "-Wno-documentation", + // Allow implicit instantiation for templated class function + "-Wno-undefined-func-template", + + // Allow explicitly marking struct as packed even when unnecessary + "-Wno-packed", + "-DDEBUG_ONLY_CODE=0", ], @@ -77,6 +83,8 @@ cc_library_shared { srcs: [ "BitTube.cpp", + "BufferHubConsumer.cpp", + "BufferHubProducer.cpp", "BufferItem.cpp", "BufferItemConsumer.cpp", "BufferQueue.cpp", @@ -90,6 +98,7 @@ cc_library_shared { "FrameTimestamps.cpp", "GLConsumer.cpp", "GuiConfig.cpp", + "HdrMetadata.cpp", "IDisplayEventConnection.cpp", "IConsumerListener.cpp", "IGraphicBufferConsumer.cpp", @@ -111,8 +120,11 @@ cc_library_shared { ], shared_libs: [ + "android.hardware.graphics.common@1.1", "libsync", "libbinder", + "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. + "libpdx_default_transport", "libcutils", "libEGL", "libGLESv2", @@ -128,9 +140,26 @@ cc_library_shared { "android.hardware.configstore-utils", ], + // bufferhub is not used when building libgui for vendors + target: { + vendor: { + cflags: ["-DNO_BUFFERHUB"], + exclude_srcs: [ + "BufferHubConsumer.cpp", + "BufferHubProducer.cpp", + ], + exclude_shared_libs: [ + "libbufferhubqueue", + "libpdx_default_transport", + ], + }, + }, + header_libs: [ + "libdvr_headers", "libnativebase_headers", "libgui_headers", + "libpdx_headers", ], export_shared_lib_headers: [ @@ -140,6 +169,7 @@ cc_library_shared { "libui", "android.hidl.token@1.0-utils", "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.common@1.1", ], export_header_lib_headers: [ diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5cdeb280a40f9150b2e7f1632ffc2e9ac7d2f0f --- /dev/null +++ b/libs/gui/BufferHubConsumer.cpp @@ -0,0 +1,161 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace android { + +using namespace dvr; + +/* static */ +sp BufferHubConsumer::Create(const std::shared_ptr& queue) { + sp consumer = new BufferHubConsumer; + consumer->mQueue = queue; + return consumer; +} + +/* static */ sp BufferHubConsumer::Create(ConsumerQueueParcelable parcelable) { + if (!parcelable.IsValid()) { + ALOGE("BufferHubConsumer::Create: Invalid consumer parcelable."); + return nullptr; + } + + sp consumer = new BufferHubConsumer; + consumer->mQueue = ConsumerQueue::Import(parcelable.TakeChannelHandle()); + return consumer; +} + +status_t BufferHubConsumer::acquireBuffer(BufferItem* /*buffer*/, nsecs_t /*presentWhen*/, + uint64_t /*maxFrameNumber*/) { + ALOGE("BufferHubConsumer::acquireBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::detachBuffer(int /*slot*/) { + ALOGE("BufferHubConsumer::detachBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::attachBuffer(int* /*outSlot*/, const sp& /*buffer*/) { + ALOGE("BufferHubConsumer::attachBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::releaseBuffer(int /*buf*/, uint64_t /*frameNumber*/, + EGLDisplay /*display*/, EGLSyncKHR /*fence*/, + const sp& /*releaseFence*/) { + ALOGE("BufferHubConsumer::releaseBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::consumerConnect(const sp& /*consumer*/, + bool /*controlledByApp*/) { + ALOGE("BufferHubConsumer::consumerConnect: not implemented."); + + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to + // make IGraphicBufferConsumer_test happy. + return NO_ERROR; +} + +status_t BufferHubConsumer::consumerDisconnect() { + ALOGE("BufferHubConsumer::consumerDisconnect: not implemented."); + + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to + // make IGraphicBufferConsumer_test happy. + return NO_ERROR; +} + +status_t BufferHubConsumer::getReleasedBuffers(uint64_t* /*slotMask*/) { + ALOGE("BufferHubConsumer::getReleasedBuffers: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) { + ALOGE("BufferHubConsumer::setDefaultBufferSize: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setMaxBufferCount(int /*bufferCount*/) { + ALOGE("BufferHubConsumer::setMaxBufferCount: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setMaxAcquiredBufferCount(int /*maxAcquiredBuffers*/) { + ALOGE("BufferHubConsumer::setMaxAcquiredBufferCount: not implemented."); + + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to + // make IGraphicBufferConsumer_test happy. + return NO_ERROR; +} + +status_t BufferHubConsumer::setConsumerName(const String8& /*name*/) { + ALOGE("BufferHubConsumer::setConsumerName: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setDefaultBufferFormat(PixelFormat /*defaultFormat*/) { + ALOGE("BufferHubConsumer::setDefaultBufferFormat: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setDefaultBufferDataSpace(android_dataspace /*defaultDataSpace*/) { + ALOGE("BufferHubConsumer::setDefaultBufferDataSpace: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setConsumerUsageBits(uint64_t /*usage*/) { + ALOGE("BufferHubConsumer::setConsumerUsageBits: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setConsumerIsProtected(bool /*isProtected*/) { + ALOGE("BufferHubConsumer::setConsumerIsProtected: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setTransformHint(uint32_t /*hint*/) { + ALOGE("BufferHubConsumer::setTransformHint: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::getSidebandStream(sp* /*outStream*/) const { + ALOGE("BufferHubConsumer::getSidebandStream: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::getOccupancyHistory( + bool /*forceFlush*/, std::vector* /*outHistory*/) { + ALOGE("BufferHubConsumer::getOccupancyHistory: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::discardFreeBuffers() { + ALOGE("BufferHubConsumer::discardFreeBuffers: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const { + ALOGE("BufferHubConsumer::dumpState: not implemented."); + return INVALID_OPERATION; +} + +IBinder* BufferHubConsumer::onAsBinder() { + ALOGE("BufferHubConsumer::onAsBinder: BufferHubConsumer should never be used as an Binder " + "object."); + return nullptr; +} + +} // namespace android diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae5cca2d2085728a5aa4eb63017cfa85d6fd842e --- /dev/null +++ b/libs/gui/BufferHubProducer.cpp @@ -0,0 +1,717 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace android { + +using namespace dvr; + +/* static */ +sp BufferHubProducer::Create(const std::shared_ptr& queue) { + sp producer = new BufferHubProducer; + producer->queue_ = queue; + return producer; +} + +/* static */ +sp BufferHubProducer::Create(ProducerQueueParcelable parcelable) { + if (!parcelable.IsValid()) { + ALOGE("BufferHubProducer::Create: Invalid producer parcelable."); + return nullptr; + } + + sp producer = new BufferHubProducer; + producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle()); + return producer; +} + +status_t BufferHubProducer::requestBuffer(int slot, sp* buf) { + ALOGV("requestBuffer: slot=%d", slot); + + std::unique_lock lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("requestBuffer: BufferHubProducer has no connected producer"); + return NO_INIT; + } + + if (slot < 0 || slot >= max_buffer_count_) { + ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_); + return BAD_VALUE; + } else if (!buffers_[slot].mBufferState.isDequeued()) { + ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot, + buffers_[slot].mBufferState.string()); + return BAD_VALUE; + } else if (buffers_[slot].mGraphicBuffer != nullptr) { + ALOGE("requestBuffer: slot %d is not empty.", slot); + return BAD_VALUE; + } else if (buffers_[slot].mBufferProducer == nullptr) { + ALOGE("requestBuffer: slot %d is not dequeued.", slot); + return BAD_VALUE; + } + + const auto& buffer_producer = buffers_[slot].mBufferProducer; + sp graphic_buffer = buffer_producer->buffer()->buffer(); + + buffers_[slot].mGraphicBuffer = graphic_buffer; + buffers_[slot].mRequestBufferCalled = true; + + *buf = graphic_buffer; + return NO_ERROR; +} + +status_t BufferHubProducer::setMaxDequeuedBufferCount(int max_dequeued_buffers) { + ALOGV("setMaxDequeuedBufferCount: max_dequeued_buffers=%d", max_dequeued_buffers); + + std::unique_lock lock(mutex_); + + if (max_dequeued_buffers <= 0 || + max_dequeued_buffers > + int(BufferHubQueue::kMaxQueueCapacity - kDefaultUndequeuedBuffers)) { + ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", max_dequeued_buffers, + BufferHubQueue::kMaxQueueCapacity); + return BAD_VALUE; + } + + // The new dequeued_buffers count should not be violated by the number + // of currently dequeued buffers. + int dequeued_count = 0; + for (const auto& buf : buffers_) { + if (buf.mBufferState.isDequeued()) { + dequeued_count++; + } + } + if (dequeued_count > max_dequeued_buffers) { + ALOGE("setMaxDequeuedBufferCount: the requested dequeued_buffers" + "count (%d) exceeds the current dequeued buffer count (%d)", + max_dequeued_buffers, dequeued_count); + return BAD_VALUE; + } + + max_dequeued_buffer_count_ = max_dequeued_buffers; + return NO_ERROR; +} + +status_t BufferHubProducer::setAsyncMode(bool async) { + if (async) { + // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer + // automatically and behaves differently from IGraphicBufferConsumer. Thus, + // android::BufferQueue's async mode (a.k.a. allocating an additional buffer + // to prevent dequeueBuffer from being blocking) technically does not apply + // here. + // + // In Daydream, non-blocking producer side dequeue is guaranteed by careful + // buffer consumer implementations. In another word, BufferHubQueue based + // dequeueBuffer should never block whether setAsyncMode(true) is set or + // not. + // + // See: IGraphicBufferProducer::setAsyncMode and + // BufferQueueProducer::setAsyncMode for more about original implementation. + ALOGW("BufferHubProducer::setAsyncMode: BufferHubQueue should always be " + "asynchronous. This call makes no effact."); + return NO_ERROR; + } + return NO_ERROR; +} + +status_t BufferHubProducer::dequeueBuffer(int* out_slot, sp* out_fence, uint32_t width, + uint32_t height, PixelFormat format, uint64_t usage, + uint64_t* /*outBufferAge*/, + FrameEventHistoryDelta* /* out_timestamps */) { + ALOGV("dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, height, format, usage); + + status_t ret; + std::unique_lock lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("dequeueBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + const uint32_t kLayerCount = 1; + if (int32_t(queue_->capacity()) < max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) { + // Lazy allocation. When the capacity of |queue_| has not reached + // |max_dequeued_buffer_count_|, allocate new buffer. + // TODO(jwcai) To save memory, the really reasonable thing to do is to go + // over existing slots and find first existing one to dequeue. + ret = AllocateBuffer(width, height, kLayerCount, format, usage); + if (ret < 0) return ret; + } + + size_t slot = 0; + std::shared_ptr buffer_producer; + + for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) { + LocalHandle fence; + auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence); + if (!buffer_status) return NO_MEMORY; + + buffer_producer = buffer_status.take(); + if (!buffer_producer) return NO_MEMORY; + + if (width == buffer_producer->width() && height == buffer_producer->height() && + uint32_t(format) == buffer_producer->format()) { + // The producer queue returns a buffer producer matches the request. + break; + } + + // Needs reallocation. + // TODO(jwcai) Consider use VLOG instead if we find this log is not useful. + ALOGI("dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different " + "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need " + "re-allocattion.", + width, height, format, slot, buffer_producer->width(), buffer_producer->height(), + buffer_producer->format()); + // Mark the slot as reallocating, so that later we can set + // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued. + buffers_[slot].mIsReallocating = true; + + // Remove the old buffer once the allocation before allocating its + // replacement. + RemoveBuffer(slot); + + // Allocate a new producer buffer with new buffer configs. Note that if + // there are already multiple buffers in the queue, the next one returned + // from |queue_->Dequeue| may not be the new buffer we just reallocated. + // Retry up to BufferHubQueue::kMaxQueueCapacity times. + ret = AllocateBuffer(width, height, kLayerCount, format, usage); + if (ret < 0) return ret; + } + + // With the BufferHub backed solution. Buffer slot returned from + // |queue_->Dequeue| is guaranteed to avaiable for producer's use. + // It's either in free state (if the buffer has never been used before) or + // in queued state (if the buffer has been dequeued and queued back to + // BufferHubQueue). + LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() && + !buffers_[slot].mBufferState.isQueued()), + "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot, + buffers_[slot].mBufferState.string()); + + buffers_[slot].mBufferState.freeQueued(); + buffers_[slot].mBufferState.dequeue(); + ALOGV("dequeueBuffer: slot=%zu", slot); + + // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we + // just need to exopose that through |BufferHubQueue| once we need fence. + *out_fence = Fence::NO_FENCE; + *out_slot = int(slot); + ret = NO_ERROR; + + if (buffers_[slot].mIsReallocating) { + ret |= BUFFER_NEEDS_REALLOCATION; + buffers_[slot].mIsReallocating = false; + } + + return ret; +} + +status_t BufferHubProducer::detachBuffer(int /* slot */) { + ALOGE("BufferHubProducer::detachBuffer not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::detachNextBuffer(sp* /* out_buffer */, + sp* /* out_fence */) { + ALOGE("BufferHubProducer::detachNextBuffer not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::attachBuffer(int* /* out_slot */, + const sp& /* buffer */) { + // With this BufferHub backed implementation, we assume (for now) all buffers + // are allocated and owned by the BufferHub. Thus the attempt of transfering + // ownership of a buffer to the buffer queue is intentionally unsupported. + LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input, + QueueBufferOutput* output) { + ALOGV("queueBuffer: slot %d", slot); + + if (output == nullptr) { + return BAD_VALUE; + } + + int64_t timestamp; + bool is_auto_timestamp; + android_dataspace dataspace; + Rect crop(Rect::EMPTY_RECT); + int scaling_mode; + uint32_t transform; + sp fence; + + input.deflate(×tamp, &is_auto_timestamp, &dataspace, &crop, &scaling_mode, &transform, + &fence); + + // Check input scaling mode is valid. + switch (scaling_mode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: + case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: + case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: + break; + default: + ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode); + return BAD_VALUE; + } + + // Check input fence is valid. + if (fence == nullptr) { + ALOGE("queueBuffer: fence is NULL"); + return BAD_VALUE; + } + + std::unique_lock lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("queueBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + if (slot < 0 || slot >= max_buffer_count_) { + ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_); + return BAD_VALUE; + } else if (!buffers_[slot].mBufferState.isDequeued()) { + ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot, + buffers_[slot].mBufferState.string()); + return BAD_VALUE; + } else if ((!buffers_[slot].mRequestBufferCalled || buffers_[slot].mGraphicBuffer == nullptr)) { + ALOGE("queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, " + "mGraphicBuffer=%p)", + slot, buffers_[slot].mRequestBufferCalled, buffers_[slot].mGraphicBuffer.get()); + return BAD_VALUE; + } + + // Post the buffer producer with timestamp in the metadata. + const auto& buffer_producer = buffers_[slot].mBufferProducer; + + // Check input crop is not out of boundary of current buffer. + Rect buffer_rect(buffer_producer->width(), buffer_producer->height()); + Rect cropped_rect(Rect::EMPTY_RECT); + crop.intersect(buffer_rect, &cropped_rect); + if (cropped_rect != crop) { + ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot); + return BAD_VALUE; + } + + LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1); + + DvrNativeBufferMetadata meta_data; + meta_data.timestamp = timestamp; + meta_data.is_auto_timestamp = int32_t(is_auto_timestamp); + meta_data.dataspace = int32_t(dataspace); + meta_data.crop_left = crop.left; + meta_data.crop_top = crop.top; + meta_data.crop_right = crop.right; + meta_data.crop_bottom = crop.bottom; + meta_data.scaling_mode = int32_t(scaling_mode); + meta_data.transform = int32_t(transform); + + buffer_producer->PostAsync(&meta_data, fence_fd); + buffers_[slot].mBufferState.queue(); + + output->width = buffer_producer->width(); + output->height = buffer_producer->height(); + output->transformHint = 0; // default value, we don't use it yet. + + // |numPendingBuffers| counts of the number of buffers that has been enqueued + // by the producer but not yet acquired by the consumer. Due to the nature + // of BufferHubQueue design, this is hard to trace from the producer's client + // side, but it's safe to assume it's zero. + output->numPendingBuffers = 0; + + // Note that we are not setting nextFrameNumber here as it seems to be only + // used by surface flinger. See more at b/22802885, ag/791760. + output->nextFrameNumber = 0; + + return NO_ERROR; +} + +status_t BufferHubProducer::cancelBuffer(int slot, const sp& fence) { + ALOGV(__FUNCTION__); + + std::unique_lock lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("cancelBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + if (slot < 0 || slot >= max_buffer_count_) { + ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_); + return BAD_VALUE; + } else if (!buffers_[slot].mBufferState.isDequeued()) { + ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot, + buffers_[slot].mBufferState.string()); + return BAD_VALUE; + } else if (fence == nullptr) { + ALOGE("cancelBuffer: fence is NULL"); + return BAD_VALUE; + } + + auto buffer_producer = buffers_[slot].mBufferProducer; + queue_->Enqueue(buffer_producer, size_t(slot), 0ULL); + buffers_[slot].mBufferState.cancel(); + buffers_[slot].mFence = fence; + ALOGV("cancelBuffer: slot %d", slot); + + return NO_ERROR; +} + +status_t BufferHubProducer::query(int what, int* out_value) { + ALOGV(__FUNCTION__); + + std::unique_lock lock(mutex_); + + if (out_value == nullptr) { + ALOGE("query: out_value was NULL"); + return BAD_VALUE; + } + + int value = 0; + switch (what) { + case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: + // TODO(b/36187402) This should be the maximum number of buffers that this + // producer queue's consumer can acquire. Set to be at least one. Need to + // find a way to set from the consumer side. + value = kDefaultUndequeuedBuffers; + break; + case NATIVE_WINDOW_BUFFER_AGE: + value = 0; + break; + case NATIVE_WINDOW_WIDTH: + value = int32_t(queue_->default_width()); + break; + case NATIVE_WINDOW_HEIGHT: + value = int32_t(queue_->default_height()); + break; + case NATIVE_WINDOW_FORMAT: + value = int32_t(queue_->default_format()); + break; + case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: + // BufferHubQueue is always operating in async mode, thus semantically + // consumer can never be running behind. See BufferQueueCore.cpp core + // for more information about the original meaning of this flag. + value = 0; + break; + case NATIVE_WINDOW_CONSUMER_USAGE_BITS: + // TODO(jwcai) This is currently not implement as we don't need + // IGraphicBufferConsumer parity. + value = 0; + break; + case NATIVE_WINDOW_DEFAULT_DATASPACE: + // TODO(jwcai) Return the default value android::BufferQueue is using as + // there is no way dvr::ConsumerQueue can set it. + value = 0; // HAL_DATASPACE_UNKNOWN + break; + case NATIVE_WINDOW_STICKY_TRANSFORM: + // TODO(jwcai) Return the default value android::BufferQueue is using as + // there is no way dvr::ConsumerQueue can set it. + value = 0; + break; + case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: + // In Daydream's implementation, the consumer end (i.e. VR Compostior) + // knows how to handle protected buffers. + value = 1; + break; + default: + return BAD_VALUE; + } + + ALOGV("query: key=%d, v=%d", what, value); + *out_value = value; + return NO_ERROR; +} + +status_t BufferHubProducer::connect(const sp& /* listener */, int api, + bool /* producer_controlled_by_app */, + QueueBufferOutput* output) { + // Consumer interaction are actually handled by buffer hub, and we need + // to maintain consumer operations here. We only need to perform basic input + // parameter checks here. + ALOGV(__FUNCTION__); + + if (output == nullptr) { + return BAD_VALUE; + } + + std::unique_lock lock(mutex_); + + if (connected_api_ != kNoConnectedApi) { + return BAD_VALUE; + } + + if (!queue_->is_connected()) { + ALOGE("BufferHubProducer::connect: This BufferHubProducer is not " + "connected to bufferhud. Has it been taken out as a parcelable?"); + return BAD_VALUE; + } + + switch (api) { + case NATIVE_WINDOW_API_EGL: + case NATIVE_WINDOW_API_CPU: + case NATIVE_WINDOW_API_MEDIA: + case NATIVE_WINDOW_API_CAMERA: + connected_api_ = api; + + output->width = queue_->default_width(); + output->height = queue_->default_height(); + + // default values, we don't use them yet. + output->transformHint = 0; + output->numPendingBuffers = 0; + output->nextFrameNumber = 0; + output->bufferReplaced = false; + + break; + default: + ALOGE("BufferHubProducer::connect: unknow API %d", api); + return BAD_VALUE; + } + + return NO_ERROR; +} + +status_t BufferHubProducer::disconnect(int api, DisconnectMode /*mode*/) { + // Consumer interaction are actually handled by buffer hub, and we need + // to maintain consumer operations here. We only need to perform basic input + // parameter checks here. + ALOGV(__FUNCTION__); + + std::unique_lock lock(mutex_); + + if (kNoConnectedApi == connected_api_) { + return NO_INIT; + } else if (api != connected_api_) { + return BAD_VALUE; + } + + FreeAllBuffers(); + connected_api_ = kNoConnectedApi; + return NO_ERROR; +} + +status_t BufferHubProducer::setSidebandStream(const sp& stream) { + if (stream != nullptr) { + // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's + // metadata. + ALOGE("SidebandStream is not currently supported."); + return INVALID_OPERATION; + } + return NO_ERROR; +} + +void BufferHubProducer::allocateBuffers(uint32_t /* width */, uint32_t /* height */, + PixelFormat /* format */, uint64_t /* usage */) { + // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number + // of buffers permitted by the current BufferQueue configuration (aka + // |max_buffer_count_|). + ALOGE("BufferHubProducer::allocateBuffers not implemented."); +} + +status_t BufferHubProducer::allowAllocation(bool /* allow */) { + ALOGE("BufferHubProducer::allowAllocation not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::setGenerationNumber(uint32_t generation_number) { + ALOGV(__FUNCTION__); + + std::unique_lock lock(mutex_); + generation_number_ = generation_number; + return NO_ERROR; +} + +String8 BufferHubProducer::getConsumerName() const { + // BufferHub based implementation could have one to many producer/consumer + // relationship, thus |getConsumerName| from the producer side does not + // make any sense. + ALOGE("BufferHubProducer::getConsumerName not supported."); + return String8("BufferHubQueue::DummyConsumer"); +} + +status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) { + if (shared_buffer_mode) { + ALOGE("BufferHubProducer::setSharedBufferMode(true) is not supported."); + // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow. + return INVALID_OPERATION; + } + // Setting to default should just work as a no-op. + return NO_ERROR; +} + +status_t BufferHubProducer::setAutoRefresh(bool auto_refresh) { + if (auto_refresh) { + ALOGE("BufferHubProducer::setAutoRefresh(true) is not supported."); + return INVALID_OPERATION; + } + // Setting to default should just work as a no-op. + return NO_ERROR; +} + +status_t BufferHubProducer::setDequeueTimeout(nsecs_t timeout) { + ALOGV(__FUNCTION__); + + std::unique_lock lock(mutex_); + dequeue_timeout_ms_ = static_cast(timeout / (1000 * 1000)); + return NO_ERROR; +} + +status_t BufferHubProducer::getLastQueuedBuffer(sp* /* out_buffer */, + sp* /* out_fence */, + float /*out_transform_matrix*/[16]) { + ALOGE("BufferHubProducer::getLastQueuedBuffer not implemented."); + return INVALID_OPERATION; +} + +void BufferHubProducer::getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) { + ALOGE("BufferHubProducer::getFrameTimestamps not implemented."); +} + +status_t BufferHubProducer::getUniqueId(uint64_t* out_id) const { + ALOGV(__FUNCTION__); + + *out_id = unique_id_; + return NO_ERROR; +} + +status_t BufferHubProducer::getConsumerUsage(uint64_t* out_usage) const { + ALOGV(__FUNCTION__); + + // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS + *out_usage = 0; + return NO_ERROR; +} + +status_t BufferHubProducer::TakeAsParcelable(ProducerQueueParcelable* out_parcelable) { + if (!out_parcelable || out_parcelable->IsValid()) return BAD_VALUE; + + if (connected_api_ != kNoConnectedApi) { + ALOGE("BufferHubProducer::TakeAsParcelable: BufferHubProducer has " + "connected client. Must disconnect first."); + return BAD_VALUE; + } + + if (!queue_->is_connected()) { + ALOGE("BufferHubProducer::TakeAsParcelable: This BufferHubProducer " + "is not connected to bufferhud. Has it been taken out as a " + "parcelable?"); + return BAD_VALUE; + } + + auto status = queue_->TakeAsParcelable(); + if (!status) { + ALOGE("BufferHubProducer::TakeAsParcelable: Failed to take out " + "ProducuerQueueParcelable from the producer queue, error: %s.", + status.GetErrorMessage().c_str()); + return BAD_VALUE; + } + + *out_parcelable = status.take(); + return NO_ERROR; +} + +status_t BufferHubProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, + PixelFormat format, uint64_t usage) { + auto status = queue_->AllocateBuffer(width, height, layer_count, uint32_t(format), usage); + if (!status) { + ALOGE("BufferHubProducer::AllocateBuffer: Failed to allocate buffer: %s", + status.GetErrorMessage().c_str()); + return NO_MEMORY; + } + + size_t slot = status.get(); + auto buffer_producer = queue_->GetBuffer(slot); + + LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu", + slot); + + buffers_[slot].mBufferProducer = buffer_producer; + + return NO_ERROR; +} + +status_t BufferHubProducer::RemoveBuffer(size_t slot) { + auto status = queue_->RemoveBuffer(slot); + if (!status) { + ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer: %s", + status.GetErrorMessage().c_str()); + return INVALID_OPERATION; + } + + // Reset in memory objects related the the buffer. + buffers_[slot].mBufferProducer = nullptr; + buffers_[slot].mGraphicBuffer = nullptr; + buffers_[slot].mBufferState.detachProducer(); + return NO_ERROR; +} + +status_t BufferHubProducer::FreeAllBuffers() { + for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) { + // Reset in memory objects related the the buffer. + buffers_[slot].mGraphicBuffer = nullptr; + buffers_[slot].mBufferState.reset(); + buffers_[slot].mRequestBufferCalled = false; + buffers_[slot].mBufferProducer = nullptr; + buffers_[slot].mFence = Fence::NO_FENCE; + } + + auto status = queue_->FreeAllBuffers(); + if (!status) { + ALOGE("BufferHubProducer::FreeAllBuffers: Failed to free all buffers on " + "the queue: %s", + status.GetErrorMessage().c_str()); + } + + if (queue_->capacity() != 0 || queue_->count() != 0) { + LOG_ALWAYS_FATAL("BufferHubProducer::FreeAllBuffers: Not all buffers are freed."); + } + + return NO_ERROR; +} + +status_t BufferHubProducer::exportToParcel(Parcel* parcel) { + status_t res = TakeAsParcelable(&pending_producer_parcelable_); + if (res != NO_ERROR) return res; + + if (!pending_producer_parcelable_.IsValid()) { + ALOGE("BufferHubProducer::exportToParcel: Invalid parcelable object."); + return BAD_VALUE; + } + + res = parcel->writeUint32(USE_BUFFER_HUB); + if (res != NO_ERROR) { + ALOGE("BufferHubProducer::exportToParcel: Cannot write magic, res=%d.", res); + return res; + } + + return pending_producer_parcelable_.writeToParcel(parcel); +} + +IBinder* BufferHubProducer::onAsBinder() { + ALOGE("BufferHubProducer::onAsBinder: BufferHubProducer should never be used as an Binder " + "object."); + return nullptr; +} + +} // namespace android diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index 9da4ea80e037e5a8dc8288f599b171357cccef7c..f50379b3edb9761db1e8ac54cdd79386bea95457 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -39,8 +39,8 @@ static inline constexpr T to64(const uint32_t lo, const uint32_t hi) { } BufferItem::BufferItem() : - mGraphicBuffer(nullptr), - mFence(nullptr), + mGraphicBuffer(NULL), + mFence(NULL), mCrop(Rect::INVALID_RECT), mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), @@ -55,7 +55,8 @@ BufferItem::BufferItem() : mSurfaceDamage(), mAutoRefresh(false), mQueuedBuffer(true), - mIsStale(false) { + mIsStale(false), + mApi(0) { } BufferItem::~BufferItem() {} @@ -84,30 +85,32 @@ size_t BufferItem::getPodSize() const { addAligned(size, mAutoRefresh); addAligned(size, mQueuedBuffer); addAligned(size, mIsStale); + addAligned(size, mApi); return size; } size_t BufferItem::getFlattenedSize() const { size_t size = sizeof(uint32_t); // Flags - if (mGraphicBuffer != nullptr) { + if (mGraphicBuffer != 0) { size += mGraphicBuffer->getFlattenedSize(); size = FlattenableUtils::align<4>(size); } - if (mFence != nullptr) { + if (mFence != 0) { size += mFence->getFlattenedSize(); size = FlattenableUtils::align<4>(size); } size += mSurfaceDamage.getFlattenedSize(); + size += mHdrMetadata.getFlattenedSize(); size = FlattenableUtils::align<8>(size); return size + getPodSize(); } size_t BufferItem::getFdCount() const { size_t count = 0; - if (mGraphicBuffer != nullptr) { + if (mGraphicBuffer != 0) { count += mGraphicBuffer->getFdCount(); } - if (mFence != nullptr) { + if (mFence != 0) { count += mFence->getFdCount(); } return count; @@ -134,13 +137,13 @@ status_t BufferItem::flatten( FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); flags = 0; - if (mGraphicBuffer != nullptr) { + if (mGraphicBuffer != 0) { status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); flags |= 1; } - if (mFence != nullptr) { + if (mFence != 0) { status_t err = mFence->flatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); @@ -151,6 +154,10 @@ status_t BufferItem::flatten( if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + err = mHdrMetadata.flatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize()); + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; @@ -172,6 +179,7 @@ status_t BufferItem::flatten( writeAligned(buffer, size, mAutoRefresh); writeAligned(buffer, size, mQueuedBuffer); writeAligned(buffer, size, mIsStale); + writeAligned(buffer, size, mApi); return NO_ERROR; } @@ -212,6 +220,10 @@ status_t BufferItem::unflatten( if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + err = mHdrMetadata.unflatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize()); + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; @@ -238,6 +250,7 @@ status_t BufferItem::unflatten( readAligned(buffer, size, mAutoRefresh); readAligned(buffer, size, mQueuedBuffer); readAligned(buffer, size, mIsStale); + readAligned(buffer, size, mApi); return NO_ERROR; } diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 3aa4e449cc4920c9f2f360e127b8e438af396888..89bc0c4c2dba0ccfc5b95e985c3b2b8cacf7fbdf 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -49,16 +49,6 @@ BufferItemConsumer::BufferItemConsumer( BufferItemConsumer::~BufferItemConsumer() {} -void BufferItemConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - BI_LOGE("setName: BufferItemConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); -} - void BufferItemConsumer::setBufferFreedListener( const wp& listener) { Mutex::Autolock _l(mMutex); @@ -102,10 +92,13 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, Mutex::Autolock _l(mMutex); err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence); + if (err != OK) { + BI_LOGE("Failed to addReleaseFenceLocked"); + } err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - if (err != OK) { + if (err != OK && err != IGraphicBufferConsumer::STALE_BUFFER_SLOT) { BI_LOGE("Failed to release buffer: %s (%d)", strerror(-err), err); } @@ -114,7 +107,7 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, void BufferItemConsumer::freeBufferLocked(int slotIndex) { sp listener = mBufferFreedListener.promote(); - if (listener != nullptr && mSlots[slotIndex].mGraphicBuffer != nullptr) { + if (listener != NULL && mSlots[slotIndex].mGraphicBuffer != NULL) { // Fire callback if we have a listener registered and the buffer being freed is valid. BI_LOGV("actually calling onBufferFreed"); listener->onBufferFreed(mSlots[slotIndex].mGraphicBuffer); diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 7da4db4d3fcac36c4c6de683dc9d05e13c3033cf..a8da1347cb529977eb18d46bcf3a31843363fa69 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -18,6 +18,11 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 +#ifndef NO_BUFFERHUB +#include +#include +#endif + #include #include #include @@ -33,7 +38,7 @@ BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} void BufferQueue::ProxyConsumerListener::onDisconnect() { sp listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onDisconnect(); } } @@ -41,7 +46,7 @@ void BufferQueue::ProxyConsumerListener::onDisconnect() { void BufferQueue::ProxyConsumerListener::onFrameAvailable( const BufferItem& item) { sp listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onFrameAvailable(item); } } @@ -49,21 +54,21 @@ void BufferQueue::ProxyConsumerListener::onFrameAvailable( void BufferQueue::ProxyConsumerListener::onFrameReplaced( const BufferItem& item) { sp listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onFrameReplaced(item); } } void BufferQueue::ProxyConsumerListener::onBuffersReleased() { sp listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } } void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { sp listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onSidebandStreamChanged(); } } @@ -80,25 +85,53 @@ void BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps( void BufferQueue::createBufferQueue(sp* outProducer, sp* outConsumer, bool consumerIsSurfaceFlinger) { - LOG_ALWAYS_FATAL_IF(outProducer == nullptr, + LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL"); - LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, + LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL"); sp core(new BufferQueueCore()); - LOG_ALWAYS_FATAL_IF(core == nullptr, + LOG_ALWAYS_FATAL_IF(core == NULL, "BufferQueue: failed to create BufferQueueCore"); sp producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger)); - LOG_ALWAYS_FATAL_IF(producer == nullptr, + LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer"); sp consumer(new BufferQueueConsumer(core)); - LOG_ALWAYS_FATAL_IF(consumer == nullptr, + LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer"); *outProducer = producer; *outConsumer = consumer; } +#ifndef NO_BUFFERHUB +void BufferQueue::createBufferHubQueue(sp* outProducer, + sp* outConsumer) { + LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL"); + LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL"); + + sp producer; + sp consumer; + + dvr::ProducerQueueConfigBuilder configBuilder; + std::shared_ptr producerQueue = + dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{}); + LOG_ALWAYS_FATAL_IF(producerQueue == NULL, "BufferQueue: failed to create ProducerQueue."); + + std::shared_ptr consumerQueue = producerQueue->CreateConsumerQueue(); + LOG_ALWAYS_FATAL_IF(consumerQueue == NULL, "BufferQueue: failed to create ConsumerQueue."); + + producer = BufferHubProducer::Create(producerQueue); + consumer = BufferHubConsumer::Create(consumerQueue); + + LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer"); + LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer"); + + *outProducer = producer; + *outConsumer = consumer; +} +#endif + }; // namespace android diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 31eb29b8f61e342bcbc7ea64f0a97260042ab478..d70e1422b0e5097d4d4b94ac4e3d4c8a47c13d5f 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -35,7 +35,9 @@ #include #include +#ifndef __ANDROID_VNDK__ #include +#endif #include @@ -253,7 +255,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer // on the consumer side if (outBuffer->mAcquireCalled) { - outBuffer->mGraphicBuffer = nullptr; + outBuffer->mGraphicBuffer = NULL; } mCore->mQueue.erase(front); @@ -270,7 +272,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, VALIDATE_CONSISTENCY(); } - if (listener != nullptr) { + if (listener != NULL) { for (int i = 0; i < numDroppedBuffers; ++i) { listener->onBufferReleased(); } @@ -319,10 +321,10 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, const sp& buffer) { ATRACE_CALL(); - if (outSlot == nullptr) { + if (outSlot == NULL) { BQ_LOGE("attachBuffer: outSlot must not be NULL"); return BAD_VALUE; - } else if (buffer == nullptr) { + } else if (buffer == NULL) { BQ_LOGE("attachBuffer: cannot attach NULL buffer"); return BAD_VALUE; } @@ -411,7 +413,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, ATRACE_BUFFER_INDEX(slot); if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || - releaseFence == nullptr) { + releaseFence == NULL) { BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot, releaseFence.get()); return BAD_VALUE; @@ -463,7 +465,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBufferReleased(); } @@ -474,7 +476,7 @@ status_t BufferQueueConsumer::connect( const sp& consumerListener, bool controlledByApp) { ATRACE_CALL(); - if (consumerListener == nullptr) { + if (consumerListener == NULL) { BQ_LOGE("connect: consumerListener may not be NULL"); return BAD_VALUE; } @@ -502,13 +504,13 @@ status_t BufferQueueConsumer::disconnect() { Mutex::Autolock lock(mCore->mMutex); - if (mCore->mConsumerListener == nullptr) { + if (mCore->mConsumerListener == NULL) { BQ_LOGE("disconnect: no consumer is connected"); return BAD_VALUE; } mCore->mIsAbandoned = true; - mCore->mConsumerListener = nullptr; + mCore->mConsumerListener = NULL; mCore->mQueue.clear(); mCore->freeAllBuffersLocked(); mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; @@ -519,7 +521,7 @@ status_t BufferQueueConsumer::disconnect() { status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { ATRACE_CALL(); - if (outSlotMask == nullptr) { + if (outSlotMask == NULL) { BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL"); return BAD_VALUE; } @@ -671,7 +673,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( } } // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -757,14 +759,20 @@ status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResul } const IPCThreadState* ipc = IPCThreadState::self(); - const pid_t pid = ipc->getCallingPid(); const uid_t uid = ipc->getCallingUid(); +#ifndef __ANDROID_VNDK__ + // permission check can't be done for vendors as vendors have no access to + // the PermissionController + const pid_t pid = ipc->getCallingPid(); if ((uid != shellUid) && !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) { outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer " "from pid=%d, uid=%d\n", pid, uid); +#else + if (uid != shellUid) { +#endif android_errorWriteWithInfoLog(0x534e4554, "27046057", - static_cast(uid), nullptr, 0); + static_cast(uid), NULL, 0); return PERMISSION_DENIED; } diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 0c7b7e20db183df0ab8a90c2f2986e4f7ff18c62..c8021e4d54d778aad2ba674d0fe97a81fa24b94e 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -166,7 +166,7 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount( } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -221,7 +221,7 @@ status_t BufferQueueProducer::setAsyncMode(bool async) { } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } return NO_ERROR; @@ -450,11 +450,11 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou mSlots[found].mBufferState.dequeue(); - if ((buffer == nullptr) || + if ((buffer == NULL) || buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) { mSlots[found].mAcquireCalled = false; - mSlots[found].mGraphicBuffer = nullptr; + mSlots[found].mGraphicBuffer = NULL; mSlots[found].mRequestBufferCalled = false; mSlots[found].mEglDisplay = EGL_NO_DISPLAY; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; @@ -472,7 +472,7 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64, mCore->mBufferAge); - if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) { + if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { BQ_LOGE("dequeueBuffer: about to return a NULL fence - " "slot=%d w=%d h=%d format=%u", found, buffer->width, buffer->height, buffer->format); @@ -613,7 +613,7 @@ status_t BufferQueueProducer::detachBuffer(int slot) { listener = mCore->mConsumerListener; } - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -624,10 +624,10 @@ status_t BufferQueueProducer::detachNextBuffer(sp* outBuffer, sp* outFence) { ATRACE_CALL(); - if (outBuffer == nullptr) { + if (outBuffer == NULL) { BQ_LOGE("detachNextBuffer: outBuffer must not be NULL"); return BAD_VALUE; - } else if (outFence == nullptr) { + } else if (outFence == NULL) { BQ_LOGE("detachNextBuffer: outFence must not be NULL"); return BAD_VALUE; } @@ -671,7 +671,7 @@ status_t BufferQueueProducer::detachNextBuffer(sp* outBuffer, listener = mCore->mConsumerListener; } - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -682,10 +682,10 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, const sp& buffer) { ATRACE_CALL(); - if (outSlot == nullptr) { + if (outSlot == NULL) { BQ_LOGE("attachBuffer: outSlot must not be NULL"); return BAD_VALUE; - } else if (buffer == nullptr) { + } else if (buffer == NULL) { BQ_LOGE("attachBuffer: cannot attach NULL buffer"); return BAD_VALUE; } @@ -765,8 +765,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, &crop, &scalingMode, &transform, &acquireFence, &stickyTransform, &getFrameTimestamps); const Region& surfaceDamage = input.getSurfaceDamage(); + const HdrMetadata& hdrMetadata = input.getHdrMetadata(); - if (acquireFence == nullptr) { + if (acquireFence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); return BAD_VALUE; } @@ -825,9 +826,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, } BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d" - " crop=[%d,%d,%d,%d] transform=%#x scale=%s", - slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, - dataSpace, crop.left, crop.top, crop.right, crop.bottom, + " validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s", + slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, dataSpace, + hdrMetadata.validTypes, crop.left, crop.top, crop.right, crop.bottom, transform, BufferItem::scalingModeName(static_cast(scalingMode))); @@ -866,6 +867,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mTimestamp = requestedPresentTimestamp; item.mIsAutoTimestamp = isAutoTimestamp; item.mDataSpace = dataSpace; + item.mHdrMetadata = hdrMetadata; item.mFrameNumber = currentFrameNumber; item.mSlot = slot; item.mFence = acquireFence; @@ -876,6 +878,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mSurfaceDamage = surfaceDamage; item.mQueuedBuffer = true; item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh; + item.mApi = mCore->mConnectedApi; mStickyTransform = stickyTransform; @@ -970,9 +973,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCallbackCondition.wait(mCallbackMutex); } - if (frameAvailableListener != nullptr) { + if (frameAvailableListener != NULL) { frameAvailableListener->onFrameAvailable(item); - } else if (frameReplacedListener != nullptr) { + } else if (frameReplacedListener != NULL) { frameReplacedListener->onFrameReplaced(item); } @@ -1037,7 +1040,7 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp& fence) { BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " "(state = %s)", slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; - } else if (fence == nullptr) { + } else if (fence == NULL) { BQ_LOGE("cancelBuffer: fence is NULL"); return BAD_VALUE; } @@ -1067,7 +1070,7 @@ int BufferQueueProducer::query(int what, int *outValue) { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); - if (outValue == nullptr) { + if (outValue == NULL) { BQ_LOGE("query: outValue was NULL"); return BAD_VALUE; } @@ -1118,6 +1121,9 @@ int BufferQueueProducer::query(int what, int *outValue) { case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: value = static_cast(mCore->mConsumerIsProtected); break; + case NATIVE_WINDOW_MAX_BUFFER_COUNT: + value = static_cast(mCore->mMaxBufferCount); + break; default: return BAD_VALUE; } @@ -1140,12 +1146,12 @@ status_t BufferQueueProducer::connect(const sp& listener, return NO_INIT; } - if (mCore->mConsumerListener == nullptr) { + if (mCore->mConsumerListener == NULL) { BQ_LOGE("connect: BufferQueue has no consumer"); return NO_INIT; } - if (output == nullptr) { + if (output == NULL) { BQ_LOGE("connect: output was NULL"); return BAD_VALUE; } @@ -1183,10 +1189,10 @@ status_t BufferQueueProducer::connect(const sp& listener, output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; - if (listener != nullptr) { + if (listener != NULL) { // Set up a death notification so that we can disconnect // automatically if the remote producer dies - if (IInterface::asBinder(listener)->remoteBinder() != nullptr) { + if (IInterface::asBinder(listener)->remoteBinder() != NULL) { status = IInterface::asBinder(listener)->linkToDeath( static_cast(this)); if (status != NO_ERROR) { @@ -1263,7 +1269,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->freeAllBuffersLocked(); // Remove our death notification callback if we have one - if (mCore->mLinkedToDeath != nullptr) { + if (mCore->mLinkedToDeath != NULL) { sp token = IInterface::asBinder(mCore->mLinkedToDeath); // This can fail if we're here because of the death @@ -1273,8 +1279,8 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { } mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; - mCore->mLinkedToDeath = nullptr; - mCore->mConnectedProducerListener = nullptr; + mCore->mLinkedToDeath = NULL; + mCore->mConnectedProducerListener = NULL; mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); @@ -1297,7 +1303,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); listener->onDisconnect(); } @@ -1313,7 +1319,7 @@ status_t BufferQueueProducer::setSidebandStream(const sp& stream) listener = mCore->mConsumerListener; } // Autolock scope - if (listener != nullptr) { + if (listener != NULL) { listener->onSidebandStreamChanged(); } return NO_ERROR; @@ -1328,6 +1334,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, uint32_t allocHeight = 0; PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN; uint64_t allocUsage = 0; + std::string allocName; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); @@ -1347,6 +1354,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocHeight = height > 0 ? height : mCore->mDefaultHeight; allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; + allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); mCore->mIsAllocating = true; } // Autolock scope @@ -1355,7 +1363,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, for (size_t i = 0; i < newBufferCount; ++i) { sp graphicBuffer = new GraphicBuffer( allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT, - allocUsage, {mConsumerName.string(), mConsumerName.size()}); + allocUsage, allocName); status_t result = graphicBuffer->initCheck(); @@ -1527,7 +1535,7 @@ void BufferQueueProducer::addAndGetFrameTimestamps( Mutex::Autolock lock(mCore->mMutex); listener = mCore->mConsumerListener; } - if (listener != nullptr) { + if (listener != NULL) { listener->addAndGetFrameTimestamps(newTimestamps, outDelta); } } diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 2a9d742fc944bafb565c521d9743ad22ceb76c70..f9e292e19920705df9186bfdd9f97272f68b70d2 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -96,7 +96,7 @@ void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { void ConsumerBase::freeBufferLocked(int slotIndex) { CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mSlots[slotIndex].mGraphicBuffer = nullptr; + mSlots[slotIndex].mGraphicBuffer = 0; mSlots[slotIndex].mFence = Fence::NO_FENCE; mSlots[slotIndex].mFrameNumber = 0; } @@ -110,7 +110,7 @@ void ConsumerBase::onFrameAvailable(const BufferItem& item) { listener = mFrameAvailableListener.promote(); } - if (listener != nullptr) { + if (listener != NULL) { CB_LOGV("actually calling onFrameAvailable"); listener->onFrameAvailable(item); } @@ -125,7 +125,7 @@ void ConsumerBase::onFrameReplaced(const BufferItem &item) { listener = mFrameAvailableListener.promote(); } - if (listener != nullptr) { + if (listener != NULL) { CB_LOGV("actually calling onFrameReplaced"); listener->onFrameReplaced(item); } @@ -182,6 +182,16 @@ bool ConsumerBase::isAbandoned() { return mAbandoned; } +void ConsumerBase::setName(const String8& name) { + Mutex::Autolock _l(mMutex); + if (mAbandoned) { + CB_LOGE("setName: ConsumerBase is abandoned!"); + return; + } + mName = name; + mConsumer->setConsumerName(name); +} + void ConsumerBase::setFrameAvailableListener( const wp& listener) { CB_LOGV("setFrameAvailableListener"); @@ -237,6 +247,50 @@ status_t ConsumerBase::setDefaultBufferDataSpace( return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); } +status_t ConsumerBase::setConsumerUsageBits(uint64_t usage) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setConsumerUsageBits: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setConsumerUsageBits(usage); +} + +status_t ConsumerBase::setTransformHint(uint32_t hint) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setTransformHint: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setTransformHint(hint); +} + +status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); +} + +sp ConsumerBase::getSidebandStream() const { + Mutex::Autolock _l(mMutex); + if (mAbandoned) { + CB_LOGE("getSidebandStream: ConsumerBase is abandoned!"); + return nullptr; + } + + sp stream; + status_t err = mConsumer->getSidebandStream(&stream); + if (err != NO_ERROR) { + CB_LOGE("failed to get sideband stream: %d", err); + return nullptr; + } + + return stream; +} + status_t ConsumerBase::getOccupancyHistory(bool forceFlush, std::vector* outHistory) { Mutex::Autolock _l(mMutex); @@ -298,8 +352,8 @@ status_t ConsumerBase::acquireBufferLocked(BufferItem *item, return err; } - if (item->mGraphicBuffer != nullptr) { - if (mSlots[item->mSlot].mGraphicBuffer != nullptr) { + if (item->mGraphicBuffer != NULL) { + if (mSlots[item->mSlot].mGraphicBuffer != NULL) { freeBufferLocked(item->mSlot); } mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer; @@ -414,7 +468,7 @@ bool ConsumerBase::stillTracking(int slot, if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { return false; } - return (mSlots[slot].mGraphicBuffer != nullptr && + return (mSlots[slot].mGraphicBuffer != NULL && mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); } diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index 9f09e0c0d4a8a7f981e23ccecb82a5d1e70fd6d6..8edf60400ced8fdfd0e97bf84f227fa45b6648a9 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -18,11 +18,11 @@ #define LOG_TAG "CpuConsumer" //#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include -#include -#include #include +#include +#include + #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) @@ -44,20 +44,19 @@ CpuConsumer::CpuConsumer(const sp& bq, mConsumer->setMaxAcquiredBufferCount(static_cast(maxLockedBuffers)); } -CpuConsumer::~CpuConsumer() { - // ConsumerBase destructor does all the work. +size_t CpuConsumer::findAcquiredBufferLocked(uintptr_t id) const { + for (size_t i = 0; i < mMaxLockedBuffers; i++) { + const auto& ab = mAcquiredBuffers[i]; + // note that this finds AcquiredBuffer::kUnusedId as well + if (ab.mLockedBufferId == id) { + return i; + } + } + return mMaxLockedBuffers; // an invalid index } - - -void CpuConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - CC_LOGE("setName: CpuConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); +static uintptr_t getLockedBufferId(const CpuConsumer::LockedBuffer& buffer) { + return reinterpret_cast(buffer.data); } static bool isPossiblyYUV(PixelFormat format) { @@ -88,10 +87,74 @@ static bool isPossiblyYUV(PixelFormat format) { } } +status_t CpuConsumer::lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const { + android_ycbcr ycbcr = android_ycbcr(); + + PixelFormat format = item.mGraphicBuffer->getPixelFormat(); + PixelFormat flexFormat = format; + if (isPossiblyYUV(format)) { + int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; + status_t err = item.mGraphicBuffer->lockAsyncYCbCr(GraphicBuffer::USAGE_SW_READ_OFTEN, + item.mCrop, &ycbcr, fenceFd); + if (err == OK) { + flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; + if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { + CC_LOGV("locking buffer of format %#x as flex YUV", format); + } + } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", strerror(-err), err); + return err; + } + } + + if (ycbcr.y != nullptr) { + outBuffer->data = reinterpret_cast(ycbcr.y); + outBuffer->stride = static_cast(ycbcr.ystride); + outBuffer->dataCb = reinterpret_cast(ycbcr.cb); + outBuffer->dataCr = reinterpret_cast(ycbcr.cr); + outBuffer->chromaStride = static_cast(ycbcr.cstride); + outBuffer->chromaStep = static_cast(ycbcr.chroma_step); + } else { + // not flexible YUV; try lockAsync + void* bufferPointer = nullptr; + int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; + status_t err = item.mGraphicBuffer->lockAsync(GraphicBuffer::USAGE_SW_READ_OFTEN, + item.mCrop, &bufferPointer, fenceFd); + if (err != OK) { + CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), err); + return err; + } + + outBuffer->data = reinterpret_cast(bufferPointer); + outBuffer->stride = item.mGraphicBuffer->getStride(); + outBuffer->dataCb = nullptr; + outBuffer->dataCr = nullptr; + outBuffer->chromaStride = 0; + outBuffer->chromaStep = 0; + } + + outBuffer->width = item.mGraphicBuffer->getWidth(); + outBuffer->height = item.mGraphicBuffer->getHeight(); + outBuffer->format = format; + outBuffer->flexFormat = flexFormat; + + outBuffer->crop = item.mCrop; + outBuffer->transform = item.mTransform; + outBuffer->scalingMode = item.mScalingMode; + outBuffer->timestamp = item.mTimestamp; + outBuffer->dataSpace = item.mDataSpace; + outBuffer->frameNumber = item.mFrameNumber; + + return OK; +} + status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t err; if (!nativeBuffer) return BAD_VALUE; + + Mutex::Autolock _l(mMutex); + if (mCurrentLockedBuffers == mMaxLockedBuffers) { CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.", mMaxLockedBuffers); @@ -99,9 +162,6 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } BufferItem b; - - Mutex::Autolock _l(mMutex); - err = acquireBufferLocked(&b, 0); if (err != OK) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { @@ -112,94 +172,23 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } } - int slot = b.mSlot; - - void *bufferPointer = nullptr; - android_ycbcr ycbcr = android_ycbcr(); - - PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat(); - PixelFormat flexFormat = format; - if (isPossiblyYUV(format)) { - if (b.mFence.get()) { - err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &ycbcr, - b.mFence->dup()); - } else { - err = mSlots[slot].mGraphicBuffer->lockYCbCr( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &ycbcr); - } - if (err == OK) { - bufferPointer = ycbcr.y; - flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; - if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { - CC_LOGV("locking buffer of format %#x as flex YUV", format); - } - } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { - CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", - strerror(-err), err); - return err; - } + if (b.mGraphicBuffer == nullptr) { + b.mGraphicBuffer = mSlots[b.mSlot].mGraphicBuffer; } - if (bufferPointer == nullptr) { // not flexible YUV - if (b.mFence.get()) { - err = mSlots[slot].mGraphicBuffer->lockAsync( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &bufferPointer, - b.mFence->dup()); - } else { - err = mSlots[slot].mGraphicBuffer->lock( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &bufferPointer); - } - if (err != OK) { - CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", - strerror(-err), err); - return err; - } + err = lockBufferItem(b, nativeBuffer); + if (err != OK) { + return err; } - size_t lockedIdx = 0; - for (; lockedIdx < static_cast(mMaxLockedBuffers); lockedIdx++) { - if (mAcquiredBuffers[lockedIdx].mSlot == - BufferQueue::INVALID_BUFFER_SLOT) { - break; - } - } - assert(lockedIdx < mMaxLockedBuffers); - - AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); - ab.mSlot = slot; - ab.mBufferPointer = bufferPointer; - ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer; - - nativeBuffer->data = - reinterpret_cast(bufferPointer); - nativeBuffer->width = mSlots[slot].mGraphicBuffer->getWidth(); - nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight(); - nativeBuffer->format = format; - nativeBuffer->flexFormat = flexFormat; - nativeBuffer->stride = (ycbcr.y != nullptr) ? - static_cast(ycbcr.ystride) : - mSlots[slot].mGraphicBuffer->getStride(); - - nativeBuffer->crop = b.mCrop; - nativeBuffer->transform = b.mTransform; - nativeBuffer->scalingMode = b.mScalingMode; - nativeBuffer->timestamp = b.mTimestamp; - nativeBuffer->dataSpace = b.mDataSpace; - nativeBuffer->frameNumber = b.mFrameNumber; - - nativeBuffer->dataCb = reinterpret_cast(ycbcr.cb); - nativeBuffer->dataCr = reinterpret_cast(ycbcr.cr); - nativeBuffer->chromaStride = static_cast(ycbcr.cstride); - nativeBuffer->chromaStep = static_cast(ycbcr.chroma_step); + // find an unused AcquiredBuffer + size_t lockedIdx = findAcquiredBufferLocked(AcquiredBuffer::kUnusedId); + ALOG_ASSERT(lockedIdx < mMaxLockedBuffers); + AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); + + ab.mSlot = b.mSlot; + ab.mGraphicBuffer = b.mGraphicBuffer; + ab.mLockedBufferId = getLockedBufferId(*nativeBuffer); mCurrentLockedBuffers++; @@ -208,60 +197,34 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); - size_t lockedIdx = 0; - void *bufPtr = reinterpret_cast(nativeBuffer.data); - for (; lockedIdx < static_cast(mMaxLockedBuffers); lockedIdx++) { - if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break; - } + uintptr_t id = getLockedBufferId(nativeBuffer); + size_t lockedIdx = + (id != AcquiredBuffer::kUnusedId) ? findAcquiredBufferLocked(id) : mMaxLockedBuffers; if (lockedIdx == mMaxLockedBuffers) { CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); return BAD_VALUE; } - return releaseAcquiredBufferLocked(lockedIdx); -} + AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); -status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) { - status_t err; - int fd = -1; - - err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd); + int fenceFd = -1; + status_t err = ab.mGraphicBuffer->unlockAsync(&fenceFd); if (err != OK) { CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__, lockedIdx); return err; } - int buf = mAcquiredBuffers[lockedIdx].mSlot; - if (CC_LIKELY(fd != -1)) { - sp fence(new Fence(fd)); - addReleaseFenceLocked( - mAcquiredBuffers[lockedIdx].mSlot, - mSlots[buf].mGraphicBuffer, - fence); - } - // release the buffer if it hasn't already been freed by the BufferQueue. - // This can happen, for example, when the producer of this buffer - // disconnected after this buffer was acquired. - if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer == - mSlots[buf].mGraphicBuffer)) { - releaseBufferLocked( - buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - } + sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); + addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence); + releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer); - AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); - ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT; - ab.mBufferPointer = nullptr; - ab.mGraphicBuffer.clear(); + ab.reset(); mCurrentLockedBuffers--; - return OK; -} -void CpuConsumer::freeBufferLocked(int slotIndex) { - ConsumerBase::freeBufferLocked(slotIndex); + return OK; } } // namespace android diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index f5cf1c4d5a811a70c88f77e2906d122d8c6ae98f..1757ec1cd3c4a0c124fa68b15d094d23ab78e1c9 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -34,9 +34,9 @@ namespace android { DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) { sp sf(ComposerService::getComposerService()); - if (sf != nullptr) { + if (sf != NULL) { mEventConnection = sf->createDisplayEventConnection(vsyncSource); - if (mEventConnection != nullptr) { + if (mEventConnection != NULL) { mDataChannel = std::make_unique(); mEventConnection->stealReceiveChannel(mDataChannel.get()); } @@ -47,13 +47,13 @@ DisplayEventReceiver::~DisplayEventReceiver() { } status_t DisplayEventReceiver::initCheck() const { - if (mDataChannel != nullptr) + if (mDataChannel != NULL) return NO_ERROR; return NO_INIT; } int DisplayEventReceiver::getFd() const { - if (mDataChannel == nullptr) + if (mDataChannel == NULL) return NO_INIT; return mDataChannel->getFd(); @@ -63,7 +63,7 @@ status_t DisplayEventReceiver::setVsyncRate(uint32_t count) { if (int32_t(count) < 0) return BAD_VALUE; - if (mEventConnection != nullptr) { + if (mEventConnection != NULL) { mEventConnection->setVsyncRate(count); return NO_ERROR; } @@ -71,7 +71,7 @@ status_t DisplayEventReceiver::setVsyncRate(uint32_t count) { } status_t DisplayEventReceiver::requestNextVsync() { - if (mEventConnection != nullptr) { + if (mEventConnection != NULL) { mEventConnection->requestNextVsync(); return NO_ERROR; } diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp index fccca97f544f14dc43b812b1d8573b52947eeb01..a379ad6306edf3b7e7f68c07b3672b099a94acca 100644 --- a/libs/gui/FrameTimestamps.cpp +++ b/libs/gui/FrameTimestamps.cpp @@ -628,7 +628,6 @@ FrameEventHistoryDelta& FrameEventHistoryDelta::operator=( ALOGE("FrameEventHistoryDelta assign clobbering history."); } mDeltas = std::move(src.mDeltas); - ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty."); return *this; } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 59e78cc6bf1fbf812c9e2bd8b50445f6da912555..885efec9b9881a8c74b2b2ac4a0020b4985c88c8 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -31,6 +31,8 @@ #include +#include + #include #include #include @@ -75,33 +77,7 @@ static const struct { "_______________" }; -// Transform matrices -static float mtxIdentity[16] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, -}; -static float mtxFlipH[16] = { - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; -static float mtxFlipV[16] = { - 1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 1, -}; -static float mtxRot90[16] = { - 0, 1, 0, 0, - -1, 0, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; - -static void mtxMul(float out[16], const float a[16], const float b[16]); +static const mat4 mtxIdentity; Mutex GLConsumer::sStaticInitLock; sp GLConsumer::sReleasedTexImageBuffer; @@ -173,7 +149,7 @@ GLConsumer::GLConsumer(const sp& bq, uint32_t tex, { GLC_LOGV("GLConsumer"); - memcpy(mCurrentTransformMatrix, mtxIdentity, + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); @@ -202,7 +178,7 @@ GLConsumer::GLConsumer(const sp& bq, uint32_t texTarget, { GLC_LOGV("GLConsumer"); - memcpy(mCurrentTransformMatrix, mtxIdentity, + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); @@ -315,7 +291,7 @@ status_t GLConsumer::releaseTexImage() { return err; } - if (mReleasedTexImage == nullptr) { + if (mReleasedTexImage == NULL) { mReleasedTexImage = new EglImage(getDebugTexImageBuffer()); } @@ -345,7 +321,7 @@ status_t GLConsumer::releaseTexImage() { sp GLConsumer::getDebugTexImageBuffer() { Mutex::Autolock _l(sStaticInitLock); - if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) { + if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) { // The first time, create the debug texture in case the application // continues to use it. sp buffer = new GraphicBuffer( @@ -381,7 +357,7 @@ status_t GLConsumer::acquireBufferLocked(BufferItem *item, // If item->mGraphicBuffer is not null, this buffer has not been acquired // before, so any prior EglImage created is using a stale buffer. This // replaces any old EglImage with a new one (using the new buffer). - if (item->mGraphicBuffer != nullptr) { + if (item->mGraphicBuffer != NULL) { int slot = item->mSlot; mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer); } @@ -455,7 +431,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item, GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureImage != NULL ? - mCurrentTextureImage->graphicBufferHandle() : nullptr, + mCurrentTextureImage->graphicBufferHandle() : 0, slot, mSlots[slot].mGraphicBuffer->handle); // Hang onto the pointer so that it isn't freed in the call to @@ -515,7 +491,7 @@ status_t GLConsumer::bindTextureImageLocked() { glBindTexture(mTexTarget, mTexName); if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && - mCurrentTextureImage == nullptr) { + mCurrentTextureImage == NULL) { GLC_LOGE("bindTextureImage: no currently-bound texture"); return NO_INIT; } @@ -679,7 +655,7 @@ status_t GLConsumer::attachToContext(uint32_t tex) { mTexName = tex; mAttached = true; - if (mCurrentTextureImage != nullptr) { + if (mCurrentTextureImage != NULL) { // This may wait for a buffer a second time. This is likely required if // this is a different context, since otherwise the wait could be skipped // by bouncing through another context. For the same context the extra @@ -700,7 +676,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (SyncFeatures::getInstance().useNativeFenceSync()) { EGLSyncKHR sync = eglCreateSyncKHR(dpy, - EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); if (sync == EGL_NO_SYNC_KHR) { GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError()); @@ -744,7 +720,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { // Create a fence for the outstanding accesses in the current // OpenGL ES context. - fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr); + fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); if (fence == EGL_NO_SYNC_KHR) { GLC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError()); @@ -758,25 +734,6 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { return OK; } -bool GLConsumer::isExternalFormat(PixelFormat format) -{ - switch (format) { - // supported YUV formats - case HAL_PIXEL_FORMAT_YV12: - // Legacy/deprecated YUV formats - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_422_I: - return true; - } - - // Any OEM format needs to be considered - if (format>=0x100 && format<=0x1FF) - return true; - - return false; -} - uint32_t GLConsumer::getCurrentTextureTarget() const { return mTexTarget; } @@ -795,11 +752,11 @@ void GLConsumer::setFilteringEnabled(bool enabled) { bool needsRecompute = mFilteringEnabled != enabled; mFilteringEnabled = enabled; - if (needsRecompute && mCurrentTextureImage==nullptr) { + if (needsRecompute && mCurrentTextureImage==NULL) { GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); } - if (needsRecompute && mCurrentTextureImage != nullptr) { + if (needsRecompute && mCurrentTextureImage != NULL) { computeCurrentTransformMatrixLocked(); } } @@ -820,34 +777,37 @@ void GLConsumer::computeCurrentTransformMatrixLocked() { void GLConsumer::computeTransformMatrix(float outTransform[16], const sp& buf, const Rect& cropRect, uint32_t transform, bool filtering) { - - float xform[16]; - for (int i = 0; i < 16; i++) { - xform[i] = mtxIdentity[i]; - } + // Transform matrices + static const mat4 mtxFlipH( + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1 + ); + static const mat4 mtxFlipV( + 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 1 + ); + static const mat4 mtxRot90( + 0, 1, 0, 0, + -1, 0, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1 + ); + + mat4 xform; if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - float result[16]; - mtxMul(result, xform, mtxFlipH); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxFlipH; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - float result[16]; - mtxMul(result, xform, mtxFlipV); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxFlipV; } if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - float result[16]; - mtxMul(result, xform, mtxRot90); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxRot90; } - float mtxBeforeFlipV[16]; if (!cropRect.isEmpty()) { float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; float bufferWidth = buf->getWidth(); @@ -893,25 +853,63 @@ void GLConsumer::computeTransformMatrix(float outTransform[16], sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; } - float crop[16] = { + + mat4 crop( sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, - tx, ty, 0, 1, - }; - - mtxMul(mtxBeforeFlipV, crop, xform); - } else { - for (int i = 0; i < 16; i++) { - mtxBeforeFlipV[i] = xform[i]; - } + tx, ty, 0, 1 + ); + xform = crop * xform; } // SurfaceFlinger expects the top of its window textures to be at a Y // coordinate of 0, so GLConsumer must behave the same way. We don't // want to expose this to applications, however, so we must add an // additional vertical flip to the transform after all the other transforms. - mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV); + xform = mtxFlipV * xform; + + memcpy(outTransform, xform.asArray(), sizeof(xform)); +} + +Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) { + Rect outCrop = crop; + + uint32_t newWidth = static_cast(crop.width()); + uint32_t newHeight = static_cast(crop.height()); + + if (newWidth * bufferHeight > newHeight * bufferWidth) { + newWidth = newHeight * bufferWidth / bufferHeight; + ALOGV("too wide: newWidth = %d", newWidth); + } else if (newWidth * bufferHeight < newHeight * bufferWidth) { + newHeight = newWidth * bufferHeight / bufferWidth; + ALOGV("too tall: newHeight = %d", newHeight); + } + + uint32_t currentWidth = static_cast(crop.width()); + uint32_t currentHeight = static_cast(crop.height()); + + // The crop is too wide + if (newWidth < currentWidth) { + uint32_t dw = currentWidth - newWidth; + auto halfdw = dw / 2; + outCrop.left += halfdw; + // Not halfdw because it would subtract 1 too few when dw is odd + outCrop.right -= (dw - halfdw); + // The crop is too tall + } else if (newHeight < currentHeight) { + uint32_t dh = currentHeight - newHeight; + auto halfdh = dh / 2; + outCrop.top += halfdh; + // Not halfdh because it would subtract 1 too few when dh is odd + outCrop.bottom -= (dh - halfdh); + } + + ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", + outCrop.left, outCrop.top, + outCrop.right,outCrop.bottom); + + return outCrop; } nsecs_t GLConsumer::getTimestamp() { @@ -940,50 +938,14 @@ sp GLConsumer::getCurrentBuffer(int* outSlot) const { } return (mCurrentTextureImage == nullptr) ? - nullptr : mCurrentTextureImage->graphicBuffer(); + NULL : mCurrentTextureImage->graphicBuffer(); } Rect GLConsumer::getCurrentCrop() const { Mutex::Autolock lock(mMutex); - - Rect outCrop = mCurrentCrop; - if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { - uint32_t newWidth = static_cast(mCurrentCrop.width()); - uint32_t newHeight = static_cast(mCurrentCrop.height()); - - if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) { - newWidth = newHeight * mDefaultWidth / mDefaultHeight; - GLC_LOGV("too wide: newWidth = %d", newWidth); - } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) { - newHeight = newWidth * mDefaultHeight / mDefaultWidth; - GLC_LOGV("too tall: newHeight = %d", newHeight); - } - - uint32_t currentWidth = static_cast(mCurrentCrop.width()); - uint32_t currentHeight = static_cast(mCurrentCrop.height()); - - // The crop is too wide - if (newWidth < currentWidth) { - uint32_t dw = currentWidth - newWidth; - auto halfdw = dw / 2; - outCrop.left += halfdw; - // Not halfdw because it would subtract 1 too few when dw is odd - outCrop.right -= (dw - halfdw); - // The crop is too tall - } else if (newHeight < currentHeight) { - uint32_t dh = currentHeight - newHeight; - auto halfdh = dh / 2; - outCrop.top += halfdh; - // Not halfdh because it would subtract 1 too few when dh is odd - outCrop.bottom -= (dh - halfdh); - } - - GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", - outCrop.left, outCrop.top, - outCrop.right,outCrop.bottom); - } - - return outCrop; + return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) + ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight) + : mCurrentCrop; } uint32_t GLConsumer::getCurrentTransform() const { @@ -1006,11 +968,6 @@ std::shared_ptr GLConsumer::getCurrentFenceTime() const { return mCurrentFenceTime; } -status_t GLConsumer::doGLFenceWait() const { - Mutex::Autolock lock(mMutex); - return doGLFenceWaitLocked(); -} - status_t GLConsumer::doGLFenceWaitLocked() const { EGLDisplay dpy = eglGetCurrentDisplay(); @@ -1027,7 +984,8 @@ status_t GLConsumer::doGLFenceWaitLocked() const { } if (mCurrentFence->isValid()) { - if (SyncFeatures::getInstance().useWaitSync()) { + if (SyncFeatures::getInstance().useWaitSync() && + SyncFeatures::getInstance().useNativeFenceSync()) { // Create an EGLSyncKHR from the current fence. int fenceFd = mCurrentFence->dup(); if (fenceFd == -1) { @@ -1086,61 +1044,8 @@ void GLConsumer::abandonLocked() { ConsumerBase::abandonLocked(); } -void GLConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - GLC_LOGE("setName: GLConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); -} - -status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setDefaultBufferFormat: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -status_t GLConsumer::setDefaultBufferDataSpace( - android_dataspace defaultDataSpace) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setDefaultBufferDataSpace: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); -} - status_t GLConsumer::setConsumerUsageBits(uint64_t usage) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!"); - return NO_INIT; - } - usage |= DEFAULT_USAGE_FLAGS; - return mConsumer->setConsumerUsageBits(usage); -} - -status_t GLConsumer::setTransformHint(uint32_t hint) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setTransformHint: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setTransformHint(hint); -} - -status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setMaxAcquiredBufferCount: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); + return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); } void GLConsumer::dumpLocked(String8& result, const char* prefix) const @@ -1155,28 +1060,6 @@ void GLConsumer::dumpLocked(String8& result, const char* prefix) const ConsumerBase::dumpLocked(result, prefix); } -static void mtxMul(float out[16], const float a[16], const float b[16]) { - out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; - out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; - out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; - out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; - - out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; - out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; - out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; - out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; - - out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; - out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; - out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; - out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; - - out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; - out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; - out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; - out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; -} - GLConsumer::EglImage::EglImage(sp graphicBuffer) : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), @@ -1267,7 +1150,7 @@ EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy, attrs[3] = attrs[11]; attrs[4] = EGL_NONE; } - eglInitialize(dpy, nullptr, nullptr); + eglInitialize(dpy, 0, 0); EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); if (image == EGL_NO_IMAGE_KHR) { diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b715e431d5663e01efecbbf580e0d86cb3634266 --- /dev/null +++ b/libs/gui/HdrMetadata.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace android { + +size_t HdrMetadata::getFlattenedSize() const { + size_t size = sizeof(validTypes); + if (validTypes & SMPTE2086) { + size += sizeof(smpte2086); + } + if (validTypes & CTA861_3) { + size += sizeof(cta8613); + } + return size; +} + +status_t HdrMetadata::flatten(void* buffer, size_t size) const { + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, validTypes); + if (validTypes & SMPTE2086) { + FlattenableUtils::write(buffer, size, smpte2086); + } + if (validTypes & CTA861_3) { + FlattenableUtils::write(buffer, size, cta8613); + } + + return NO_ERROR; +} + +status_t HdrMetadata::unflatten(void const* buffer, size_t size) { + if (size < sizeof(validTypes)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, validTypes); + if (validTypes & SMPTE2086) { + if (size < sizeof(smpte2086)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, smpte2086); + } + if (validTypes & CTA861_3) { + if (size < sizeof(cta8613)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, cta8613); + } + + return NO_ERROR; +} + +bool HdrMetadata::operator==(const HdrMetadata& rhs) const { + if (validTypes != rhs.validTypes) return false; + + if ((validTypes & SMPTE2086) == SMPTE2086) { + if (smpte2086.displayPrimaryRed.x != rhs.smpte2086.displayPrimaryRed.x || + smpte2086.displayPrimaryRed.y != rhs.smpte2086.displayPrimaryRed.y || + smpte2086.displayPrimaryGreen.x != rhs.smpte2086.displayPrimaryGreen.x || + smpte2086.displayPrimaryGreen.y != rhs.smpte2086.displayPrimaryGreen.y || + smpte2086.displayPrimaryBlue.x != rhs.smpte2086.displayPrimaryBlue.x || + smpte2086.displayPrimaryBlue.y != rhs.smpte2086.displayPrimaryBlue.y || + smpte2086.whitePoint.x != rhs.smpte2086.whitePoint.x || + smpte2086.whitePoint.y != rhs.smpte2086.whitePoint.y || + smpte2086.maxLuminance != rhs.smpte2086.maxLuminance || + smpte2086.minLuminance != rhs.smpte2086.minLuminance) { + return false; + } + } + + if ((validTypes & CTA861_3) == CTA861_3) { + if (cta8613.maxFrameAverageLightLevel != rhs.cta8613.maxFrameAverageLightLevel || + cta8613.maxContentLightLevel != rhs.cta8613.maxContentLightLevel) { + return false; + } + } + + return true; +} + +} // namespace android diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 23e9ddc014e53ee50646b1ba09af93835691643e..0749fde1add9eaa90937a96ad6ffc85ab6a0018a 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -27,6 +27,9 @@ #include #include +#ifndef NO_BUFFERHUB +#include +#endif #include #include #include @@ -187,10 +190,10 @@ public: virtual status_t detachNextBuffer(sp* outBuffer, sp* outFence) { - if (outBuffer == nullptr) { + if (outBuffer == NULL) { ALOGE("detachNextBuffer: outBuffer must not be NULL"); return BAD_VALUE; - } else if (outFence == nullptr) { + } else if (outFence == NULL) { ALOGE("detachNextBuffer: outFence must not be NULL"); return BAD_VALUE; } @@ -298,7 +301,7 @@ public: int api, bool producerControlledByApp, QueueBufferOutput* output) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - if (listener != nullptr) { + if (listener != NULL) { data.writeInt32(1); data.writeStrongBinder(IInterface::asBinder(listener)); } else { @@ -653,6 +656,79 @@ IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer, // ---------------------------------------------------------------------- +status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { + status_t res = OK; + res = parcel->writeUint32(USE_BUFFER_QUEUE); + if (res != NO_ERROR) { + ALOGE("exportToParcel: Cannot write magic, res=%d.", res); + return res; + } + + return parcel->writeStrongBinder(IInterface::asBinder(this)); +} + +/* static */ +status_t IGraphicBufferProducer::exportToParcel(const sp& producer, + Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("exportToParcel: Invalid parcel object."); + return BAD_VALUE; + } + + if (producer == nullptr) { + status_t res = OK; + res = parcel->writeUint32(IGraphicBufferProducer::USE_BUFFER_QUEUE); + if (res != NO_ERROR) return res; + return parcel->writeStrongBinder(nullptr); + } else { + return producer->exportToParcel(parcel); + } +} + +/* static */ +sp IGraphicBufferProducer::createFromParcel(const Parcel* parcel) { + uint32_t outMagic = 0; + status_t res = NO_ERROR; + + res = parcel->readUint32(&outMagic); + if (res != NO_ERROR) { + ALOGE("createFromParcel: Failed to read magic, error=%d.", res); + return nullptr; + } + + switch (outMagic) { + case USE_BUFFER_QUEUE: { + sp binder; + res = parcel->readNullableStrongBinder(&binder); + if (res != NO_ERROR) { + ALOGE("createFromParcel: Can't read strong binder."); + return nullptr; + } + return interface_cast(binder); + } + case USE_BUFFER_HUB: { + ALOGE("createFromParcel: BufferHub not implemented."); +#ifndef NO_BUFFERHUB + dvr::ProducerQueueParcelable producerParcelable; + res = producerParcelable.readFromParcel(parcel); + if (res != NO_ERROR) { + ALOGE("createFromParcel: Failed to read from parcel, error=%d", res); + return nullptr; + } + return BufferHubProducer::Create(std::move(producerParcelable)); +#else + return nullptr; +#endif + } + default: { + ALOGE("createFromParcel: Unexpected mgaic: 0x%x.", outMagic); + return nullptr; + } + } +} + +// ---------------------------------------------------------------------------- + status_t BnGraphicBufferProducer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -662,8 +738,8 @@ status_t BnGraphicBufferProducer::onTransact( int bufferIdx = data.readInt32(); sp buffer; int result = requestBuffer(bufferIdx, &buffer); - reply->writeInt32(buffer != nullptr); - if (buffer != nullptr) { + reply->writeInt32(buffer != 0); + if (buffer != 0) { reply->write(*buffer); } reply->writeInt32(result); @@ -721,12 +797,12 @@ status_t BnGraphicBufferProducer::onTransact( int32_t result = detachNextBuffer(&buffer, &fence); reply->writeInt32(result); if (result == NO_ERROR) { - reply->writeInt32(buffer != nullptr); - if (buffer != nullptr) { + reply->writeInt32(buffer != NULL); + if (buffer != NULL) { reply->write(*buffer); } - reply->writeInt32(fence != nullptr); - if (fence != nullptr) { + reply->writeInt32(fence != NULL); + if (fence != NULL) { reply->write(*fence); } } @@ -951,7 +1027,8 @@ constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() { size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { return minFlattenedSize() + fence->getFlattenedSize() + - surfaceDamage.getFlattenedSize(); + surfaceDamage.getFlattenedSize() + + hdrMetadata.getFlattenedSize(); } size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { @@ -978,7 +1055,12 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( if (result != NO_ERROR) { return result; } - return surfaceDamage.flatten(buffer, size); + result = surfaceDamage.flatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.flatten(buffer, size); } status_t IGraphicBufferProducer::QueueBufferInput::unflatten( @@ -1002,7 +1084,12 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( if (result != NO_ERROR) { return result; } - return surfaceDamage.unflatten(buffer, size); + result = surfaceDamage.unflatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.unflatten(buffer, size); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8e7f814313017be8cc9981b79839421dacd698e2..e22bc708c9ab5e7db759be5bc0dd5af064629384 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -29,8 +29,7 @@ #include #include #include - -#include +#include #include @@ -44,6 +43,8 @@ namespace android { +using ui::ColorMode; + class BpSurfaceComposer : public BpInterface { public: @@ -101,17 +102,13 @@ public: remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - virtual status_t captureScreen(const sp& display, - const sp& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - ISurfaceComposer::Rotation rotation) - { + virtual status_t captureScreen(const sp& display, sp* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, + ISurfaceComposer::Rotation rotation) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); - data.writeStrongBinder(IInterface::asBinder(producer)); data.write(sourceCrop); data.writeUint32(reqWidth); data.writeUint32(reqHeight); @@ -119,8 +116,46 @@ public: data.writeInt32(maxLayerZ); data.writeInt32(static_cast(useIdentityTransform)); data.writeInt32(static_cast(rotation)); - remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); - return reply.readInt32(); + status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); + + if (err != NO_ERROR) { + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + return err; + } + + *outBuffer = new GraphicBuffer(); + reply.read(**outBuffer); + return err; + } + + virtual status_t captureLayers(const sp& layerHandleBinder, + sp* outBuffer, const Rect& sourceCrop, + float frameScale, bool childrenOnly) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(layerHandleBinder); + data.write(sourceCrop); + data.writeFloat(frameScale); + data.writeBool(childrenOnly); + status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); + + if (err != NO_ERROR) { + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + return err; + } + + *outBuffer = new GraphicBuffer(); + reply.read(**outBuffer); + + return err; } virtual bool authenticateSurfaceTexture( @@ -317,7 +352,7 @@ public: } virtual status_t getDisplayColorModes(const sp& display, - Vector* outColorModes) { + Vector* outColorModes) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -340,34 +375,34 @@ public: outColorModes->clear(); outColorModes->resize(numModes); for (size_t i = 0; i < numModes; ++i) { - outColorModes->replaceAt(static_cast(reply.readInt32()), i); + outColorModes->replaceAt(static_cast(reply.readInt32()), i); } } return result; } - virtual android_color_mode_t getActiveColorMode(const sp& display) { + virtual ColorMode getActiveColorMode(const sp& display) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result); - return static_cast(result); + return static_cast(result); } result = data.writeStrongBinder(display); if (result != NO_ERROR) { ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result); - return static_cast(result); + return static_cast(result); } result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply); if (result != NO_ERROR) { ALOGE("getActiveColorMode failed to transact: %d", result); - return static_cast(result); + return static_cast(result); } - return static_cast(reply.readInt32()); + return static_cast(reply.readInt32()); } virtual status_t setActiveColorMode(const sp& display, - android_color_mode_t colorMode) { + ColorMode colorMode) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -379,7 +414,7 @@ public: ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result); return result; } - result = data.writeInt32(colorMode); + result = data.writeInt32(static_cast(colorMode)); if (result != NO_ERROR) { ALOGE("setActiveColorMode failed to writeInt32: %d", result); return result; @@ -571,8 +606,7 @@ status_t BnSurfaceComposer::onTransact( case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); - sp producer = - interface_cast(data.readStrongBinder()); + sp outBuffer; Rect sourceCrop(Rect::EMPTY_RECT); data.read(sourceCrop); uint32_t reqWidth = data.readUint32(); @@ -582,11 +616,30 @@ status_t BnSurfaceComposer::onTransact( bool useIdentityTransform = static_cast(data.readInt32()); int32_t rotation = data.readInt32(); - status_t res = captureScreen(display, producer, - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, - static_cast(rotation)); + status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight, + minLayerZ, maxLayerZ, useIdentityTransform, + static_cast(rotation)); reply->writeInt32(res); + if (res == NO_ERROR) { + reply->write(*outBuffer); + } + return NO_ERROR; + } + case CAPTURE_LAYERS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp layerHandleBinder = data.readStrongBinder(); + sp outBuffer; + Rect sourceCrop(Rect::EMPTY_RECT); + data.read(sourceCrop); + float frameScale = data.readFloat(); + bool childrenOnly = data.readBool(); + + status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale, + childrenOnly); + reply->writeInt32(res); + if (res == NO_ERROR) { + reply->write(*outBuffer); + } return NO_ERROR; } case AUTHENTICATE_SURFACE: { @@ -688,7 +741,7 @@ status_t BnSurfaceComposer::onTransact( } case GET_DISPLAY_COLOR_MODES: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - Vector colorModes; + Vector colorModes; sp display = nullptr; status_t result = data.readStrongBinder(&display); if (result != NO_ERROR) { @@ -700,7 +753,7 @@ status_t BnSurfaceComposer::onTransact( if (result == NO_ERROR) { reply->writeUint32(static_cast(colorModes.size())); for (size_t i = 0; i < colorModes.size(); ++i) { - reply->writeInt32(colorModes[i]); + reply->writeInt32(static_cast(colorModes[i])); } } return NO_ERROR; @@ -713,7 +766,7 @@ status_t BnSurfaceComposer::onTransact( ALOGE("getActiveColorMode failed to readStrongBinder: %d", result); return result; } - android_color_mode_t colorMode = getActiveColorMode(display); + ColorMode colorMode = getActiveColorMode(display); result = reply->writeInt32(static_cast(colorMode)); return result; } @@ -732,7 +785,7 @@ status_t BnSurfaceComposer::onTransact( return result; } result = setActiveColorMode(display, - static_cast(colorModeInt)); + static_cast(colorModeInt)); result = reply->writeInt32(result); return result; } diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 679f44b57b99f821023274eb4152c16b65bbaf67..a6890eeb190383c59ad17975b748a9306e32c5ce 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -47,8 +47,8 @@ public: ~BpSurfaceComposerClient() override; status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format, - uint32_t flags, const sp& parent, uint32_t windowType, - uint32_t ownerUid, sp* handle, + uint32_t flags, const sp& parent, int32_t windowType, + int32_t ownerUid, sp* handle, sp* gbp) override { return callRemote(Tag::CREATE_SURFACE, name, width, height, diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp index 57ddde075af744143f9369dcb94b5a86c9aafb26..d3dc16d30e87897b92392831cff7a0b089029fdd 100644 --- a/libs/gui/LayerDebugInfo.cpp +++ b/libs/gui/LayerDebugInfo.cpp @@ -43,7 +43,10 @@ status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { RETURN_ON_ERROR(parcel->writeInt32(mHeight)); RETURN_ON_ERROR(parcel->write(mCrop)); RETURN_ON_ERROR(parcel->write(mFinalCrop)); - RETURN_ON_ERROR(parcel->writeFloat(mAlpha)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.r)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.g)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.b)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.a)); RETURN_ON_ERROR(parcel->writeUint32(mFlags)); RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat)); RETURN_ON_ERROR(parcel->writeUint32(static_cast(mDataSpace))); @@ -79,7 +82,14 @@ status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) { RETURN_ON_ERROR(parcel->readInt32(&mHeight)); RETURN_ON_ERROR(parcel->read(mCrop)); RETURN_ON_ERROR(parcel->read(mFinalCrop)); - RETURN_ON_ERROR(parcel->readFloat(&mAlpha)); + mColor.r = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.g = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.b = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.a = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); RETURN_ON_ERROR(parcel->readUint32(&mFlags)); RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat)); // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways? @@ -116,8 +126,10 @@ std::string to_string(const LayerDebugInfo& info) { result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty); result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str()); result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str()); - result.appendFormat("alpha=%.3f, flags=0x%08x, ", - static_cast(info.mAlpha), info.mFlags); + result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ", + static_cast(info.mColor.r), static_cast(info.mColor.g), + static_cast(info.mColor.b), static_cast(info.mColor.a), + info.mFlags); result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]", static_cast(info.mMatrix[0][0]), static_cast(info.mMatrix[0][1]), static_cast(info.mMatrix[1][0]), static_cast(info.mMatrix[1][1])); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 9b06e636105e0ace2a1b527d7494e101237e2442..01acc2de2051201d27923ac1fdc90a268aa8aace 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include namespace android { @@ -45,6 +45,10 @@ status_t layer_state_t::write(Parcel& output) const output.writeInt32(overrideScalingMode); output.writeStrongBinder(IInterface::asBinder(barrierGbp)); output.writeStrongBinder(relativeLayerHandle); + output.writeStrongBinder(parentHandleForChild); + output.writeFloat(color.r); + output.writeFloat(color.g); + output.writeFloat(color.b); output.write(transparentRegion); return NO_ERROR; } @@ -77,6 +81,10 @@ status_t layer_state_t::read(const Parcel& input) barrierGbp = interface_cast(input.readStrongBinder()); relativeLayerHandle = input.readStrongBinder(); + parentHandleForChild = input.readStrongBinder(); + color.r = input.readFloat(); + color.g = input.readFloat(); + color.b = input.readFloat(); input.read(transparentRegion); return NO_ERROR; } @@ -128,5 +136,104 @@ status_t DisplayState::read(const Parcel& input) { return NO_ERROR; } +void DisplayState::merge(const DisplayState& other) { + if (other.what & eSurfaceChanged) { + what |= eSurfaceChanged; + surface = other.surface; + } + if (other.what & eLayerStackChanged) { + what |= eLayerStackChanged; + layerStack = other.layerStack; + } + if (other.what & eDisplayProjectionChanged) { + what |= eDisplayProjectionChanged; + orientation = other.orientation; + viewport = other.viewport; + frame = other.frame; + } + if (other.what & eDisplaySizeChanged) { + what |= eDisplaySizeChanged; + width = other.width; + height = other.height; + } +} + +void layer_state_t::merge(const layer_state_t& other) { + if (other.what & ePositionChanged) { + what |= ePositionChanged; + x = other.x; + y = other.y; + } + if (other.what & eLayerChanged) { + what |= eLayerChanged; + z = other.z; + } + if (other.what & eSizeChanged) { + what |= eSizeChanged; + w = other.w; + h = other.h; + } + if (other.what & eAlphaChanged) { + what |= eAlphaChanged; + alpha = other.alpha; + } + if (other.what & eMatrixChanged) { + what |= eMatrixChanged; + matrix = other.matrix; + } + if (other.what & eTransparentRegionChanged) { + what |= eTransparentRegionChanged; + transparentRegion = other.transparentRegion; + } + if (other.what & eFlagsChanged) { + what |= eFlagsChanged; + flags = other.flags; + mask = other.mask; + } + if (other.what & eLayerStackChanged) { + what |= eLayerStackChanged; + layerStack = other.layerStack; + } + if (other.what & eCropChanged) { + what |= eCropChanged; + crop = other.crop; + } + if (other.what & eDeferTransaction) { + what |= eDeferTransaction; + barrierHandle = other.barrierHandle; + barrierGbp = other.barrierGbp; + frameNumber = other.frameNumber; + } + if (other.what & eFinalCropChanged) { + what |= eFinalCropChanged; + finalCrop = other.finalCrop; + } + if (other.what & eOverrideScalingModeChanged) { + what |= eOverrideScalingModeChanged; + overrideScalingMode = other.overrideScalingMode; + } + if (other.what & eGeometryAppliesWithResize) { + what |= eGeometryAppliesWithResize; + } + if (other.what & eReparentChildren) { + what |= eReparentChildren; + reparentHandle = other.reparentHandle; + } + if (other.what & eDetachChildren) { + what |= eDetachChildren; + } + if (other.what & eRelativeLayerChanged) { + what |= eRelativeLayerChanged; + z = other.z; + relativeLayerHandle = other.relativeLayerHandle; + } + if (other.what & eReparent) { + what |= eReparent; + parentHandleForChild = other.parentHandleForChild; + } + if (other.what & eDestroySurface) { + what |= eDestroySurface; + } +} }; // namespace android diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp index 2f8e104ea0a2969666680c0cb95cdc5b938db24c..52c906775edbf4cf551fc3e518b08bafc2720980 100644 --- a/libs/gui/StreamSplitter.cpp +++ b/libs/gui/StreamSplitter.cpp @@ -38,11 +38,11 @@ namespace android { status_t StreamSplitter::createSplitter( const sp& inputQueue, sp* outSplitter) { - if (inputQueue == nullptr) { + if (inputQueue == NULL) { ALOGE("createSplitter: inputQueue must not be NULL"); return BAD_VALUE; } - if (outSplitter == nullptr) { + if (outSplitter == NULL) { ALOGE("createSplitter: outSplitter must not be NULL"); return BAD_VALUE; } @@ -74,7 +74,7 @@ StreamSplitter::~StreamSplitter() { status_t StreamSplitter::addOutput( const sp& outputQueue) { - if (outputQueue == nullptr) { + if (outputQueue == NULL) { ALOGE("addOutput: outputQueue must not be NULL"); return BAD_VALUE; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e55e6e415aa72e8b9167f8138b461116b2c866a7..339bd0fa4e41c2beba65edec1f3308e0c2abc48d 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -44,6 +44,9 @@ namespace android { +using ui::ColorMode; +using ui::Dataspace; + Surface::Surface(const sp& bufferProducer, bool controlledByApp) : mGraphicBufferProducer(bufferProducer), mCrop(Rect::EMPTY_RECT), @@ -78,7 +81,7 @@ Surface::Surface(const sp& bufferProducer, bool controll mReqFormat = 0; mReqUsage = 0; mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; - mDataSpace = HAL_DATASPACE_UNKNOWN; + mDataSpace = Dataspace::UNKNOWN; mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; @@ -153,7 +156,7 @@ status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) { ATRACE_CALL(); DisplayStatInfo stats; - status_t result = composerService()->getDisplayStats(nullptr, &stats); + status_t result = composerService()->getDisplayStats(NULL, &stats); if (result != NO_ERROR) { return result; } @@ -326,7 +329,7 @@ status_t Surface::getWideColorSupport(bool* supported) { sp display( composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - Vector colorModes; + Vector colorModes; status_t err = composerService()->getDisplayColorModes(display, &colorModes); @@ -338,11 +341,11 @@ status_t Surface::getWideColorSupport(bool* supported) { &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); *supported = false; - for (android_color_mode_t colorMode : colorModes) { + for (ColorMode colorMode : colorModes) { switch (colorMode) { - case HAL_COLOR_MODE_DISPLAY_P3: - case HAL_COLOR_MODE_ADOBE_RGB: - case HAL_COLOR_MODE_DCI_P3: + case ColorMode::DISPLAY_P3: + case ColorMode::ADOBE_RGB: + case ColorMode::DCI_P3: if (wideColorBoardConfig) { *supported = true; } @@ -494,7 +497,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot != BufferItem::INVALID_BUFFER_SLOT) { sp& gbuf(mSlots[mSharedBufferSlot].buffer); - if (gbuf != nullptr) { + if (gbuf != NULL) { *buffer = gbuf.get(); *fenceFd = -1; return OK; @@ -534,7 +537,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { sp& gbuf(mSlots[buf].buffer); // this should never happen - ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); + ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { freeAllBuffers(); @@ -612,7 +615,7 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, int Surface::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != nullptr && + if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) { return i; } @@ -664,8 +667,12 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, - mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, - fence, mStickyTransform, mEnableFrameTimestamps); + static_cast(mDataSpace), crop, mScalingMode, + mTransform ^ mStickyTransform, fence, mStickyTransform, + mEnableFrameTimestamps); + + // we should send HDR metadata as needed if this becomes a bottleneck + input.setHdrMetadata(mHdrMetadata); if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { input.setSurfaceDamage(Region::INVALID_REGION); @@ -878,6 +885,10 @@ int Surface::query(int what, int* value) const { *value = mGraphicBufferProducer != nullptr ? 1 : 0; return NO_ERROR; } + case NATIVE_WINDOW_DATASPACE: { + *value = static_cast(mDataSpace); + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -944,6 +955,12 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: res = dispatchSetBuffersDataSpace(args); break; + case NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA: + res = dispatchSetBuffersSmpte2086Metadata(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA: + res = dispatchSetBuffersCta8613Metadata(args); + break; case NATIVE_WINDOW_SET_SURFACE_DAMAGE: res = dispatchSetSurfaceDamage(args); break; @@ -1083,11 +1100,22 @@ int Surface::dispatchSetSidebandStream(va_list args) { } int Surface::dispatchSetBuffersDataSpace(va_list args) { - android_dataspace dataspace = - static_cast(va_arg(args, int)); + Dataspace dataspace = static_cast(va_arg(args, int)); return setBuffersDataSpace(dataspace); } +int Surface::dispatchSetBuffersSmpte2086Metadata(va_list args) { + const android_smpte2086_metadata* metadata = + va_arg(args, const android_smpte2086_metadata*); + return setBuffersSmpte2086Metadata(metadata); +} + +int Surface::dispatchSetBuffersCta8613Metadata(va_list args) { + const android_cta861_3_metadata* metadata = + va_arg(args, const android_cta861_3_metadata*); + return setBuffersCta8613Metadata(metadata); +} + int Surface::dispatchSetSurfaceDamage(va_list args) { android_native_rect_t* rects = va_arg(args, android_native_rect_t*); size_t numRects = va_arg(args, size_t); @@ -1236,7 +1264,7 @@ int Surface::detachNextBuffer(sp* outBuffer, ATRACE_CALL(); ALOGV("Surface::detachNextBuffer"); - if (outBuffer == nullptr || outFence == nullptr) { + if (outBuffer == NULL || outFence == NULL) { return BAD_VALUE; } @@ -1245,8 +1273,8 @@ int Surface::detachNextBuffer(sp* outBuffer, mRemovedBuffers.clear(); } - sp buffer(nullptr); - sp fence(nullptr); + sp buffer(NULL); + sp fence(NULL); status_t result = mGraphicBufferProducer->detachNextBuffer( &buffer, &fence); if (result != NO_ERROR) { @@ -1254,19 +1282,19 @@ int Surface::detachNextBuffer(sp* outBuffer, } *outBuffer = buffer; - if (fence != nullptr && fence->isValid()) { + if (fence != NULL && fence->isValid()) { *outFence = fence; } else { *outFence = Fence::NO_FENCE; } for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != nullptr && + if (mSlots[i].buffer != NULL && mSlots[i].buffer->getId() == buffer->getId()) { if (mReportRemovedBuffers) { mRemovedBuffers.push_back(mSlots[i].buffer); } - mSlots[i].buffer = nullptr; + mSlots[i].buffer = NULL; } } @@ -1317,7 +1345,7 @@ int Surface::setCrop(Rect const* rect) ATRACE_CALL(); Rect realRect(Rect::EMPTY_RECT); - if (rect == nullptr || rect->isEmpty()) { + if (rect == NULL || rect->isEmpty()) { realRect.clear(); } else { realRect = *rect; @@ -1504,7 +1532,7 @@ int Surface::setBuffersTimestamp(int64_t timestamp) return NO_ERROR; } -int Surface::setBuffersDataSpace(android_dataspace dataSpace) +int Surface::setBuffersDataSpace(Dataspace dataSpace) { ALOGV("Surface::setBuffersDataSpace"); Mutex::Autolock lock(mMutex); @@ -1512,9 +1540,39 @@ int Surface::setBuffersDataSpace(android_dataspace dataSpace) return NO_ERROR; } +int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) { + ALOGV("Surface::setBuffersSmpte2086Metadata"); + Mutex::Autolock lock(mMutex); + if (metadata) { + mHdrMetadata.smpte2086 = *metadata; + mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086; + } else { + mHdrMetadata.validTypes &= ~HdrMetadata::SMPTE2086; + } + return NO_ERROR; +} + +int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) { + ALOGV("Surface::setBuffersCta8613Metadata"); + Mutex::Autolock lock(mMutex); + if (metadata) { + mHdrMetadata.cta8613 = *metadata; + mHdrMetadata.validTypes |= HdrMetadata::CTA861_3; + } else { + mHdrMetadata.validTypes &= ~HdrMetadata::CTA861_3; + } + return NO_ERROR; +} + +Dataspace Surface::getBuffersDataSpace() { + ALOGV("Surface::getBuffersDataSpace"); + Mutex::Autolock lock(mMutex); + return mDataSpace; +} + void Surface::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].buffer = nullptr; + mSlots[i].buffer = 0; } } @@ -1554,12 +1612,12 @@ static status_t copyBlt( // src and dst with, height and format must be identical. no verification // is done here. status_t err; - uint8_t* src_bits = nullptr; + uint8_t* src_bits = NULL; err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), reinterpret_cast(&src_bits)); ALOGE_IF(err, "error locking src buffer %s", strerror(-err)); - uint8_t* dst_bits = nullptr; + uint8_t* dst_bits = NULL; err = dst->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), reinterpret_cast(&dst_bits), *dstFenceFd); ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); @@ -1607,7 +1665,7 @@ static status_t copyBlt( status_t Surface::lock( ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) { - if (mLockedBuffer != nullptr) { + if (mLockedBuffer != 0) { ALOGE("Surface::lock failed, already locked"); return INVALID_OPERATION; } @@ -1639,7 +1697,7 @@ status_t Surface::lock( // figure out if we can copy the frontbuffer back const sp& frontBuffer(mPostedBuffer); - const bool canCopyBack = (frontBuffer != nullptr && + const bool canCopyBack = (frontBuffer != 0 && backBuffer->width == frontBuffer->width && backBuffer->height == frontBuffer->height && backBuffer->format == frontBuffer->format); @@ -1701,7 +1759,7 @@ status_t Surface::lock( status_t Surface::unlockAndPost() { - if (mLockedBuffer == nullptr) { + if (mLockedBuffer == 0) { ALOGE("Surface::unlockAndPost failed, no locked buffer"); return INVALID_OPERATION; } @@ -1715,7 +1773,7 @@ status_t Surface::unlockAndPost() mLockedBuffer->handle, strerror(-err)); mPostedBuffer = mLockedBuffer; - mLockedBuffer = nullptr; + mLockedBuffer = 0; return err; } @@ -1754,4 +1812,25 @@ status_t Surface::getAndFlushRemovedBuffers(std::vector>* out) return OK; } +status_t Surface::attachAndQueueBuffer(Surface* surface, sp buffer) { + if (buffer == nullptr) { + return BAD_VALUE; + } + int err = static_cast(surface)->perform(surface, NATIVE_WINDOW_API_CONNECT, + NATIVE_WINDOW_API_CPU); + if (err != OK) { + return err; + } + err = surface->attachBuffer(buffer->getNativeBuffer()); + if (err != OK) { + return err; + } + err = static_cast(surface)->queueBuffer(surface, buffer->getNativeBuffer(), -1); + if (err != OK) { + return err; + } + err = surface->disconnect(NATIVE_WINDOW_API_CPU); + return err; +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 053b9afb86c273cbd3df81bd65901e805ff3d422..63560c4b89481443d3ad6a9f94098064190d8060 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -37,13 +36,15 @@ #include #include #include +#include #include #include #include -#include namespace android { + +using ui::ColorMode; // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); @@ -80,7 +81,7 @@ void ComposerService::connectLocked() { /*static*/ sp ComposerService::getComposerService() { ComposerService& instance = ComposerService::getInstance(); Mutex::Autolock _l(instance.mLock); - if (instance.mComposerService == nullptr) { + if (instance.mComposerService == NULL) { ComposerService::getInstance().connectLocked(); assert(instance.mComposerService != NULL); ALOGD("ComposerService reconnected"); @@ -91,239 +92,150 @@ void ComposerService::connectLocked() { void ComposerService::composerServiceDied() { Mutex::Autolock _l(mLock); - mComposerService = nullptr; - mDeathObserver = nullptr; + mComposerService = NULL; + mDeathObserver = NULL; } // --------------------------------------------------------------------------- -static inline -int compare_type(const ComposerState& lhs, const ComposerState& rhs) { - if (lhs.client < rhs.client) return -1; - if (lhs.client > rhs.client) return 1; - if (lhs.state.surface < rhs.state.surface) return -1; - if (lhs.state.surface > rhs.state.surface) return 1; - return 0; -} - -static inline -int compare_type(const DisplayState& lhs, const DisplayState& rhs) { - return compare_type(lhs.token, rhs.token); -} - -class Composer : public Singleton -{ - friend class Singleton; - - mutable Mutex mLock; - SortedVector mComposerStates; - SortedVector mDisplayStates; - uint32_t mForceSynchronous; - uint32_t mTransactionNestCount; - bool mAnimation; - - Composer() : Singleton(), - mForceSynchronous(0), mTransactionNestCount(0), - mAnimation(false) - { } - - void openGlobalTransactionImpl(); - void closeGlobalTransactionImpl(bool synchronous); - void setAnimationTransactionImpl(); - status_t enableVSyncInjectionsImpl(bool enable); - status_t injectVSyncImpl(nsecs_t when); - - layer_state_t* getLayerStateLocked( - const sp& client, const sp& id); - - DisplayState& getDisplayStateLocked(const sp& token); - -public: - sp createDisplay(const String8& displayName, bool secure); - void destroyDisplay(const sp& display); - sp getBuiltInDisplay(int32_t id); - - status_t setPosition(const sp& client, const sp& id, - float x, float y); - status_t setSize(const sp& client, const sp& id, - uint32_t w, uint32_t h); - status_t setLayer(const sp& client, const sp& id, - int32_t z); - status_t setRelativeLayer(const sp& client, const sp& id, - const sp& relativeTo, int32_t z); - status_t setFlags(const sp& client, const sp& id, - uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint( - const sp& client, const sp& id, - const Region& transparentRegion); - status_t setAlpha(const sp& client, const sp& id, - float alpha); - status_t setMatrix(const sp& client, const sp& id, - float dsdx, float dtdx, float dtdy, float dsdy); - status_t setOrientation(int orientation); - status_t setCrop(const sp& client, const sp& id, - const Rect& crop); - status_t setFinalCrop(const sp& client, - const sp& id, const Rect& crop); - status_t setLayerStack(const sp& client, - const sp& id, uint32_t layerStack); - status_t deferTransactionUntil(const sp& client, - const sp& id, const sp& handle, - uint64_t frameNumber); - status_t deferTransactionUntil(const sp& client, - const sp& id, const sp& barrierSurface, - uint64_t frameNumber); - status_t reparentChildren(const sp& client, - const sp& id, - const sp& newParentHandle); - status_t detachChildren(const sp& client, - const sp& id); - status_t setOverrideScalingMode(const sp& client, - const sp& id, int32_t overrideScalingMode); - status_t setGeometryAppliesWithResize(const sp& client, - const sp& id); - - status_t setDisplaySurface(const sp& token, - sp bufferProducer); - void setDisplayLayerStack(const sp& token, uint32_t layerStack); - void setDisplayProjection(const sp& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect); - void setDisplaySize(const sp& token, uint32_t width, uint32_t height); - - static void setAnimationTransaction() { - Composer::getInstance().setAnimationTransactionImpl(); - } - - static void openGlobalTransaction() { - Composer::getInstance().openGlobalTransactionImpl(); +SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : + mForceSynchronous(other.mForceSynchronous), + mTransactionNestCount(other.mTransactionNestCount), + mAnimation(other.mAnimation), + mEarlyWakeup(other.mEarlyWakeup) { + mDisplayStates = other.mDisplayStates; + mComposerStates = other.mComposerStates; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { + for (auto const& kv : other.mComposerStates) { + if (mComposerStates.count(kv.first) == 0) { + mComposerStates[kv.first] = kv.second; + } else { + mComposerStates[kv.first].state.merge(kv.second.state); + } } + other.mComposerStates.clear(); - static void closeGlobalTransaction(bool synchronous) { - Composer::getInstance().closeGlobalTransactionImpl(synchronous); + for (auto const& state : other.mDisplayStates) { + ssize_t index = mDisplayStates.indexOf(state); + if (index < 0) { + mDisplayStates.add(state); + } else { + mDisplayStates.editItemAt(static_cast(index)).merge(state); + } } + other.mDisplayStates.clear(); - static status_t enableVSyncInjections(bool enable) { - return Composer::getInstance().enableVSyncInjectionsImpl(enable); - } + return *this; +} - static status_t injectVSync(nsecs_t when) { - return Composer::getInstance().injectVSyncImpl(when); +status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { + if (mStatus != NO_ERROR) { + return mStatus; } -}; - -ANDROID_SINGLETON_STATIC_INSTANCE(Composer); - -// --------------------------------------------------------------------------- -sp Composer::createDisplay(const String8& displayName, bool secure) { - return ComposerService::getComposerService()->createDisplay(displayName, - secure); -} + sp sf(ComposerService::getComposerService()); -void Composer::destroyDisplay(const sp& display) { - return ComposerService::getComposerService()->destroyDisplay(display); -} + Vector composerStates; + Vector displayStates; + uint32_t flags = 0; -sp Composer::getBuiltInDisplay(int32_t id) { - return ComposerService::getComposerService()->getBuiltInDisplay(id); -} + mForceSynchronous |= synchronous; -void Composer::openGlobalTransactionImpl() { - { // scope for the lock - Mutex::Autolock _l(mLock); - mTransactionNestCount += 1; + for (auto const& kv : mComposerStates){ + composerStates.add(kv.second); } -} -void Composer::closeGlobalTransactionImpl(bool synchronous) { - sp sm(ComposerService::getComposerService()); - - Vector transaction; - Vector displayTransaction; - uint32_t flags = 0; + mComposerStates.clear(); - { // scope for the lock - Mutex::Autolock _l(mLock); - mForceSynchronous |= synchronous; - if (!mTransactionNestCount) { - ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior " - "call to openGlobalTransaction()."); - } else if (--mTransactionNestCount) { - return; - } + displayStates = mDisplayStates; + mDisplayStates.clear(); - transaction = mComposerStates; - mComposerStates.clear(); + if (mForceSynchronous) { + flags |= ISurfaceComposer::eSynchronous; + } + if (mAnimation) { + flags |= ISurfaceComposer::eAnimation; + } + if (mEarlyWakeup) { + flags |= ISurfaceComposer::eEarlyWakeup; + } - displayTransaction = mDisplayStates; - mDisplayStates.clear(); + mForceSynchronous = false; + mAnimation = false; + mEarlyWakeup = false; - if (mForceSynchronous) { - flags |= ISurfaceComposer::eSynchronous; - } - if (mAnimation) { - flags |= ISurfaceComposer::eAnimation; - } + sf->setTransactionState(composerStates, displayStates, flags); + mStatus = NO_ERROR; + return NO_ERROR; +} - mForceSynchronous = false; - mAnimation = false; - } +// --------------------------------------------------------------------------- - sm->setTransactionState(transaction, displayTransaction, flags); +sp SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) { + return ComposerService::getComposerService()->createDisplay(displayName, + secure); } -status_t Composer::enableVSyncInjectionsImpl(bool enable) { - sp sm(ComposerService::getComposerService()); - return sm->enableVSyncInjections(enable); +void SurfaceComposerClient::destroyDisplay(const sp& display) { + return ComposerService::getComposerService()->destroyDisplay(display); } -status_t Composer::injectVSyncImpl(nsecs_t when) { - sp sm(ComposerService::getComposerService()); - return sm->injectVSync(when); +sp SurfaceComposerClient::getBuiltInDisplay(int32_t id) { + return ComposerService::getComposerService()->getBuiltInDisplay(id); } -void Composer::setAnimationTransactionImpl() { - Mutex::Autolock _l(mLock); +void SurfaceComposerClient::Transaction::setAnimationTransaction() { mAnimation = true; } -layer_state_t* Composer::getLayerStateLocked( - const sp& client, const sp& id) { - - ComposerState s; - s.client = client->mClient; - s.state.surface = id; +void SurfaceComposerClient::Transaction::setEarlyWakeup() { + mEarlyWakeup = true; +} - ssize_t index = mComposerStates.indexOf(s); - if (index < 0) { +layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp& sc) { + if (mComposerStates.count(sc) == 0) { // we don't have it, add an initialized layer_state to our list - index = mComposerStates.add(s); + ComposerState s; + s.client = sc->getClient()->mClient; + s.state.surface = sc->getHandle(); + mComposerStates[sc] = s; } - ComposerState* const out = mComposerStates.editArray(); - return &(out[index].state); + return &(mComposerStates[sc].state); } -status_t Composer::setPosition(const sp& client, - const sp& id, float x, float y) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition( + const sp& sc, float x, float y) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::ePositionChanged; s->x = x; s->y = y; - return NO_ERROR; + return *this; } -status_t Composer::setSize(const sp& client, - const sp& id, uint32_t w, uint32_t h) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::show( + const sp& sc) { + return setFlags(sc, 0, layer_state_t::eLayerHidden); +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide( + const sp& sc) { + return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize( + const sp& sc, uint32_t w, uint32_t h) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eSizeChanged; s->w = w; s->h = h; @@ -331,41 +243,41 @@ status_t Composer::setSize(const sp& client, // Resizing a surface makes the transaction synchronous. mForceSynchronous = true; - return NO_ERROR; + return *this; } -status_t Composer::setLayer(const sp& client, - const sp& id, int32_t z) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer( + const sp& sc, int32_t z) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eLayerChanged; s->z = z; - return NO_ERROR; + return *this; } -status_t Composer::setRelativeLayer(const sp& client, - const sp& id, const sp& relativeTo, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(const sp& sc, const sp& relativeTo, int32_t z) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; } s->what |= layer_state_t::eRelativeLayerChanged; s->relativeLayerHandle = relativeTo; s->z = z; - return NO_ERROR; + return *this; } -status_t Composer::setFlags(const sp& client, - const sp& id, uint32_t flags, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags( + const sp& sc, uint32_t flags, uint32_t mask) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } if ((mask & layer_state_t::eLayerOpaque) || (mask & layer_state_t::eLayerHidden) || (mask & layer_state_t::eLayerSecure)) { @@ -374,50 +286,54 @@ status_t Composer::setFlags(const sp& client, s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; - return NO_ERROR; + return *this; } -status_t Composer::setTransparentRegionHint( - const sp& client, const sp& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransparentRegionHint( + const sp& sc, const Region& transparentRegion) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eTransparentRegionChanged; s->transparentRegion = transparentRegion; - return NO_ERROR; + return *this; } -status_t Composer::setAlpha(const sp& client, - const sp& id, float alpha) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha( + const sp& sc, float alpha) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eAlphaChanged; s->alpha = alpha; - return NO_ERROR; + return *this; } -status_t Composer::setLayerStack(const sp& client, - const sp& id, uint32_t layerStack) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack( + const sp& sc, uint32_t layerStack) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eLayerStackChanged; s->layerStack = layerStack; - return NO_ERROR; + return *this; } -status_t Composer::setMatrix(const sp& client, - const sp& id, float dsdx, float dtdx, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix( + const sp& sc, float dsdx, float dtdx, float dtdy, float dsdy) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eMatrixChanged; layer_state_t::matrix22_t matrix; matrix.dsdx = dsdx; @@ -425,93 +341,115 @@ status_t Composer::setMatrix(const sp& client, matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; - return NO_ERROR; + return *this; } -status_t Composer::setCrop(const sp& client, - const sp& id, const Rect& crop) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop( + const sp& sc, const Rect& crop) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eCropChanged; s->crop = crop; - return NO_ERROR; + return *this; } -status_t Composer::setFinalCrop(const sp& client, - const sp& id, const Rect& crop) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp& sc, const Rect& crop) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eFinalCropChanged; s->finalCrop = crop; - return NO_ERROR; + return *this; } -status_t Composer::deferTransactionUntil( - const sp& client, const sp& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil( + const sp& sc, const sp& handle, uint64_t frameNumber) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDeferTransaction; s->barrierHandle = handle; s->frameNumber = frameNumber; - return NO_ERROR; + return *this; } -status_t Composer::deferTransactionUntil( - const sp& client, const sp& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil( + const sp& sc, const sp& barrierSurface, uint64_t frameNumber) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDeferTransaction; s->barrierGbp = barrierSurface->getIGraphicBufferProducer(); s->frameNumber = frameNumber; - return NO_ERROR; + return *this; } -status_t Composer::reparentChildren( - const sp& client, - const sp& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren( + const sp& sc, const sp& newParentHandle) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eReparentChildren; s->reparentHandle = newParentHandle; - return NO_ERROR; + return *this; } -status_t Composer::detachChildren( - const sp& client, - const sp& id) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent( + const sp& sc, + const sp& newParentHandle) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eReparent; + s->parentHandleForChild = newParentHandle; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor( + const sp& sc, + const half3& color) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eColorChanged; + s->color = color; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren( + const sp& sc) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; } s->what |= layer_state_t::eDetachChildren; - return NO_ERROR; + return *this; } -status_t Composer::setOverrideScalingMode( - const sp& client, - const sp& id, int32_t overrideScalingMode) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode( + const sp& sc, int32_t overrideScalingMode) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } switch (overrideScalingMode) { @@ -524,29 +462,40 @@ status_t Composer::setOverrideScalingMode( default: ALOGE("unknown scaling mode: %d", overrideScalingMode); - return BAD_VALUE; + mStatus = BAD_VALUE; + return *this; } s->what |= layer_state_t::eOverrideScalingModeChanged; s->overrideScalingMode = overrideScalingMode; - return NO_ERROR; + return *this; } -status_t Composer::setGeometryAppliesWithResize( - const sp& client, - const sp& id) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize( + const sp& sc) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eGeometryAppliesWithResize; - return NO_ERROR; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::destroySurface( + const sp& sc) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eDestroySurface; + return *this; } // --------------------------------------------------------------------------- -DisplayState& Composer::getDisplayStateLocked(const sp& token) { +DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { DisplayState s; s.token = token; ssize_t index = mDisplayStates.indexOf(s); @@ -558,8 +507,8 @@ DisplayState& Composer::getDisplayStateLocked(const sp& token) { return mDisplayStates.editItemAt(static_cast(index)); } -status_t Composer::setDisplaySurface(const sp& token, - sp bufferProducer) { +status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp& token, + const sp& bufferProducer) { if (bufferProducer.get() != nullptr) { // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. @@ -571,27 +520,24 @@ status_t Composer::setDisplaySurface(const sp& token, return err; } } - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); + DisplayState& s(getDisplayState(token)); s.surface = bufferProducer; s.what |= DisplayState::eSurfaceChanged; return NO_ERROR; } -void Composer::setDisplayLayerStack(const sp& token, +void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp& token, uint32_t layerStack) { - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); + DisplayState& s(getDisplayState(token)); s.layerStack = layerStack; s.what |= DisplayState::eLayerStackChanged; } -void Composer::setDisplayProjection(const sp& token, +void SurfaceComposerClient::Transaction::setDisplayProjection(const sp& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect) { - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); + DisplayState& s(getDisplayState(token)); s.orientation = orientation; s.viewport = layerStackRect; s.frame = displayRect; @@ -599,9 +545,8 @@ void Composer::setDisplayProjection(const sp& token, mForceSynchronous = true; // TODO: do we actually still need this? } -void Composer::setDisplaySize(const sp& token, uint32_t width, uint32_t height) { - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); +void SurfaceComposerClient::Transaction::setDisplaySize(const sp& token, uint32_t width, uint32_t height) { + DisplayState& s(getDisplayState(token)); s.width = width; s.height = height; s.what |= DisplayState::eDisplaySizeChanged; @@ -610,23 +555,28 @@ void Composer::setDisplaySize(const sp& token, uint32_t width, uint32_t // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() - : mStatus(NO_INIT), mComposer(Composer::getInstance()) + : mStatus(NO_INIT) { } SurfaceComposerClient::SurfaceComposerClient(const sp& root) - : mStatus(NO_INIT), mComposer(Composer::getInstance()), mParent(root) + : mStatus(NO_INIT), mParent(root) +{ +} + +SurfaceComposerClient::SurfaceComposerClient(const sp& client) + : mStatus(NO_ERROR), mClient(client) { } void SurfaceComposerClient::onFirstRef() { - sp sm(ComposerService::getComposerService()); - if (sm != nullptr) { + sp sf(ComposerService::getComposerService()); + if (sf != 0 && mStatus == NO_INIT) { auto rootProducer = mParent.promote(); sp conn; - conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) : - sm->createConnection(); - if (conn != nullptr) { + conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) : + sf->createConnection(); + if (conn != 0) { mClient = conn; mStatus = NO_ERROR; } @@ -648,15 +598,15 @@ sp SurfaceComposerClient::connection() const { status_t SurfaceComposerClient::linkToComposerDeath( const sp& recipient, void* cookie, uint32_t flags) { - sp sm(ComposerService::getComposerService()); - return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags); + sp sf(ComposerService::getComposerService()); + return IInterface::asBinder(sf)->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { // this can be called more than once. sp client; Mutex::Autolock _lm(mLock); - if (mClient != nullptr) { + if (mClient != 0) { client = mClient; // hold ref while lock is held mClient.clear(); } @@ -670,10 +620,28 @@ sp SurfaceComposerClient::createSurface( PixelFormat format, uint32_t flags, SurfaceControl* parent, - uint32_t windowType, - uint32_t ownerUid) + int32_t windowType, + int32_t ownerUid) +{ + sp s; + createSurfaceChecked(name, w, h, format, &s, flags, parent, windowType, ownerUid); + return s; +} + +status_t SurfaceComposerClient::createSurfaceChecked( + const String8& name, + uint32_t w, + uint32_t h, + PixelFormat format, + sp* outSurface, + uint32_t flags, + SurfaceControl* parent, + int32_t windowType, + int32_t ownerUid) { sp sur; + status_t err = mStatus; + if (mStatus == NO_ERROR) { sp handle; sp parentHandle; @@ -682,27 +650,14 @@ sp SurfaceComposerClient::createSurface( if (parent != nullptr) { parentHandle = parent->getHandle(); } - status_t err = mClient->createSurface(name, w, h, format, flags, parentHandle, + err = mClient->createSurface(name, w, h, format, flags, parentHandle, windowType, ownerUid, &handle, &gbp); ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - sur = new SurfaceControl(this, handle, gbp); + *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */); } } - return sur; -} - -sp SurfaceComposerClient::createDisplay(const String8& displayName, - bool secure) { - return Composer::getInstance().createDisplay(displayName, secure); -} - -void SurfaceComposerClient::destroyDisplay(const sp& display) { - Composer::getInstance().destroyDisplay(display); -} - -sp SurfaceComposerClient::getBuiltInDisplay(int32_t id) { - return Composer::getInstance().getBuiltInDisplay(id); + return err; } status_t SurfaceComposerClient::destroySurface(const sp& sid) { @@ -727,152 +682,18 @@ status_t SurfaceComposerClient::getLayerFrameStats(const sp& token, return mClient->getLayerFrameStats(token, outStats); } -inline Composer& SurfaceComposerClient::getComposer() { - return mComposer; -} - // ---------------------------------------------------------------------------- -void SurfaceComposerClient::openGlobalTransaction() { - Composer::openGlobalTransaction(); -} - -void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) { - Composer::closeGlobalTransaction(synchronous); -} - -void SurfaceComposerClient::setAnimationTransaction() { - Composer::setAnimationTransaction(); -} - status_t SurfaceComposerClient::enableVSyncInjections(bool enable) { - return Composer::enableVSyncInjections(enable); + sp sf(ComposerService::getComposerService()); + return sf->enableVSyncInjections(enable); } status_t SurfaceComposerClient::injectVSync(nsecs_t when) { - return Composer::injectVSync(when); -} - -// ---------------------------------------------------------------------------- - -status_t SurfaceComposerClient::setCrop(const sp& id, const Rect& crop) { - return getComposer().setCrop(this, id, crop); -} - -status_t SurfaceComposerClient::setFinalCrop(const sp& id, - const Rect& crop) { - return getComposer().setFinalCrop(this, id, crop); -} - -status_t SurfaceComposerClient::setPosition(const sp& id, float x, float y) { - return getComposer().setPosition(this, id, x, y); -} - -status_t SurfaceComposerClient::setSize(const sp& id, uint32_t w, uint32_t h) { - return getComposer().setSize(this, id, w, h); -} - -status_t SurfaceComposerClient::setLayer(const sp& id, int32_t z) { - return getComposer().setLayer(this, id, z); -} - -status_t SurfaceComposerClient::setRelativeLayer(const sp& id, - const sp& relativeTo, int32_t z) { - return getComposer().setRelativeLayer(this, id, relativeTo, z); -} - -status_t SurfaceComposerClient::hide(const sp& id) { - return getComposer().setFlags(this, id, - layer_state_t::eLayerHidden, - layer_state_t::eLayerHidden); -} - -status_t SurfaceComposerClient::show(const sp& id) { - return getComposer().setFlags(this, id, - 0, - layer_state_t::eLayerHidden); -} - -status_t SurfaceComposerClient::setFlags(const sp& id, uint32_t flags, - uint32_t mask) { - return getComposer().setFlags(this, id, flags, mask); -} - -status_t SurfaceComposerClient::setTransparentRegionHint(const sp& id, - const Region& transparentRegion) { - return getComposer().setTransparentRegionHint(this, id, transparentRegion); -} - -status_t SurfaceComposerClient::setAlpha(const sp& id, float alpha) { - return getComposer().setAlpha(this, id, alpha); -} - -status_t SurfaceComposerClient::setLayerStack(const sp& id, uint32_t layerStack) { - return getComposer().setLayerStack(this, id, layerStack); -} - -status_t SurfaceComposerClient::setMatrix(const sp& id, float dsdx, float dtdx, - float dtdy, float dsdy) { - return getComposer().setMatrix(this, id, dsdx, dtdx, dtdy, dsdy); -} - -status_t SurfaceComposerClient::deferTransactionUntil(const sp& id, - const sp& handle, uint64_t frameNumber) { - return getComposer().deferTransactionUntil(this, id, handle, frameNumber); -} - -status_t SurfaceComposerClient::deferTransactionUntil(const sp& id, - const sp& barrierSurface, uint64_t frameNumber) { - return getComposer().deferTransactionUntil(this, id, barrierSurface, frameNumber); -} - -status_t SurfaceComposerClient::reparentChildren(const sp& id, - const sp& newParentHandle) { - return getComposer().reparentChildren(this, id, newParentHandle); -} - -status_t SurfaceComposerClient::detachChildren(const sp& id) { - return getComposer().detachChildren(this, id); -} - -status_t SurfaceComposerClient::setOverrideScalingMode( - const sp& id, int32_t overrideScalingMode) { - return getComposer().setOverrideScalingMode( - this, id, overrideScalingMode); + sp sf(ComposerService::getComposerService()); + return sf->injectVSync(when); } -status_t SurfaceComposerClient::setGeometryAppliesWithResize( - const sp& id) { - return getComposer().setGeometryAppliesWithResize(this, id); -} - -// ---------------------------------------------------------------------------- - -status_t SurfaceComposerClient::setDisplaySurface(const sp& token, - sp bufferProducer) { - return Composer::getInstance().setDisplaySurface(token, bufferProducer); -} - -void SurfaceComposerClient::setDisplayLayerStack(const sp& token, - uint32_t layerStack) { - Composer::getInstance().setDisplayLayerStack(token, layerStack); -} - -void SurfaceComposerClient::setDisplayProjection(const sp& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect) { - Composer::getInstance().setDisplayProjection(token, orientation, - layerStackRect, displayRect); -} - -void SurfaceComposerClient::setDisplaySize(const sp& token, - uint32_t width, uint32_t height) { - Composer::getInstance().setDisplaySize(token, width, height); -} - -// ---------------------------------------------------------------------------- - status_t SurfaceComposerClient::getDisplayConfigs( const sp& display, Vector* configs) { @@ -906,16 +727,16 @@ status_t SurfaceComposerClient::setActiveConfig(const sp& display, int } status_t SurfaceComposerClient::getDisplayColorModes(const sp& display, - Vector* outColorModes) { + Vector* outColorModes) { return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes); } -android_color_mode_t SurfaceComposerClient::getActiveColorMode(const sp& display) { +ColorMode SurfaceComposerClient::getActiveColorMode(const sp& display) { return ComposerService::getComposerService()->getActiveColorMode(display); } status_t SurfaceComposerClient::setActiveColorMode(const sp& display, - android_color_mode_t colorMode) { + ColorMode colorMode) { return ComposerService::getComposerService()->setActiveColorMode(display, colorMode); } @@ -940,149 +761,37 @@ status_t SurfaceComposerClient::getHdrCapabilities(const sp& display, // ---------------------------------------------------------------------------- -status_t ScreenshotClient::capture( - const sp& display, - const sp& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform) { - sp s(ComposerService::getComposerService()); - if (s == nullptr) return NO_INIT; - return s->captureScreen(display, producer, sourceCrop, - reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform); -} - -status_t ScreenshotClient::captureToBuffer(const sp& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, - uint32_t rotation, - sp* outBuffer) { +status_t ScreenshotClient::capture(const sp& display, Rect sourceCrop, uint32_t reqWidth, + uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, uint32_t rotation, + sp* outBuffer) { sp s(ComposerService::getComposerService()); - if (s == nullptr) return NO_INIT; - - sp gbpConsumer; - sp producer; - BufferQueue::createBufferQueue(&producer, &gbpConsumer); - sp consumer(new BufferItemConsumer(gbpConsumer, - GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER, - 1, true)); - - status_t ret = s->captureScreen(display, producer, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, - static_cast(rotation)); + if (s == NULL) return NO_INIT; + status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, minLayerZ, + maxLayerZ, useIdentityTransform, + static_cast(rotation)); if (ret != NO_ERROR) { return ret; } - BufferItem b; - consumer->acquireBuffer(&b, 0, true); - *outBuffer = b.mGraphicBuffer; return ret; } -ScreenshotClient::ScreenshotClient() - : mHaveBuffer(false) { - memset(&mBuffer, 0, sizeof(mBuffer)); -} - -ScreenshotClient::~ScreenshotClient() { - ScreenshotClient::release(); -} - -sp ScreenshotClient::getCpuConsumer() const { - if (mCpuConsumer == nullptr) { - sp consumer; - BufferQueue::createBufferQueue(&mProducer, &consumer); - mCpuConsumer = new CpuConsumer(consumer, 1); - mCpuConsumer->setName(String8("ScreenshotClient")); - } - return mCpuConsumer; -} - -status_t ScreenshotClient::update(const sp& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation) { +status_t ScreenshotClient::captureLayers(const sp& layerHandle, Rect sourceCrop, + float frameScale, sp* outBuffer) { sp s(ComposerService::getComposerService()); - if (s == nullptr) return NO_INIT; - sp cpuConsumer = getCpuConsumer(); - - if (mHaveBuffer) { - mCpuConsumer->unlockBuffer(mBuffer); - memset(&mBuffer, 0, sizeof(mBuffer)); - mHaveBuffer = false; - } - - status_t err = s->captureScreen(display, mProducer, sourceCrop, - reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, - static_cast(rotation)); - - if (err == NO_ERROR) { - err = mCpuConsumer->lockNextBuffer(&mBuffer); - if (err == NO_ERROR) { - mHaveBuffer = true; - } - } - return err; -} - -status_t ScreenshotClient::update(const sp& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform) { - - return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -status_t ScreenshotClient::update(const sp& display, Rect sourceCrop, - bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, 0, 0, - INT32_MIN, INT32_MAX, - useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -status_t ScreenshotClient::update(const sp& display, Rect sourceCrop, - uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, - INT32_MIN, INT32_MAX, - useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -void ScreenshotClient::release() { - if (mHaveBuffer) { - mCpuConsumer->unlockBuffer(mBuffer); - memset(&mBuffer, 0, sizeof(mBuffer)); - mHaveBuffer = false; - } - mCpuConsumer.clear(); -} - -void const* ScreenshotClient::getPixels() const { - return mBuffer.data; -} - -uint32_t ScreenshotClient::getWidth() const { - return mBuffer.width; -} - -uint32_t ScreenshotClient::getHeight() const { - return mBuffer.height; -} - -PixelFormat ScreenshotClient::getFormat() const { - return mBuffer.format; -} - -uint32_t ScreenshotClient::getStride() const { - return mBuffer.stride; -} - -size_t ScreenshotClient::getSize() const { - return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format); + if (s == NULL) return NO_INIT; + status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale, + false /* childrenOnly */); + return ret; } -android_dataspace ScreenshotClient::getDataSpace() const { - return mBuffer.dataSpace; +status_t ScreenshotClient::captureChildLayers(const sp& layerHandle, Rect sourceCrop, + float frameScale, sp* outBuffer) { + sp s(ComposerService::getComposerService()); + if (s == NULL) return NO_INIT; + status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale, + true /* childrenOnly */); + return ret; } - // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 08e3b60f6c0142d3c37bd84b76e667becd47b3b6..5eafbb35556d7208776cfc5f0f1d2e283c760ec1 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -48,8 +48,9 @@ namespace android { SurfaceControl::SurfaceControl( const sp& client, const sp& handle, - const sp& gbp) - : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp) + const sp& gbp, + bool owned) + : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), mOwned(owned) { } @@ -60,7 +61,9 @@ SurfaceControl::~SurfaceControl() void SurfaceControl::destroy() { - if (isValid()) { + // Avoid destroying the server-side surface if we are not the owner of it, meaning that we + // retrieved it from another process. + if (isValid() && mOwned) { mClient->destroySurface(mHandle); } // clear all references and trigger an IPC now, to make sure things @@ -83,7 +86,7 @@ void SurfaceControl::clear() } void SurfaceControl::disconnect() { - if (mGraphicBufferProducer != nullptr) { + if (mGraphicBufferProducer != NULL) { mGraphicBufferProducer->disconnect( BufferQueueCore::CURRENTLY_CONNECTED_API); } @@ -92,117 +95,11 @@ void SurfaceControl::disconnect() { bool SurfaceControl::isSameSurface( const sp& lhs, const sp& rhs) { - if (lhs == nullptr || rhs == nullptr) + if (lhs == 0 || rhs == 0) return false; return lhs->mHandle == rhs->mHandle; } -status_t SurfaceControl::setLayerStack(uint32_t layerStack) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setLayerStack(mHandle, layerStack); -} - -status_t SurfaceControl::setLayer(int32_t layer) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setLayer(mHandle, layer); -} - -status_t SurfaceControl::setRelativeLayer(const sp& relativeTo, int32_t layer) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setRelativeLayer(mHandle, relativeTo, layer); -} - -status_t SurfaceControl::setPosition(float x, float y) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setPosition(mHandle, x, y); -} -status_t SurfaceControl::setGeometryAppliesWithResize() { - status_t err = validate(); - if (err < 0) return err; - return mClient->setGeometryAppliesWithResize(mHandle); -} -status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setSize(mHandle, w, h); -} -status_t SurfaceControl::hide() { - status_t err = validate(); - if (err < 0) return err; - return mClient->hide(mHandle); -} -status_t SurfaceControl::show() { - status_t err = validate(); - if (err < 0) return err; - return mClient->show(mHandle); -} -status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setFlags(mHandle, flags, mask); -} -status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setTransparentRegionHint(mHandle, transparent); -} -status_t SurfaceControl::setAlpha(float alpha) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setAlpha(mHandle, alpha); -} -status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setMatrix(mHandle, dsdx, dtdx, dtdy, dsdy); -} -status_t SurfaceControl::setCrop(const Rect& crop) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setCrop(mHandle, crop); -} -status_t SurfaceControl::setFinalCrop(const Rect& crop) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setFinalCrop(mHandle, crop); -} - -status_t SurfaceControl::deferTransactionUntil(const sp& handle, - uint64_t frameNumber) { - status_t err = validate(); - if (err < 0) return err; - return mClient->deferTransactionUntil(mHandle, handle, frameNumber); -} - -status_t SurfaceControl::deferTransactionUntil(const sp& handle, - uint64_t frameNumber) { - status_t err = validate(); - if (err < 0) return err; - return mClient->deferTransactionUntil(mHandle, handle, frameNumber); -} - -status_t SurfaceControl::reparentChildren(const sp& newParentHandle) { - status_t err = validate(); - if (err < 0) return err; - return mClient->reparentChildren(mHandle, newParentHandle); -} - -status_t SurfaceControl::detachChildren() { - status_t err = validate(); - if (err < 0) return err; - return mClient->detachChildren(mHandle); -} - -status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setOverrideScalingMode(mHandle, overrideScalingMode); -} - status_t SurfaceControl::clearLayerFrameStats() const { status_t err = validate(); if (err < 0) return err; @@ -219,7 +116,7 @@ status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const { status_t SurfaceControl::validate() const { - if (mHandle==nullptr || mClient==nullptr) { + if (mHandle==0 || mClient==0) { ALOGE("invalid handle (%p) or client (%p)", mHandle.get(), mClient.get()); return NO_INIT; @@ -231,7 +128,7 @@ status_t SurfaceControl::writeSurfaceToParcel( const sp& control, Parcel* parcel) { sp bp; - if (control != nullptr) { + if (control != NULL) { bp = control->mGraphicBufferProducer; } return parcel->writeStrongBinder(IInterface::asBinder(bp)); @@ -249,7 +146,7 @@ sp SurfaceControl::generateSurfaceLocked() const sp SurfaceControl::getSurface() const { Mutex::Autolock _l(mLock); - if (mSurfaceData == nullptr) { + if (mSurfaceData == 0) { return generateSurfaceLocked(); } return mSurfaceData; @@ -267,5 +164,35 @@ sp SurfaceControl::getHandle() const return mHandle; } +sp SurfaceControl::getClient() const +{ + return mClient; +} + +void SurfaceControl::writeToParcel(Parcel* parcel) +{ + parcel->writeStrongBinder(ISurfaceComposerClient::asBinder(mClient->getClient())); + parcel->writeStrongBinder(mHandle); + parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); +} + +sp SurfaceControl::readFromParcel(Parcel* parcel) +{ + sp client = parcel->readStrongBinder(); + sp handle = parcel->readStrongBinder(); + if (client == nullptr || handle == nullptr) + { + ALOGE("Invalid parcel"); + return nullptr; + } + sp gbp; + parcel->readNullableStrongBinder(&gbp); + + // We aren't the original owner of the surface. + return new SurfaceControl(new SurfaceComposerClient( + interface_cast(client)), + handle.get(), interface_cast(gbp), false /* owned */); +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp index fcae05c8ad076aeacc932786be53fb5473caeee7..afa15c5cda36d4a58822ec4615649593f6e06cef 100644 --- a/libs/gui/SyncFeatures.cpp +++ b/libs/gui/SyncFeatures.cpp @@ -41,7 +41,7 @@ SyncFeatures::SyncFeatures() : Singleton(), // This can only be called after EGL has been initialized; otherwise the // check below will abort. const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); - LOG_ALWAYS_FATAL_IF(exts == nullptr, "eglQueryStringImplementationANDROID failed"); + LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed"); if (strstr(exts, "EGL_ANDROID_native_fence_sync")) { // This makes GLConsumer use the EGL_ANDROID_native_fence_sync // extension to create Android native fences to signal when all diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h new file mode 100644 index 0000000000000000000000000000000000000000..d38077014b45a6e4be7eea8dc92df71e14f0af37 --- /dev/null +++ b/libs/gui/include/gui/BufferHubConsumer.h @@ -0,0 +1,112 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERHUBCONSUMER_H_ +#define ANDROID_GUI_BUFFERHUBCONSUMER_H_ + +#include +#include +#include + +namespace android { + +class BufferHubConsumer : public IGraphicBufferConsumer { +public: + // Creates a BufferHubConsumer instance by importing an existing producer queue. + static sp Create(const std::shared_ptr& queue); + + // Creates a BufferHubConsumer instance by importing an existing producer + // parcelable. Note that this call takes the ownership of the parcelable + // object and is guaranteed to succeed if parcelable object is valid. + static sp Create(dvr::ConsumerQueueParcelable parcelable); + + // See |IGraphicBufferConsumer::acquireBuffer| + status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) override; + + // See |IGraphicBufferConsumer::detachBuffer| + status_t detachBuffer(int slot) override; + + // See |IGraphicBufferConsumer::attachBuffer| + status_t attachBuffer(int* outSlot, const sp& buffer) override; + + // See |IGraphicBufferConsumer::releaseBuffer| + status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, + const sp& releaseFence) override; + + // See |IGraphicBufferConsumer::consumerConnect| + status_t consumerConnect(const sp& consumer, bool controlledByApp) override; + + // See |IGraphicBufferConsumer::consumerDisconnect| + status_t consumerDisconnect() override; + + // See |IGraphicBufferConsumer::getReleasedBuffers| + status_t getReleasedBuffers(uint64_t* slotMask) override; + + // See |IGraphicBufferConsumer::setDefaultBufferSize| + status_t setDefaultBufferSize(uint32_t w, uint32_t h) override; + + // See |IGraphicBufferConsumer::setMaxBufferCount| + status_t setMaxBufferCount(int bufferCount) override; + + // See |IGraphicBufferConsumer::setMaxAcquiredBufferCount| + status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override; + + // See |IGraphicBufferConsumer::setConsumerName| + status_t setConsumerName(const String8& name) override; + + // See |IGraphicBufferConsumer::setDefaultBufferFormat| + status_t setDefaultBufferFormat(PixelFormat defaultFormat) override; + + // See |IGraphicBufferConsumer::setDefaultBufferDataSpace| + status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) override; + + // See |IGraphicBufferConsumer::setConsumerUsageBits| + status_t setConsumerUsageBits(uint64_t usage) override; + + // See |IGraphicBufferConsumer::setConsumerIsProtected| + status_t setConsumerIsProtected(bool isProtected) override; + + // See |IGraphicBufferConsumer::setTransformHint| + status_t setTransformHint(uint32_t hint) override; + + // See |IGraphicBufferConsumer::getSidebandStream| + status_t getSidebandStream(sp* outStream) const override; + + // See |IGraphicBufferConsumer::getOccupancyHistory| + status_t getOccupancyHistory(bool forceFlush, + std::vector* outHistory) override; + + // See |IGraphicBufferConsumer::discardFreeBuffers| + status_t discardFreeBuffers() override; + + // See |IGraphicBufferConsumer::dumpState| + status_t dumpState(const String8& prefix, String8* outResult) const override; + + // BufferHubConsumer provides its own logic to cast to a binder object. + IBinder* onAsBinder() override; + +private: + // Private constructor to force use of |Create|. + BufferHubConsumer() = default; + + // Concrete implementation backed by BufferHubBuffer. + std::shared_ptr mQueue; +}; + +} // namespace android + +#endif // ANDROID_GUI_BUFFERHUBCONSUMER_H_ diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h new file mode 100644 index 0000000000000000000000000000000000000000..23c9909826e79ada32ab421fba46fe988ef7bac2 --- /dev/null +++ b/libs/gui/include/gui/BufferHubProducer.h @@ -0,0 +1,219 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERHUBPRODUCER_H_ +#define ANDROID_GUI_BUFFERHUBPRODUCER_H_ + +#include +#include +#include +#include + +namespace android { + +class BufferHubProducer : public IGraphicBufferProducer { +public: + static constexpr int kNoConnectedApi = -1; + + // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer + // side logic doesn't limit the number of buffer it can acquire + // simultaneously. We need a way for consumer logic to configure and enforce + // that. + static constexpr int kDefaultUndequeuedBuffers = 1; + + // Creates a BufferHubProducer instance by importing an existing prodcuer + // queue. + static sp Create(const std::shared_ptr& producer); + + // Creates a BufferHubProducer instance by importing an existing prodcuer + // parcelable. Note that this call takes the ownership of the parcelable + // object and is guaranteed to succeed if parcelable object is valid. + static sp Create(dvr::ProducerQueueParcelable parcelable); + + // See |IGraphicBufferProducer::requestBuffer| + status_t requestBuffer(int slot, sp* buf) override; + + // For the BufferHub based implementation. All buffers in the queue are + // allowed to be dequeued from the consumer side. It call always returns + // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting + // |max_dequeued_buffers| here can be considered the same as setting queue + // capacity. + // + // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info + status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override; + + // See |IGraphicBufferProducer::setAsyncMode| + status_t setAsyncMode(bool async) override; + + // See |IGraphicBufferProducer::dequeueBuffer| + status_t dequeueBuffer(int* out_slot, sp* out_fence, uint32_t width, uint32_t height, + PixelFormat format, uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) override; + + // See |IGraphicBufferProducer::detachBuffer| + status_t detachBuffer(int slot) override; + + // See |IGraphicBufferProducer::detachNextBuffer| + status_t detachNextBuffer(sp* out_buffer, sp* out_fence) override; + + // See |IGraphicBufferProducer::attachBuffer| + status_t attachBuffer(int* out_slot, const sp& buffer) override; + + // See |IGraphicBufferProducer::queueBuffer| + status_t queueBuffer(int slot, const QueueBufferInput& input, + QueueBufferOutput* output) override; + + // See |IGraphicBufferProducer::cancelBuffer| + status_t cancelBuffer(int slot, const sp& fence) override; + + // See |IGraphicBufferProducer::query| + status_t query(int what, int* out_value) override; + + // See |IGraphicBufferProducer::connect| + status_t connect(const sp& listener, int api, + bool producer_controlled_by_app, QueueBufferOutput* output) override; + + // See |IGraphicBufferProducer::disconnect| + status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) override; + + // See |IGraphicBufferProducer::setSidebandStream| + status_t setSidebandStream(const sp& stream) override; + + // See |IGraphicBufferProducer::allocateBuffers| + void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, + uint64_t usage) override; + + // See |IGraphicBufferProducer::allowAllocation| + status_t allowAllocation(bool allow) override; + + // See |IGraphicBufferProducer::setGenerationNumber| + status_t setGenerationNumber(uint32_t generation_number) override; + + // See |IGraphicBufferProducer::getConsumerName| + String8 getConsumerName() const override; + + // See |IGraphicBufferProducer::setSharedBufferMode| + status_t setSharedBufferMode(bool shared_buffer_mode) override; + + // See |IGraphicBufferProducer::setAutoRefresh| + status_t setAutoRefresh(bool auto_refresh) override; + + // See |IGraphicBufferProducer::setDequeueTimeout| + status_t setDequeueTimeout(nsecs_t timeout) override; + + // See |IGraphicBufferProducer::getLastQueuedBuffer| + status_t getLastQueuedBuffer(sp* out_buffer, sp* out_fence, + float out_transform_matrix[16]) override; + + // See |IGraphicBufferProducer::getFrameTimestamps| + void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override; + + // See |IGraphicBufferProducer::getUniqueId| + status_t getUniqueId(uint64_t* out_id) const override; + + // See |IGraphicBufferProducer::getConsumerUsage| + status_t getConsumerUsage(uint64_t* out_usage) const override; + + // Takes out the current producer as a binder parcelable object. Note that the + // producer must be disconnected to be exportable. After successful export, + // the producer queue can no longer be connected again. Returns NO_ERROR when + // takeout is successful and out_parcelable will hold the new parcelable + // object. Also note that out_parcelable cannot be NULL and must points to an + // invalid parcelable. + status_t TakeAsParcelable(dvr::ProducerQueueParcelable* out_parcelable); + + IBinder* onAsBinder() override; + +protected: + // See |IGraphicBufferProducer::exportToParcel| + status_t exportToParcel(Parcel* parcel) override; + +private: + using LocalHandle = pdx::LocalHandle; + + // Private constructor to force use of |Create|. + BufferHubProducer() {} + + static uint64_t genUniqueId() { + static std::atomic counter{0}; + static uint64_t id = static_cast(getpid()) << 32; + return id | counter++; + } + + // Allocate new buffer through BufferHub and add it into |queue_| for + // bookkeeping. + status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, + PixelFormat format, uint64_t usage); + + // Remove a buffer via BufferHubRPC. + status_t RemoveBuffer(size_t slot); + + // Free all buffers which are owned by the prodcuer. Note that if graphic + // buffers are acquired by the consumer, we can't . + status_t FreeAllBuffers(); + + // Concreate implementation backed by BufferHubBuffer. + std::shared_ptr queue_; + + // Mutex for thread safety. + std::mutex mutex_; + + // Connect client API, should be one of the NATIVE_WINDOW_API_* flags. + int connected_api_{kNoConnectedApi}; + + // |max_buffer_count_| sets the capacity of the underlying buffer queue. + int32_t max_buffer_count_{dvr::BufferHubQueue::kMaxQueueCapacity}; + + // |max_dequeued_buffer_count_| set the maximum number of buffers that can + // be dequeued at the same momment. + int32_t max_dequeued_buffer_count_{1}; + + // Sets how long dequeueBuffer or attachBuffer will block if a buffer or + // slot is not yet available. The timeout is stored in milliseconds. + int dequeue_timeout_ms_{dvr::BufferHubQueue::kNoTimeOut}; + + // |generation_number_| stores the current generation number of the attached + // producer. Any attempt to attach a buffer with a different generation + // number will fail. + // TOOD(b/38137191) Currently not used as we don't support + // IGraphicBufferProducer::detachBuffer. + uint32_t generation_number_{0}; + + // |buffers_| stores the buffers that have been dequeued from + // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets + // filled in with the result of |Dequeue|. + // TODO(jwcai) The buffer allocated to a slot will also be replaced if the + // requested buffer usage or geometry differs from that of the buffer + // allocated to a slot. + struct BufferHubSlot : public BufferSlot { + BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {} + // BufferSlot comes from android framework, using m prefix to comply with + // the name convention with the reset of data fields from BufferSlot. + std::shared_ptr mBufferProducer; + bool mIsReallocating; + }; + BufferHubSlot buffers_[dvr::BufferHubQueue::kMaxQueueCapacity]; + + // A uniqueId used by IGraphicBufferProducer interface. + const uint64_t unique_id_{genUniqueId()}; + + // A pending parcelable object which keeps the bufferhub channel alive. + dvr::ProducerQueueParcelable pending_producer_parcelable_; +}; + +} // namespace android + +#endif // ANDROID_GUI_BUFFERHUBPRODUCER_H_ diff --git a/libs/gui/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h index 55637a9be463c2c42539ee9d6818394b7d09d87a..218bb424fbe94a3a7f2df65bdc9e2724bf086d90 100644 --- a/libs/gui/include/gui/BufferItem.h +++ b/libs/gui/include/gui/BufferItem.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GUI_BUFFERITEM_H #define ANDROID_GUI_BUFFERITEM_H +#include + #include #include #include @@ -86,6 +88,9 @@ class BufferItem : public Flattenable { // dataSpace is format-dependent. android_dataspace mDataSpace; + // mHdrMetadata is the HDR metadata associated with this buffer slot. + HdrMetadata mHdrMetadata; + // mFrameNumber is the number of the queued frame for this slot. uint64_t mFrameNumber; @@ -122,6 +127,9 @@ class BufferItem : public Flattenable { // Indicates that this BufferItem contains a stale buffer which has already // been released by the BufferQueue. bool mIsStale; + + // Indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer. + int mApi; }; } // namespace android diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index d9c57757f564eb43a8a5515bb4928522d986ce8f..a905610ee25ff0a1bf0bbae304d4dde595748dd1 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -57,10 +57,6 @@ class BufferItemConsumer: public ConsumerBase ~BufferItemConsumer() override; - // set the name of the BufferItemConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - // setBufferFreedListener sets the listener object that will be notified // when an old buffer is being freed. void setBufferFreedListener(const wp& listener); diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index ba5cbf7eb458e6e63e9d6c2e55a648841101a305..da952744f34459a70cdef1866785602c32795249 100644 --- a/libs/gui/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h @@ -79,6 +79,12 @@ public: sp* outConsumer, bool consumerIsSurfaceFlinger = false); +#ifndef NO_BUFFERHUB + // Creates an IGraphicBufferProducer and IGraphicBufferConsumer pair backed by BufferHub. + static void createBufferHubQueue(sp* outProducer, + sp* outConsumer); +#endif + BufferQueue() = delete; // Create through createBufferQueue }; diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index e9fc8fd1eaf7cbd8836a9fd58f4ec97a81da8fc2..366ced380b7ca63a14cf8d9771d84cb14010bdf8 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -89,6 +89,18 @@ public: // See IGraphicBufferConsumer::setDefaultBufferDataSpace status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); + // See IGraphicBufferConsumer::setConsumerUsageBits + status_t setConsumerUsageBits(uint64_t usage); + + // See IGraphicBufferConsumer::setTransformHint + status_t setTransformHint(uint32_t hint); + + // See IGraphicBufferConsumer::setMaxAcquiredBufferCount + status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); + + // See IGraphicBufferConsumer::getSidebandStream + sp getSidebandStream() const; + // See IGraphicBufferConsumer::getOccupancyHistory status_t getOccupancyHistory(bool forceFlush, std::vector* outHistory); @@ -187,7 +199,7 @@ protected: // ConsumerBase::releaseBufferLocked. virtual status_t releaseBufferLocked(int slot, const sp graphicBuffer, - EGLDisplay display, EGLSyncKHR eglFence); + EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR); // returns true iff the slot still has the graphicBuffer in it. bool stillTracking(int slot, const sp graphicBuffer); diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h index 58602bf321670b5c379a602397be0dfb178fb429..d375611e5bb1be0010973a6f151385e8c8606aa5 100644 --- a/libs/gui/include/gui/CpuConsumer.h +++ b/libs/gui/include/gui/CpuConsumer.h @@ -94,12 +94,6 @@ class CpuConsumer : public ConsumerBase CpuConsumer(const sp& bq, size_t maxLockedBuffers, bool controlledByApp = false); - virtual ~CpuConsumer(); - - // set the name of the CpuConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - // Gets the next graphics buffer from the producer and locks it for CPU use, // filling out the passed-in locked buffer structure with the native pointer // and metadata. Returns BAD_VALUE if no new buffer is available, and @@ -119,31 +113,39 @@ class CpuConsumer : public ConsumerBase private: // Maximum number of buffers that can be locked at a time - size_t mMaxLockedBuffers; - - status_t releaseAcquiredBufferLocked(size_t lockedIdx); - - virtual void freeBufferLocked(int slotIndex); + const size_t mMaxLockedBuffers; // Tracking for buffers acquired by the user struct AcquiredBuffer { + static constexpr uintptr_t kUnusedId = 0; + // Need to track the original mSlot index and the buffer itself because // the mSlot entry may be freed/reused before the acquired buffer is // released. int mSlot; sp mGraphicBuffer; - void *mBufferPointer; + uintptr_t mLockedBufferId; AcquiredBuffer() : mSlot(BufferQueue::INVALID_BUFFER_SLOT), - mBufferPointer(NULL) { + mLockedBufferId(kUnusedId) { + } + + void reset() { + mSlot = BufferQueue::INVALID_BUFFER_SLOT; + mGraphicBuffer.clear(); + mLockedBufferId = kUnusedId; } }; + + size_t findAcquiredBufferLocked(uintptr_t id) const; + + status_t lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const; + Vector mAcquiredBuffers; // Count of currently locked buffers size_t mCurrentLockedBuffers; - }; } // namespace android diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 75f2ccaaea57b2eaa67bc308aa1dc960aaef8b7e..71ed3bf23998ec6aec3a7617e0cebd28eab59033 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -138,6 +138,10 @@ public: const sp& buf, const Rect& cropRect, uint32_t transform, bool filtering); + // Scale the crop down horizontally or vertically such that it has the + // same aspect ratio as the buffer does. + static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight); + // getTimestamp retrieves the timestamp associated with the texture image // set by the most recent call to updateTexImage. // @@ -197,22 +201,9 @@ public: // buffer is ready to be read from. std::shared_ptr getCurrentFenceTime() const; - // doGLFenceWait inserts a wait command into the OpenGL ES command stream - // to ensure that it is safe for future OpenGL ES commands to access the - // current texture buffer. - status_t doGLFenceWait() const; - - // set the name of the GLConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - - // These functions call the corresponding BufferQueue implementation - // so the refactoring can proceed smoothly - status_t setDefaultBufferFormat(PixelFormat defaultFormat); - status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); + // setConsumerUsageBits overrides the ConsumerBase method to OR + // DEFAULT_USAGE_FLAGS to usage. status_t setConsumerUsageBits(uint64_t usage); - status_t setTransformHint(uint32_t hint); - status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); // detachFromContext detaches the GLConsumer from the calling thread's // current OpenGL ES context. This context must be the same as the context @@ -267,8 +258,6 @@ protected: return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence); } - static bool isExternalFormat(PixelFormat format); - struct PendingRelease { PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer(), display(nullptr), fence(nullptr) {} diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h new file mode 100644 index 0000000000000000000000000000000000000000..9800602d6c6a348dc8d75cbb41aadd0ce91340e6 --- /dev/null +++ b/libs/gui/include/gui/HdrMetadata.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +namespace android { + +struct HdrMetadata : public LightFlattenable { + enum Type : uint32_t { + SMPTE2086 = 1 << 0, + CTA861_3 = 1 << 1, + }; + uint32_t validTypes{0}; + + android_smpte2086_metadata smpte2086{}; + android_cta861_3_metadata cta8613{}; + + // LightFlattenable + bool isFixedSize() const { return false; } + size_t getFlattenedSize() const; + status_t flatten(void* buffer, size_t size) const; + status_t unflatten(void const* buffer, size_t size); + + bool operator==(const HdrMetadata& rhs) const; +}; + +} // namespace android diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 039dc0d657812256607bda1e231f3a96cda80845..887654e05bbdecb55b8112f8240401ef3f30ebce 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -72,6 +73,14 @@ public: RELEASE_ALL_BUFFERS = 0x2, }; + enum { + // A parcelable magic indicates using Binder BufferQueue as transport + // backend. + USE_BUFFER_QUEUE = 0x62717565, // 'bque' + // A parcelable magic indicates using BufferHub as transport backend. + USE_BUFFER_HUB = 0x62687562, // 'bhub' + }; + // requestBuffer requests a new buffer for the given index. The server (i.e. // the IGraphicBufferProducer implementation) assigns the newly created // buffer to the given slot index, and the client is expected to mirror the @@ -354,6 +363,9 @@ public: const Region& getSurfaceDamage() const { return surfaceDamage; } void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; } + const HdrMetadata& getHdrMetadata() const { return hdrMetadata; } + void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; } + private: int64_t timestamp{0}; int isAutoTimestamp{0}; @@ -365,6 +377,7 @@ public: sp fence; Region surfaceDamage; bool getFrameTimestamps{false}; + HdrMetadata hdrMetadata; }; struct QueueBufferOutput : public Flattenable { @@ -599,6 +612,24 @@ public: // returned by querying the now deprecated // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; + + // Static method exports any IGraphicBufferProducer object to a parcel. It + // handles null producer as well. + static status_t exportToParcel(const sp& producer, + Parcel* parcel); + + // Factory method that creates a new IBGP instance from the parcel. + static sp createFromParcel(const Parcel* parcel); + +protected: + // Exports the current producer as a binder parcelable object. Note that the + // producer must be disconnected to be exportable. After successful export, + // the producer queue can no longer be connected again. Returns NO_ERROR + // when the export is successful and writes an implementation defined + // parcelable object into the parcel. For traditional Android BufferQueue, + // it writes a strong binder object; for BufferHub, it writes a + // ProducerQueueParcelable object. + virtual status_t exportToParcel(Parcel* parcel); }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index b2267426a8be69acf8b6c830c4563aceb9537359..e40157206d7380a4a72ed44441715c26cc5910b0 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -29,6 +29,8 @@ #include #include +#include +#include #include @@ -59,6 +61,11 @@ public: enum { eSynchronous = 0x01, eAnimation = 0x02, + + // Indicates that this transaction will likely result in a lot of layers being composed, and + // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this + // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns) + eEarlyWakeup = 0x04 }; enum { @@ -159,20 +166,25 @@ public: virtual status_t setActiveConfig(const sp& display, int id) = 0; virtual status_t getDisplayColorModes(const sp& display, - Vector* outColorModes) = 0; - virtual android_color_mode_t getActiveColorMode(const sp& display) = 0; + Vector* outColorModes) = 0; + virtual ui::ColorMode getActiveColorMode(const sp& display) = 0; virtual status_t setActiveColorMode(const sp& display, - android_color_mode_t colorMode) = 0; + ui::ColorMode colorMode) = 0; /* Capture the specified screen. requires READ_FRAME_BUFFER permission * This function will fail if there is a secure window on screen. */ - virtual status_t captureScreen(const sp& display, - const sp& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - Rotation rotation = eRotateNone) = 0; + virtual status_t captureScreen(const sp& display, sp* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, + Rotation rotation = eRotateNone) = 0; + + /** + * Capture a subtree of the layer hierarchy, potentially ignoring the root node. + */ + virtual status_t captureLayers(const sp& layerHandleBinder, + sp* outBuffer, const Rect& sourceCrop, + float frameScale = 1.0, bool childrenOnly = false) = 0; /* Clears the frame statistics for animations. * @@ -226,6 +238,7 @@ public: SET_ACTIVE_CONFIG, CONNECT_DISPLAY, CAPTURE_SCREEN, + CAPTURE_LAYERS, CLEAR_ANIMATION_FRAME_STATS, GET_ANIMATION_FRAME_STATS, SET_POWER_MODE, diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 2c613ea8c5b2c91da08acd9d637371a54982f07e..8dfc99a4b710aa803873cb6aec5d61a202698d62 100644 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h @@ -41,7 +41,7 @@ public: eCursorWindow = 0x00002000, eFXSurfaceNormal = 0x00000000, - eFXSurfaceDim = 0x00020000, + eFXSurfaceColor = 0x00020000, eFXSurfaceMask = 0x000F0000, }; @@ -49,8 +49,8 @@ public: * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags, const sp& parent, uint32_t windowType, - uint32_t ownerUid, sp* handle, + uint32_t flags, const sp& parent, int32_t windowType, + int32_t ownerUid, sp* handle, sp* gbp) = 0; /* diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h index 8453e043ef1b5003248af320a276ba2736ee7d75..92bd8c5b28b3a28f54efa18c09bc5e0b4046de88 100644 --- a/libs/gui/include/gui/LayerDebugInfo.h +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -22,6 +22,7 @@ #include #include +#include namespace android { @@ -52,7 +53,7 @@ public: int32_t mHeight = -1; Rect mCrop = Rect::INVALID_RECT; Rect mFinalCrop = Rect::INVALID_RECT; - float mAlpha = 0.f; + half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf); uint32_t mFlags = 0; PixelFormat mPixelFormat = PIXEL_FORMAT_NONE; android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/gui/LayerState.h similarity index 84% rename from libs/gui/include/private/gui/LayerState.h rename to libs/gui/include/gui/LayerState.h index 307c76470234986ac3a068144d466b341432df1a..788962e4908c61b65ed2bdbe1ea0ba91ddd8437a 100644 --- a/libs/gui/include/private/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace android { @@ -59,7 +60,10 @@ struct layer_state_t { eGeometryAppliesWithResize = 0x00001000, eReparentChildren = 0x00002000, eDetachChildren = 0x00004000, - eRelativeLayerChanged = 0x00008000 + eRelativeLayerChanged = 0x00008000, + eReparent = 0x00010000, + eColorChanged = 0x00020000, + eDestroySurface = 0x00040000 }; layer_state_t() @@ -74,6 +78,7 @@ struct layer_state_t { matrix.dsdy = matrix.dtdx = 0.0f; } + void merge(const layer_state_t& other); status_t write(Parcel& output) const; status_t read(const Parcel& input); @@ -107,6 +112,10 @@ struct layer_state_t { sp relativeLayerHandle; + sp parentHandleForChild; + + half3 color; + // non POD must be last. see write/read Region transparentRegion; }; @@ -137,6 +146,7 @@ struct DisplayState { }; DisplayState(); + void merge(const DisplayState& other); uint32_t what; sp token; @@ -150,6 +160,20 @@ struct DisplayState { status_t read(const Parcel& input); }; +static inline +int compare_type(const ComposerState& lhs, const ComposerState& rhs) { + if (lhs.client < rhs.client) return -1; + if (lhs.client > rhs.client) return 1; + if (lhs.state.surface < rhs.state.surface) return -1; + if (lhs.state.surface > rhs.state.surface) return 1; + return 0; +} + +static inline +int compare_type(const DisplayState& lhs, const DisplayState& rhs) { + return compare_type(lhs.token, rhs.token); +} + }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 55dd6bf0677974ca85fd339d58bd436cf84365b6..9aeafae198d563e41309c073c7be7beccf85b313 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -17,10 +17,12 @@ #ifndef ANDROID_GUI_SURFACE_H #define ANDROID_GUI_SURFACE_H -#include #include +#include +#include #include +#include #include #include @@ -214,6 +216,8 @@ private: int dispatchUnlockAndPost(va_list args); int dispatchSetSidebandStream(va_list args); int dispatchSetBuffersDataSpace(va_list args); + int dispatchSetBuffersSmpte2086Metadata(va_list args); + int dispatchSetBuffersCta8613Metadata(va_list args); int dispatchSetSurfaceDamage(va_list args); int dispatchSetSharedBufferMode(va_list args); int dispatchSetAutoRefresh(va_list args); @@ -242,7 +246,9 @@ protected: virtual int setBuffersTransform(uint32_t transform); virtual int setBuffersStickyTransform(uint32_t transform); virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setBuffersDataSpace(android_dataspace dataSpace); + virtual int setBuffersDataSpace(ui::Dataspace dataSpace); + virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata); + virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata); virtual int setCrop(Rect const* rect); virtual int setUsage(uint64_t reqUsage); virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects); @@ -281,6 +287,10 @@ public: // detachNextBuffer, or attachBuffer call. status_t getAndFlushRemovedBuffers(std::vector>* out); + ui::Dataspace getBuffersDataSpace(); + + static status_t attachAndQueueBuffer(Surface* surface, sp buffer); + protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; @@ -331,9 +341,13 @@ protected: int64_t mTimestamp; // mDataSpace is the buffer dataSpace that will be used for the next buffer - // queue operation. It defaults to HAL_DATASPACE_UNKNOWN, which + // queue operation. It defaults to Dataspace::UNKNOWN, which // means that the buffer contains some type of color data. - android_dataspace mDataSpace; + ui::Dataspace mDataSpace; + + // mHdrMetadata is the HDR metadata that will be used for the next buffer + // queue operation. There is no HDR metadata by default. + HdrMetadata mHdrMetadata; // mCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 145c0597bde6937fe880a89e3648065635d900e7..377fe68c4154de4af693680affff5981903385ca 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -19,6 +19,7 @@ #include #include +#include #include @@ -28,17 +29,19 @@ #include #include +#include #include #include #include +#include +#include namespace android { // --------------------------------------------------------------------------- struct DisplayInfo; -class Composer; class HdrCapabilities; class ISurfaceComposerClient; class IGraphicBufferProducer; @@ -51,6 +54,7 @@ class SurfaceComposerClient : public RefBase friend class Composer; public: SurfaceComposerClient(); + SurfaceComposerClient(const sp& client); SurfaceComposerClient(const sp& parent); virtual ~SurfaceComposerClient(); @@ -85,13 +89,14 @@ public: // Gets the list of supported color modes for the given display static status_t getDisplayColorModes(const sp& display, - Vector* outColorModes); + Vector* outColorModes); // Gets the active color mode for the given display - static android_color_mode_t getActiveColorMode(const sp& display); + static ui::ColorMode getActiveColorMode(const sp& display); // Sets the active color mode for the given display - static status_t setActiveColorMode(const sp& display, android_color_mode_t colorMode); + static status_t setActiveColorMode(const sp& display, + ui::ColorMode colorMode); /* Triggers screen on/off or low power mode and waits for it to complete */ static void setDisplayPowerMode(const sp& display, int mode); @@ -107,8 +112,20 @@ public: PixelFormat format, // pixel-format desired uint32_t flags = 0, // usage flags SurfaceControl* parent = nullptr, // parent - uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.) - uint32_t ownerUid = 0 // UID of the task + int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.) + int32_t ownerUid = -1 // UID of the task + ); + + status_t createSurfaceChecked( + const String8& name,// name of the surface + uint32_t w, // width in pixel + uint32_t h, // height in pixel + PixelFormat format, // pixel-format desired + sp* outSurface, + uint32_t flags = 0, // usage flags + SurfaceControl* parent = nullptr, // parent + int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.) + int32_t ownerUid = -1 // UID of the task ); //! Create a virtual display @@ -121,157 +138,185 @@ public: //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi. static sp getBuiltInDisplay(int32_t id); - // ------------------------------------------------------------------------ - // Composer parameters - // All composer parameters must be changed within a transaction - // several surfaces can be updated in one transaction, all changes are - // committed at once when the transaction is closed. - // closeGlobalTransaction() requires an IPC with the server. - - //! Open a composer transaction on all active SurfaceComposerClients. - static void openGlobalTransaction(); - - //! Close a composer transaction on all active SurfaceComposerClients. - static void closeGlobalTransaction(bool synchronous = false); - static status_t enableVSyncInjections(bool enable); static status_t injectVSync(nsecs_t when); - //! Flag the currently open transaction as an animation transaction. - static void setAnimationTransaction(); - - status_t hide(const sp& id); - status_t show(const sp& id); - status_t setFlags(const sp& id, uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint(const sp& id, const Region& transparent); - status_t setLayer(const sp& id, int32_t layer); - status_t setRelativeLayer(const sp& id, - const sp& relativeTo, int32_t layer); - status_t setAlpha(const sp& id, float alpha=1.0f); - status_t setMatrix(const sp& id, float dsdx, float dtdx, float dtdy, float dsdy); - status_t setPosition(const sp& id, float x, float y); - status_t setSize(const sp& id, uint32_t w, uint32_t h); - status_t setCrop(const sp& id, const Rect& crop); - status_t setFinalCrop(const sp& id, const Rect& crop); - status_t setLayerStack(const sp& id, uint32_t layerStack); - status_t deferTransactionUntil(const sp& id, - const sp& handle, uint64_t frameNumber); - status_t deferTransactionUntil(const sp& id, - const sp& handle, uint64_t frameNumber); - status_t reparentChildren(const sp& id, - const sp& newParentHandle); - status_t detachChildren(const sp& id); - status_t setOverrideScalingMode(const sp& id, - int32_t overrideScalingMode); - status_t setGeometryAppliesWithResize(const sp& id); + struct SCHash { + std::size_t operator()(const sp& sc) const { + return std::hash{}(sc.get()); + } + }; + + class Transaction { + std::unordered_map, ComposerState, SCHash> mComposerStates; + SortedVector mDisplayStates; + uint32_t mForceSynchronous = 0; + uint32_t mTransactionNestCount = 0; + bool mAnimation = false; + bool mEarlyWakeup = false; + + int mStatus = NO_ERROR; + + layer_state_t* getLayerState(const sp& sc); + DisplayState& getDisplayState(const sp& token); + + public: + Transaction() = default; + virtual ~Transaction() = default; + Transaction(Transaction const& other); + + status_t apply(bool synchronous = false); + // Merge another transaction in to this one, clearing other + // as if it had been applied. + Transaction& merge(Transaction&& other); + Transaction& show(const sp& sc); + Transaction& hide(const sp& sc); + Transaction& setPosition(const sp& sc, + float x, float y); + Transaction& setSize(const sp& sc, + uint32_t w, uint32_t h); + Transaction& setLayer(const sp& sc, + int32_t z); + + // Sets a Z order relative to the Surface specified by "relativeTo" but + // without becoming a full child of the relative. Z-ordering works exactly + // as if it were a child however. + // + // As a nod to sanity, only non-child surfaces may have a relative Z-order. + // + // This overrides any previous call and is overriden by any future calls + // to setLayer. + // + // If the relative is removed, the Surface will have no layer and be + // invisible, until the next time set(Relative)Layer is called. + Transaction& setRelativeLayer(const sp& sc, + const sp& relativeTo, int32_t z); + Transaction& setFlags(const sp& sc, + uint32_t flags, uint32_t mask); + Transaction& setTransparentRegionHint(const sp& sc, + const Region& transparentRegion); + Transaction& setAlpha(const sp& sc, + float alpha); + Transaction& setMatrix(const sp& sc, + float dsdx, float dtdx, float dtdy, float dsdy); + Transaction& setCrop(const sp& sc, const Rect& crop); + Transaction& setFinalCrop(const sp& sc, const Rect& crop); + Transaction& setLayerStack(const sp& sc, uint32_t layerStack); + // Defers applying any changes made in this transaction until the Layer + // identified by handle reaches the given frameNumber. If the Layer identified + // by handle is removed, then we will apply this transaction regardless of + // what frame number has been reached. + Transaction& deferTransactionUntil(const sp& sc, + const sp& handle, + uint64_t frameNumber); + // A variant of deferTransactionUntil which identifies the Layer we wait for by + // Surface instead of Handle. Useful for clients which may not have the + // SurfaceControl for some of their Surfaces. Otherwise behaves identically. + Transaction& deferTransactionUntil(const sp& sc, + const sp& barrierSurface, + uint64_t frameNumber); + // Reparents all children of this layer to the new parent handle. + Transaction& reparentChildren(const sp& sc, + const sp& newParentHandle); + + /// Reparents the current layer to the new parent handle. The new parent must not be null. + // This can be used instead of reparentChildren if the caller wants to + // only re-parent a specific child. + Transaction& reparent(const sp& sc, + const sp& newParentHandle); + + Transaction& setColor(const sp& sc, const half3& color); + + // Detaches all child surfaces (and their children recursively) + // from their SurfaceControl. + // The child SurfaceControls will not throw exceptions or return errors, + // but transactions will have no effect. + // The child surfaces will continue to follow their parent surfaces, + // and remain eligible for rendering, but their relative state will be + // frozen. We use this in the WindowManager, in app shutdown/relaunch + // scenarios, where the app would otherwise clean up its child Surfaces. + // Sometimes the WindowManager needs to extend their lifetime slightly + // in order to perform an exit animation or prevent flicker. + Transaction& detachChildren(const sp& sc); + // Set an override scaling mode as documented in + // the override scaling mode will take precedence over any client + // specified scaling mode. -1 will clear the override scaling mode. + Transaction& setOverrideScalingMode(const sp& sc, + int32_t overrideScalingMode); + + // If the size changes in this transaction, all geometry updates specified + // in this transaction will not complete until a buffer of the new size + // arrives. As some elements normally apply immediately, this enables + // freezing the total geometry of a surface until a resize is completed. + Transaction& setGeometryAppliesWithResize(const sp& sc); + + Transaction& destroySurface(const sp& sc); + + status_t setDisplaySurface(const sp& token, + const sp& bufferProducer); + + void setDisplayLayerStack(const sp& token, uint32_t layerStack); + + /* setDisplayProjection() defines the projection of layer stacks + * to a given display. + * + * - orientation defines the display's orientation. + * - layerStackRect defines which area of the window manager coordinate + * space will be used. + * - displayRect defines where on the display will layerStackRect be + * mapped to. displayRect is specified post-orientation, that is + * it uses the orientation seen by the end-user. + */ + void setDisplayProjection(const sp& token, + uint32_t orientation, + const Rect& layerStackRect, + const Rect& displayRect); + void setDisplaySize(const sp& token, uint32_t width, uint32_t height); + void setAnimationTransaction(); + void setEarlyWakeup(); + }; status_t destroySurface(const sp& id); status_t clearLayerFrameStats(const sp& token) const; status_t getLayerFrameStats(const sp& token, FrameStats* outStats) const; - static status_t clearAnimationFrameStats(); static status_t getAnimationFrameStats(FrameStats* outStats); static status_t getHdrCapabilities(const sp& display, HdrCapabilities* outCapabilities); - static status_t setDisplaySurface(const sp& token, - sp bufferProducer); - static void setDisplayLayerStack(const sp& token, - uint32_t layerStack); - static void setDisplaySize(const sp& token, uint32_t width, uint32_t height); - - /* setDisplayProjection() defines the projection of layer stacks - * to a given display. - * - * - orientation defines the display's orientation. - * - layerStackRect defines which area of the window manager coordinate - * space will be used. - * - displayRect defines where on the display will layerStackRect be - * mapped to. displayRect is specified post-orientation, that is - * it uses the orientation seen by the end-user. - */ static void setDisplayProjection(const sp& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect); + inline sp getClient() { return mClient; } + private: virtual void onFirstRef(); - Composer& getComposer(); mutable Mutex mLock; status_t mStatus; sp mClient; - Composer& mComposer; wp mParent; }; // --------------------------------------------------------------------------- -class ScreenshotClient -{ +class ScreenshotClient { public: // if cropping isn't required, callers may pass in a default Rect, e.g.: // capture(display, producer, Rect(), reqWidth, ...); - static status_t capture( - const sp& display, - const sp& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform); - static status_t captureToBuffer( - const sp& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - uint32_t rotation, - sp* outbuffer); -private: - mutable sp mCpuConsumer; - mutable sp mProducer; - CpuConsumer::LockedBuffer mBuffer; - bool mHaveBuffer; - -public: - ScreenshotClient(); - ~ScreenshotClient(); - - // frees the previous screenshot and captures a new one - // if cropping isn't required, callers may pass in a default Rect, e.g.: - // update(display, Rect(), useIdentityTransform); - status_t update(const sp& display, - Rect sourceCrop, bool useIdentityTransform); - status_t update(const sp& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - bool useIdentityTransform); - status_t update(const sp& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform); - status_t update(const sp& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation); - - sp getCpuConsumer() const; - - // release memory occupied by the screenshot - void release(); - - // pixels are valid until this object is freed or - // release() or update() is called - void const* getPixels() const; - - uint32_t getWidth() const; - uint32_t getHeight() const; - PixelFormat getFormat() const; - uint32_t getStride() const; - // size of allocated memory in bytes - size_t getSize() const; - android_dataspace getDataSpace() const; + static status_t capture(const sp& display, Rect sourceCrop, uint32_t reqWidth, + uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, uint32_t rotation, + sp* outBuffer); + static status_t captureLayers(const sp& layerHandle, Rect sourceCrop, float frameScale, + sp* outBuffer); + static status_t captureChildLayers(const sp& layerHandle, Rect sourceCrop, + float frameScale, sp* outBuffer); }; // --------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index c15209d32c567fe99c4d94edf3d14583d78738b9..bd987dd6386210cda4f91ac78f32d96e71a1f139 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -29,6 +29,7 @@ #include #include +#include namespace android { @@ -43,6 +44,9 @@ class SurfaceComposerClient; class SurfaceControl : public RefBase { public: + static sp readFromParcel(Parcel* parcel); + void writeToParcel(Parcel* parcel); + static bool isValid(const sp& surface) { return (surface != 0) && surface->isValid(); } @@ -60,87 +64,6 @@ public: // disconnect any api that's connected void disconnect(); - status_t setLayerStack(uint32_t layerStack); - status_t setLayer(int32_t layer); - - // Sets a Z order relative to the Surface specified by "relativeTo" but - // without becoming a full child of the relative. Z-ordering works exactly - // as if it were a child however. - // - // As a nod to sanity, only non-child surfaces may have a relative Z-order. - // - // This overrides any previous and is overriden by any future calls - // to setLayer. - // - // If the relative dissapears, the Surface will have no layer and be - // invisible, until the next time set(Relative)Layer is called. - // - // TODO: This is probably a hack. Currently it exists only to work around - // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type - // which allows inserting a window between a SurfaceView and it's main application - // window. However, since we are using child windows for the SurfaceView, but not using - // child windows elsewhere in O, the WindowManager can't set the layer appropriately. - // This is only used by the "TvInputService" and following the port of ViewRootImpl - // to child surfaces, we can then port this and remove this method. - status_t setRelativeLayer(const sp& relativeTo, int32_t layer); - status_t setPosition(float x, float y); - status_t setSize(uint32_t w, uint32_t h); - status_t hide(); - status_t show(); - status_t setFlags(uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint(const Region& transparent); - status_t setAlpha(float alpha=1.0f); - - // Experimentarily it appears that the matrix transforms the - // on-screen rectangle and it's contents before the position is - // applied. - // - // TODO: Test with other combinations to find approximate transformation rules. - // - // For example: - // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives - // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y)) - status_t setMatrix(float dsdx, float dtdx, float dtdy, float dsdy); - status_t setCrop(const Rect& crop); - status_t setFinalCrop(const Rect& crop); - - // If the size changes in this transaction, all geometry updates specified - // in this transaction will not complete until a buffer of the new size - // arrives. As some elements normally apply immediately, this enables - // freezing the total geometry of a surface until a resize is completed. - status_t setGeometryAppliesWithResize(); - - // Defers applying any changes made in this transaction until the Layer - // identified by handle reaches the given frameNumber. If the Layer identified - // by handle is removed, then we will apply this transaction regardless of - // what frame number has been reached. - status_t deferTransactionUntil(const sp& handle, uint64_t frameNumber); - - // A variant of deferTransactionUntil which identifies the Layer we wait for by - // Surface instead of Handle. Useful for clients which may not have the - // SurfaceControl for some of their Surfaces. Otherwise behaves identically. - status_t deferTransactionUntil(const sp& barrier, uint64_t frameNumber); - - // Reparents all children of this layer to the new parent handle. - status_t reparentChildren(const sp& newParentHandle); - - // Detaches all child surfaces (and their children recursively) - // from their SurfaceControl. - // The child SurfaceControl's will not throw exceptions or return errors, - // but transactions will have no effect. - // The child surfaces will continue to follow their parent surfaces, - // and remain eligible for rendering, but their relative state will be - // frozen. We use this in the WindowManager, in app shutdown/relaunch - // scenarios, where the app would otherwise clean up its child Surfaces. - // Sometimes the WindowManager needs to extend their lifetime slightly - // in order to perform an exit animation or prevent flicker. - status_t detachChildren(); - - // Set an override scaling mode as documented in - // the override scaling mode will take precedence over any client - // specified scaling mode. -1 will clear the override scaling mode. - status_t setOverrideScalingMode(int32_t overrideScalingMode); - static status_t writeSurfaceToParcel( const sp& control, Parcel* parcel); @@ -151,6 +74,8 @@ public: status_t clearLayerFrameStats() const; status_t getLayerFrameStats(FrameStats* outStats) const; + sp getClient() const; + private: // can't be copied SurfaceControl& operator = (SurfaceControl& rhs); @@ -162,7 +87,8 @@ private: SurfaceControl( const sp& client, const sp& handle, - const sp& gbp); + const sp& gbp, + bool owned); ~SurfaceControl(); @@ -175,6 +101,7 @@ private: sp mGraphicBufferProducer; mutable Mutex mLock; mutable sp mSurfaceData; + bool mOwned; }; }; // namespace android diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 908959ce1aae41fc55feed5be731a38b093dd784..01e90e0eb8fddda733595a25fd9d12bb07313e4b 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -49,3 +49,35 @@ cc_test { "libnativewindow" ], } + +// Build a separate binary for each source file to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) +cc_test { + name: "libgui_separate_binary_test", + test_suites: ["device-tests"], + + clang: true, + cflags: [ + "-Wall", + "-Werror", + ], + + test_per_src: true, + srcs: [ + "SurfaceParcelable_test.cpp", + ], + + shared_libs: [ + "liblog", + "libbinder", + "libcutils", + "libgui", + "libui", + "libutils", + "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. + "libpdx_default_transport", + ], + + header_libs: [ + "libdvr_headers", + ], +} diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index 588e54142f5c82488e1ecc4de346a5449a80f313..36be7d93689cdbccea243ef3b01a688507f685f2 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #define CPU_CONSUMER_TEST_FORMAT_RAW 0 #define CPU_CONSUMER_TEST_FORMAT_Y8 0 @@ -681,6 +682,70 @@ TEST_P(CpuConsumerTest, FromCpuLockMax) { } } +TEST_P(CpuConsumerTest, FromCpuInvalid) { + status_t err = mCC->lockNextBuffer(nullptr); + ASSERT_EQ(BAD_VALUE, err) << "lockNextBuffer did not fail"; + + CpuConsumer::LockedBuffer b; + err = mCC->unlockBuffer(b); + ASSERT_EQ(BAD_VALUE, err) << "unlockBuffer did not fail"; +} + +TEST_P(CpuConsumerTest, FromCpuMultiThread) { + CpuConsumerTestParams params = GetParam(); + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1)); + + for (int i = 0; i < 10; i++) { + std::atomic threadReadyCount(0); + auto lockAndUnlock = [&]() { + threadReadyCount++; + // busy wait + while (threadReadyCount < params.maxLockedBuffers + 1); + + CpuConsumer::LockedBuffer b; + status_t err = mCC->lockNextBuffer(&b); + if (err == NO_ERROR) { + usleep(1000); + err = mCC->unlockBuffer(b); + ASSERT_NO_ERROR(err, "Could not unlock buffer: "); + } else if (err == NOT_ENOUGH_DATA) { + // there are params.maxLockedBuffers+1 threads so one of the + // threads might get this error + } else { + FAIL() << "Could not lock buffer"; + } + }; + + // produce buffers + for (int j = 0; j < params.maxLockedBuffers + 1; j++) { + const int64_t time = 1234L; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, &stride)); + } + + // spawn threads + std::vector threads; + for (int j = 0; j < params.maxLockedBuffers + 1; j++) { + threads.push_back(std::thread(lockAndUnlock)); + } + + // join threads + for (auto& thread : threads) { + thread.join(); + } + + // we produced N+1 buffers, but the threads might only consume N + CpuConsumer::LockedBuffer b; + if (mCC->lockNextBuffer(&b) == NO_ERROR) { + mCC->unlockBuffer(b); + } + + if (HasFatalFailure()) { + break; + } + } +} + CpuConsumerTestParams y8TestSets[] = { { 512, 512, 1, HAL_PIXEL_FORMAT_Y8}, { 512, 512, 3, HAL_PIXEL_FORMAT_Y8}, diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp index 1739d9c7cac9a7907ed7cf402e3cd0a43a6e083f..a91552f7fee8a0aa871da96fef23a2e4f1b4954b 100644 --- a/libs/gui/tests/GLTest.cpp +++ b/libs/gui/tests/GLTest.cpp @@ -22,6 +22,8 @@ namespace android { +using Transaction = SurfaceComposerClient::Transaction; + static int abs(int value) { return value > 0 ? value : -value; } @@ -68,10 +70,10 @@ void GLTest::SetUp() { ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); - ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); + Transaction t; + ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7FFFFFFF) + .show(mSurfaceControl) + .apply()); sp window = mSurfaceControl->getSurface(); mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window); diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index dd23bd4cb298726292ec1ee5f4b8b2250450577e..a35cf111743c6a6360d6c47023b564ad6d326bfa 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -42,6 +42,10 @@ #define TEST_CONTROLLED_BY_APP false #define TEST_PRODUCER_USAGE_BITS (0) +#ifndef USE_BUFFER_HUB_AS_BUFFER_QUEUE +#define USE_BUFFER_HUB_AS_BUFFER_QUEUE 0 +#endif + namespace android { namespace { @@ -66,9 +70,15 @@ namespace { const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0; const int QUEUE_BUFFER_INPUT_TRANSFORM = 0; const sp QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; + + // Enums to control which IGraphicBufferProducer backend to test. + enum IGraphicBufferProducerTestCode { + USE_BUFFER_QUEUE_PRODUCER = 0, + USE_BUFFER_HUB_PRODUCER, + }; }; // namespace anonymous -class IGraphicBufferProducerTest : public ::testing::Test { +class IGraphicBufferProducerTest : public ::testing::TestWithParam { protected: IGraphicBufferProducerTest() {} @@ -81,10 +91,27 @@ protected: mDC = new DummyConsumer; - BufferQueue::createBufferQueue(&mProducer, &mConsumer); + switch (GetParam()) { + case USE_BUFFER_QUEUE_PRODUCER: { + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + break; + } + case USE_BUFFER_HUB_PRODUCER: { + BufferQueue::createBufferHubQueue(&mProducer, &mConsumer); + break; + } + default: { + // Should never reach here. + LOG_ALWAYS_FATAL("Invalid test params: %u", GetParam()); + break; + } + } // Test check: Can't connect producer if no consumer yet - ASSERT_EQ(NO_INIT, TryConnectProducer()); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + ASSERT_EQ(NO_INIT, TryConnectProducer()); + } // Must connect consumer before producer connects will succeed. ASSERT_OK(mConsumer->consumerConnect(mDC, /*controlledByApp*/false)); @@ -229,7 +256,7 @@ protected: // accessible from test body sp mConsumer; }; -TEST_F(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { IGraphicBufferProducer::QueueBufferOutput output; // NULL output returns BAD_VALUE @@ -247,7 +274,7 @@ TEST_F(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { // TODO: get a token from a dead process somehow } -TEST_F(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Can't connect when there is already a producer connected @@ -259,20 +286,23 @@ TEST_F(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { ASSERT_OK(mConsumer->consumerDisconnect()); // Can't connect when IGBP is abandoned - EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN, - TEST_API, - TEST_CONTROLLED_BY_APP, - &output)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN, + TEST_API, + TEST_CONTROLLED_BY_APP, + &output)); + } } -TEST_F(IGraphicBufferProducerTest, Disconnect_Succeeds) { +TEST_P(IGraphicBufferProducerTest, Disconnect_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); ASSERT_OK(mProducer->disconnect(TEST_API)); } -TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, Disconnect_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Must disconnect with same API number @@ -283,7 +313,7 @@ TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) { // TODO: somehow kill mProducer so that this returns DEAD_OBJECT } -TEST_F(IGraphicBufferProducerTest, Query_Succeeds) { +TEST_P(IGraphicBufferProducerTest, Query_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int32_t value = -1; @@ -308,7 +338,7 @@ TEST_F(IGraphicBufferProducerTest, Query_Succeeds) { } -TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, Query_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // One past the end of the last 'query' enum value. Update this if we add more enums. @@ -334,14 +364,17 @@ TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) { ASSERT_OK(mConsumer->consumerDisconnect()); // BQ was abandoned - EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value)); + } // TODO: other things in window.h that are supported by Surface::query // but not by BufferQueue::query } // TODO: queue under more complicated situations not involving just a single buffer -TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { +TEST_P(IGraphicBufferProducerTest, Queue_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int dequeuedSlot = -1; @@ -371,16 +404,21 @@ TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { EXPECT_EQ(DEFAULT_WIDTH, output.width); EXPECT_EQ(DEFAULT_HEIGHT, output.height); EXPECT_EQ(DEFAULT_TRANSFORM_HINT, output.transformHint); + // Since queueBuffer was called exactly once - EXPECT_EQ(1u, output.numPendingBuffers); - EXPECT_EQ(2u, output.nextFrameNumber); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/70041889): BufferHubProducer need to support metadata: numPendingBuffers + EXPECT_EQ(1u, output.numPendingBuffers); + // TODO(b/70041952): BufferHubProducer need to support metadata: nextFrameNumber + EXPECT_EQ(2u, output.nextFrameNumber); + } } // Buffer was not in the dequeued state EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output)); } -TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, Queue_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Invalid slot number @@ -463,15 +501,16 @@ TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { ASSERT_OK(mConsumer->consumerDisconnect()); // The buffer queue has been abandoned. - { + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. EXPECT_EQ(NO_INIT, mProducer->queueBuffer(dequeuedSlot, input, &output)); } } -TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { +TEST_P(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int dequeuedSlot = -1; @@ -488,7 +527,7 @@ TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { mProducer->cancelBuffer(dequeuedSlot, dequeuedFence); } -TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { +TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int minUndequeuedBuffers; ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, @@ -540,7 +579,7 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers-1)); } -TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { +TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int minUndequeuedBuffers; ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, @@ -578,12 +617,19 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { ASSERT_OK(mConsumer->consumerDisconnect()); // Fail because the buffer queue was abandoned - EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers)) - << "bufferCount: " << minBuffers; - + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers)) + << "bufferCount: " << minBuffers; + } } -TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { +TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { + if (GetParam() == USE_BUFFER_HUB_PRODUCER) { + // TODO(b/36724099): Add support for BufferHubProducer::setAsyncMode(true) + return; + } + ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1; ASSERT_NO_FATAL_FAILURE(ConnectProducer()); ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true; @@ -609,7 +655,7 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { } } -TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { +TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Fails) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Prerequisite to fail out a valid setBufferCount call { @@ -628,11 +674,13 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { ASSERT_OK(mConsumer->consumerDisconnect()); // Fail because the buffer queue was abandoned - EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " - << false; + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/36724099): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " << false; + } } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_dequeueBuffer) { int slot = -1; sp fence; @@ -642,15 +690,18 @@ TEST_F(IGraphicBufferProducerTest, TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)); } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_detachNextBuffer) { sp fence; sp buffer; - ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/38137191): Implement BufferHubProducer::detachBuffer + ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence)); + } } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_requestBuffer) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); @@ -674,7 +725,7 @@ TEST_F(IGraphicBufferProducerTest, } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_detachBuffer) { int slot = -1; sp fence; @@ -684,10 +735,13 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_OK(mProducer->disconnect(TEST_API)); - ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/38137191): Implement BufferHubProducer::detachBuffer + ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot)); + } } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_queueBuffer) { int slot = -1; sp fence; @@ -704,7 +758,7 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output)); } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_cancelBuffer) { int slot = -1; sp fence; @@ -717,7 +771,7 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, fence)); } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_attachBuffer) { int slot = -1; sp fence; @@ -725,11 +779,27 @@ TEST_F(IGraphicBufferProducerTest, setupDequeueRequestBuffer(&slot, &fence, &buffer); - ASSERT_OK(mProducer->detachBuffer(slot)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/38137191): Implement BufferHubProducer::detachBuffer + ASSERT_OK(mProducer->detachBuffer(slot)); + } ASSERT_OK(mProducer->disconnect(TEST_API)); - ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/69981968): Implement BufferHubProducer::attachBuffer + ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); + } } +#if USE_BUFFER_HUB_AS_BUFFER_QUEUE +INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest, + ::testing::Values(USE_BUFFER_QUEUE_PRODUCER, USE_BUFFER_HUB_PRODUCER)); +#else +// TODO(b/70046255): Remove the #ifdef here and always tests both backends once BufferHubQueue can +// pass all existing libgui tests. +INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest, + ::testing::Values(USE_BUFFER_QUEUE_PRODUCER)); +#endif + } // namespace android diff --git a/libs/gui/tests/SurfaceParcelable_test.cpp b/libs/gui/tests/SurfaceParcelable_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..686dc82f3e8e96201b8527b48b5d543c619797fb --- /dev/null +++ b/libs/gui/tests/SurfaceParcelable_test.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SurfaceParcelable_test" + +#include + +#include +#include +#include +#include +#include +#include + +namespace android { + +static const String16 kTestServiceName = String16("SurfaceParcelableTestService"); +static const String16 kSurfaceName = String16("TEST_SURFACE"); +static const uint32_t kBufferWidth = 100; +static const uint32_t kBufferHeight = 1; +static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; + +enum SurfaceParcelableTestServiceCode { + CREATE_BUFFER_QUEUE_SURFACE = IBinder::FIRST_CALL_TRANSACTION, + CREATE_BUFFER_HUB_SURFACE, +}; + +class SurfaceParcelableTestService : public BBinder { +public: + SurfaceParcelableTestService() { + // BufferQueue + BufferQueue::createBufferQueue(&mBufferQueueProducer, &mBufferQueueConsumer); + + // BufferHub + dvr::ProducerQueueConfigBuilder configBuilder; + mProducerQueue = dvr::ProducerQueue::Create(configBuilder.SetDefaultWidth(kBufferWidth) + .SetDefaultHeight(kBufferHeight) + .SetDefaultFormat(kBufferFormat) + .Build(), + dvr::UsagePolicy{}); + mBufferHubProducer = BufferHubProducer::Create(mProducerQueue); + } + + ~SurfaceParcelableTestService() = default; + + virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply, + uint32_t /*flags*/ = 0) { + switch (code) { + case CREATE_BUFFER_QUEUE_SURFACE: { + view::Surface surfaceShim; + surfaceShim.name = kSurfaceName; + surfaceShim.graphicBufferProducer = mBufferQueueProducer; + return surfaceShim.writeToParcel(reply); + } + case CREATE_BUFFER_HUB_SURFACE: { + view::Surface surfaceShim; + surfaceShim.name = kSurfaceName; + surfaceShim.graphicBufferProducer = mBufferHubProducer; + return surfaceShim.writeToParcel(reply); + } + default: + return UNKNOWN_TRANSACTION; + }; + } + +protected: + sp mBufferQueueProducer; + sp mBufferQueueConsumer; + + std::shared_ptr mProducerQueue; + sp mBufferHubProducer; +}; + +static int runBinderServer() { + ProcessState::self()->startThreadPool(); + + sp sm = defaultServiceManager(); + sp service = new SurfaceParcelableTestService; + sm->addService(kTestServiceName, service, false); + + ALOGI("Binder server running..."); + + while (true) { + int stat, retval; + retval = wait(&stat); + if (retval == -1 && errno == ECHILD) { + break; + } + } + + ALOGI("Binder server exiting..."); + return 0; +} + +class SurfaceParcelableTest : public ::testing::TestWithParam { +protected: + virtual void SetUp() { + mService = defaultServiceManager()->getService(kTestServiceName); + if (mService == nullptr) { + ALOGE("Failed to connect to the test service."); + return; + } + + ALOGI("Binder service is ready for client."); + } + + status_t GetSurface(view::Surface* surfaceShim) { + ALOGI("...Test: %d", GetParam()); + + uint32_t opCode = GetParam(); + Parcel data; + Parcel reply; + status_t error = mService->transact(opCode, data, &reply); + if (error != NO_ERROR) { + ALOGE("Failed to get surface over binder, error=%d.", error); + return error; + } + + error = surfaceShim->readFromParcel(&reply); + if (error != NO_ERROR) { + ALOGE("Failed to get surface from parcel, error=%d.", error); + return error; + } + + return NO_ERROR; + } + +private: + sp mService; +}; + +TEST_P(SurfaceParcelableTest, SendOverBinder) { + view::Surface surfaceShim; + EXPECT_EQ(GetSurface(&surfaceShim), NO_ERROR); + EXPECT_EQ(surfaceShim.name, kSurfaceName); + EXPECT_FALSE(surfaceShim.graphicBufferProducer == nullptr); +} + +INSTANTIATE_TEST_CASE_P(SurfaceBackends, SurfaceParcelableTest, + ::testing::Values(CREATE_BUFFER_QUEUE_SURFACE, CREATE_BUFFER_HUB_SURFACE)); + +} // namespace android + +int main(int argc, char** argv) { + pid_t pid = fork(); + if (pid == 0) { + android::ProcessState::self()->startThreadPool(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + + } else { + ALOGI("Test process pid: %d.", pid); + return android::runBinderServer(); + } +} diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index ca43c68f92e87146ce4231a7f8b26634063ad408..2c02ba657d6c9001acb9d22bb366cd1256eb728a 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -41,10 +42,16 @@ using namespace std::chrono_literals; // retrieve wide-color and hdr settings from configstore using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +using ui::ColorMode; + +using Transaction = SurfaceComposerClient::Transaction; static bool hasWideColorDisplay = getBool(false); +static bool hasHdrDisplay = + getBool(false); + class FakeSurfaceComposer; class FakeProducerFrameEventHistory; @@ -52,7 +59,6 @@ static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits::max(); class SurfaceTest : public ::testing::Test { protected: - SurfaceTest() { ProcessState::self()->startThreadPool(); } @@ -69,10 +75,10 @@ protected: ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff)); - ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); + Transaction t; + ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff) + .show(mSurfaceControl) + .apply()); mSurface = mSurfaceControl->getSurface(); ASSERT_TRUE(mSurface != NULL); @@ -87,6 +93,16 @@ protected: sp mSurfaceControl; }; +TEST_F(SurfaceTest, CreateSurfaceReturnsErrorBadClient) { + mComposerClient->dispose(); + ASSERT_EQ(NO_INIT, mComposerClient->initCheck()); + + sp sc; + status_t err = mComposerClient->createSurfaceChecked( + String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, &sc, 0); + ASSERT_EQ(NO_INIT, err); +} + TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) { sp anw(mSurface); int result = -123; @@ -114,14 +130,11 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp anw(mSurface); // Verify the screenshot works with no protected buffers. - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp cpuConsumer = new CpuConsumer(consumer, 1); sp sf(ComposerService::getComposerService()); sp display(sf->getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain)); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), + sp outBuffer; + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), 64, 64, 0, 0x7fffffff, false)); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), @@ -152,7 +165,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { &buf)); ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), 64, 64, 0, 0x7fffffff, false)); } @@ -295,6 +308,68 @@ TEST_F(SurfaceTest, GetWideColorSupport) { ASSERT_EQ(hasWideColorDisplay, supported); } +TEST_F(SurfaceTest, GetHdrSupport) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp surface = new Surface(producer); + sp window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + + bool supported; + status_t result = surface->getHdrSupport(&supported); + ASSERT_EQ(NO_ERROR, result); + + // NOTE: This is not a CTS test. + // This test verifies that when the BoardConfig TARGET_HAS_HDR_DISPLAY + // is TRUE, getHdrSupport is also true. + // TODO: Add check for an HDR color mode on the primary display. + ASSERT_EQ(hasHdrDisplay, supported); +} + +TEST_F(SurfaceTest, SetHdrMetadata) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp surface = new Surface(producer); + sp window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + + bool supported; + status_t result = surface->getHdrSupport(&supported); + ASSERT_EQ(NO_ERROR, result); + + if (!hasHdrDisplay || !supported) { + return; + } + const android_smpte2086_metadata smpte2086 = { + {0.680, 0.320}, + {0.265, 0.690}, + {0.150, 0.060}, + {0.3127, 0.3290}, + 100.0, + 0.1, + }; + const android_cta861_3_metadata cta861_3 = { + 78.0, + 62.0, + }; + int error = native_window_set_buffers_smpte2086_metadata(window.get(), &smpte2086); + ASSERT_EQ(error, NO_ERROR); + error = native_window_set_buffers_cta861_3_metadata(window.get(), &cta861_3); + ASSERT_EQ(error, NO_ERROR); +} + TEST_F(SurfaceTest, DynamicSetBufferCount) { sp producer; sp consumer; @@ -512,21 +587,26 @@ public: return NO_ERROR; } status_t getDisplayColorModes(const sp& /*display*/, - Vector* /*outColorModes*/) override { + Vector* /*outColorModes*/) override { return NO_ERROR; } - android_color_mode_t getActiveColorMode(const sp& /*display*/) + ColorMode getActiveColorMode(const sp& /*display*/) override { - return HAL_COLOR_MODE_NATIVE; + return ColorMode::NATIVE; } status_t setActiveColorMode(const sp& /*display*/, - android_color_mode_t /*colorMode*/) override { return NO_ERROR; } + ColorMode /*colorMode*/) override { return NO_ERROR; } status_t captureScreen(const sp& /*display*/, - const sp& /*producer*/, + sp* /*outBuffer*/, Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/, int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/, bool /*useIdentityTransform*/, Rotation /*rotation*/) override { return NO_ERROR; } + virtual status_t captureLayers(const sp& /*parentHandle*/, + sp* /*outBuffer*/, const Rect& /*sourceCrop*/, + float /*frameScale*/, bool /*childrenOnly*/) override { + return NO_ERROR; + } status_t clearAnimationFrameStats() override { return NO_ERROR; } status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { return NO_ERROR; @@ -800,7 +880,7 @@ protected: (iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame]; FrameEvents* newFrame = &mFrames[iNewFrame]; - uint64_t nOldFrame = iOldFrame + 1; + uint64_t nOldFrame = (iOldFrame == NO_FRAME_INDEX) ? 0 : iOldFrame + 1; uint64_t nNewFrame = iNewFrame + 1; // Latch, Composite, and Release the frames in a plausible order. diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp index 5ed3d3bebb4ea9b1664ff18819c08eb5b40378f9..d64dfd55be8aa7b14b186b876ad3bca004ef564f 100644 --- a/libs/gui/view/Surface.cpp +++ b/libs/gui/view/Surface.cpp @@ -45,10 +45,7 @@ status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const { if (res != OK) return res; } - res = parcel->writeStrongBinder( - IGraphicBufferProducer::asBinder(graphicBufferProducer)); - - return res; + return IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel); } status_t Surface::readFromParcel(const Parcel* parcel) { @@ -70,16 +67,7 @@ status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) { } } - sp binder; - - res = parcel->readNullableStrongBinder(&binder); - if (res != OK) { - ALOGE("%s: Can't read strong binder", __FUNCTION__); - return res; - } - - graphicBufferProducer = interface_cast(binder); - + graphicBufferProducer = IGraphicBufferProducer::createFromParcel(parcel); return OK; } diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 905d336bfe21835b564a2492cff8d3bd70c54e17..aa0bf17ca30defa81d923bb8c690fc3c322c9a22 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -99,34 +99,34 @@ size_t InputMessage::size() const { // --- InputChannel --- -InputChannel::InputChannel(const String8& name, int fd) : +InputChannel::InputChannel(const std::string& name, int fd) : mName(name), mFd(fd) { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel constructed: name='%s', fd=%d", - mName.string(), fd); + mName.c_str(), fd); #endif int result = fcntl(mFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket " - "non-blocking. errno=%d", mName.string(), errno); + "non-blocking. errno=%d", mName.c_str(), errno); } InputChannel::~InputChannel() { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel destroyed: name='%s', fd=%d", - mName.string(), mFd); + mName.c_str(), mFd); #endif ::close(mFd); } -status_t InputChannel::openInputChannelPair(const String8& name, +status_t InputChannel::openInputChannelPair(const std::string& name, sp& outServerChannel, sp& outClientChannel) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { status_t result = -errno; ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", - name.string(), errno); + name.c_str(), errno); outServerChannel.clear(); outClientChannel.clear(); return result; @@ -138,12 +138,12 @@ status_t InputChannel::openInputChannelPair(const String8& name, setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); - String8 serverChannelName = name; - serverChannelName.append(" (server)"); + std::string serverChannelName = name; + serverChannelName += " (server)"; outServerChannel = new InputChannel(serverChannelName, sockets[0]); - String8 clientChannelName = name; - clientChannelName.append(" (client)"); + std::string clientChannelName = name; + clientChannelName += " (client)"; outClientChannel = new InputChannel(clientChannelName, sockets[1]); return OK; } @@ -158,7 +158,7 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { if (nWrite < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(), + ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(), msg->header.type, error); #endif if (error == EAGAIN || error == EWOULDBLOCK) { @@ -173,13 +173,13 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { if (size_t(nWrite) != msgLength) { #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ error sending message type %d, send was incomplete", - mName.string(), msg->header.type); + mName.c_str(), msg->header.type); #endif return DEAD_OBJECT; } #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type); + ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type); #endif return OK; } @@ -193,7 +193,7 @@ status_t InputChannel::receiveMessage(InputMessage* msg) { if (nRead < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno); + ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno); #endif if (error == EAGAIN || error == EWOULDBLOCK) { return WOULD_BLOCK; @@ -206,20 +206,20 @@ status_t InputChannel::receiveMessage(InputMessage* msg) { if (nRead == 0) { // check for EOF #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string()); + ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str()); #endif return DEAD_OBJECT; } if (!msg->isValid(nRead)) { #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received invalid message", mName.string()); + ALOGD("channel '%s' ~ received invalid message", mName.c_str()); #endif return BAD_VALUE; } #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type); + ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type); #endif return OK; } @@ -254,8 +254,8 @@ status_t InputPublisher::publishKeyEvent( #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d," - "downTime=%lld, eventTime=%lld", - mChannel->getName().string(), seq, + "downTime=%" PRId64 ", eventTime=%" PRId64, + mChannel->getName().c_str(), seq, deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, downTime, eventTime); #endif @@ -305,9 +305,9 @@ status_t InputPublisher::publishMotionEvent( ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, " "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, " - "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " + "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", " "pointerCount=%" PRIu32, - mChannel->getName().string(), seq, + mChannel->getName().c_str(), seq, deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); #endif @@ -319,7 +319,7 @@ status_t InputPublisher::publishMotionEvent( if (pointerCount > MAX_POINTERS || pointerCount < 1) { ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".", - mChannel->getName().string(), pointerCount); + mChannel->getName().c_str(), pointerCount); return BAD_VALUE; } @@ -352,7 +352,7 @@ status_t InputPublisher::publishMotionEvent( status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ receiveFinishedSignal", - mChannel->getName().string()); + mChannel->getName().c_str()); #endif InputMessage msg; @@ -364,7 +364,7 @@ status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandle } if (msg.header.type != InputMessage::TYPE_FINISHED) { ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer", - mChannel->getName().string(), msg.header.type); + mChannel->getName().c_str(), msg.header.type); return UNKNOWN_ERROR; } *outSeq = msg.body.finished.seq; @@ -401,8 +401,8 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) { #if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld", - mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime); + ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64, + mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime); #endif *outSeq = 0; @@ -426,7 +426,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, if (*outEvent) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } @@ -445,7 +445,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, *outEvent = keyEvent; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed key event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } @@ -458,7 +458,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ appended to batch event", - mChannel->getName().string()); + mChannel->getName().c_str()); #endif break; } else { @@ -474,7 +474,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event and " "deferred current event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } @@ -488,7 +488,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ started batch event", - mChannel->getName().string()); + mChannel->getName().c_str()); #endif break; } @@ -503,14 +503,14 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, *displayId = mMsg.body.motion.displayId; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u", - mChannel->getName().string(), *outSeq); + mChannel->getName().c_str(), *outSeq); #endif break; } default: ALOGE("channel '%s' consumer ~ Received unexpected message of type %d", - mChannel->getName().string(), mMsg.header.type); + mChannel->getName().c_str(), mMsg.header.type); return UNKNOWN_ERROR; } } @@ -841,7 +841,7 @@ bool InputConsumer::shouldResampleTool(int32_t toolType) { status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s", - mChannel->getName().string(), seq, handled ? "true" : "false"); + mChannel->getName().c_str(), seq, handled ? "true" : "false"); #endif if (!seq) { diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 0627ca6d6f44b1fdeafd2337ac08839abfb39d49..cba11116061c9e8bbdfa707a106e293bfd3c45e0 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -824,6 +824,9 @@ status_t KeyCharacterMap::Parser::parseType() { } else if (typeToken == "FULL") { type = KEYBOARD_TYPE_FULL; } else if (typeToken == "SPECIAL_FUNCTION") { + ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set " + "the property 'keyboard.specialFunction' to '1' there instead."); + // TODO: return BAD_VALUE here in Q type = KEYBOARD_TYPE_SPECIAL_FUNCTION; } else if (typeToken == "OVERLAY") { type = KEYBOARD_TYPE_OVERLAY; diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index 07f22897858bcfc303137b316a22e3c105df3a13..11842ee7ffe206168ba82e2c7ec1170582274133 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -148,9 +148,19 @@ String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier, // --- Global functions --- +bool isKeyboardSpecialFunction(const PropertyMap* config) { + if (config == nullptr) { + return false; + } + bool isSpecialFunction = false; + config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction); + return isSpecialFunction; +} + bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration, const KeyMap* keyMap) { - if (!keyMap->haveKeyCharacterMap() + // TODO: remove the third OR statement (SPECIAL_FUNCTION) in Q + if (!keyMap->haveKeyCharacterMap() || isKeyboardSpecialFunction(deviceConfiguration) || keyMap->keyCharacterMap->getKeyboardType() == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) { return false; diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 62acea360e23233593abed861eb7f27c2f87d7e7..c07a81245a13759bfc42e75a5d42b2a51e2b31e2 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -75,7 +75,9 @@ static std::string vectorToString(const float* a, uint32_t m) { str += " ]"; return str; } +#endif +#if DEBUG_STRATEGY static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { std::string str; str = "["; @@ -141,6 +143,11 @@ bool VelocityTracker::configureStrategy(const char* strategy) { } VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) { + if (!strcmp("impulse", strategy)) { + // Physical model of pushing an object. Quality: VERY GOOD. + // Works with duplicate coordinates, unclean finger liftoff. + return new ImpulseVelocityTrackerStrategy(); + } if (!strcmp("lsq1", strategy)) { // 1st order least squares. Quality: POOR. // Frequently underfits the touch data especially when the finger accelerates @@ -318,8 +325,8 @@ void VelocityTracker::addMovement(const MotionEvent* event) { eventTime = event->getHistoricalEventTime(h); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; - positions[index].x = event->getHistoricalX(i, h); - positions[index].y = event->getHistoricalY(i, h); + positions[index].x = event->getHistoricalRawX(i, h); + positions[index].y = event->getHistoricalRawY(i, h); } addMovement(eventTime, idBits, positions); } @@ -327,8 +334,8 @@ void VelocityTracker::addMovement(const MotionEvent* event) { eventTime = event->getEventTime(); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; - positions[index].x = event->getX(i); - positions[index].y = event->getY(i); + positions[index].x = event->getRawX(i); + positions[index].y = event->getRawY(i); } addMovement(eventTime, idBits, positions); } @@ -352,9 +359,6 @@ bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const { // --- LeastSquaresVelocityTrackerStrategy --- -const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON; -const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE; - LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy( uint32_t degree, Weighting weighting) : mDegree(degree), mWeighting(weighting) { @@ -863,10 +867,6 @@ void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, // --- LegacyVelocityTrackerStrategy --- -const nsecs_t LegacyVelocityTrackerStrategy::HORIZON; -const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE; -const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION; - LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() { clear(); } @@ -979,4 +979,194 @@ bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, return true; } +// --- ImpulseVelocityTrackerStrategy --- + +ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() { + clear(); +} + +ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() { +} + +void ImpulseVelocityTrackerStrategy::clear() { + mIndex = 0; + mMovements[0].idBits.clear(); +} + +void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { + BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); + mMovements[mIndex].idBits = remainingIdBits; +} + +void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, + const VelocityTracker::Position* positions) { + if (++mIndex == HISTORY_SIZE) { + mIndex = 0; + } + + Movement& movement = mMovements[mIndex]; + movement.eventTime = eventTime; + movement.idBits = idBits; + uint32_t count = idBits.count(); + for (uint32_t i = 0; i < count; i++) { + movement.positions[i] = positions[i]; + } +} + +/** + * Calculate the total impulse provided to the screen and the resulting velocity. + * + * The touchscreen is modeled as a physical object. + * Initial condition is discussed below, but for now suppose that v(t=0) = 0 + * + * The kinetic energy of the object at the release is E=0.5*m*v^2 + * Then vfinal = sqrt(2E/m). The goal is to calculate E. + * + * The kinetic energy at the release is equal to the total work done on the object by the finger. + * The total work W is the sum of all dW along the path. + * + * dW = F*dx, where dx is the piece of path traveled. + * Force is change of momentum over time, F = dp/dt = m dv/dt. + * Then substituting: + * dW = m (dv/dt) * dx = m * v * dv + * + * Summing along the path, we get: + * W = sum(dW) = sum(m * v * dv) = m * sum(v * dv) + * Since the mass stays constant, the equation for final velocity is: + * vfinal = sqrt(2*sum(v * dv)) + * + * Here, + * dv : change of velocity = (v[i+1]-v[i]) + * dx : change of distance = (x[i+1]-x[i]) + * dt : change of time = (t[i+1]-t[i]) + * v : instantaneous velocity = dx/dt + * + * The final formula is: + * vfinal = sqrt(2) * sqrt(sum((v[i]-v[i-1])*|v[i]|)) for all i + * The absolute value is needed to properly account for the sign. If the velocity over a + * particular segment descreases, then this indicates braking, which means that negative + * work was done. So for two positive, but decreasing, velocities, this contribution would be + * negative and will cause a smaller final velocity. + * + * Initial condition + * There are two ways to deal with initial condition: + * 1) Assume that v(0) = 0, which would mean that the screen is initially at rest. + * This is not entirely accurate. We are only taking the past X ms of touch data, where X is + * currently equal to 100. However, a touch event that created a fling probably lasted for longer + * than that, which would mean that the user has already been interacting with the touchscreen + * and it has probably already been moving. + * 2) Assume that the touchscreen has already been moving at a certain velocity, calculate this + * initial velocity and the equivalent energy, and start with this initial energy. + * Consider an example where we have the following data, consisting of 3 points: + * time: t0, t1, t2 + * x : x0, x1, x2 + * v : 0 , v1, v2 + * Here is what will happen in each of these scenarios: + * 1) By directly applying the formula above with the v(0) = 0 boundary condition, we will get + * vfinal = sqrt(2*(|v1|*(v1-v0) + |v2|*(v2-v1))). This can be simplified since v0=0 + * vfinal = sqrt(2*(|v1|*v1 + |v2|*(v2-v1))) = sqrt(2*(v1^2 + |v2|*(v2 - v1))) + * since velocity is a real number + * 2) If we treat the screen as already moving, then it must already have an energy (per mass) + * equal to 1/2*v1^2. Then the initial energy should be 1/2*v1*2, and only the second segment + * will contribute to the total kinetic energy (since we can effectively consider that v0=v1). + * This will give the following expression for the final velocity: + * vfinal = sqrt(2*(1/2*v1^2 + |v2|*(v2-v1))) + * This analysis can be generalized to an arbitrary number of samples. + * + * + * Comparing the two equations above, we see that the only mathematical difference + * is the factor of 1/2 in front of the first velocity term. + * This boundary condition would allow for the "proper" calculation of the case when all of the + * samples are equally spaced in time and distance, which should suggest a constant velocity. + * + * Note that approach 2) is sensitive to the proper ordering of the data in time, since + * the boundary condition must be applied to the oldest sample to be accurate. + */ +static float kineticEnergyToVelocity(float work) { + static constexpr float sqrt2 = 1.41421356237; + return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2; +} + +static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) { + // The input should be in reversed time order (most recent sample at index i=0) + // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function + static constexpr float SECONDS_PER_NANO = 1E-9; + + if (count < 2) { + return 0; // if 0 or 1 points, velocity is zero + } + if (t[1] > t[0]) { // Algorithm will still work, but not perfectly + ALOGE("Samples provided to calculateImpulseVelocity in the wrong order"); + } + if (count == 2) { // if 2 points, basic linear calculation + if (t[1] == t[0]) { + ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]); + return 0; + } + return (x[1] - x[0]) / (SECONDS_PER_NANO * (t[1] - t[0])); + } + // Guaranteed to have at least 3 points here + float work = 0; + for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time + if (t[i] == t[i-1]) { + ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]); + continue; + } + float vprev = kineticEnergyToVelocity(work); // v[i-1] + float vcurr = (x[i] - x[i-1]) / (SECONDS_PER_NANO * (t[i] - t[i-1])); // v[i] + work += (vcurr - vprev) * fabsf(vcurr); + if (i == count - 1) { + work *= 0.5; // initial condition, case 2) above + } + } + return kineticEnergyToVelocity(work); +} + +bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id, + VelocityTracker::Estimator* outEstimator) const { + outEstimator->clear(); + + // Iterate over movement samples in reverse time order and collect samples. + float x[HISTORY_SIZE]; + float y[HISTORY_SIZE]; + nsecs_t time[HISTORY_SIZE]; + size_t m = 0; // number of points that will be used for fitting + size_t index = mIndex; + const Movement& newestMovement = mMovements[mIndex]; + do { + const Movement& movement = mMovements[index]; + if (!movement.idBits.hasBit(id)) { + break; + } + + nsecs_t age = newestMovement.eventTime - movement.eventTime; + if (age > HORIZON) { + break; + } + + const VelocityTracker::Position& position = movement.getPosition(id); + x[m] = position.x; + y[m] = position.y; + time[m] = movement.eventTime; + index = (index == 0 ? HISTORY_SIZE : index) - 1; + } while (++m < HISTORY_SIZE); + + if (m == 0) { + return false; // no data + } + outEstimator->xCoeff[0] = 0; + outEstimator->yCoeff[0] = 0; + outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m); + outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m); + outEstimator->xCoeff[2] = 0; + outEstimator->yCoeff[2] = 0; + outEstimator->time = newestMovement.eventTime; + outEstimator->degree = 2; // similar results to 2nd degree fit + outEstimator->confidence = 1; +#if DEBUG_STRATEGY + ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]); +#endif + return true; +} + } // namespace android diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 8137e3dbf6f736f88fb2f3ce4efa042152d9bc82..aca9521c76d318640a75087cae267954167d839b 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -6,6 +6,7 @@ cc_test { "InputChannel_test.cpp", "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", + "VelocityTracker_test.cpp", ], cflags: [ "-Wall", @@ -19,6 +20,7 @@ cc_test { "libutils", "libbinder", "libui", + "libbase", ] } diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp index e71ebe2a1d677acb36263c1da1e8a8ca4e3e0940..96c165cac2b1743b6820338e414dd9a0998b9b29 100644 --- a/libs/input/tests/InputChannel_test.cpp +++ b/libs/input/tests/InputChannel_test.cpp @@ -41,9 +41,9 @@ TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptor // of a pipe and to check for EPIPE on the other end after the channel is destroyed. Pipe pipe; - sp inputChannel = new InputChannel(String8("channel name"), pipe.sendFd); + sp inputChannel = new InputChannel("channel name", pipe.sendFd); - EXPECT_STREQ("channel name", inputChannel->getName().string()) + EXPECT_STREQ("channel name", inputChannel->getName().c_str()) << "channel should have provided name"; EXPECT_EQ(pipe.sendFd, inputChannel->getFd()) << "channel should have provided fd"; @@ -60,16 +60,16 @@ TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptor TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { sp serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; // Name - EXPECT_STREQ("channel name (server)", serverChannel->getName().string()) + EXPECT_STREQ("channel name (server)", serverChannel->getName().c_str()) << "server channel should have suffixed name"; - EXPECT_STREQ("channel name (client)", clientChannel->getName().string()) + EXPECT_STREQ("channel name (client)", clientChannel->getName().c_str()) << "client channel should have suffixed name"; // Server->Client communication @@ -111,7 +111,7 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) { sp serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) @@ -125,7 +125,7 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) { TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { sp serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) @@ -141,7 +141,7 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) { TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) { sp serverChannel, clientChannel; - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); ASSERT_EQ(OK, result) diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 34c52d03d1813e7389674adb9c7ee750a33f06e1..c5322414fdda3fc08089234d26c087cfd4f8e60b 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -36,7 +36,7 @@ protected: PreallocatedInputEventFactory mEventFactory; virtual void SetUp() { - status_t result = InputChannel::openInputChannelPair(String8("channel name"), + status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); mPublisher = new InputPublisher(serverChannel); @@ -254,19 +254,36 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) { ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); } +TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) { + status_t status; + const size_t pointerCount = 1; + PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } + + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); + ASSERT_EQ(BAD_VALUE, status) + << "publisher publishMotionEvent should return BAD_VALUE"; +} + TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) { status_t status; const size_t pointerCount = 0; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } -TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) { +TEST_F(InputPublisherAndConsumerTest, + PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) { status_t status; const size_t pointerCount = MAX_POINTERS + 1; PointerProperties pointerProperties[pointerCount]; @@ -276,7 +293,7 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43b6012e0dd807344ec61434c3f6299963ba1f62 --- /dev/null +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VelocityTracker_test" + +#include + +#include +#include +#include