Merge "Revert "Adds out parameters for crop rectangle and transform""
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 021fdb5..9a8ec32 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -126,7 +126,6 @@
{ "aidl", "AIDL calls", ATRACE_TAG_AIDL, { } },
{ "nnapi", "NNAPI", ATRACE_TAG_NNAPI, { } },
{ "rro", "Runtime Resource Overlay", ATRACE_TAG_RRO, { } },
- { "sysprop", "System Property", ATRACE_TAG_SYSPROP, { } },
{ k_coreServiceCategory, "Core services", 0, { } },
{ k_pdxServiceCategory, "PDX services", 0, { } },
{ "sched", "CPU Scheduling", 0, {
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 37fc9a9..e3c4ede 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -266,7 +266,10 @@
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu15/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu15/trace
-on post-fs-data
+# Only create the tracing instance if persist.mm_events.enabled
+# Attempting to remove the tracing instance after it has been created
+# will likely fail with EBUSY as it would be in use by traced_probes.
+on post-fs-data && property:persist.mm_events.enabled=true
# Create MM Events Tracing Instance for Kmem Activity Trigger
mkdir /sys/kernel/debug/tracing/instances/mm_events 0755 system system
mkdir /sys/kernel/tracing/instances/mm_events 0755 system system
@@ -275,10 +278,18 @@
chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/buffer_size_kb
chmod 0666 /sys/kernel/tracing/instances/mm_events/buffer_size_kb
+# Set the default buffer size to the minimum
+ write /sys/kernel/debug/tracing/instances/mm_events/buffer_size_kb 1
+ write /sys/kernel/tracing/instances/mm_events/buffer_size_kb 1
+
# Read and enable tracing
chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/tracing_on
chmod 0666 /sys/kernel/tracing/instances/mm_events/tracing_on
+# Tracing disabled by default
+ write /sys/kernel/debug/tracing/instances/mm_events/tracing_on 0
+ write /sys/kernel/tracing/instances/mm_events/tracing_on 0
+
# Read and truncate kernel trace
chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/trace
chmod 0666 /sys/kernel/tracing/instances/mm_events/trace
diff --git a/cmds/cmd/fuzzer/Android.bp b/cmds/cmd/fuzzer/Android.bp
new file mode 100644
index 0000000..8262bc2
--- /dev/null
+++ b/cmds/cmd/fuzzer/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_cmds_cmd_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_cmds_cmd_license"],
+}
+
+cc_fuzz {
+ name: "cmd_fuzzer",
+ srcs: [
+ "cmd_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libcmd",
+ "libutils",
+ "liblog",
+ "libselinux",
+ ],
+ shared_libs: [
+ "libbinder",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/cmds/cmd/fuzzer/README.md b/cmds/cmd/fuzzer/README.md
new file mode 100644
index 0000000..db37ece
--- /dev/null
+++ b/cmds/cmd/fuzzer/README.md
@@ -0,0 +1,51 @@
+# Fuzzer for libcmd_fuzzer
+
+## Plugin Design Considerations
+The fuzzer plugin for libcmd is designed based on the understanding of the library and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+libcmd supports the following parameters:
+1. In (parameter name: `in`)
+2. Out (parameter name: `out`)
+3. Err (parameter name: `err`)
+4. Run Mode (parameter name: `runMode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `in` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider|
+| `out` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider|
+| `err` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider|
+| `runMode` | 1.`RunMode::kStandalone` 2. `RunMode::kLibrary` | Value chosen from valid values using FuzzedDataProvider|
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the cmd module.
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build cmd_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) cmd_fuzzer
+```
+#### Steps to run
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/${TARGET_ARCH}/cmd_fuzzer/cmd_fuzzer
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/cmds/cmd/fuzzer/cmd_fuzzer.cpp b/cmds/cmd/fuzzer/cmd_fuzzer.cpp
new file mode 100644
index 0000000..ab514a1
--- /dev/null
+++ b/cmds/cmd/fuzzer/cmd_fuzzer.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/TextOutput.h>
+#include <cmd.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+using namespace std;
+using namespace android;
+
+class TestTextOutput : public TextOutput {
+public:
+ TestTextOutput() {}
+ virtual ~TestTextOutput() {}
+
+ virtual status_t print(const char* /*txt*/, size_t /*len*/) { return NO_ERROR; }
+ virtual void moveIndent(int /*delta*/) { return; }
+ virtual void pushBundle() { return; }
+ virtual void popBundle() { return; }
+};
+
+class CmdFuzzer {
+public:
+ void process(const uint8_t* data, size_t size);
+
+private:
+ FuzzedDataProvider* mFDP = nullptr;
+};
+
+void CmdFuzzer::process(const uint8_t* data, size_t size) {
+ mFDP = new FuzzedDataProvider(data, size);
+ vector<string> arguments;
+ if (mFDP->ConsumeBool()) {
+ if (mFDP->ConsumeBool()) {
+ arguments = {"-w", "media.aaudio"};
+ } else {
+ arguments = {"-l"};
+ }
+ } else {
+ while (mFDP->remaining_bytes() > 0) {
+ size_t sizestr = mFDP->ConsumeIntegralInRange<size_t>(1, mFDP->remaining_bytes());
+ string argument = mFDP->ConsumeBytesAsString(sizestr);
+ arguments.emplace_back(argument);
+ }
+ }
+ vector<string_view> argSV;
+ for (auto& argument : arguments) {
+ argSV.emplace_back(argument.c_str());
+ }
+ int32_t in = open("/dev/null", O_RDWR | O_CREAT);
+ int32_t out = open("/dev/null", O_RDWR | O_CREAT);
+ int32_t err = open("/dev/null", O_RDWR | O_CREAT);
+ TestTextOutput output;
+ TestTextOutput error;
+ RunMode runMode = mFDP->ConsumeBool() ? RunMode::kStandalone : RunMode::kLibrary;
+ cmdMain(argSV, output, error, in, out, err, runMode);
+ delete mFDP;
+ close(in);
+ close(out);
+ close(err);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ CmdFuzzer cmdFuzzer;
+ cmdFuzzer.process(data, size);
+ return 0;
+}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 2d11b90..75505f3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1237,7 +1237,7 @@
std::string path(title);
path.append(" - ").append(String8(service).c_str());
size_t bytes_written = 0;
- status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
+ status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
if (status == OK) {
dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
std::chrono::duration<double> elapsed_seconds;
@@ -1316,7 +1316,7 @@
path.append("_HIGH");
}
path.append(kProtoExt);
- status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
+ status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
if (status == OK) {
status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
bool dumpTerminated = (status == OK);
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 83a52b8..f8fdaa0 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -62,13 +62,14 @@
"usage: dumpsys\n"
" To dump all services.\n"
"or:\n"
- " dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--thread] [--help | -l | "
- "--skip SERVICES "
+ " dumpsys [-t TIMEOUT] [--priority LEVEL] [--dump] [--pid] [--thread] [--help | "
+ "-l | --skip SERVICES "
"| SERVICE [ARGS]]\n"
" --help: shows this help\n"
" -l: only list services, do not dump them\n"
" -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
" -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
+ " --dump: ask the service to dump itself (this is the default)\n"
" --pid: dump PID instead of usual dump\n"
" --proto: filter services that support dumping data in proto format. Dumps\n"
" will be in proto format.\n"
@@ -127,10 +128,11 @@
bool showListOnly = false;
bool skipServices = false;
bool asProto = false;
- Type type = Type::DUMP;
+ int dumpTypeFlags = 0;
int timeoutArgMs = 10000;
int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
static struct option longOptions[] = {{"help", no_argument, 0, 0},
+ {"dump", no_argument, 0, 0},
{"pid", no_argument, 0, 0},
{"priority", required_argument, 0, 0},
{"proto", no_argument, 0, 0},
@@ -168,12 +170,14 @@
usage();
return -1;
}
+ } else if (!strcmp(longOptions[optionIndex].name, "dump")) {
+ dumpTypeFlags |= TYPE_DUMP;
} else if (!strcmp(longOptions[optionIndex].name, "pid")) {
- type = Type::PID;
+ dumpTypeFlags |= TYPE_PID;
} else if (!strcmp(longOptions[optionIndex].name, "stability")) {
- type = Type::STABILITY;
+ dumpTypeFlags |= TYPE_STABILITY;
} else if (!strcmp(longOptions[optionIndex].name, "thread")) {
- type = Type::THREAD;
+ dumpTypeFlags |= TYPE_THREAD;
}
break;
@@ -211,6 +215,10 @@
}
}
+ if (dumpTypeFlags == 0) {
+ dumpTypeFlags = TYPE_DUMP;
+ }
+
for (int i = optind; i < argc; i++) {
if (skipServices) {
skippedServices.add(String16(argv[i]));
@@ -263,7 +271,7 @@
const String16& serviceName = services[i];
if (IsSkipped(skippedServices, serviceName)) continue;
- if (startDumpThread(type, serviceName, args) == OK) {
+ if (startDumpThread(dumpTypeFlags, serviceName, args) == OK) {
bool addSeparator = (N > 1);
if (addSeparator) {
writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags);
@@ -330,18 +338,21 @@
}
}
-static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd) {
+static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd, bool exclusive) {
pid_t pid;
status_t status = service->getDebugPid(&pid);
if (status != OK) {
return status;
}
+ if (!exclusive) {
+ WriteStringToFd("Service host process PID: ", fd.get());
+ }
WriteStringToFd(std::to_string(pid) + "\n", fd.get());
return OK;
}
static status_t dumpStabilityToFd(const sp<IBinder>& service, const unique_fd& fd) {
- WriteStringToFd(internal::Stability::debugToString(service) + "\n", fd);
+ WriteStringToFd("Stability: " + internal::Stability::debugToString(service) + "\n", fd);
return OK;
}
@@ -362,7 +373,14 @@
return OK;
}
-status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
+static void reportDumpError(const String16& serviceName, status_t error, const char* context) {
+ if (error == OK) return;
+
+ std::cerr << "Error with service '" << serviceName << "' while " << context << ": "
+ << statusToString(error) << std::endl;
+}
+
+status_t Dumpsys::startDumpThread(int dumpTypeFlags, const String16& serviceName,
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);
if (service == nullptr) {
@@ -383,29 +401,23 @@
// dump blocks until completion, so spawn a thread..
activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
- status_t err = 0;
-
- switch (type) {
- case Type::DUMP:
- err = service->dump(remote_end.get(), args);
- break;
- case Type::PID:
- err = dumpPidToFd(service, remote_end);
- break;
- case Type::STABILITY:
- err = dumpStabilityToFd(service, remote_end);
- break;
- case Type::THREAD:
- err = dumpThreadsToFd(service, remote_end);
- break;
- default:
- std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl;
- return;
+ if (dumpTypeFlags & TYPE_PID) {
+ status_t err = dumpPidToFd(service, remote_end, dumpTypeFlags == TYPE_PID);
+ reportDumpError(serviceName, err, "dumping PID");
+ }
+ if (dumpTypeFlags & TYPE_STABILITY) {
+ status_t err = dumpStabilityToFd(service, remote_end);
+ reportDumpError(serviceName, err, "dumping stability");
+ }
+ if (dumpTypeFlags & TYPE_THREAD) {
+ status_t err = dumpThreadsToFd(service, remote_end);
+ reportDumpError(serviceName, err, "dumping thread info");
}
- if (err != OK) {
- std::cerr << "Error dumping service info status_t: " << statusToString(err) << " "
- << serviceName << std::endl;
+ // other types always act as a header, this is usually longer
+ if (dumpTypeFlags & TYPE_DUMP) {
+ status_t err = service->dump(remote_end.get(), args);
+ reportDumpError(serviceName, err, "dumping");
}
});
return OK;
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 1b3ae6a..05c5d5e 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -51,24 +51,25 @@
*/
static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
- enum class Type {
- DUMP, // dump using `dump` function
- PID, // dump pid of server only
- STABILITY, // dump stability information of server
- THREAD, // dump thread usage of server only
+ enum Type {
+ TYPE_DUMP = 0x1, // dump using `dump` function
+ TYPE_PID = 0x2, // dump pid of server only
+ TYPE_STABILITY = 0x4, // dump stability information of server
+ TYPE_THREAD = 0x8, // dump thread usage of server only
};
/**
* Starts a thread to connect to a service and get its dump output. The thread redirects
* the output to a pipe. Thread must be stopped by a subsequent call to {@code
* stopDumpThread}.
+ * @param dumpTypeFlags operations to perform
* @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(Type type, const String16& serviceName,
+ status_t startDumpThread(int dumpTypeFlags, const String16& serviceName,
const Vector<String16>& args);
/**
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 277f445..312f4d7 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -200,7 +200,7 @@
CaptureStdout();
CaptureStderr();
dump_.setServiceArgs(args, supportsProto, priorityFlags);
- status_t status = dump_.startDumpThread(Dumpsys::Type::DUMP, serviceName, args);
+ status_t status = dump_.startDumpThread(Dumpsys::TYPE_DUMP, serviceName, args);
EXPECT_THAT(status, Eq(0));
status = dump_.writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(500), false,
elapsedDuration, bytesWritten);
@@ -627,6 +627,28 @@
AssertOutputFormat(format);
}
+// Tests 'dumpsys --thread --stability'
+TEST_F(DumpsysTest, ListAllServicesWithMultipleOptions) {
+ ExpectListServices({"Locksmith", "Valet"});
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet");
+
+ CallMain({"--pid", "--stability"});
+ AssertRunningServices({"Locksmith", "Valet"});
+
+ AssertOutputContains(std::to_string(getpid()));
+ AssertOutputContains("stability");
+}
+
+// Tests 'dumpsys --pid --stability service_name'
+TEST_F(DumpsysTest, ListServiceWithMultipleOptions) {
+ ExpectCheckService("Locksmith");
+ CallMain({"--pid", "--stability", "Locksmith"});
+
+ AssertOutputContains(std::to_string(getpid()));
+ AssertOutputContains("stability");
+}
+
TEST_F(DumpsysTest, GetBytesWritten) {
const char* serviceName = "service2";
const char* dumpContents = "dump1";
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index ec3bc61..c18d3f5 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -24,7 +24,7 @@
cc_defaults {
name: "idlcli-defaults",
shared_libs: [
- "android.hardware.vibrator-V2-ndk_platform",
+ "android.hardware.vibrator-V2-ndk",
"android.hardware.vibrator@1.0",
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 2722e21..ff73c94 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -28,6 +28,7 @@
#include <sstream>
#include <android-base/file.h>
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl-hash/Hash.h>
@@ -691,8 +692,7 @@
}
auto&& hashArray = hashChain[hashIndex];
- std::vector<uint8_t> hashVec{hashArray.data(), hashArray.data() + hashArray.size()};
- entry->hash = Hash::hexString(hashVec);
+ entry->hash = android::base::HexString(hashArray.data(), hashArray.size());
});
if (!hashRet.isOk()) {
handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
index 8e21975..1753343 100644
--- a/cmds/lshal/TableEntry.cpp
+++ b/cmds/lshal/TableEntry.cpp
@@ -18,6 +18,7 @@
#include <map>
+#include <android-base/hex.h>
#include <android-base/strings.h>
#include <hidl-hash/Hash.h>
#include <vintf/parse_string.h>
@@ -104,7 +105,8 @@
}
std::string TableEntry::isReleased() const {
- static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
+ static const std::string unreleased = android::base::HexString(Hash::kEmptyHash.data(),
+ Hash::kEmptyHash.size());
if (hash.empty()) {
return "?";
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 29d4409..a177027 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -52,6 +52,7 @@
BackgroundBlurRadiusChange background_blur_radius = 20;
ShadowRadiusChange shadow_radius = 21;
BlurRegionsChange blur_regions = 22;
+ TrustedOverlayChange trusted_overlay = 23;
}
}
@@ -197,6 +198,10 @@
required float radius = 1;
}
+message TrustedOverlayChange {
+ required float is_trusted_overlay = 1;
+}
+
message BlurRegionsChange {
repeated BlurRegionChange blur_regions = 1;
}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 9d88ca6..c0cbad8 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -14,3 +14,11 @@
src: "android.hardware.biometrics.face.xml",
filename_from_src: true,
}
+
+prebuilt_etc {
+ name: "android.software.app_compat_overrides.xml",
+ product_specific: true,
+ sub_dir: "permissions",
+ src: "android.software.app_compat_overrides.xml",
+ filename_from_src: true,
+}
diff --git a/data/etc/android.software.app_compat_overrides.xml b/data/etc/android.software.app_compat_overrides.xml
new file mode 100644
index 0000000..2f9726a
--- /dev/null
+++ b/data/etc/android.software.app_compat_overrides.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Feature for devices that are opted-in to receive per-app compatibility
+ overrides. -->
+<permissions>
+ <feature name="android.software.app_compat_overrides" />
+</permissions>
diff --git a/docs/Doxyfile b/docs/Doxyfile
index a1bd960..ea22337 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -1638,6 +1638,7 @@
"__attribute__(x)=" \
__ANDROID__ \
__BIONIC__ \
+ "U_IN_DOXYGEN=1" \ # Required by the ICU4C module only
# 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/include/android/input.h b/include/android/input.h
index bb98beb..f03facb 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -169,6 +169,9 @@
/** Drag event */
AINPUT_EVENT_TYPE_DRAG = 5,
+
+ /** TouchMode event */
+ AINPUT_EVENT_TYPE_TOUCH_MODE = 6,
};
/**
diff --git a/include/input/Input.h b/include/input/Input.h
index cd9b486..2e42409 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -886,6 +886,25 @@
float mX, mY;
};
+/*
+ * Touch mode events.
+ */
+class TouchModeEvent : public InputEvent {
+public:
+ virtual ~TouchModeEvent() {}
+
+ virtual int32_t getType() const override { return AINPUT_EVENT_TYPE_TOUCH_MODE; }
+
+ inline bool isInTouchMode() const { return mIsInTouchMode; }
+
+ void initialize(int32_t id, bool isInTouchMode);
+
+ void initialize(const TouchModeEvent& from);
+
+protected:
+ bool mIsInTouchMode;
+};
+
/**
* Base class for verified events.
* Do not create a VerifiedInputEvent explicitly.
@@ -950,6 +969,7 @@
virtual FocusEvent* createFocusEvent() = 0;
virtual CaptureEvent* createCaptureEvent() = 0;
virtual DragEvent* createDragEvent() = 0;
+ virtual TouchModeEvent* createTouchModeEvent() = 0;
};
/*
@@ -966,6 +986,7 @@
virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; }
virtual CaptureEvent* createCaptureEvent() override { return &mCaptureEvent; }
virtual DragEvent* createDragEvent() override { return &mDragEvent; }
+ virtual TouchModeEvent* createTouchModeEvent() override { return &mTouchModeEvent; }
private:
KeyEvent mKeyEvent;
@@ -973,6 +994,7 @@
FocusEvent mFocusEvent;
CaptureEvent mCaptureEvent;
DragEvent mDragEvent;
+ TouchModeEvent mTouchModeEvent;
};
/*
@@ -988,6 +1010,7 @@
virtual FocusEvent* createFocusEvent() override;
virtual CaptureEvent* createCaptureEvent() override;
virtual DragEvent* createDragEvent() override;
+ virtual TouchModeEvent* createTouchModeEvent() override;
void recycle(InputEvent* event);
@@ -999,6 +1022,7 @@
std::queue<std::unique_ptr<FocusEvent>> mFocusEventPool;
std::queue<std::unique_ptr<CaptureEvent>> mCaptureEventPool;
std::queue<std::unique_ptr<DragEvent>> mDragEventPool;
+ std::queue<std::unique_ptr<TouchModeEvent>> mTouchModeEventPool;
};
} // namespace android
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index a790b56..9a150eb 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -72,6 +72,7 @@
CAPTURE,
DRAG,
TIMELINE,
+ TOUCH_MODE,
};
struct Header {
@@ -206,6 +207,15 @@
inline size_t size() const { return sizeof(Timeline); }
} timeline;
+
+ struct TouchMode {
+ int32_t eventId;
+ // The following 2 fields take up 4 bytes total
+ bool isInTouchMode;
+ uint8_t empty[3];
+
+ inline size_t size() const { return sizeof(TouchMode); }
+ } touchMode;
} __attribute__((aligned(8))) body;
bool isValid(size_t actualSize) const;
@@ -388,6 +398,15 @@
*/
status_t publishDragEvent(uint32_t seq, int32_t eventId, float x, float y, bool isExiting);
+ /* Publishes a touch mode event to the input channel.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t publishTouchModeEvent(uint32_t seq, int32_t eventId, bool isInTouchMode);
+
struct Finished {
uint32_t seq;
bool handled;
@@ -658,6 +677,7 @@
static void initializeFocusEvent(FocusEvent* event, const InputMessage* msg);
static void initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg);
static void initializeDragEvent(DragEvent* event, const InputMessage* msg);
+ static void initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg);
static void addSample(MotionEvent* event, const InputMessage* msg);
static bool canAddSample(const Batch& batch, const InputMessage* msg);
static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h
new file mode 100644
index 0000000..5832bf4
--- /dev/null
+++ b/include/private/performance_hint_private.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H
+#define ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+struct APerformanceHintManager;
+struct APerformanceHintSession;
+
+/**
+ * An opaque type representing a handle to a performance hint manager.
+ * It must be released after use.
+ *
+ * <p>To use:<ul>
+ * <li>Obtain the performance hint manager instance by calling
+ * {@link APerformanceHint_getManager} function.</li>
+ * <li>Create an {@link APerformanceHintSession} with
+ * {@link APerformanceHint_createSession}.</li>
+ * <li>Get the preferred update rate in nanoseconds with
+ * {@link APerformanceHint_getPreferredUpdateRateNanos}.</li>
+ */
+typedef struct APerformanceHintManager APerformanceHintManager;
+
+/**
+ * An opaque type representing a handle to a performance hint session.
+ * A session can only be acquired from a {@link APerformanceHintManager}
+ * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be
+ * freed with {@link APerformanceHint_closeSession} after use.
+ *
+ * A Session represents a group of threads with an inter-related workload such that hints for
+ * their performance should be considered as a unit. The threads in a given session should be
+ * long-life and not created or destroyed dynamically.
+ *
+ * <p>Each session is expected to have a periodic workload with a target duration for each
+ * cycle. The cycle duration is likely greater than the target work duration to allow other
+ * parts of the pipeline to run within the available budget. For example, a renderer thread may
+ * work at 60hz in order to produce frames at the display's frame but have a target work
+ * duration of only 6ms.</p>
+ *
+ * <p>After each cycle of work, the client is expected to use
+ * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to
+ * complete.</p>
+ *
+ * <p>To use:<ul>
+ * <li>Update a sessions target duration for each cycle of work
+ * with {@link APerformanceHint_updateTargetWorkDuration}.</li>
+ * <li>Report the actual duration for the last cycle of work with
+ * {@link APerformanceHint_reportActualWorkDuration}.</li>
+ * <li>Release the session instance with
+ * {@link APerformanceHint_closeSession}.</li></ul></p>
+ */
+typedef struct APerformanceHintSession APerformanceHintSession;
+
+/**
+ * Acquire an instance of the performance hint manager.
+ *
+ * @return manager instance on success, nullptr on failure.
+ */
+APerformanceHintManager* APerformanceHint_getManager();
+
+/**
+ * Creates a session for the given set of threads and sets their initial target work
+ * duration.
+ * @param manager The performance hint manager instance.
+ * @param threadIds The list of threads to be associated with this session. They must be part of
+ * this app's thread group.
+ * @param size the size of threadIds.
+ * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session.
+ * This must be positive.
+ * @return manager instance on success, nullptr on failure.
+ */
+APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
+ const int32_t* threadIds, size_t size,
+ int64_t initialTargetWorkDurationNanos);
+
+/**
+ * Get preferred update rate information for this device.
+ *
+ * @param manager The performance hint manager instance.
+ * @return the preferred update rate supported by device software.
+ */
+int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager);
+
+/**
+ * Updates this session's target duration for each cycle of work.
+ *
+ * @param session The performance hint session instance to update.
+ * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive.
+ * @return 0 on success
+ * EINVAL if targetDurationNanos is not positive.
+ * EPIPE if communication with the system service has failed.
+ */
+int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
+ int64_t targetDurationNanos);
+
+/**
+ * Reports the actual duration for the last cycle of work.
+ *
+ * <p>The system will attempt to adjust the core placement of the threads within the thread
+ * group and/or the frequency of the core on which they are run to bring the actual duration
+ * close to the target duration.</p>
+ *
+ * @param session The performance hint session instance to update.
+ * @param actualDurationNanos how long the thread group took to complete its last task in
+ * nanoseconds. This must be positive.
+ * @return 0 on success
+ * EINVAL if actualDurationNanos is not positive.
+ * EPIPE if communication with the system service has failed.
+ */
+int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
+ int64_t actualDurationNanos);
+
+/**
+ * Release the performance hint manager pointer acquired via
+ * {@link APerformanceHint_createSession}.
+ *
+ * @param session The performance hint session instance to release.
+ */
+void APerformanceHint_closeSession(APerformanceHintSession* session);
+
+/**
+ * For testing only.
+ */
+void APerformanceHint_setIHintManagerForTesting(void* iManager);
+
+__END_DECLS
+
+#endif // ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b4271dc..c18b1ce 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -120,6 +120,7 @@
"RpcSession.cpp",
"RpcServer.cpp",
"RpcState.cpp",
+ "RpcTransportRaw.cpp",
"Static.cpp",
"Stability.cpp",
"Status.cpp",
@@ -144,9 +145,6 @@
enabled: false,
},
host: {
- static_libs: [
- "libbase",
- ],
srcs: [
"ServiceManagerHost.cpp",
"UtilsHost.cpp",
@@ -187,6 +185,10 @@
"libutils",
],
+ static_libs: [
+ "libbase",
+ ],
+
header_libs: [
"libbinder_headers",
"libandroid_runtime_vm_headers",
@@ -285,7 +287,7 @@
// Do not expand the visibility.
visibility: [
"//packages/modules/Virtualization/authfs:__subpackages__",
- "//packages/modules/Virtualization/compos",
+ "//packages/modules/Virtualization/compos:__subpackages__",
"//packages/modules/Virtualization/microdroid",
],
}
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 3099296..765e21c 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -261,15 +261,15 @@
if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
using android::internal::Stability;
- auto category = Stability::getCategory(this);
+ int16_t stability = Stability::getRepr(this);
Stability::Level required = privateVendor ? Stability::VENDOR
: Stability::getLocalLevel();
- if (CC_UNLIKELY(!Stability::check(category, required))) {
+ if (CC_UNLIKELY(!Stability::check(stability, required))) {
ALOGE("Cannot do a user transaction on a %s binder (%s) in a %s context.",
- category.debugString().c_str(),
- String8(getInterfaceDescriptor()).c_str(),
- Stability::levelString(required).c_str());
+ Stability::levelString(stability).c_str(),
+ String8(getInterfaceDescriptor()).c_str(),
+ Stability::levelString(required).c_str());
return BAD_TYPE;
}
}
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index 8676955..e4ac4b4 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -26,22 +26,6 @@
namespace android {
-std::string hexString(const void* bytes, size_t len) {
- if (bytes == nullptr) return "<null>";
-
- const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
- const char chars[] = "0123456789abcdef";
- std::string result;
- result.resize(len * 2);
-
- for (size_t i = 0; i < len; i++) {
- result[2 * i] = chars[bytes8[i] >> 4];
- result[2 * i + 1] = chars[bytes8[i] & 0xf];
- }
-
- return result;
-}
-
// ---------------------------------------------------------------------
static const char indentStr[] =
diff --git a/libs/binder/Debug.h b/libs/binder/Debug.h
index 7ca087e..262dfba 100644
--- a/libs/binder/Debug.h
+++ b/libs/binder/Debug.h
@@ -23,8 +23,6 @@
namespace android {
// ---------------------------------------------------------------------------
-std::string hexString(const void* data, size_t size);
-
const char* stringForIndent(int32_t indentLevel);
typedef void (*debugPrintFunc)(void* cookie, const char* txt);
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 2175fd4..6e318ea 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -154,8 +154,7 @@
return checkPermission(permission, pid, uid);
}
-bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
-{
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logPermissionFailure) {
static Mutex gPermissionControllerLock;
static sp<IPermissionController> gPermissionController;
@@ -180,8 +179,10 @@
// Is this a permission failure, or did the controller go away?
if (IInterface::asBinder(pc)->isBinderAlive()) {
- ALOGW("Permission failure: %s from uid=%d pid=%d",
- String8(permission).string(), uid, pid);
+ if (logPermissionFailure) {
+ ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).string(),
+ uid, pid);
+ }
return false;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index a2ac96e..e623874 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -173,7 +173,7 @@
status_t Parcel::finishFlattenBinder(const sp<IBinder>& binder)
{
internal::Stability::tryMarkCompilationUnit(binder.get());
- int16_t rep = internal::Stability::getCategory(binder.get()).repr();
+ int16_t rep = internal::Stability::getRepr(binder.get());
return writeInt32(rep);
}
diff --git a/libs/binder/RpcAddress.cpp b/libs/binder/RpcAddress.cpp
index 98dee9a..ffc94b9 100644
--- a/libs/binder/RpcAddress.cpp
+++ b/libs/binder/RpcAddress.cpp
@@ -16,6 +16,7 @@
#include <binder/RpcAddress.h>
+#include <android-base/hex.h>
#include <binder/Parcel.h>
#include "Debug.h"
@@ -94,7 +95,7 @@
}
std::string RpcAddress::toString() const {
- return hexString(mRawAddr.get(), sizeof(RpcWireAddress));
+ return base::HexString(mRawAddr.get(), sizeof(RpcWireAddress));
}
status_t RpcAddress::writeToParcel(Parcel* parcel) const {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index c6cf2c5..879e462 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -26,6 +26,7 @@
#include <android-base/scopeguard.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
+#include <binder/RpcTransportRaw.h>
#include <log/log.h>
#include "RpcSocketAddress.h"
@@ -37,13 +38,17 @@
using base::ScopeGuard;
using base::unique_fd;
-RpcServer::RpcServer() {}
+RpcServer::RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
+ : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {}
RpcServer::~RpcServer() {
(void)shutdown();
}
-sp<RpcServer> RpcServer::make() {
- return sp<RpcServer>::make();
+sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+ // Default is without TLS.
+ if (rpcTransportCtxFactory == nullptr)
+ rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
+ return sp<RpcServer>::make(std::move(rpcTransportCtxFactory));
}
void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
@@ -61,14 +66,13 @@
return setupSocketServer(VsockSocketAddress(kAnyCid, port));
}
-bool RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) {
- const char* kAddr = "127.0.0.1";
-
+bool RpcServer::setupInetServer(const char* address, unsigned int port,
+ unsigned int* assignedPort) {
if (assignedPort != nullptr) *assignedPort = 0;
- auto aiStart = InetSocketAddress::getAddrInfo(kAddr, port);
+ auto aiStart = InetSocketAddress::getAddrInfo(address, port);
if (aiStart == nullptr) return false;
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
- InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
+ InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, address, port);
if (!setupSocketServer(socketAddress)) {
continue;
}
@@ -95,7 +99,7 @@
return true;
}
- ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
+ ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", address,
port);
return false;
}
@@ -110,6 +114,10 @@
return mMaxThreads;
}
+void RpcServer::setProtocolVersion(uint32_t version) {
+ mProtocolVersion = version;
+}
+
void RpcServer::setRootObject(const sp<IBinder>& binder) {
std::lock_guard<std::mutex> _l(mLock);
mRootObjectWeak = mRootObject = binder;
@@ -150,6 +158,10 @@
mJoinThreadRunning = true;
mShutdownTrigger = RpcSession::FdTrigger::make();
LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Cannot create join signaler");
+
+ mCtx = mRpcTransportCtxFactory->newServerCtx();
+ LOG_ALWAYS_FATAL_IF(mCtx == nullptr, "Unable to create RpcTransportCtx with %s sockets",
+ mRpcTransportCtxFactory->toCString());
}
status_t status;
@@ -216,6 +228,7 @@
LOG_RPC_DETAIL("Finished waiting on shutdown.");
mShutdownTrigger = nullptr;
+ mCtx = nullptr;
return true;
}
@@ -241,17 +254,56 @@
// mShutdownTrigger can only be cleared once connection threads have joined.
// It must be set before this thread is started
LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr);
+ LOG_ALWAYS_FATAL_IF(server->mCtx == nullptr);
+
+ status_t status = OK;
+
+ int clientFdForLog = clientFd.get();
+ auto client = server->mCtx->newTransport(std::move(clientFd));
+ if (client == nullptr) {
+ ALOGE("Dropping accept4()-ed socket because sslAccept fails");
+ status = DEAD_OBJECT;
+ // still need to cleanup before we can return
+ } else {
+ LOG_RPC_DETAIL("Created RpcTransport %p for client fd %d", client.get(), clientFdForLog);
+ }
RpcConnectionHeader header;
- status_t status = server->mShutdownTrigger->interruptableReadFully(clientFd.get(), &header,
- sizeof(header));
- bool idValid = status == OK;
- if (!idValid) {
- ALOGE("Failed to read ID for client connecting to RPC server: %s",
- statusToString(status).c_str());
- // still need to cleanup before we can return
+ if (status == OK) {
+ status = server->mShutdownTrigger->interruptableReadFully(client.get(), &header,
+ sizeof(header));
+ if (status != OK) {
+ ALOGE("Failed to read ID for client connecting to RPC server: %s",
+ statusToString(status).c_str());
+ // still need to cleanup before we can return
+ }
}
- bool incoming = header.options & RPC_CONNECTION_OPTION_INCOMING;
+
+ bool incoming = false;
+ uint32_t protocolVersion = 0;
+ RpcAddress sessionId = RpcAddress::zero();
+ bool requestingNewSession = false;
+
+ if (status == OK) {
+ incoming = header.options & RPC_CONNECTION_OPTION_INCOMING;
+ protocolVersion = std::min(header.version,
+ server->mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION));
+ sessionId = RpcAddress::fromRawEmbedded(&header.sessionId);
+ requestingNewSession = sessionId.isZero();
+
+ if (requestingNewSession) {
+ RpcNewSessionResponse response{
+ .version = protocolVersion,
+ };
+
+ status = server->mShutdownTrigger->interruptableWriteFully(client.get(), &response,
+ sizeof(response));
+ if (status != OK) {
+ ALOGE("Failed to send new session response: %s", statusToString(status).c_str());
+ // still need to cleanup before we can return
+ }
+ }
+ }
std::thread thisThread;
sp<RpcSession> session;
@@ -269,19 +321,16 @@
};
server->mConnectingThreads.erase(threadId);
- if (!idValid || server->mShutdownTrigger->isTriggered()) {
+ if (status != OK || server->mShutdownTrigger->isTriggered()) {
return;
}
- RpcAddress sessionId = RpcAddress::fromRawEmbedded(&header.sessionId);
-
- if (sessionId.isZero()) {
+ if (requestingNewSession) {
if (incoming) {
ALOGE("Cannot create a new session with an incoming connection, would leak");
return;
}
- sessionId = RpcAddress::zero();
size_t tries = 0;
do {
// don't block if there is some entropy issue
@@ -295,6 +344,7 @@
session = RpcSession::make();
session->setMaxThreads(server->mMaxThreads);
+ if (!session->setProtocolVersion(protocolVersion)) return;
if (!session->setForServer(server,
sp<RpcServer::EventListener>::fromExisting(
static_cast<RpcServer::EventListener*>(
@@ -316,7 +366,7 @@
}
if (incoming) {
- LOG_ALWAYS_FATAL_IF(!session->addOutgoingConnection(std::move(clientFd), true),
+ LOG_ALWAYS_FATAL_IF(!session->addOutgoingConnection(std::move(client), true),
"server state must already be initialized");
return;
}
@@ -325,7 +375,7 @@
session->preJoinThreadOwnership(std::move(thisThread));
}
- auto setupResult = session->preJoinSetup(std::move(clientFd));
+ auto setupResult = session->preJoinSetup(std::move(client));
// avoid strong cycle
server = nullptr;
@@ -369,7 +419,7 @@
return true;
}
-void RpcServer::onSessionLockedAllIncomingThreadsEnded(const sp<RpcSession>& session) {
+void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
auto id = session->mId;
LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID");
LOG_RPC_DETAIL("Dropping session with address %s", id->toString().c_str());
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index c01a03d..7565f1b 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -30,6 +30,7 @@
#include <android_runtime/vm.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
+#include <binder/RpcTransportRaw.h>
#include <binder/Stability.h>
#include <jni.h>
#include <utils/String8.h>
@@ -46,7 +47,8 @@
using base::unique_fd;
-RpcSession::RpcSession() {
+RpcSession::RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
+ : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {
LOG_RPC_DETAIL("RpcSession created %p", this);
mState = std::make_unique<RpcState>();
@@ -59,8 +61,11 @@
"Should not be able to destroy a session with servers in use.");
}
-sp<RpcSession> RpcSession::make() {
- return sp<RpcSession>::make();
+sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+ // Default is without TLS.
+ if (rpcTransportCtxFactory == nullptr)
+ rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
+ return sp<RpcSession>::make(std::move(rpcTransportCtxFactory));
}
void RpcSession::setMaxThreads(size_t threads) {
@@ -77,6 +82,31 @@
return mMaxThreads;
}
+bool RpcSession::setProtocolVersion(uint32_t version) {
+ if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT &&
+ version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+ ALOGE("Cannot start RPC session with version %u which is unknown (current protocol version "
+ "is %u).",
+ version, RPC_WIRE_PROTOCOL_VERSION);
+ return false;
+ }
+
+ std::lock_guard<std::mutex> _l(mMutex);
+ if (mProtocolVersion && version > *mProtocolVersion) {
+ ALOGE("Cannot upgrade explicitly capped protocol version %u to newer version %u",
+ *mProtocolVersion, version);
+ return false;
+ }
+
+ mProtocolVersion = version;
+ return true;
+}
+
+std::optional<uint32_t> RpcSession::getProtocolVersion() {
+ std::lock_guard<std::mutex> _l(mMutex);
+ return mProtocolVersion;
+}
+
bool RpcSession::setupUnixDomainClient(const char* path) {
return setupSocketClient(UnixSocketAddress(path));
}
@@ -96,7 +126,19 @@
return false;
}
+bool RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
+ return setupClient([&](const RpcAddress& sessionId, bool incoming) {
+ // std::move'd from fd becomes -1 (!ok())
+ if (!fd.ok()) {
+ fd = request();
+ if (!fd.ok()) return false;
+ }
+ return initAndAddConnection(std::move(fd), sessionId, incoming);
+ });
+}
+
bool RpcSession::addNullDebuggingClient() {
+ // Note: only works on raw sockets.
unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
if (serverFd == -1) {
@@ -104,7 +146,17 @@
return false;
}
- return addOutgoingConnection(std::move(serverFd), false);
+ auto ctx = mRpcTransportCtxFactory->newClientCtx();
+ if (ctx == nullptr) {
+ ALOGE("Unable to create RpcTransportCtx for null debugging client");
+ return false;
+ }
+ auto server = ctx->newTransport(std::move(serverFd));
+ if (server == nullptr) {
+ ALOGE("Unable to set up RpcTransport");
+ return false;
+ }
+ return addOutgoingConnection(std::move(server), false);
}
sp<IBinder> RpcSession::getRootObject() {
@@ -132,6 +184,7 @@
if (wait) {
LOG_ALWAYS_FATAL_IF(mShutdownListener == nullptr, "Shutdown listener not installed");
mShutdownListener->waitForShutdown(_l);
+
LOG_ALWAYS_FATAL_IF(!mThreads.empty(), "Shutdown failed");
}
@@ -179,11 +232,13 @@
return mWrite == -1;
}
+status_t RpcSession::FdTrigger::triggerablePoll(RpcTransport* rpcTransport, int16_t event) {
+ return triggerablePoll(rpcTransport->pollSocket(), event);
+}
+
status_t RpcSession::FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
while (true) {
- pollfd pfd[]{{.fd = fd.get(),
- .events = static_cast<int16_t>(event | POLLHUP),
- .revents = 0},
+ pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
{.fd = mRead.get(), .events = POLLHUP, .revents = 0}};
int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
if (ret < 0) {
@@ -199,28 +254,30 @@
}
}
-status_t RpcSession::FdTrigger::interruptableWriteFully(base::borrowed_fd fd, const void* data,
- size_t size) {
+status_t RpcSession::FdTrigger::interruptableWriteFully(RpcTransport* rpcTransport,
+ const void* data, size_t size) {
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(data);
const uint8_t* end = buffer + size;
MAYBE_WAIT_IN_FLAKE_MODE;
status_t status;
- while ((status = triggerablePoll(fd, POLLOUT)) == OK) {
- ssize_t writeSize = TEMP_FAILURE_RETRY(send(fd.get(), buffer, end - buffer, MSG_NOSIGNAL));
- if (writeSize == 0) return DEAD_OBJECT;
-
- if (writeSize < 0) {
- return -errno;
+ while ((status = triggerablePoll(rpcTransport, POLLOUT)) == OK) {
+ auto writeSize = rpcTransport->send(buffer, end - buffer);
+ if (!writeSize.ok()) {
+ LOG_RPC_DETAIL("RpcTransport::send(): %s", writeSize.error().message().c_str());
+ return writeSize.error().code() == 0 ? UNKNOWN_ERROR : -writeSize.error().code();
}
- buffer += writeSize;
+
+ if (*writeSize == 0) return DEAD_OBJECT;
+
+ buffer += *writeSize;
if (buffer == end) return OK;
}
return status;
}
-status_t RpcSession::FdTrigger::interruptableReadFully(base::borrowed_fd fd, void* data,
+status_t RpcSession::FdTrigger::interruptableReadFully(RpcTransport* rpcTransport, void* data,
size_t size) {
uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
uint8_t* end = buffer + size;
@@ -228,14 +285,16 @@
MAYBE_WAIT_IN_FLAKE_MODE;
status_t status;
- while ((status = triggerablePoll(fd, POLLIN)) == OK) {
- ssize_t readSize = TEMP_FAILURE_RETRY(recv(fd.get(), buffer, end - buffer, MSG_NOSIGNAL));
- if (readSize == 0) return DEAD_OBJECT; // EOF
-
- if (readSize < 0) {
- return -errno;
+ while ((status = triggerablePoll(rpcTransport, POLLIN)) == OK) {
+ auto readSize = rpcTransport->recv(buffer, end - buffer);
+ if (!readSize.ok()) {
+ LOG_RPC_DETAIL("RpcTransport::recv(): %s", readSize.error().message().c_str());
+ return readSize.error().code() == 0 ? UNKNOWN_ERROR : -readSize.error().code();
}
- buffer += readSize;
+
+ if (*readSize == 0) return DEAD_OBJECT; // EOF
+
+ buffer += *readSize;
if (buffer == end) return OK;
}
return status;
@@ -261,7 +320,7 @@
return OK;
}
-void RpcSession::WaitForShutdownListener::onSessionLockedAllIncomingThreadsEnded(
+void RpcSession::WaitForShutdownListener::onSessionAllIncomingThreadsEnded(
const sp<RpcSession>& session) {
(void)session;
mShutdown = true;
@@ -288,12 +347,19 @@
}
}
-RpcSession::PreJoinSetupResult RpcSession::preJoinSetup(base::unique_fd fd) {
+RpcSession::PreJoinSetupResult RpcSession::preJoinSetup(
+ std::unique_ptr<RpcTransport> rpcTransport) {
// must be registered to allow arbitrary client code executing commands to
// be able to do nested calls (we can't only read from it)
- sp<RpcConnection> connection = assignIncomingConnectionToThisThread(std::move(fd));
+ sp<RpcConnection> connection = assignIncomingConnectionToThisThread(std::move(rpcTransport));
- status_t status = mState->readConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+ status_t status;
+
+ if (connection == nullptr) {
+ status = DEAD_OBJECT;
+ } else {
+ status = mState->readConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+ }
return PreJoinSetupResult{
.connection = std::move(connection),
@@ -360,6 +426,7 @@
sp<RpcConnection>& connection = setupResult.connection;
if (setupResult.status == OK) {
+ LOG_ALWAYS_FATAL_IF(!connection, "must have connection if setup succeeded");
JavaThreadAttacher javaThreadAttacher;
while (true) {
status_t status = session->state()->getAndExecuteCommand(connection, session,
@@ -375,9 +442,6 @@
statusToString(setupResult.status).c_str());
}
- LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection),
- "bad state: connection object guaranteed to be in list");
-
sp<RpcSession::EventListener> listener;
{
std::lock_guard<std::mutex> _l(session->mMutex);
@@ -389,6 +453,12 @@
listener = session->mEventListener.promote();
}
+ // done after all cleanup, since session shutdown progresses via callbacks here
+ if (connection != nullptr) {
+ LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection),
+ "bad state: connection object guaranteed to be in list");
+ }
+
session = nullptr;
if (listener != nullptr) {
@@ -405,7 +475,8 @@
return server;
}
-bool RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+bool RpcSession::setupClient(
+ const std::function<bool(const RpcAddress& sessionId, bool incoming)>& connectAndInit) {
{
std::lock_guard<std::mutex> _l(mMutex);
LOG_ALWAYS_FATAL_IF(mOutgoingConnections.size() != 0,
@@ -413,44 +484,61 @@
mOutgoingConnections.size());
}
- if (!setupOneSocketConnection(addr, RpcAddress::zero(), false /*incoming*/)) return false;
+ if (!connectAndInit(RpcAddress::zero(), false /*incoming*/)) return false;
+
+ {
+ ExclusiveConnection connection;
+ status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+ ConnectionUse::CLIENT, &connection);
+ if (status != OK) return false;
+
+ uint32_t version;
+ status = state()->readNewSessionResponse(connection.get(),
+ sp<RpcSession>::fromExisting(this), &version);
+ if (!setProtocolVersion(version)) return false;
+ }
// TODO(b/189955605): we should add additional sessions dynamically
// instead of all at once.
// TODO(b/186470974): first risk of blocking
size_t numThreadsAvailable;
if (status_t status = getRemoteMaxThreads(&numThreadsAvailable); status != OK) {
- ALOGE("Could not get max threads after initial session to %s: %s", addr.toString().c_str(),
+ ALOGE("Could not get max threads after initial session setup: %s",
statusToString(status).c_str());
return false;
}
if (status_t status = readId(); status != OK) {
- ALOGE("Could not get session id after initial session to %s; %s", addr.toString().c_str(),
+ ALOGE("Could not get session id after initial session setup: %s",
statusToString(status).c_str());
return false;
}
- // we've already setup one client
- for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
- // TODO(b/189955605): shutdown existing connections?
- if (!setupOneSocketConnection(addr, mId.value(), false /*incoming*/)) return false;
- }
-
// TODO(b/189955605): we should add additional sessions dynamically
// instead of all at once - the other side should be responsible for setting
// up additional connections. We need to create at least one (unless 0 are
// requested to be set) in order to allow the other side to reliably make
// any requests at all.
+ // we've already setup one client
+ for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
+ if (!connectAndInit(mId.value(), false /*incoming*/)) return false;
+ }
+
for (size_t i = 0; i < mMaxThreads; i++) {
- if (!setupOneSocketConnection(addr, mId.value(), true /*incoming*/)) return false;
+ if (!connectAndInit(mId.value(), true /*incoming*/)) return false;
}
return true;
}
-bool RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, const RpcAddress& id,
+bool RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+ return setupClient([&](const RpcAddress& sessionId, bool incoming) {
+ return setupOneSocketConnection(addr, sessionId, incoming);
+ });
+}
+
+bool RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, const RpcAddress& sessionId,
bool incoming) {
for (size_t tries = 0; tries < 5; tries++) {
if (tries > 0) usleep(10000);
@@ -474,33 +562,60 @@
strerror(savedErrno));
return false;
}
-
- RpcConnectionHeader header{.options = 0};
- memcpy(&header.sessionId, &id.viewRawEmbedded(), sizeof(RpcWireAddress));
-
- if (incoming) header.options |= RPC_CONNECTION_OPTION_INCOMING;
-
- if (sizeof(header) != TEMP_FAILURE_RETRY(write(serverFd.get(), &header, sizeof(header)))) {
- int savedErrno = errno;
- ALOGE("Could not write connection header to socket at %s: %s", addr.toString().c_str(),
- strerror(savedErrno));
- return false;
- }
-
LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
- if (incoming) {
- return addIncomingConnection(std::move(serverFd));
- } else {
- return addOutgoingConnection(std::move(serverFd), true);
- }
+ return initAndAddConnection(std::move(serverFd), sessionId, incoming);
}
ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
return false;
}
-bool RpcSession::addIncomingConnection(unique_fd fd) {
+bool RpcSession::initAndAddConnection(unique_fd fd, const RpcAddress& sessionId, bool incoming) {
+ auto ctx = mRpcTransportCtxFactory->newClientCtx();
+ if (ctx == nullptr) {
+ ALOGE("Unable to create client RpcTransportCtx with %s sockets",
+ mRpcTransportCtxFactory->toCString());
+ return false;
+ }
+ auto server = ctx->newTransport(std::move(fd));
+ if (server == nullptr) {
+ ALOGE("Unable to set up RpcTransport in %s context", mRpcTransportCtxFactory->toCString());
+ return false;
+ }
+
+ LOG_RPC_DETAIL("Socket at client with RpcTransport %p", server.get());
+
+ RpcConnectionHeader header{
+ .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
+ .options = 0,
+ };
+ memcpy(&header.sessionId, &sessionId.viewRawEmbedded(), sizeof(RpcWireAddress));
+
+ if (incoming) header.options |= RPC_CONNECTION_OPTION_INCOMING;
+
+ auto sentHeader = server->send(&header, sizeof(header));
+ if (!sentHeader.ok()) {
+ ALOGE("Could not write connection header to socket: %s",
+ sentHeader.error().message().c_str());
+ return false;
+ }
+ if (*sentHeader != sizeof(header)) {
+ ALOGE("Could not write connection header to socket: sent %zd bytes, expected %zd",
+ *sentHeader, sizeof(header));
+ return false;
+ }
+
+ LOG_RPC_DETAIL("Socket at client: header sent");
+
+ if (incoming) {
+ return addIncomingConnection(std::move(server));
+ } else {
+ return addOutgoingConnection(std::move(server), true /*init*/);
+ }
+}
+
+bool RpcSession::addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport) {
std::mutex mutex;
std::condition_variable joinCv;
std::unique_lock<std::mutex> lock(mutex);
@@ -509,13 +624,13 @@
bool ownershipTransferred = false;
thread = std::thread([&]() {
std::unique_lock<std::mutex> threadLock(mutex);
- unique_fd movedFd = std::move(fd);
+ std::unique_ptr<RpcTransport> movedRpcTransport = std::move(rpcTransport);
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
sp<RpcSession> session = thiz;
session->preJoinThreadOwnership(std::move(thread));
// only continue once we have a response or the connection fails
- auto setupResult = session->preJoinSetup(std::move(movedFd));
+ auto setupResult = session->preJoinSetup(std::move(movedRpcTransport));
ownershipTransferred = true;
threadLock.unlock();
@@ -529,7 +644,7 @@
return true;
}
-bool RpcSession::addOutgoingConnection(unique_fd fd, bool init) {
+bool RpcSession::addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport, bool init) {
sp<RpcConnection> connection = sp<RpcConnection>::make();
{
std::lock_guard<std::mutex> _l(mMutex);
@@ -542,7 +657,7 @@
if (mShutdownTrigger == nullptr) return false;
}
- connection->fd = std::move(fd);
+ connection->rpcTransport = std::move(rpcTransport);
connection->exclusiveTid = gettid();
mOutgoingConnections.push_back(connection);
}
@@ -577,26 +692,44 @@
return true;
}
-sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(unique_fd fd) {
+sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(
+ std::unique_ptr<RpcTransport> rpcTransport) {
std::lock_guard<std::mutex> _l(mMutex);
+
+ if (mIncomingConnections.size() >= mMaxThreads) {
+ ALOGE("Cannot add thread to session with %zu threads (max is set to %zu)",
+ mIncomingConnections.size(), mMaxThreads);
+ return nullptr;
+ }
+
+ // Don't accept any more connections, some have shutdown. Usually this
+ // happens when new connections are still being established as part of a
+ // very short-lived session which shuts down after it already started
+ // accepting new connections.
+ if (mIncomingConnections.size() < mMaxIncomingConnections) {
+ return nullptr;
+ }
+
sp<RpcConnection> session = sp<RpcConnection>::make();
- session->fd = std::move(fd);
+ session->rpcTransport = std::move(rpcTransport);
session->exclusiveTid = gettid();
+
mIncomingConnections.push_back(session);
+ mMaxIncomingConnections = mIncomingConnections.size();
return session;
}
bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
- std::lock_guard<std::mutex> _l(mMutex);
+ std::unique_lock<std::mutex> _l(mMutex);
if (auto it = std::find(mIncomingConnections.begin(), mIncomingConnections.end(), connection);
it != mIncomingConnections.end()) {
mIncomingConnections.erase(it);
if (mIncomingConnections.size() == 0) {
sp<EventListener> listener = mEventListener.promote();
if (listener) {
- listener->onSessionLockedAllIncomingThreadsEnded(
- sp<RpcSession>::fromExisting(this));
+ _l.unlock();
+ listener->onSessionAllIncomingThreadsEnded(sp<RpcSession>::fromExisting(this));
}
}
return true;
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 332c75f..23382c3 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -18,6 +18,7 @@
#include "RpcState.h"
+#include <android-base/hex.h>
#include <android-base/scopeguard.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
@@ -272,8 +273,8 @@
status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, const char* what, const void* data,
size_t size) {
- LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, connection->fd.get(),
- hexString(data, size).c_str());
+ LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ android::base::HexString(data, size).c_str());
if (size > std::numeric_limits<ssize_t>::max()) {
ALOGE("Cannot send %s at size %zu (too big)", what, size);
@@ -281,11 +282,12 @@
return BAD_VALUE;
}
- if (status_t status = session->mShutdownTrigger->interruptableWriteFully(connection->fd.get(),
- data, size);
+ if (status_t status =
+ session->mShutdownTrigger->interruptableWriteFully(connection->rpcTransport.get(),
+ data, size);
status != OK) {
- LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on fd %d, error: %s", what, size,
- connection->fd.get(), statusToString(status).c_str());
+ LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
+ connection->rpcTransport.get(), statusToString(status).c_str());
(void)session->shutdownAndWait(false);
return status;
}
@@ -303,15 +305,28 @@
}
if (status_t status =
- session->mShutdownTrigger->interruptableReadFully(connection->fd.get(), data, size);
+ session->mShutdownTrigger->interruptableReadFully(connection->rpcTransport.get(),
+ data, size);
status != OK) {
- LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on fd %d, error: %s", what, size,
- connection->fd.get(), statusToString(status).c_str());
+ LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
+ connection->rpcTransport.get(), statusToString(status).c_str());
return status;
}
- LOG_RPC_DETAIL("Received %s on fd %d: %s", what, connection->fd.get(),
- hexString(data, size).c_str());
+ LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ android::base::HexString(data, size).c_str());
+ return OK;
+}
+
+status_t RpcState::readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint32_t* version) {
+ RpcNewSessionResponse response;
+ if (status_t status =
+ rpcRec(connection, session, "new session response", &response, sizeof(response));
+ status != OK) {
+ return status;
+ }
+ *version = response.version;
return OK;
}
@@ -477,7 +492,8 @@
return status;
if (flags & IBinder::FLAG_ONEWAY) {
- LOG_RPC_DETAIL("Oneway command, so no longer waiting on %d", connection->fd.get());
+ LOG_RPC_DETAIL("Oneway command, so no longer waiting on RpcTransport %p",
+ connection->rpcTransport.get());
// Do not wait on result.
// However, too many oneway calls may cause refcounts to build up and fill up the socket,
@@ -572,7 +588,7 @@
status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, CommandType type) {
- LOG_RPC_DETAIL("getAndExecuteCommand on fd %d", connection->fd.get());
+ LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get());
RpcWireHeader command;
if (status_t status = rpcRec(connection, session, "command header", &command, sizeof(command));
@@ -585,8 +601,7 @@
status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, CommandType type) {
uint8_t buf;
- while (0 < TEMP_FAILURE_RETRY(
- recv(connection->fd.get(), &buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT))) {
+ while (connection->rpcTransport->peek(&buf, sizeof(buf)).value_or(0) > 0) {
status_t status = getAndExecuteCommand(connection, session, type);
if (status != OK) return status;
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 5ac0b97..1446eec 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -60,6 +60,8 @@
RpcState();
~RpcState();
+ status_t readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint32_t* version);
status_t sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session);
status_t readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
new file mode 100644
index 0000000..2fc1945
--- /dev/null
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RpcRawTransport"
+#include <log/log.h>
+
+#include <binder/RpcTransportRaw.h>
+
+#include "RpcState.h"
+
+using android::base::ErrnoError;
+using android::base::Result;
+
+namespace android {
+
+namespace {
+
+// RpcTransport with TLS disabled.
+class RpcTransportRaw : public RpcTransport {
+public:
+ explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
+ Result<size_t> send(const void *buf, size_t size) override {
+ ssize_t ret = TEMP_FAILURE_RETRY(::send(mSocket.get(), buf, size, MSG_NOSIGNAL));
+ if (ret < 0) {
+ return ErrnoError() << "send()";
+ }
+ return ret;
+ }
+ Result<size_t> recv(void *buf, size_t size) override {
+ ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_NOSIGNAL));
+ if (ret < 0) {
+ return ErrnoError() << "recv()";
+ }
+ return ret;
+ }
+ Result<size_t> peek(void *buf, size_t size) override {
+ ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_PEEK | MSG_DONTWAIT));
+ if (ret < 0) {
+ return ErrnoError() << "recv(MSG_PEEK)";
+ }
+ return ret;
+ }
+ bool pending() override { return false; }
+ android::base::borrowed_fd pollSocket() const override { return mSocket; }
+
+private:
+ android::base::unique_fd mSocket;
+};
+
+// RpcTransportCtx with TLS disabled.
+class RpcTransportCtxRaw : public RpcTransportCtx {
+public:
+ std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd) const {
+ return std::make_unique<RpcTransportRaw>(std::move(fd));
+ }
+};
+} // namespace
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newServerCtx() const {
+ return std::make_unique<RpcTransportCtxRaw>();
+}
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newClientCtx() const {
+ return std::make_unique<RpcTransportCtxRaw>();
+}
+
+const char *RpcTransportCtxFactoryRaw::toCString() const {
+ return "raw";
+}
+
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryRaw::make() {
+ return std::unique_ptr<RpcTransportCtxFactoryRaw>(new RpcTransportCtxFactoryRaw());
+}
+
+} // namespace android
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 2a44c7a..0f8efd2 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -37,9 +37,20 @@
* either as part of a new session or an existing session
*/
struct RpcConnectionHeader {
+ uint32_t version; // maximum supported by caller
+ uint8_t reserver0[4];
RpcWireAddress sessionId;
uint8_t options;
- uint8_t reserved[7];
+ uint8_t reserved1[7];
+};
+
+/**
+ * In response to an RpcConnectionHeader which corresponds to a new session,
+ * this returns information to the server.
+ */
+struct RpcNewSessionResponse {
+ uint32_t version; // maximum supported by callee <= maximum supported by caller
+ uint8_t reserved[4];
};
#define RPC_CONNECTION_INIT_OKAY "cci"
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index 00b69d5..2d05fb2 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -23,20 +23,6 @@
namespace android {
namespace internal {
-// the libbinder parcel format is currently unstable
-
-// oldest version which is supported
-constexpr uint8_t kBinderWireFormatOldest = 1;
-// current version
-constexpr uint8_t kBinderWireFormatVersion = 1;
-
-Stability::Category Stability::Category::currentFromLevel(Level level) {
- return {
- .version = kBinderWireFormatVersion,
- .level = level,
- };
-}
-
void Stability::forceDowngradeToStability(const sp<IBinder>& binder, Level level) {
// Downgrading a remote binder would require also copying the version from
// the binder sent here. In practice though, we don't need to downgrade the
@@ -44,8 +30,7 @@
// what we can do to it.
LOG_ALWAYS_FATAL_IF(!binder || !binder->localBinder(), "Can only downgrade local binder");
- auto stability = Category::currentFromLevel(level);
- status_t result = setRepr(binder.get(), stability.repr(), REPR_LOG | REPR_ALLOW_DOWNGRADE);
+ status_t result = setRepr(binder.get(), level, REPR_LOG | REPR_ALLOW_DOWNGRADE);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
@@ -61,41 +46,31 @@
forceDowngradeToStability(binder, Level::VENDOR);
}
-std::string Stability::Category::debugString() {
- return levelString(level) + " wire protocol version "
- + std::to_string(version);
-}
-
void Stability::markCompilationUnit(IBinder* binder) {
- auto stability = Category::currentFromLevel(getLocalLevel());
- status_t result = setRepr(binder, stability.repr(), REPR_LOG);
+ status_t result = setRepr(binder, getLocalLevel(), REPR_LOG);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
void Stability::markVintf(IBinder* binder) {
- auto stability = Category::currentFromLevel(Level::VINTF);
- status_t result = setRepr(binder, stability.repr(), REPR_LOG);
+ status_t result = setRepr(binder, Level::VINTF, REPR_LOG);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
std::string Stability::debugToString(const sp<IBinder>& binder) {
- auto stability = getCategory(binder.get());
- return stability.debugString();
+ return levelString(getRepr(binder.get()));
}
void Stability::markVndk(IBinder* binder) {
- auto stability = Category::currentFromLevel(Level::VENDOR);
- status_t result = setRepr(binder, stability.repr(), REPR_LOG);
+ status_t result = setRepr(binder, Level::VENDOR, REPR_LOG);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
bool Stability::requiresVintfDeclaration(const sp<IBinder>& binder) {
- return check(getCategory(binder.get()), Level::VINTF);
+ return check(getRepr(binder.get()), Level::VINTF);
}
void Stability::tryMarkCompilationUnit(IBinder* binder) {
- auto stability = Category::currentFromLevel(getLocalLevel());
- (void) setRepr(binder, stability.repr(), REPR_NONE);
+ (void)setRepr(binder, getLocalLevel(), REPR_NONE);
}
Stability::Level Stability::getLocalLevel() {
@@ -111,92 +86,77 @@
#endif
}
-status_t Stability::setRepr(IBinder* binder, int32_t representation, uint32_t flags) {
+status_t Stability::setRepr(IBinder* binder, int32_t setting, uint32_t flags) {
bool log = flags & REPR_LOG;
bool allowDowngrade = flags & REPR_ALLOW_DOWNGRADE;
- auto current = getCategory(binder);
- auto setting = Category::fromRepr(representation);
-
- // If we have ahold of a binder with a newer declared version, then it
- // should support older versions, and we will simply write our parcels with
- // the current wire parcel format.
- if (setting.version < kBinderWireFormatOldest) {
- // always log, because this shouldn't happen
- ALOGE("Cannot accept binder with older binder wire protocol version "
- "%u. Versions less than %u are unsupported.", setting.version,
- kBinderWireFormatOldest);
- return BAD_TYPE;
- }
+ int16_t current = getRepr(binder);
// null binder is always written w/ 'UNDECLARED' stability
if (binder == nullptr) {
- if (setting.level == UNDECLARED) {
+ if (setting == UNDECLARED) {
return OK;
} else {
if (log) {
- ALOGE("Null binder written with stability %s.",
- levelString(setting.level).c_str());
+ ALOGE("Null binder written with stability %s.", levelString(setting).c_str());
}
return BAD_TYPE;
}
}
- if (!isDeclaredLevel(setting.level)) {
+ if (!isDeclaredLevel(setting)) {
if (log) {
- ALOGE("Can only set known stability, not %u.", setting.level);
+ ALOGE("Can only set known stability, not %d.", setting);
}
return BAD_TYPE;
}
+ Level levelSetting = static_cast<Level>(setting);
if (current == setting) return OK;
- bool hasAlreadyBeenSet = current.repr() != 0;
- bool isAllowedDowngrade = allowDowngrade && check(current, setting.level);
+ bool hasAlreadyBeenSet = current != Level::UNDECLARED;
+ bool isAllowedDowngrade = allowDowngrade && check(current, levelSetting);
if (hasAlreadyBeenSet && !isAllowedDowngrade) {
if (log) {
ALOGE("Interface being set with %s but it is already marked as %s",
- setting.debugString().c_str(),
- current.debugString().c_str());
+ levelString(setting).c_str(), levelString(current).c_str());
}
return BAD_TYPE;
}
if (isAllowedDowngrade) {
- ALOGI("Interface set with %s downgraded to %s stability",
- current.debugString().c_str(),
- setting.debugString().c_str());
+ ALOGI("Interface set with %s downgraded to %s stability", levelString(current).c_str(),
+ levelString(setting).c_str());
}
BBinder* local = binder->localBinder();
if (local != nullptr) {
- local->mStability = setting.repr();
+ local->mStability = setting;
} else {
- binder->remoteBinder()->mStability = setting.repr();
+ binder->remoteBinder()->mStability = setting;
}
return OK;
}
-Stability::Category Stability::getCategory(IBinder* binder) {
+int16_t Stability::getRepr(IBinder* binder) {
if (binder == nullptr) {
- return Category::currentFromLevel(Level::UNDECLARED);
+ return Level::UNDECLARED;
}
BBinder* local = binder->localBinder();
if (local != nullptr) {
- return Category::fromRepr(local->mStability);
+ return local->mStability;
}
- return Category::fromRepr(binder->remoteBinder()->mStability);
+ return binder->remoteBinder()->mStability;
}
-bool Stability::check(Category provided, Level required) {
- bool stable = (provided.level & required) == required;
+bool Stability::check(int16_t provided, Level required) {
+ bool stable = (provided & required) == required;
- if (provided.level != UNDECLARED && !isDeclaredLevel(provided.level)) {
- ALOGE("Unknown stability when checking interface stability %d.",
- provided.level);
+ if (provided != UNDECLARED && !isDeclaredLevel(provided)) {
+ ALOGE("Unknown stability when checking interface stability %d.", provided);
stable = false;
}
@@ -204,11 +164,11 @@
return stable;
}
-bool Stability::isDeclaredLevel(Level stability) {
+bool Stability::isDeclaredLevel(int32_t stability) {
return stability == VENDOR || stability == SYSTEM || stability == VINTF;
}
-std::string Stability::levelString(Level level) {
+std::string Stability::levelString(int32_t level) {
switch (level) {
case Level::UNDECLARED: return "undeclared stability";
case Level::VENDOR: return "vendor stability";
diff --git a/libs/binder/UtilsHost.cpp b/libs/binder/UtilsHost.cpp
index e524dab..d121ce2 100644
--- a/libs/binder/UtilsHost.cpp
+++ b/libs/binder/UtilsHost.cpp
@@ -111,15 +111,15 @@
errWrite.reset();
ret.pid = pid;
- auto handlePoll = [](android::base::unique_fd* fd, const pollfd& pfd, std::string* s) {
+ auto handlePoll = [](android::base::unique_fd* fd, const pollfd* pfd, std::string* s) {
if (!fd->ok()) return true;
- if (pfd.revents & POLLIN) {
+ if (pfd->revents & POLLIN) {
char buf[1024];
ssize_t n = TEMP_FAILURE_RETRY(read(fd->get(), buf, sizeof(buf)));
if (n < 0) return false;
if (n > 0) *s += std::string_view(buf, n);
}
- if (pfd.revents & POLLHUP) {
+ if (pfd->revents & POLLHUP) {
fd->reset();
}
return true;
@@ -142,9 +142,9 @@
int pollRet = poll(fds, nfds, 1000 /* ms timeout */);
if (pollRet == -1) return android::base::ErrnoError() << "poll()";
- if (!handlePoll(&ret.outPipe, *outPollFd, &ret.stdout))
+ if (!handlePoll(&ret.outPipe, outPollFd, &ret.stdout))
return android::base::ErrnoError() << "read(stdout)";
- if (!handlePoll(&ret.errPipe, *errPollFd, &ret.stderr))
+ if (!handlePoll(&ret.errPipe, errPollFd, &ret.stderr))
return android::base::ErrnoError() << "read(stderr)";
if (end && end(ret)) return ret;
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 8e46147..d152005 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -167,7 +167,8 @@
bool checkCallingPermission(const String16& permission);
bool checkCallingPermission(const String16& permission,
int32_t* outPid, int32_t* outUid);
-bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid,
+ bool logPermissionFailure = true);
#ifndef __ANDROID__
// Create an IServiceManager that delegates the service manager on the device via adb.
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index c8d2857..4abf3b9 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -19,6 +19,7 @@
#include <binder/IBinder.h>
#include <binder/RpcAddress.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -47,7 +48,8 @@
*/
class RpcServer final : public virtual RefBase, private RpcSession::EventListener {
public:
- static sp<RpcServer> make();
+ static sp<RpcServer> make(
+ std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
/**
* This represents a session for responses, e.g.:
@@ -72,8 +74,14 @@
* Set |port| to 0 to pick an ephemeral port; see discussion of
* /proc/sys/net/ipv4/ip_local_port_range in ip(7). In this case, |assignedPort|
* will be set to the picked port number, if it is not null.
+ *
+ * Set the IPv4 address for the socket to be listening on.
+ * "127.0.0.1" allows for local connections from the same device.
+ * "0.0.0.0" allows for connections on any IP address that the device may
+ * have
*/
- [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
+ [[nodiscard]] bool setupInetServer(const char* address, unsigned int port,
+ unsigned int* assignedPort);
/**
* If setup*Server has been successful, return true. Otherwise return false.
@@ -105,6 +113,13 @@
size_t getMaxThreads();
/**
+ * By default, the latest protocol version which is supported by a client is
+ * used. However, this can be used in order to prevent newer protocol
+ * versions from ever being used. This is expected to be useful for testing.
+ */
+ void setProtocolVersion(uint32_t version);
+
+ /**
* The root object can be retrieved by any client, without any
* authentication. TODO(b/183988761)
*
@@ -154,16 +169,18 @@
private:
friend sp<RpcServer>;
- RpcServer();
+ explicit RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
- void onSessionLockedAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
+ void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd);
bool setupSocketServer(const RpcSocketAddress& address);
+ const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
bool mAgreedExperimental = false;
size_t mMaxThreads = 1;
+ std::optional<uint32_t> mProtocolVersion;
base::unique_fd mServer; // socket we are accepting sessions on
std::mutex mLock; // for below
@@ -175,6 +192,7 @@
std::map<RpcAddress, sp<RpcSession>> mSessions;
std::unique_ptr<RpcSession::FdTrigger> mShutdownTrigger;
std::condition_variable mShutdownCv;
+ std::unique_ptr<RpcTransportCtx> mCtx;
};
} // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index fdca2a9..0b46606 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -18,6 +18,8 @@
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
#include <binder/RpcAddress.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -36,6 +38,11 @@
class RpcServer;
class RpcSocketAddress;
class RpcState;
+class RpcTransport;
+
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 0;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL;
/**
* This represents a session (group of connections) between a client
@@ -44,7 +51,8 @@
*/
class RpcSession final : public virtual RefBase {
public:
- static sp<RpcSession> make();
+ static sp<RpcSession> make(
+ std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
/**
* Set the maximum number of threads allowed to be made (for things like callbacks).
@@ -60,6 +68,13 @@
size_t getMaxThreads();
/**
+ * By default, the minimum of the supported versions of the client and the
+ * server will be used. Usually, this API should only be used for debugging.
+ */
+ [[nodiscard]] bool setProtocolVersion(uint32_t version);
+ std::optional<uint32_t> getProtocolVersion();
+
+ /**
* This should be called once per thread, matching 'join' in the remote
* process.
*/
@@ -76,6 +91,19 @@
[[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
/**
+ * Starts talking to an RPC server which has already been connected to. This
+ * is expected to be used when another process has permission to connect to
+ * a binder RPC service, but this process only has permission to talk to
+ * that service.
+ *
+ * For convenience, if 'fd' is -1, 'request' will be called.
+ *
+ * For future compatibility, 'request' should not reference any stack data.
+ */
+ [[nodiscard]] bool setupPreconnectedClient(base::unique_fd fd,
+ std::function<base::unique_fd()>&& request);
+
+ /**
* For debugging!
*
* Sets up an empty connection. All queries to this connection which require a
@@ -131,7 +159,7 @@
friend sp<RpcSession>;
friend RpcServer;
friend RpcState;
- RpcSession();
+ explicit RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
/** This is not a pipe. */
struct FdTrigger {
@@ -167,33 +195,35 @@
* true - succeeded in completely processing 'size'
* false - interrupted (failure or trigger)
*/
- status_t interruptableReadFully(base::borrowed_fd fd, void* data, size_t size);
- status_t interruptableWriteFully(base::borrowed_fd fd, const void* data, size_t size);
+ status_t interruptableReadFully(RpcTransport* rpcTransport, void* data, size_t size);
+ status_t interruptableWriteFully(RpcTransport* rpcTransport, const void* data, size_t size);
private:
+ status_t triggerablePoll(RpcTransport* rpcTransport, int16_t event);
+
base::unique_fd mWrite;
base::unique_fd mRead;
};
class EventListener : public virtual RefBase {
public:
- virtual void onSessionLockedAllIncomingThreadsEnded(const sp<RpcSession>& session) = 0;
+ virtual void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) = 0;
virtual void onSessionIncomingThreadEnded() = 0;
};
class WaitForShutdownListener : public EventListener {
public:
- void onSessionLockedAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
+ void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
void waitForShutdown(std::unique_lock<std::mutex>& lock);
private:
std::condition_variable mCv;
- bool mShutdown = false;
+ volatile bool mShutdown = false;
};
struct RpcConnection : public RefBase {
- base::unique_fd fd;
+ std::unique_ptr<RpcTransport> rpcTransport;
// whether this or another thread is currently using this fd to make
// or receive transactions.
@@ -219,19 +249,24 @@
// Status of setup
status_t status;
};
- PreJoinSetupResult preJoinSetup(base::unique_fd fd);
+ PreJoinSetupResult preJoinSetup(std::unique_ptr<RpcTransport> rpcTransport);
// join on thread passed to preJoinThreadOwnership
static void join(sp<RpcSession>&& session, PreJoinSetupResult&& result);
+ [[nodiscard]] bool setupClient(
+ const std::function<bool(const RpcAddress& sessionId, bool incoming)>& connectAndInit);
[[nodiscard]] bool setupSocketClient(const RpcSocketAddress& address);
[[nodiscard]] bool setupOneSocketConnection(const RpcSocketAddress& address,
- const RpcAddress& sessionId, bool server);
- [[nodiscard]] bool addIncomingConnection(base::unique_fd fd);
- [[nodiscard]] bool addOutgoingConnection(base::unique_fd fd, bool init);
+ const RpcAddress& sessionId, bool incoming);
+ [[nodiscard]] bool initAndAddConnection(base::unique_fd fd, const RpcAddress& sessionId,
+ bool incoming);
+ [[nodiscard]] bool addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport);
+ [[nodiscard]] bool addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport, bool init);
[[nodiscard]] bool setForServer(const wp<RpcServer>& server,
const wp<RpcSession::EventListener>& eventListener,
const RpcAddress& sessionId);
- sp<RpcConnection> assignIncomingConnectionToThisThread(base::unique_fd fd);
+ sp<RpcConnection> assignIncomingConnectionToThisThread(
+ std::unique_ptr<RpcTransport> rpcTransport);
[[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
enum class ConnectionUse {
@@ -264,6 +299,8 @@
bool mReentrant = false;
};
+ const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
+
// On the other side of a session, for each of mOutgoingConnections here, there should
// be one of mIncomingConnections on the other side (and vice versa).
//
@@ -291,12 +328,14 @@
std::mutex mMutex; // for all below
size_t mMaxThreads = 0;
+ std::optional<uint32_t> mProtocolVersion;
std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
size_t mWaitingThreads = 0;
// hint index into clients, ++ when sending an async transaction
size_t mOutgoingConnectionsOffset = 0;
std::vector<sp<RpcConnection>> mOutgoingConnections;
+ size_t mMaxIncomingConnections = 0;
std::vector<sp<RpcConnection>> mIncomingConnections;
std::map<std::thread::id, std::thread> mThreads;
};
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
new file mode 100644
index 0000000..1164600
--- /dev/null
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Wraps the transport layer of RPC. Implementation may use plain sockets or TLS.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+
+// Represents a socket connection.
+class RpcTransport {
+public:
+ virtual ~RpcTransport() = default;
+
+ // replacement of ::send(). errno may not be set if TLS is enabled.
+ virtual android::base::Result<size_t> send(const void *buf, size_t size) = 0;
+
+ // replacement of ::recv(). errno may not be set if TLS is enabled.
+ virtual android::base::Result<size_t> recv(void *buf, size_t size) = 0;
+
+ // replacement of ::recv(MSG_PEEK). errno may not be set if TLS is enabled.
+ //
+ // Implementation details:
+ // - For TLS, this may invoke syscalls and read data from the transport
+ // into an internal buffer in userspace. After that, pending() == true.
+ // - For raw sockets, this calls ::recv(MSG_PEEK), which leaves the data in the kernel buffer;
+ // pending() is always false.
+ virtual android::base::Result<size_t> peek(void *buf, size_t size) = 0;
+
+ // Returns true if there are data pending in a userspace buffer that RpcTransport holds.
+ //
+ // Implementation details:
+ // - For TLS, this does not invoke any syscalls or read any data from the
+ // transport. This only returns whether there are data pending in the internal buffer in
+ // userspace.
+ // - For raw sockets, this always returns false.
+ virtual bool pending() = 0;
+
+ // Returns fd for polling.
+ //
+ // Do not directly read / write on this raw fd!
+ [[nodiscard]] virtual android::base::borrowed_fd pollSocket() const = 0;
+
+protected:
+ RpcTransport() = default;
+};
+
+// Represents the context that generates the socket connection.
+class RpcTransportCtx {
+public:
+ virtual ~RpcTransportCtx() = default;
+ [[nodiscard]] virtual std::unique_ptr<RpcTransport> newTransport(
+ android::base::unique_fd fd) const = 0;
+
+protected:
+ RpcTransportCtx() = default;
+};
+
+// A factory class that generates RpcTransportCtx.
+class RpcTransportCtxFactory {
+public:
+ virtual ~RpcTransportCtxFactory() = default;
+ // Creates server context.
+ [[nodiscard]] virtual std::unique_ptr<RpcTransportCtx> newServerCtx() const = 0;
+
+ // Creates client context.
+ [[nodiscard]] virtual std::unique_ptr<RpcTransportCtx> newClientCtx() const = 0;
+
+ // Return a short description of this transport (e.g. "raw"). For logging / debugging / testing
+ // only.
+ [[nodiscard]] virtual const char *toCString() const = 0;
+
+protected:
+ RpcTransportCtxFactory() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcTransportRaw.h b/libs/binder/include/binder/RpcTransportRaw.h
new file mode 100644
index 0000000..6fb1f92
--- /dev/null
+++ b/libs/binder/include/binder/RpcTransportRaw.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Wraps the transport layer of RPC. Implementation uses plain sockets.
+// Note: don't use directly. You probably want newServerRpcTransportCtx / newClientRpcTransportCtx.
+
+#pragma once
+
+#include <memory>
+
+#include <binder/RpcTransport.h>
+
+namespace android {
+
+// RpcTransportCtxFactory with TLS disabled.
+class RpcTransportCtxFactoryRaw : public RpcTransportCtxFactory {
+public:
+ static std::unique_ptr<RpcTransportCtxFactory> make();
+
+ std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
+ std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
+ const char* toCString() const override;
+
+private:
+ RpcTransportCtxFactoryRaw() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index 629b565..ce4362f 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -44,10 +44,9 @@
// to old servers, and new servers know how to interpret the 8-byte result,
// they can still communicate.
//
-// Every binder object has a stability level associated with it, and when
-// communicating with a binder, we make sure that the command we sent is one
-// that it knows how to process. The summary of stability of a binder is
-// represented by a Stability::Category object.
+// This class is specifically about (1). (2) is not currently tracked by
+// libbinder for regular binder calls, and everything on the system uses the
+// same copy of libbinder.
class Stability final {
public:
@@ -128,7 +127,10 @@
static void tryMarkCompilationUnit(IBinder* binder);
- enum Level : uint8_t {
+ // Currently, we use int16_t for Level so that it can fit in BBinder.
+ // However, on the wire, we have 4 bytes reserved for stability, so whenever
+ // we ingest a Level, we always accept an int32_t.
+ enum Level : int16_t {
UNDECLARED = 0,
VENDOR = 0b000011,
@@ -136,37 +138,6 @@
VINTF = 0b111111,
};
- // This is the format of stability passed on the wire. It is only 2 bytes
- // long, but 2 bytes in addition to this are reserved here. The difference
- // in size is in order to free up space in BBinder, which is fixed by
- // prebuilts inheriting from it.
- struct Category {
- static inline Category fromRepr(int16_t representation) {
- return *reinterpret_cast<Category*>(&representation);
- }
- int16_t repr() const { return *reinterpret_cast<const int16_t*>(this); }
- static inline Category currentFromLevel(Level level);
-
- bool operator== (const Category& o) const {
- return repr() == o.repr();
- }
- bool operator!= (const Category& o) const {
- return !(*this == o);
- }
-
- std::string debugString();
-
- // This is the version of the wire protocol associated with the host
- // process of a particular binder. As the wire protocol changes, if
- // sending a transaction to a binder with an old version, the Parcel
- // class must write parcels according to the version documented here.
- uint8_t version;
-
- // bitmask of Stability::Level
- Level level;
- };
- static_assert(sizeof(Category) == sizeof(int16_t));
-
// returns the stability according to how this was built
static Level getLocalLevel();
@@ -179,18 +150,18 @@
REPR_ALLOW_DOWNGRADE = 2,
};
// applies stability to binder if stability level is known
- __attribute__((warn_unused_result))
- static status_t setRepr(IBinder* binder, int32_t representation, uint32_t flags);
+ __attribute__((warn_unused_result)) static status_t setRepr(IBinder* binder, int32_t setting,
+ uint32_t flags);
// get stability information as encoded on the wire
- static Category getCategory(IBinder* binder);
+ static int16_t getRepr(IBinder* binder);
// whether a transaction on binder is allowed, if the transaction
// is done from a context with a specific stability level
- static bool check(Category provided, Level required);
+ static bool check(int16_t provided, Level required);
- static bool isDeclaredLevel(Level level);
- static std::string levelString(Level level);
+ static bool isDeclaredLevel(int32_t level);
+ static std::string levelString(int32_t level);
Stability();
};
diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp
index 488009f..8ee396e 100644
--- a/libs/binder/ndk/tests/Android.bp
+++ b/libs/binder/ndk/tests/Android.bp
@@ -71,7 +71,7 @@
srcs: ["libbinder_ndk_unit_test.cpp"],
static_libs: [
"IBinderNdkUnitTest-cpp",
- "IBinderNdkUnitTest-ndk_platform",
+ "IBinderNdkUnitTest-ndk",
],
test_suites: [
"general-tests",
@@ -88,8 +88,8 @@
],
static_libs: [
"IBinderVendorDoubleLoadTest-cpp",
- "IBinderVendorDoubleLoadTest-ndk_platform",
- "libbinder_aidl_test_stub-ndk_platform",
+ "IBinderVendorDoubleLoadTest-ndk",
+ "libbinder_aidl_test_stub-ndk",
],
// critical that libbinder/libbinder_ndk are shared for VTS
shared_libs: [
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index a3f7620..a0e991c 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -493,7 +493,7 @@
assert_eq!(parcel.read::<i32>().unwrap(), 15);
let start = parcel.get_data_position();
- assert_eq!(parcel.read::<bool>().unwrap(), true);
+ assert!(parcel.read::<bool>().unwrap());
unsafe {
assert!(parcel.set_data_position(start).is_ok());
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 607860f..ecc61f4 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -50,7 +50,7 @@
"libbinder_ndk",
],
static_libs: [
- "IBinderRustNdkInteropTest-ndk_platform",
+ "IBinderRustNdkInteropTest-ndk",
"libbinder_ndk_rust_interop",
],
test_suites: ["general-tests"],
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index 4702e45..415ede1 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -90,7 +90,7 @@
pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
let service_name = CStr::from_ptr(service_name).to_str().unwrap();
let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default());
- match binder::add_service(&service_name, service.as_binder()) {
+ match binder::add_service(service_name, service.as_binder()) {
Ok(_) => StatusCode::OK as c_int,
Err(e) => e as c_int,
}
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 62df9b7..a6e3f7d 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -47,6 +47,7 @@
namespace {
+const char* kLocalInetAddress = "127.0.0.1";
using ServiceRetriever = decltype(&android::IServiceManager::checkService);
int Usage(const char* program) {
@@ -86,7 +87,7 @@
}
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
- if (!rpcServer->setupInetServer(0, &port)) {
+ if (!rpcServer->setupInetServer(kLocalInetAddress, 0, &port)) {
LOG(ERROR) << "setupInetServer failed";
return EX_SOFTWARE;
}
@@ -199,7 +200,7 @@
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
rpcServer->setRootObject(service);
unsigned int port;
- if (!rpcServer->setupInetServer(0, &port)) {
+ if (!rpcServer->setupInetServer(kLocalInetAddress, 0, &port)) {
LOG(ERROR) << "Unable to set up inet server";
return EX_SOFTWARE;
}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 24afcf6..b7ad199 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -160,7 +160,7 @@
],
static_libs: [
"binderRpcTestIface-cpp",
- "binderRpcTestIface-ndk_platform",
+ "binderRpcTestIface-ndk",
],
test_suites: ["general-tests"],
require_root: true,
@@ -296,7 +296,7 @@
],
static_libs: [
"binderStabilityTestIface-cpp",
- "binderStabilityTestIface-ndk_platform",
+ "binderStabilityTestIface-ndk",
],
test_suites: ["device-tests", "vts"],
diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp
index 2d30c8d..307151c 100644
--- a/libs/binder/tests/binderClearBufTest.cpp
+++ b/libs/binder/tests/binderClearBufTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <binder/Binder.h>
#include <binder/IBinder.h>
@@ -30,22 +31,6 @@
const String16 kServerName = String16("binderClearBuf");
-std::string hexString(const void* bytes, size_t len) {
- if (bytes == nullptr) return "<null>";
-
- const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
- char chars[] = "0123456789abcdef";
- std::string result;
- result.resize(len * 2);
-
- for (size_t i = 0; i < len; i++) {
- result[2 * i] = chars[bytes8[i] >> 4];
- result[2 * i + 1] = chars[bytes8[i] & 0xf];
- }
-
- return result;
-}
-
class FooBar : public BBinder {
public:
enum {
@@ -83,7 +68,7 @@
lastReply = reply.data();
lastReplySize = reply.dataSize();
}
- *outBuffer = hexString(lastReply, lastReplySize);
+ *outBuffer = android::base::HexString(lastReply, lastReplySize);
return result;
}
};
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 4c3225f..65db7f6 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1192,7 +1192,7 @@
if (rpcServer == nullptr) return {};
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
- if (!rpcServer->setupInetServer(0, &port)) {
+ if (!rpcServer->setupInetServer("127.0.0.1", 0, &port)) {
ADD_FAILURE() << "setupInetServer failed";
return {};
}
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index a457e67..5f4a7b5 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -18,21 +18,31 @@
#include <android-base/logging.h>
#include <benchmark/benchmark.h>
#include <binder/Binder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
#include <thread>
+#include <signal.h>
+#include <sys/prctl.h>
#include <sys/types.h>
#include <unistd.h>
using android::BBinder;
+using android::defaultServiceManager;
using android::IBinder;
using android::interface_cast;
+using android::IPCThreadState;
+using android::IServiceManager;
using android::OK;
+using android::ProcessState;
using android::RpcServer;
using android::RpcSession;
using android::sp;
+using android::String16;
using android::binder::Status;
class MyBinderRpcBenchmark : public BnBinderRpcBenchmark {
@@ -46,28 +56,51 @@
}
};
-static sp<RpcSession> gSession = RpcSession::make();
+enum Transport {
+ KERNEL,
+ RPC,
+};
-void BM_getRootObject(benchmark::State& state) {
- while (state.KeepRunning()) {
- CHECK(gSession->getRootObject() != nullptr);
+static void EachTransport(benchmark::internal::Benchmark* b) {
+#ifdef __BIONIC__
+ b->Args({Transport::KERNEL});
+#endif
+ b->Args({Transport::RPC});
+}
+
+static sp<RpcSession> gSession = RpcSession::make();
+#ifdef __BIONIC__
+static const String16 kKernelBinderInstance = String16(u"binderRpcBenchmark-control");
+static sp<IBinder> gKernelBinder;
+#endif
+
+static sp<IBinder> getBinderForOptions(benchmark::State& state) {
+ Transport transport = static_cast<Transport>(state.range(0));
+ switch (transport) {
+#ifdef __BIONIC__
+ case KERNEL:
+ return gKernelBinder;
+#endif
+ case RPC:
+ return gSession->getRootObject();
+ default:
+ LOG(FATAL) << "Unknown transport value: " << transport;
+ return nullptr;
}
}
-BENCHMARK(BM_getRootObject);
void BM_pingTransaction(benchmark::State& state) {
- sp<IBinder> binder = gSession->getRootObject();
- CHECK(binder != nullptr);
+ sp<IBinder> binder = getBinderForOptions(state);
while (state.KeepRunning()) {
CHECK_EQ(OK, binder->pingBinder());
}
}
-BENCHMARK(BM_pingTransaction);
+BENCHMARK(BM_pingTransaction)->Apply(EachTransport);
void BM_repeatString(benchmark::State& state) {
- sp<IBinder> binder = gSession->getRootObject();
- CHECK(binder != nullptr);
+ sp<IBinder> binder = getBinderForOptions(state);
+
sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
CHECK(iface != nullptr);
@@ -92,7 +125,7 @@
CHECK(ret.isOk()) << ret;
}
}
-BENCHMARK(BM_repeatString);
+BENCHMARK(BM_repeatString)->Apply(EachTransport);
void BM_repeatBinder(benchmark::State& state) {
sp<IBinder> binder = gSession->getRootObject();
@@ -109,7 +142,7 @@
CHECK(ret.isOk()) << ret;
}
}
-BENCHMARK(BM_repeatBinder);
+BENCHMARK(BM_repeatBinder)->Apply(EachTransport);
int main(int argc, char** argv) {
::benchmark::Initialize(&argc, argv);
@@ -118,13 +151,36 @@
std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark";
(void)unlink(addr.c_str());
- std::thread([addr]() {
+ std::cerr << "Tests suffixes:" << std::endl;
+ std::cerr << "\t\\" << Transport::KERNEL << " is KERNEL" << std::endl;
+ std::cerr << "\t\\" << Transport::RPC << " is RPC" << std::endl;
+
+ if (0 == fork()) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
sp<RpcServer> server = RpcServer::make();
server->setRootObject(sp<MyBinderRpcBenchmark>::make());
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
CHECK(server->setupUnixDomainServer(addr.c_str()));
server->join();
- }).detach();
+ exit(1);
+ }
+
+#ifdef __BIONIC__
+ if (0 == fork()) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
+ CHECK_EQ(OK,
+ defaultServiceManager()->addService(kKernelBinderInstance,
+ sp<MyBinderRpcBenchmark>::make()));
+ IPCThreadState::self()->joinThreadPool();
+ exit(1);
+ }
+
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+
+ gKernelBinder = defaultServiceManager()->waitForService(kKernelBinderInstance);
+ CHECK_NE(nullptr, gKernelBinder.get());
+#endif
for (size_t tries = 0; tries < 5; tries++) {
usleep(10000);
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 40ebd9c..36a6804 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -29,6 +29,8 @@
#include <binder/ProcessState.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
#include <gtest/gtest.h>
#include <chrono>
@@ -40,6 +42,7 @@
#include <sys/prctl.h>
#include <unistd.h>
+#include "../RpcSocketAddress.h" // for testing preconnected clients
#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
@@ -47,6 +50,25 @@
namespace android {
+static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
+ RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+const char* kLocalInetAddress = "127.0.0.1";
+
+enum class RpcSecurity { RAW };
+
+static inline std::vector<RpcSecurity> RpcSecurityValues() {
+ return {RpcSecurity::RAW};
+}
+
+static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(RpcSecurity rpcSecurity) {
+ switch (rpcSecurity) {
+ case RpcSecurity::RAW:
+ return RpcTransportCtxFactoryRaw::make();
+ default:
+ LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
+ }
+}
+
TEST(BinderRpcParcel, EntireParcelFormatted) {
Parcel p;
p.writeInt32(3);
@@ -54,10 +76,17 @@
EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
}
-TEST(BinderRpc, SetExternalServer) {
+class BinderRpcSimple : public ::testing::TestWithParam<RpcSecurity> {
+public:
+ static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
+ return newFactory(info.param)->toCString();
+ }
+};
+
+TEST_P(BinderRpcSimple, SetExternalServerTest) {
base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
int sinkFd = sink.get();
- auto server = RpcServer::make();
+ auto server = RpcServer::make(newFactory(GetParam()));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
ASSERT_FALSE(server->hasServer());
ASSERT_TRUE(server->setupExternalServer(std::move(sink)));
@@ -67,6 +96,19 @@
ASSERT_EQ(sinkFd, retrieved.get());
}
+TEST(BinderRpc, CannotUseNextWireVersion) {
+ auto session = RpcSession::make();
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
+}
+
+TEST(BinderRpc, CanUseExperimentalWireVersion) {
+ auto session = RpcSession::make();
+ EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
+}
+
using android::binder::Status;
#define EXPECT_OK(status) \
@@ -368,12 +410,15 @@
};
enum class SocketType {
+ PRECONNECTED,
UNIX,
VSOCK,
INET,
};
-static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
- switch (info.param) {
+static inline std::string PrintToString(SocketType socketType) {
+ switch (socketType) {
+ case SocketType::PRECONNECTED:
+ return "preconnected_uds";
case SocketType::UNIX:
return "unix_domain_socket";
case SocketType::VSOCK:
@@ -386,7 +431,21 @@
}
}
-class BinderRpc : public ::testing::TestWithParam<SocketType> {
+static base::unique_fd connectToUds(const char* addrStr) {
+ UnixSocketAddress addr(addrStr);
+ base::unique_fd serverFd(
+ TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ int savedErrno = errno;
+ CHECK(serverFd.ok()) << "Could not create socket " << addrStr << ": " << strerror(savedErrno);
+
+ if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ int savedErrno = errno;
+ LOG(FATAL) << "Could not connect to socket " << addrStr << ": " << strerror(savedErrno);
+ }
+ return serverFd;
+}
+
+class BinderRpc : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity>> {
public:
struct Options {
size_t numThreads = 1;
@@ -394,13 +453,19 @@
size_t numIncomingConnections = 0;
};
+ static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [type, security] = info.param;
+ return PrintToString(type) + "_" + newFactory(security)->toCString();
+ }
+
// This creates a new process serving an interface on a certain number of
// threads.
ProcessSession createRpcTestSocketServerProcess(
const Options& options, const std::function<void(const sp<RpcServer>&)>& configure) {
CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
- SocketType socketType = GetParam();
+ SocketType socketType = std::get<0>(GetParam());
+ RpcSecurity rpcSecurity = std::get<1>(GetParam());
unsigned int vsockPort = allocateVsockPort();
std::string addr = allocateSocketAddress();
@@ -408,7 +473,7 @@
auto ret = ProcessSession{
.host = Process([&](android::base::borrowed_fd writeEnd) {
- sp<RpcServer> server = RpcServer::make();
+ sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
server->setMaxThreads(options.numThreads);
@@ -416,6 +481,8 @@
unsigned int outPort = 0;
switch (socketType) {
+ case SocketType::PRECONNECTED:
+ [[fallthrough]];
case SocketType::UNIX:
CHECK(server->setupUnixDomainServer(addr.c_str())) << addr;
break;
@@ -423,7 +490,7 @@
CHECK(server->setupVsockServer(vsockPort));
break;
case SocketType::INET: {
- CHECK(server->setupInetServer(0, &outPort));
+ CHECK(server->setupInetServer(kLocalInetAddress, 0, &outPort));
CHECK_NE(0, outPort);
break;
}
@@ -450,10 +517,16 @@
}
for (size_t i = 0; i < options.numSessions; i++) {
- sp<RpcSession> session = RpcSession::make();
+ sp<RpcSession> session = RpcSession::make(newFactory(rpcSecurity));
session->setMaxThreads(options.numIncomingConnections);
switch (socketType) {
+ case SocketType::PRECONNECTED:
+ if (session->setupPreconnectedClient({}, [=]() {
+ return connectToUds(addr.c_str());
+ }))
+ goto success;
+ break;
case SocketType::UNIX:
if (session->setupUnixDomainClient(addr.c_str())) goto success;
break;
@@ -1114,13 +1187,14 @@
}
static bool testSupportVsockLoopback() {
+ // We don't need to enable TLS to know if vsock is supported.
unsigned int vsockPort = allocateVsockPort();
- sp<RpcServer> server = RpcServer::make();
+ sp<RpcServer> server = RpcServer::make(RpcTransportCtxFactoryRaw::make());
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
CHECK(server->setupVsockServer(vsockPort));
server->start();
- sp<RpcSession> session = RpcSession::make();
+ sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
bool okay = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
while (!server->shutdown()) usleep(10000);
ALOGE("Detected vsock loopback supported: %d", okay);
@@ -1128,7 +1202,7 @@
}
static std::vector<SocketType> testSocketTypes() {
- std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET};
+ std::vector<SocketType> ret = {SocketType::PRECONNECTED, SocketType::UNIX, SocketType::INET};
static bool hasVsockLoopback = testSupportVsockLoopback();
@@ -1139,10 +1213,13 @@
return ret;
}
-INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, ::testing::ValuesIn(testSocketTypes()),
- PrintSocketType);
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
+ ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
+ ::testing::ValuesIn(RpcSecurityValues())),
+ BinderRpc::PrintParamInfo);
-class BinderRpcServerRootObject : public ::testing::TestWithParam<std::tuple<bool, bool>> {};
+class BinderRpcServerRootObject
+ : public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
TEST_P(BinderRpcServerRootObject, WeakRootObject) {
using SetFn = std::function<void(RpcServer*, sp<IBinder>)>;
@@ -1150,8 +1227,8 @@
return isStrong ? SetFn(&RpcServer::setRootObject) : SetFn(&RpcServer::setRootObjectWeak);
};
- auto server = RpcServer::make();
- auto [isStrong1, isStrong2] = GetParam();
+ auto [isStrong1, isStrong2, rpcSecurity] = GetParam();
+ auto server = RpcServer::make(newFactory(rpcSecurity));
auto binder1 = sp<BBinder>::make();
IBinder* binderRaw1 = binder1.get();
setRootObject(isStrong1)(server.get(), binder1);
@@ -1168,7 +1245,8 @@
}
INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerRootObject,
- ::testing::Combine(::testing::Bool(), ::testing::Bool()));
+ ::testing::Combine(::testing::Bool(), ::testing::Bool(),
+ ::testing::ValuesIn(RpcSecurityValues())));
class OneOffSignal {
public:
@@ -1191,10 +1269,10 @@
bool mValue = false;
};
-TEST(BinderRpc, Shutdown) {
+TEST_P(BinderRpcSimple, Shutdown) {
auto addr = allocateSocketAddress();
unlink(addr.c_str());
- auto server = RpcServer::make();
+ auto server = RpcServer::make(newFactory(GetParam()));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
ASSERT_TRUE(server->setupUnixDomainServer(addr.c_str()));
auto joinEnds = std::make_shared<OneOffSignal>();
@@ -1237,7 +1315,7 @@
auto rpcServer = RpcServer::make();
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
- ASSERT_TRUE(rpcServer->setupInetServer(0, &port));
+ ASSERT_TRUE(rpcServer->setupInetServer(kLocalInetAddress, 0, &port));
auto socket = rpcServer->releaseServer();
auto keepAlive = sp<BBinder>::make();
@@ -1255,6 +1333,9 @@
ASSERT_EQ(OK, rpcBinder->pingBinder());
}
+INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
+ BinderRpcSimple::PrintTestParam);
+
} // namespace android
int main(int argc, char** argv) {
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 74b8eb8..acf3f8f 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -23,7 +23,6 @@
"main.cpp",
"random_fd.cpp",
"random_parcel.cpp",
- "util.cpp",
],
static_libs: [
"libbase",
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index a717ce9..f1fe164 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -18,11 +18,13 @@
#include "binder.h"
#include "util.h"
+#include <android-base/hex.h>
#include <android/os/IServiceManager.h>
#include <binder/ParcelableHolder.h>
#include <binder/PersistableBundle.h>
using ::android::status_t;
+using ::android::base::HexString;
enum ByteEnum : int8_t {};
enum IntEnum : int32_t {};
@@ -128,7 +130,7 @@
[] (const ::android::Parcel& p, uint8_t len) {
FUZZ_LOG() << "about to readInplace";
const void* r = p.readInplace(len);
- FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << hexString(r, len);
+ FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << (r ? HexString(r, len) : "null");
},
PARCEL_READ_OPT_STATUS(int32_t, readInt32),
PARCEL_READ_OPT_STATUS(uint32_t, readUint32),
@@ -153,7 +155,7 @@
FUZZ_LOG() << "about to readString8Inplace";
size_t outLen = 0;
const char* str = p.readString8Inplace(&outLen);
- std::string bytes = hexString(str, sizeof(char) * (outLen + 1));
+ std::string bytes = str ? HexString(str, sizeof(char) * (outLen + 1)) : "null";
FUZZ_LOG() << "readString8Inplace: " << bytes << " size: " << outLen;
},
PARCEL_READ_OPT_STATUS(android::String16, readString16),
@@ -163,7 +165,7 @@
FUZZ_LOG() << "about to readString16Inplace";
size_t outLen = 0;
const char16_t* str = p.readString16Inplace(&outLen);
- std::string bytes = hexString(str, sizeof(char16_t) * (outLen + 1));
+ std::string bytes = str ? HexString(str, sizeof(char16_t) * (outLen + 1)) : "null";
FUZZ_LOG() << "readString16Inplace: " << bytes << " size: " << outLen;
},
PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readStrongBinder),
diff --git a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
index 35b5ebc..ee9840f 100644
--- a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
@@ -18,10 +18,12 @@
#include "hwbinder.h"
#include "util.h"
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <hwbinder/Parcel.h>
using ::android::status_t;
+using ::android::base::HexString;
// TODO: support scatter-gather types
@@ -70,13 +72,13 @@
FUZZ_LOG() << "about to read";
std::vector<uint8_t> data (length);
status_t status = p.read(data.data(), length);
- FUZZ_LOG() << "read status: " << status << " data: " << hexString(data.data(), data.size());
+ FUZZ_LOG() << "read status: " << status << " data: " << HexString(data.data(), data.size());
},
[] (const ::android::hardware::Parcel& p, uint8_t length) {
FUZZ_LOG() << "about to read";
std::vector<uint8_t> data (length);
const void* inplace = p.readInplace(length);
- FUZZ_LOG() << "read status: " << hexString(inplace, length);
+ FUZZ_LOG() << "read status: " << (inplace ? HexString(inplace, length) : "null");
},
PARCEL_READ_WITH_STATUS(int8_t, readInt8),
PARCEL_READ_WITH_STATUS(uint8_t, readUint8),
@@ -100,7 +102,7 @@
FUZZ_LOG() << "about to readString16Inplace";
size_t outSize = 0;
const char16_t* str = p.readString16Inplace(&outSize);
- FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outSize);
+ FUZZ_LOG() << "readString16Inplace: " << HexString(str, sizeof(char16_t) * outSize);
},
PARCEL_READ_OPT_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
index 2a79e85..f435dae 100644
--- a/libs/binder/tests/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -22,6 +22,7 @@
#include <iostream>
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
#include <android/binder_libbinder.h>
@@ -35,6 +36,7 @@
using android::fillRandomParcel;
using android::sp;
+using android::base::HexString;
void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
// TODO: functionality to create random parcels for libhwbinder parcels
@@ -78,8 +80,8 @@
CHECK(reads.size() <= 255) << reads.size();
FUZZ_LOG() << "backend: " << backend;
- FUZZ_LOG() << "input: " << hexString(p.data(), p.dataSize());
- FUZZ_LOG() << "instructions: " << hexString(instructions);
+ FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize());
+ FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size());
for (size_t i = 0; i + 1 < instructions.size(); i += 2) {
uint8_t a = instructions[i];
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 92fdc72..a2472f8 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <binder/IServiceManager.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTransportRaw.h>
#include <fuzzbinder/random_fd.h>
#include <utils/String16.h>
@@ -35,7 +36,7 @@
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
if (provider.ConsumeBool()) {
- auto session = sp<RpcSession>::make();
+ auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
CHECK(session->addNullDebuggingClient());
p->markForRpc(session);
fillRandomParcelData(p, std::move(provider));
diff --git a/libs/binder/tests/parcel_fuzzer/util.cpp b/libs/binder/tests/parcel_fuzzer/util.cpp
deleted file mode 100644
index 479f406..0000000
--- a/libs/binder/tests/parcel_fuzzer/util.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define FUZZ_LOG_TAG "util"
-#include "util.h"
-
-#include <android-base/logging.h>
-
-#include <iomanip>
-#include <sstream>
-
-std::string hexString(const void* bytes, size_t len) {
- if (bytes == nullptr) return "<null>";
-
- const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
- char chars[] = "0123456789abcdef";
- std::string result;
- result.resize(len * 2);
-
- for (size_t i = 0; i < len; i++) {
- result[2 * i] = chars[bytes8[i] >> 4];
- result[2 * i + 1] = chars[bytes8[i] & 0xf];
- }
-
- return result;
-}
-std::string hexString(const std::vector<uint8_t>& bytes) {
- return hexString(bytes.data(), bytes.size());
-}
diff --git a/libs/binder/tests/parcel_fuzzer/util.h b/libs/binder/tests/parcel_fuzzer/util.h
index 45e8c57..a5d0dae 100644
--- a/libs/binder/tests/parcel_fuzzer/util.h
+++ b/libs/binder/tests/parcel_fuzzer/util.h
@@ -49,6 +49,3 @@
FuzzLog& log() { return *this; }
};
#endif
-
-std::string hexString(const void* bytes, size_t len);
-std::string hexString(const std::vector<uint8_t>& bytes);
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index a0032ae..cda9e19 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -52,14 +52,14 @@
],
shared_libs: [
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
"liblog",
],
export_shared_lib_headers: [
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
],
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index b0dc27f..326da3a 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -67,6 +67,8 @@
":guiconstants_aidl",
"android/gui/FocusRequest.aidl",
"android/gui/InputApplicationInfo.aidl",
+ "android/gui/IWindowInfosListener.aidl",
+ "android/gui/IWindowInfosReportedListener.aidl",
"android/gui/WindowInfo.aidl",
"WindowInfo.cpp",
],
@@ -195,6 +197,7 @@
"SyncFeatures.cpp",
"TransactionTracing.cpp",
"view/Surface.cpp",
+ "WindowInfosListenerReporter.cpp",
"bufferqueue/1.0/B2HProducerListener.cpp",
"bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
"bufferqueue/2.0/B2HProducerListener.cpp",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index d9024fa..70f2ae7 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -166,9 +166,10 @@
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
SurfaceComposerClient::Transaction()
- .setFlags(surface, layer_state_t::eEnableBackpressure,
- layer_state_t::eEnableBackpressure)
- .apply();
+ .setFlags(surface, layer_state_t::eEnableBackpressure,
+ layer_state_t::eEnableBackpressure)
+ .setApplyToken(mApplyToken)
+ .apply();
mNumAcquired = 0;
mNumFrameAvailable = 0;
BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width,
@@ -190,7 +191,7 @@
}
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
- int32_t format) {
+ int32_t format, SurfaceComposerClient::Transaction* outTransaction) {
std::unique_lock _lock{mMutex};
if (mFormat != format) {
mFormat = format;
@@ -227,15 +228,18 @@
// We only need to update the scale if we've received at least one buffer. The reason
// for this is the scale is calculated based on the requested size and buffer size.
// If there's no buffer, the scale will always be 1.
+ SurfaceComposerClient::Transaction* destFrameTransaction =
+ (outTransaction) ? outTransaction : &t;
if (mSurfaceControl != nullptr && mLastBufferInfo.hasBuffer) {
- t.setDestinationFrame(mSurfaceControl,
- Rect(0, 0, newSize.getWidth(), newSize.getHeight()));
+ destFrameTransaction->setDestinationFrame(mSurfaceControl,
+ Rect(0, 0, newSize.getWidth(),
+ newSize.getHeight()));
}
applyTransaction = true;
}
}
if (applyTransaction) {
- t.apply();
+ t.setApplyToken(mApplyToken).apply();
}
}
@@ -453,6 +457,9 @@
incStrong((void*)transactionCallbackThunk);
Rect crop = computeCrop(bufferItem);
+ const bool updateDestinationFrame =
+ bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE ||
+ !mLastBufferInfo.hasBuffer;
mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
bufferItem.mScalingMode, crop);
@@ -470,7 +477,9 @@
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
- t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight()));
+ if (updateDestinationFrame) {
+ t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight()));
+ }
t->setBufferCrop(mSurfaceControl, crop);
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 5023b6b..2930154 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -34,7 +34,6 @@
#include <gui/BufferQueueCore.h>
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
#include <private/gui/ComposerService.h>
#include <system/window.h>
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index bab9ebf..3bf6306 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -44,6 +44,7 @@
namespace android {
+using gui::IWindowInfosListener;
using ui::ColorMode;
class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
@@ -1232,6 +1233,22 @@
return reply.readInt32(buffers);
}
+
+ status_t addWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) const override {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener));
+ return remote()->transact(BnSurfaceComposer::ADD_WINDOW_INFOS_LISTENER, data, &reply);
+ }
+
+ status_t removeWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) const override {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener));
+ return remote()->transact(BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER, data, &reply);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -2115,6 +2132,20 @@
SAFE_PARCEL(reply->writeBool, success);
return err;
}
+ case ADD_WINDOW_INFOS_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IWindowInfosListener> listener;
+ SAFE_PARCEL(data.readStrongBinder, &listener);
+
+ return addWindowInfosListener(listener);
+ }
+ case REMOVE_WINDOW_INFOS_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IWindowInfosListener> listener;
+ SAFE_PARCEL(data.readStrongBinder, &listener);
+
+ return removeWindowInfosListener(listener);
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index d73470d..23895c0 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -67,6 +67,7 @@
fixedTransformHint(ui::Transform::ROT_INVALID),
frameNumber(0),
autoRefresh(false),
+ isTrustedOverlay(false),
bufferCrop(Rect::INVALID_RECT),
destinationFrame(Rect::INVALID_RECT),
releaseBufferListener(nullptr) {
@@ -171,6 +172,7 @@
SAFE_PARCEL(output.write, stretchEffect);
SAFE_PARCEL(output.write, bufferCrop);
SAFE_PARCEL(output.write, destinationFrame);
+ SAFE_PARCEL(output.writeBool, isTrustedOverlay);
return NO_ERROR;
}
@@ -299,6 +301,7 @@
SAFE_PARCEL(input.read, stretchEffect);
SAFE_PARCEL(input.read, bufferCrop);
SAFE_PARCEL(input.read, destinationFrame);
+ SAFE_PARCEL(input.readBool, &isTrustedOverlay);
return NO_ERROR;
}
@@ -534,6 +537,10 @@
what |= eAutoRefreshChanged;
autoRefresh = other.autoRefresh;
}
+ if (other.what & eTrustedOverlayChanged) {
+ what |= eTrustedOverlayChanged;
+ isTrustedOverlay = other.isTrustedOverlay;
+ }
if (other.what & eReleaseBufferListenerChanged) {
if (releaseBufferListener) {
ALOGW("Overriding releaseBufferListener");
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index ec03c21..f620f5a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/gui/IWindowInfosListener.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/SortedVector.h>
@@ -54,6 +55,7 @@
using gui::FocusRequest;
using gui::WindowInfo;
using gui::WindowInfoHandle;
+using gui::WindowInfosListener;
using ui::ColorMode;
// ---------------------------------------------------------------------------
@@ -95,6 +97,7 @@
if (instance.mComposerService == nullptr) {
if (ComposerService::getInstance().connectLocked()) {
ALOGD("ComposerService reconnected");
+ WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService);
}
}
return instance.mComposerService;
@@ -1652,6 +1655,19 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrustedOverlay(
+ const sp<SurfaceControl>& sc, bool isTrustedOverlay) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eTrustedOverlayChanged;
+ s->isTrustedOverlay = isTrustedOverlay;
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken(
const sp<IBinder>& applyToken) {
mApplyToken = applyToken;
@@ -1768,15 +1784,10 @@
// ---------------------------------------------------------------------------
-SurfaceComposerClient::SurfaceComposerClient()
- : mStatus(NO_INIT)
-{
-}
+SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {}
SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client)
- : mStatus(NO_ERROR), mClient(client)
-{
-}
+ : mStatus(NO_ERROR), mClient(client) {}
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
@@ -2142,6 +2153,18 @@
return ComposerService::getComposerService()->getGPUContextPriority();
}
+status_t SurfaceComposerClient::addWindowInfosListener(
+ const sp<WindowInfosListener>& windowInfosListener) {
+ return WindowInfosListenerReporter::getInstance()
+ ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService());
+}
+
+status_t SurfaceComposerClient::removeWindowInfosListener(
+ const sp<WindowInfosListener>& windowInfosListener) {
+ return WindowInfosListenerReporter::getInstance()
+ ->removeWindowInfosListener(windowInfosListener, ComposerService::getComposerService());
+}
+
// ----------------------------------------------------------------------------
status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
new file mode 100644
index 0000000..c00a438
--- /dev/null
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/WindowInfosListenerReporter.h>
+
+namespace android {
+
+using gui::IWindowInfosReportedListener;
+using gui::WindowInfo;
+using gui::WindowInfosListener;
+
+sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() {
+ static sp<WindowInfosListenerReporter> sInstance = new WindowInfosListenerReporter;
+ return sInstance;
+}
+
+status_t WindowInfosListenerReporter::addWindowInfosListener(
+ const sp<WindowInfosListener>& windowInfosListener,
+ const sp<ISurfaceComposer>& surfaceComposer) {
+ status_t status = OK;
+ {
+ std::scoped_lock lock(mListenersMutex);
+ if (mWindowInfosListeners.empty()) {
+ status = surfaceComposer->addWindowInfosListener(this);
+ }
+
+ if (status == OK) {
+ mWindowInfosListeners.insert(windowInfosListener);
+ }
+ }
+
+ return status;
+}
+
+status_t WindowInfosListenerReporter::removeWindowInfosListener(
+ const sp<WindowInfosListener>& windowInfosListener,
+ const sp<ISurfaceComposer>& surfaceComposer) {
+ status_t status = OK;
+ {
+ std::scoped_lock lock(mListenersMutex);
+ if (mWindowInfosListeners.size() == 1) {
+ status = surfaceComposer->removeWindowInfosListener(this);
+ }
+
+ if (status == OK) {
+ mWindowInfosListeners.erase(windowInfosListener);
+ }
+ }
+
+ return status;
+}
+
+binder::Status WindowInfosListenerReporter::onWindowInfosChanged(
+ const std::vector<WindowInfo>& windowInfos,
+ const sp<IWindowInfosReportedListener>& windowInfosReportedListener) {
+ std::unordered_set<sp<WindowInfosListener>, ISurfaceComposer::SpHash<WindowInfosListener>>
+ windowInfosListeners;
+
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (auto listener : mWindowInfosListeners) {
+ windowInfosListeners.insert(listener);
+ }
+ }
+
+ for (auto listener : windowInfosListeners) {
+ listener->onWindowInfosChanged(windowInfos);
+ }
+
+ if (windowInfosReportedListener) {
+ windowInfosReportedListener->onWindowInfosReported();
+ }
+
+ return binder::Status::ok();
+}
+
+void WindowInfosListenerReporter::reconnect(const sp<ISurfaceComposer>& composerService) {
+ std::scoped_lock lock(mListenersMutex);
+ if (!mWindowInfosListeners.empty()) {
+ composerService->addWindowInfosListener(this);
+ }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl
new file mode 100644
index 0000000..d4553ca
--- /dev/null
+++ b/libs/gui/android/gui/IWindowInfosListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+import android.gui.IWindowInfosReportedListener;
+import android.gui.WindowInfo;
+
+/** @hide */
+oneway interface IWindowInfosListener
+{
+ void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener);
+}
diff --git a/libs/input/android/os/ISetInputWindowsListener.aidl b/libs/gui/android/gui/IWindowInfosReportedListener.aidl
similarity index 85%
rename from libs/input/android/os/ISetInputWindowsListener.aidl
rename to libs/gui/android/gui/IWindowInfosReportedListener.aidl
index bb58fb6..0e4cce6 100644
--- a/libs/input/android/os/ISetInputWindowsListener.aidl
+++ b/libs/gui/android/gui/IWindowInfosReportedListener.aidl
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package android.os;
+package android.gui;
/** @hide */
-oneway interface ISetInputWindowsListener
+oneway interface IWindowInfosReportedListener
{
- void onSetInputWindowsFinished();
+ void onWindowInfosReported();
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 0d6a673..ea9b1c6 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -96,7 +96,8 @@
void setTransactionCompleteCallback(uint64_t frameNumber,
std::function<void(int64_t)>&& transactionCompleteCallback);
- void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format);
+ void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format,
+ SurfaceComposerClient::Transaction* outTransaction = nullptr);
void flushShadowQueue() {}
status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index c0a2335..b7cd082 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -22,6 +22,7 @@
#include <android/gui/IScreenCaptureListener.h>
#include <android/gui/ITransactionTraceListener.h>
#include <android/gui/ITunnelModeEnabledListener.h>
+#include <android/gui/IWindowInfosListener.h>
#include <binder/IBinder.h>
#include <binder/IInterface.h>
#include <ftl/Flags.h>
@@ -550,6 +551,11 @@
* in MIN_UNDEQUEUED_BUFFERS.
*/
virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0;
+
+ virtual status_t addWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0;
+ virtual status_t removeWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0;
};
// ----------------------------------------------------------------------------
@@ -622,6 +628,8 @@
ON_PULL_ATOM,
ADD_TUNNEL_MODE_ENABLED_LISTENER,
REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
+ ADD_WINDOW_INFOS_LISTENER,
+ REMOVE_WINDOW_INFOS_LISTENER,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index d1a9a04..b27d9cf 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -116,6 +116,7 @@
eBlurRegionsChanged = 0x800'00000000,
eAutoRefreshChanged = 0x1000'00000000,
eStretchChanged = 0x2000'00000000,
+ eTrustedOverlayChanged = 0x4000'00000000,
};
layer_state_t();
@@ -221,6 +222,10 @@
// in shared buffer mode.
bool autoRefresh;
+ // An inherited state that indicates that this surface control and its children
+ // should be trusted for input occlusion detection purposes
+ bool isTrustedOverlay;
+
// Stretch effect to be applied to this layer
StretchEffect stretchEffect;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 1dfc83b..869cef6 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -42,6 +42,7 @@
#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerState.h>
#include <gui/SurfaceControl.h>
+#include <gui/WindowInfosListenerReporter.h>
#include <math/vec3.h>
namespace android {
@@ -535,6 +536,9 @@
// in shared buffer mode.
Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh);
+ // Sets that this surface control and its children are trusted overlays for input
+ Transaction& setTrustedOverlay(const sp<SurfaceControl>& sc, bool isTrustedOverlay);
+
// Queues up transactions using this token in SurfaceFlinger. By default, all transactions
// from a client are placed on the same queue. This can be used to prevent multiple
// transactions from blocking each other.
@@ -619,6 +623,9 @@
static status_t removeTunnelModeEnabledListener(
const sp<gui::ITunnelModeEnabledListener>& listener);
+ status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
+ status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
+
private:
virtual void onFirstRef();
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index b0c631a..7af1f0e 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -242,18 +242,6 @@
}
/**
- * Requests that the state of this object be updated to reflect
- * the most current available information about the application.
- * As this class is created as RefBase object, no pure virtual function is allowed.
- *
- * This method should only be called from within the input dispatcher's
- * critical section.
- *
- * Returns true on success, or false if the handle is no longer valid.
- */
- virtual bool updateInfo() { return false; }
-
- /**
* Updates from another input window handle.
*/
void updateFrom(const sp<WindowInfoHandle> handle);
diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h
new file mode 100644
index 0000000..8a70b9b
--- /dev/null
+++ b/libs/gui/include/gui/WindowInfosListener.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gui/WindowInfo.h>
+#include <utils/RefBase.h>
+
+namespace android::gui {
+
+class WindowInfosListener : public virtual RefBase {
+public:
+ virtual void onWindowInfosChanged(const std::vector<WindowInfo>& /*windowInfos*/) = 0;
+};
+} // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
new file mode 100644
index 0000000..7cb96e0
--- /dev/null
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/gui/BnWindowInfosListener.h>
+#include <android/gui/IWindowInfosReportedListener.h>
+#include <binder/IBinder.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/WindowInfosListener.h>
+#include <utils/Mutex.h>
+#include <unordered_set>
+
+namespace android {
+class ISurfaceComposer;
+
+class WindowInfosListenerReporter : public gui::BnWindowInfosListener {
+public:
+ static sp<WindowInfosListenerReporter> getInstance();
+ binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos,
+ const sp<gui::IWindowInfosReportedListener>&) override;
+
+ status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
+ const sp<ISurfaceComposer>&);
+ status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
+ const sp<ISurfaceComposer>&);
+ void reconnect(const sp<ISurfaceComposer>&);
+
+private:
+ std::mutex mListenersMutex;
+ std::unordered_set<sp<gui::WindowInfosListener>,
+ ISurfaceComposer::SpHash<gui::WindowInfosListener>>
+ mWindowInfosListeners GUARDED_BY(mListenersMutex);
+};
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8d7a356..d1ad478 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -902,6 +902,16 @@
status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; }
+ status_t addWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override {
+ return NO_ERROR;
+ }
+
+ status_t removeWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override {
+ return NO_ERROR;
+ }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 1a142c9..e73c3b8 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -68,12 +68,10 @@
static_libs: [
"libui-types",
- "libgui_window_info_static",
],
export_static_lib_headers: [
"libui-types",
- "libgui_window_info_static",
],
target: {
@@ -85,7 +83,6 @@
"android/os/IInputFlinger.aidl",
"android/os/InputEventInjectionResult.aidl",
"android/os/InputEventInjectionSync.aidl",
- "android/os/ISetInputWindowsListener.aidl",
],
export_shared_lib_headers: ["libbinder"],
@@ -96,6 +93,14 @@
"libui",
],
+ static_libs: [
+ "libgui_window_info_static",
+ ],
+
+ export_static_lib_headers: [
+ "libgui_window_info_static",
+ ],
+
sanitize: {
misc_undefined: ["integer"],
},
@@ -113,14 +118,18 @@
"InputTransport.cpp",
"android/os/IInputConstants.aidl",
"android/os/IInputFlinger.aidl",
- "android/os/ISetInputWindowsListener.aidl",
],
static_libs: [
"libhostgraphics",
+ "libgui_window_info_static",
],
shared_libs: [
"libbinder",
],
+
+ export_static_lib_headers: [
+ "libgui_window_info_static",
+ ],
},
},
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 82a814f..1e8ff94 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -23,6 +23,7 @@
#include <limits.h>
#include <string.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <gui/constants.h>
#include <input/Input.h>
@@ -42,6 +43,15 @@
namespace {
+// When per-window-input-rotation is enabled, InputFlinger works in the un-rotated display
+// coordinates and SurfaceFlinger includes the display rotation in the input window transforms.
+bool isPerWindowInputRotationEnabled() {
+ static const bool PER_WINDOW_INPUT_ROTATION =
+ base::GetBoolProperty("persist.debug.per_window_input_rotation", false);
+
+ return PER_WINDOW_INPUT_ROTATION;
+}
+
float transformAngle(const ui::Transform& transform, float angleRadians) {
// Construct and transform a vector oriented at the specified clockwise angle from vertical.
// Coordinate system: down is increasing Y, right is increasing X.
@@ -160,6 +170,9 @@
case AINPUT_EVENT_TYPE_DRAG: {
return "DRAG";
}
+ case AINPUT_EVENT_TYPE_TOUCH_MODE: {
+ return "TOUCH_MODE";
+ }
}
return "UNKNOWN";
}
@@ -526,6 +539,8 @@
size_t historicalIndex) const {
const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
+ if (!isPerWindowInputRotationEnabled()) return coords->getAxisValue(axis);
+
if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
// For compatibility, convert raw coordinates into "oriented screen space". Once app
// developers are educated about getRaw, we can consider removing this.
@@ -883,6 +898,19 @@
mY = from.mY;
}
+// --- TouchModeEvent ---
+
+void TouchModeEvent::initialize(int32_t id, bool isInTouchMode) {
+ InputEvent::initialize(id, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN,
+ ADISPLAY_ID_NONE, INVALID_HMAC);
+ mIsInTouchMode = isInTouchMode;
+}
+
+void TouchModeEvent::initialize(const TouchModeEvent& from) {
+ InputEvent::initialize(from);
+ mIsInTouchMode = from.mIsInTouchMode;
+}
+
// --- PooledInputEventFactory ---
PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
@@ -937,6 +965,15 @@
return event;
}
+TouchModeEvent* PooledInputEventFactory::createTouchModeEvent() {
+ if (mTouchModeEventPool.empty()) {
+ return new TouchModeEvent();
+ }
+ TouchModeEvent* event = mTouchModeEventPool.front().release();
+ mTouchModeEventPool.pop();
+ return event;
+}
+
void PooledInputEventFactory::recycle(InputEvent* event) {
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY:
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index ea8b9a7..1e93dfb 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -116,6 +116,7 @@
case Type::FOCUS:
case Type::CAPTURE:
case Type::DRAG:
+ case Type::TOUCH_MODE:
return true;
case Type::TIMELINE: {
const nsecs_t gpuCompletedTime =
@@ -151,6 +152,8 @@
return sizeof(Header) + body.drag.size();
case Type::TIMELINE:
return sizeof(Header) + body.timeline.size();
+ case Type::TOUCH_MODE:
+ return sizeof(Header) + body.touchMode.size();
}
return sizeof(Header);
}
@@ -293,6 +296,10 @@
msg->body.timeline.graphicsTimeline = body.timeline.graphicsTimeline;
break;
}
+ case InputMessage::Type::TOUCH_MODE: {
+ msg->body.touchMode.eventId = body.touchMode.eventId;
+ msg->body.touchMode.isInTouchMode = body.touchMode.isInTouchMode;
+ }
}
}
@@ -665,6 +672,22 @@
return mChannel->sendMessage(&msg);
}
+status_t InputPublisher::publishTouchModeEvent(uint32_t seq, int32_t eventId, bool isInTouchMode) {
+ if (ATRACE_ENABLED()) {
+ std::string message =
+ StringPrintf("publishTouchModeEvent(inputChannel=%s, isInTouchMode=%s)",
+ mChannel->getName().c_str(), toString(isInTouchMode));
+ ATRACE_NAME(message.c_str());
+ }
+
+ InputMessage msg;
+ msg.header.type = InputMessage::Type::TOUCH_MODE;
+ msg.header.seq = seq;
+ msg.body.touchMode.eventId = eventId;
+ msg.body.touchMode.isInTouchMode = isInTouchMode;
+ return mChannel->sendMessage(&msg);
+}
+
android::base::Result<InputPublisher::ConsumerResponse> InputPublisher::receiveConsumerResponse() {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' publisher ~ %s", mChannel->getName().c_str(), __func__);
@@ -866,6 +889,16 @@
*outEvent = dragEvent;
break;
}
+
+ case InputMessage::Type::TOUCH_MODE: {
+ TouchModeEvent* touchModeEvent = factory->createTouchModeEvent();
+ if (!touchModeEvent) return NO_MEMORY;
+
+ initializeTouchModeEvent(touchModeEvent, &mMsg);
+ *outSeq = mMsg.header.seq;
+ *outEvent = touchModeEvent;
+ break;
+ }
}
}
return OK;
@@ -1370,6 +1403,10 @@
msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
}
+void InputConsumer::initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg) {
+ event->initialize(msg->body.touchMode.eventId, msg->body.touchMode.isInTouchMode);
+}
+
void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
uint32_t pointerCount = msg->body.motion.pointerCount;
PointerCoords pointerCoords[pointerCount];
@@ -1476,6 +1513,11 @@
presentTime);
break;
}
+ case InputMessage::Type::TOUCH_MODE: {
+ out += android::base::StringPrintf("isInTouchMode=%s",
+ toString(msg.body.touchMode.isInTouchMode));
+ break;
+ }
}
out += "\n";
}
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
index 43b262f..00ebd4d 100644
--- a/libs/input/android/os/IInputFlinger.aidl
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -19,17 +19,10 @@
import android.InputChannel;
import android.gui.FocusRequest;
import android.gui.WindowInfo;
-import android.os.ISetInputWindowsListener;
/** @hide */
interface IInputFlinger
{
- // SurfaceFlinger is the caller of this method, it uses the listener callback to ensure the
- // ordering when needed.
- // SurfaceFlinger calls this only every VSync, so overflow of binder's oneway buffer
- // shouldn't be a concern.
- oneway void setInputWindows(in WindowInfo[] windowInfoHandles,
- in @nullable ISetInputWindowsListener setInputWindowsListener);
InputChannel createInputChannel(in @utf8InCpp String name);
void removeInputChannel(in IBinder connectionToken);
/**
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index a2fa319..b1ef753 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -17,6 +17,7 @@
#include <array>
#include <math.h>
+#include <android-base/properties.h>
#include <attestation/HmacKeyManager.h>
#include <binder/Parcel.h>
#include <gtest/gtest.h>
@@ -226,13 +227,34 @@
static constexpr float X_OFFSET = 1;
static constexpr float Y_OFFSET = 1.1;
+ static const std::optional<bool> INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE;
+
int32_t mId;
ui::Transform mTransform;
+ void SetUp() override;
+ void TearDown() override;
+
void initializeEventWithHistory(MotionEvent* event);
void assertEqualsEventWithHistory(const MotionEvent* event);
};
+const std::optional<bool> MotionEventTest::INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE =
+ !base::GetProperty("persist.debug.per_window_input_rotation", "").empty()
+ ? std::optional(base::GetBoolProperty("persist.debug.per_window_input_rotation", false))
+ : std::nullopt;
+
+void MotionEventTest::SetUp() {
+ // Ensure per_window_input_rotation is enabled.
+ base::SetProperty("persist.debug.per_window_input_rotation", "true");
+}
+
+void MotionEventTest::TearDown() {
+ const auto val = INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE.has_value()
+ ? (*INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE ? "true" : "false")
+ : "";
+ base::SetProperty("persist.debug.per_window_input_rotation", val);
+}
void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
mId = InputEvent::nextId();
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 5d1f2c3..8db5bf1 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -56,6 +56,7 @@
void PublishAndConsumeFocusEvent();
void PublishAndConsumeCaptureEvent();
void PublishAndConsumeDragEvent();
+ void PublishAndConsumeTouchModeEvent();
};
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
@@ -413,6 +414,46 @@
<< "finished signal's consume time should be greater than publish time";
}
+void InputPublisherAndConsumerTest::PublishAndConsumeTouchModeEvent() {
+ status_t status;
+
+ constexpr uint32_t seq = 15;
+ int32_t eventId = InputEvent::nextId();
+ constexpr bool touchModeEnabled = true;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ status = mPublisher->publishTouchModeEvent(seq, eventId, touchModeEnabled);
+ ASSERT_EQ(OK, status) << "publisher publishTouchModeEvent should return OK";
+
+ uint32_t consumeSeq;
+ InputEvent* event;
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ ASSERT_EQ(OK, status) << "consumer consume should return OK";
+
+ ASSERT_TRUE(event != nullptr) << "consumer should have returned non-NULL event";
+ ASSERT_EQ(AINPUT_EVENT_TYPE_TOUCH_MODE, event->getType())
+ << "consumer should have returned a touch mode event";
+
+ const TouchModeEvent& touchModeEvent = static_cast<const TouchModeEvent&>(*event);
+ EXPECT_EQ(seq, consumeSeq);
+ EXPECT_EQ(eventId, touchModeEvent.getId());
+ EXPECT_EQ(touchModeEnabled, touchModeEvent.isInTouchMode());
+
+ status = mConsumer->sendFinishedSignal(seq, true);
+ ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK";
+
+ Result<InputPublisher::ConsumerResponse> result = mPublisher->receiveConsumerResponse();
+ ASSERT_TRUE(result.ok()) << "receiveConsumerResponse should return OK";
+ ASSERT_TRUE(std::holds_alternative<InputPublisher::Finished>(*result));
+ const InputPublisher::Finished& finish = std::get<InputPublisher::Finished>(*result);
+ ASSERT_EQ(seq, finish.seq)
+ << "receiveConsumerResponse should have returned the original sequence number";
+ ASSERT_TRUE(finish.handled)
+ << "receiveConsumerResponse should have set handled to consumer's reply";
+ ASSERT_GE(finish.consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
+}
+
TEST_F(InputPublisherAndConsumerTest, SendTimeline) {
const int32_t inputEventId = 20;
std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
@@ -449,6 +490,10 @@
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeDragEvent());
}
+TEST_F(InputPublisherAndConsumerTest, PublishTouchModeEvent_EndToEnd) {
+ ASSERT_NO_FATAL_FAILURE(PublishAndConsumeTouchModeEvent());
+}
+
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) {
status_t status;
const size_t pointerCount = 1;
@@ -520,6 +565,7 @@
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeDragEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
+ ASSERT_NO_FATAL_FAILURE(PublishAndConsumeTouchModeEvent());
}
} // namespace android
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 59fed1f..18289a5 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -102,6 +102,10 @@
CHECK_OFFSET(InputMessage::Body::Timeline, eventId, 0);
CHECK_OFFSET(InputMessage::Body::Timeline, empty, 4);
CHECK_OFFSET(InputMessage::Body::Timeline, graphicsTimeline, 8);
+
+ CHECK_OFFSET(InputMessage::Body::TouchMode, eventId, 0);
+ CHECK_OFFSET(InputMessage::Body::TouchMode, isInTouchMode, 4);
+ CHECK_OFFSET(InputMessage::Body::TouchMode, empty, 5);
}
void TestHeaderSize() {
@@ -123,6 +127,7 @@
static_assert(sizeof(InputMessage::Body::Focus) == 8);
static_assert(sizeof(InputMessage::Body::Capture) == 8);
static_assert(sizeof(InputMessage::Body::Drag) == 16);
+ static_assert(sizeof(InputMessage::Body::TouchMode) == 8);
// Timeline
static_assert(GraphicsTimeline::SIZE == 2);
static_assert(sizeof(InputMessage::Body::Timeline) == 24);
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 8a677ce..e2f32e3 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -698,6 +698,10 @@
"gralloc and AHardwareBuffer flags don't match");
static_assert(AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE == (uint64_t)BufferUsage::GPU_MIPMAP_COMPLETE,
"gralloc and AHardwareBuffer flags don't match");
+ static_assert(AHARDWAREBUFFER_USAGE_CAMERA_WRITE == (uint64_t)BufferUsage::CAMERA_OUTPUT,
+ "gralloc and AHardwareBuffer flags don't match");
+ static_assert(AHARDWAREBUFFER_USAGE_CAMERA_READ == (uint64_t)BufferUsage::CAMERA_INPUT,
+ "gralloc and AHardwareBuffer flags don't match");
return usage;
}
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 50fe0b7..21931bb 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -91,6 +91,20 @@
AHARDWAREBUFFER_FORMAT_YCbCr_422_I = 0x14,
};
+/**
+ * Buffer usage flags.
+ */
+enum {
+ /* for future proofing, keep these in sync with hardware/gralloc.h */
+
+ /* The buffer will be written by the HW camera pipeline. */
+ AHARDWAREBUFFER_USAGE_CAMERA_WRITE = 2UL << 16,
+ /* The buffer will be read by the HW camera pipeline. */
+ AHARDWAREBUFFER_USAGE_CAMERA_READ = 4UL << 16,
+ /* Mask for the camera access values. */
+ AHARDWAREBUFFER_USAGE_CAMERA_MASK = 6UL << 16,
+};
+
__END_DECLS
#endif /* ANDROID_VNDK_NATIVEWINDOW_AHARDWAREBUFFER_H */
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index ae8f238..01df6a6 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -95,25 +95,28 @@
.alpha = 1,
};
+ base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer, &caster};
- // When sourceDataspace matches dest, the general shadow fragment shader doesn't
- // have color correction added.
- // independently, when it is not srgb, the *vertex* shader has color correction added.
- // This may be a bug, but the shader still needs to be cached as it is triggered
- // during youtube pip.
- for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
- layer.sourceDataspace = dataspace;
- // The 2nd matrix, which has different scales for x and y, will
- // generate the slower (more general case) shadow shader
- for (auto transform : {mat4(), kScaleAndTranslate, kFlip}) {
- layer.geometry.positionTransform = transform;
- caster.geometry.positionTransform = transform;
- for (bool translucent : {false, true}){
- layer.shadow.casterIsTranslucent = translucent;
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
- }
- }
+ // Four combinations of settings are used (two transforms here, and drawShadowLayers is
+ // called with two different destination data spaces) They're all rounded rect.
+ // Three of these are cache misses that generate new shaders.
+ // The first combination generates a short and simple shadow shader.
+ // The second combination, flip transform, generates two shaders. The first appears to involve
+ // gaussian_fp. The second is a long and general purpose shadow shader with a device space
+ // transformation stage.
+ // The third combination is a cache hit, nothing new.
+ // The fourth combination, flip transform with a non-SRGB destination dataspace, is new.
+ // It is unique in that nearly everything is done in the vertex shader, and that vertex shader
+ // requires color correction. This is triggered differently from every other instance of color
+ // correction. All other instances are triggered when src and dst dataspaces differ, while
+ // this one is triggered by the destination being non-srgb. Apparently since the third
+ // combination is a cache hit, this color correction is only added when the vertex shader is
+ // doing something non-trivial.
+ for (auto transform : {mat4(), kFlip}) {
+ layer.geometry.positionTransform = transform;
+ caster.geometry.positionTransform = transform;
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), &drawFence);
}
}
@@ -138,6 +141,7 @@
}},
};
+ base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
layer.sourceDataspace = dataspace;
@@ -151,7 +155,7 @@
for (auto alpha : {half(.2f), half(1.0f)}) {
layer.alpha = alpha;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd(), &drawFence);
}
}
}
@@ -174,13 +178,14 @@
.alpha = 0.5,
};
+ base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
for (auto transform : {mat4(), kScaleAndTranslate}) {
layer.geometry.positionTransform = transform;
for (float roundedCornersRadius : {0.0f, 50.f}) {
layer.geometry.roundedCornersRadius = roundedCornersRadius;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd(), &drawFence);
}
}
}
@@ -199,12 +204,13 @@
.skipContentDraw = true,
};
+ base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
// Different blur code is invoked for radii less and greater than 30 pixels
for (int radius : {9, 60}) {
layer.backgroundBlurRadius = radius;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd(), &drawFence);
}
}
@@ -240,6 +246,7 @@
},
};
+ base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
layer.source = pixelSource;
@@ -251,7 +258,7 @@
for (float alpha : {0.5f, 1.f}) {
layer.alpha = alpha,
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd(), &drawFence);
}
}
}
@@ -287,9 +294,10 @@
};
+ base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd(), &drawFence);
}
static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
@@ -316,9 +324,10 @@
};
+ base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd(), &drawFence);
}
//
@@ -381,6 +390,7 @@
ExternalTexture::Usage::WRITEABLE);
drawHolePunchLayer(renderengine, display, dstTexture);
drawSolidLayers(renderengine, display, dstTexture);
+
drawShadowLayers(renderengine, display, srcTexture);
drawShadowLayers(renderengine, p3Display, srcTexture);
@@ -421,6 +431,14 @@
drawPIPImageLayer(renderengine, display, dstTexture, externalTexture);
+ // draw one final layer synchronously to force GL submit
+ LayerSettings layer{
+ .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)},
+ };
+ auto layers = std::vector<const LayerSettings*>{&layer};
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr); // null drawFence makes it synchronous
+
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
const int shadersCompiled = renderengine->reportShadersCompiled();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 16b5884..9fbbdc3 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -1127,6 +1127,73 @@
return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
}
+/**
+ * Verifies that common, simple bounds + clip combinations can be converted into
+ * a single RRect draw call returning true if possible. If true the radii parameter
+ * will be filled with the correct radii values that combined with bounds param will
+ * produce the insected roundRect. If false, the returned state of the radii param is undefined.
+ */
+static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
+ const SkRect& insetCrop, float cornerRadius,
+ SkVector radii[4]) {
+ const bool leftEqual = bounds.fLeft == crop.fLeft;
+ const bool topEqual = bounds.fTop == crop.fTop;
+ const bool rightEqual = bounds.fRight == crop.fRight;
+ const bool bottomEqual = bounds.fBottom == crop.fBottom;
+
+ // In the event that the corners of the bounds only partially align with the crop we
+ // need to ensure that the resulting shape can still be represented as a round rect.
+ // In particular the round rect implementation will scale the value of all corner radii
+ // if the sum of the radius along any edge is greater than the length of that edge.
+ // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
+ const bool requiredWidth = bounds.width() > (cornerRadius * 2);
+ const bool requiredHeight = bounds.height() > (cornerRadius * 2);
+ if (!requiredWidth || !requiredHeight) {
+ return false;
+ }
+
+ // Check each cropped corner to ensure that it exactly matches the crop or its corner is
+ // contained within the cropped shape and does not need rounded.
+ // compute the UpperLeft corner radius
+ if (leftEqual && topEqual) {
+ radii[0].set(cornerRadius, cornerRadius);
+ } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
+ (topEqual && bounds.fLeft >= insetCrop.fLeft)) {
+ radii[0].set(0, 0);
+ } else {
+ return false;
+ }
+ // compute the UpperRight corner radius
+ if (rightEqual && topEqual) {
+ radii[1].set(cornerRadius, cornerRadius);
+ } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
+ (topEqual && bounds.fRight <= insetCrop.fRight)) {
+ radii[1].set(0, 0);
+ } else {
+ return false;
+ }
+ // compute the BottomRight corner radius
+ if (rightEqual && bottomEqual) {
+ radii[2].set(cornerRadius, cornerRadius);
+ } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
+ (bottomEqual && bounds.fRight <= insetCrop.fRight)) {
+ radii[2].set(0, 0);
+ } else {
+ return false;
+ }
+ // compute the BottomLeft corner radius
+ if (leftEqual && bottomEqual) {
+ radii[3].set(cornerRadius, cornerRadius);
+ } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
+ (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) {
+ radii[3].set(0, 0);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const FloatRect& boundsRect,
const FloatRect& cropRect,
const float cornerRadius) {
@@ -1144,66 +1211,20 @@
// converting them to a single RRect draw. It is possible there are other cases
// that can be converted.
if (crop.contains(bounds)) {
- bool intersectionIsRoundRect = true;
- // check each cropped corner to ensure that it exactly matches the crop or is full
- SkVector radii[4];
-
const auto insetCrop = crop.makeInset(cornerRadius, cornerRadius);
-
- const bool leftEqual = bounds.fLeft == crop.fLeft;
- const bool topEqual = bounds.fTop == crop.fTop;
- const bool rightEqual = bounds.fRight == crop.fRight;
- const bool bottomEqual = bounds.fBottom == crop.fBottom;
-
- // compute the UpperLeft corner radius
- if (leftEqual && topEqual) {
- radii[0].set(cornerRadius, cornerRadius);
- } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
- (topEqual && bounds.fLeft >= insetCrop.fLeft) ||
- insetCrop.contains(bounds.fLeft, bounds.fTop)) {
- radii[0].set(0, 0);
- } else {
- intersectionIsRoundRect = false;
- }
- // compute the UpperRight corner radius
- if (rightEqual && topEqual) {
- radii[1].set(cornerRadius, cornerRadius);
- } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
- (topEqual && bounds.fRight <= insetCrop.fRight) ||
- insetCrop.contains(bounds.fRight, bounds.fTop)) {
- radii[1].set(0, 0);
- } else {
- intersectionIsRoundRect = false;
- }
- // compute the BottomRight corner radius
- if (rightEqual && bottomEqual) {
- radii[2].set(cornerRadius, cornerRadius);
- } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
- (bottomEqual && bounds.fRight <= insetCrop.fRight) ||
- insetCrop.contains(bounds.fRight, bounds.fBottom)) {
- radii[2].set(0, 0);
- } else {
- intersectionIsRoundRect = false;
- }
- // compute the BottomLeft corner radius
- if (leftEqual && bottomEqual) {
- radii[3].set(cornerRadius, cornerRadius);
- } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
- (bottomEqual && bounds.fLeft >= insetCrop.fLeft) ||
- insetCrop.contains(bounds.fLeft, bounds.fBottom)) {
- radii[3].set(0, 0);
- } else {
- intersectionIsRoundRect = false;
+ if (insetCrop.contains(bounds)) {
+ return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required
}
- if (intersectionIsRoundRect) {
+ SkVector radii[4];
+ if (intersectionIsRoundRect(bounds, crop, insetCrop, cornerRadius, radii)) {
SkRRect intersectionBounds;
intersectionBounds.setRectRadii(bounds, radii);
return {intersectionBounds, clip};
}
}
- // we didn't it any of our fast paths so set the clip to the cropRect
+ // we didn't hit any of our fast paths so set the clip to the cropRect
clip.setRectXY(crop, cornerRadius, cornerRadius);
}
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index ec47f96..33053a0 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -1869,6 +1869,40 @@
expectBufferColor(Point(0, (DEFAULT_DISPLAY_HEIGHT / 2) - 1), 0, 255, 0, 255);
}
+TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) {
+ initializeRenderEngine();
+
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+
+ std::vector<const renderengine::LayerSettings*> layers;
+
+ renderengine::LayerSettings redLayer;
+ redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ redLayer.geometry.boundaries = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 32);
+ redLayer.geometry.roundedCornersRadius = 64;
+ redLayer.geometry.roundedCornersCrop = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 128);
+ // Red background.
+ redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
+ redLayer.alpha = 1.0f;
+
+ layers.push_back(&redLayer);
+ invokeDraw(settings, layers);
+
+ // Due to roundedCornersRadius, the top corners are untouched.
+ expectBufferColor(Point(0, 0), 0, 0, 0, 0);
+ expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 0), 0, 0, 0, 0);
+
+ // ensure that the entire height of the red layer was clipped by the rounded corners crop.
+ expectBufferColor(Point(0, 31), 0, 0, 0, 0);
+ expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 31), 0, 0, 0, 0);
+
+ // the bottom middle should be red
+ expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, 31), 255, 0, 0, 255);
+}
+
TEST_P(RenderEngineTest, testClear) {
initializeRenderEngine();
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 5a118ec..ba5a64f 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -158,7 +158,7 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
@@ -175,7 +175,7 @@
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.mapper@4.0",
"libgralloctypes",
],
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 24d186c..73e5749 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -96,6 +96,7 @@
"libinputflinger_base",
"libinputreporter",
"libinputreader",
+ "libgui",
],
static_libs: [
"libinputdispatcher",
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index e81dcfe..7b3658d 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -114,33 +114,6 @@
return mDispatcher;
}
-class BinderWindowHandle : public WindowInfoHandle {
-public:
- BinderWindowHandle(const WindowInfo& info) { mInfo = info; }
-
- bool updateInfo() override {
- return true;
- }
-};
-
-binder::Status InputManager::setInputWindows(
- const std::vector<WindowInfo>& infos,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) {
- std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
-
- std::vector<sp<WindowInfoHandle>> handles;
- for (const auto& info : infos) {
- handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
- handlesPerDisplay[info.displayId].push_back(new BinderWindowHandle(info));
- }
- mDispatcher->setInputWindows(handlesPerDisplay);
-
- if (setInputWindowsListener) {
- setInputWindowsListener->onSetInputWindowsFinished();
- }
- return binder::Status::ok();
-}
-
// Used by tests only.
binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) {
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 035a9a3..4c07c22 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -26,7 +26,6 @@
#include <InputDispatcherInterface.h>
#include <InputDispatcherPolicyInterface.h>
-#include <android/os/ISetInputWindowsListener.h>
#include <input/Input.h>
#include <input/InputTransport.h>
@@ -38,7 +37,6 @@
#include <utils/Vector.h>
using android::os::BnInputFlinger;
-using android::os::ISetInputWindowsListener;
namespace android {
class InputChannel;
@@ -104,10 +102,6 @@
sp<InputDispatcherInterface> getDispatcher() override;
status_t dump(int fd, const Vector<String16>& args) override;
- binder::Status setInputWindows(
- const std::vector<gui::WindowInfo>& handles,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
-
binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
binder::Status setFocusedWindow(const gui::FocusRequest&) override;
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index f77c029..5e9facf 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -185,10 +185,11 @@
const sp<InputDispatcher>& dispatcher, const std::string name)
: FakeInputReceiver(dispatcher, name), mFrame(Rect(0, 0, WIDTH, HEIGHT)) {
inputApplicationHandle->updateInfo();
+ updateInfo();
mInfo.applicationInfo = *inputApplicationHandle->getInfo();
}
- virtual bool updateInfo() override {
+ void updateInfo() {
mInfo.token = mClientChannel->getConnectionToken();
mInfo.name = "FakeWindowHandle";
mInfo.type = WindowInfo::Type::APPLICATION;
@@ -207,8 +208,6 @@
mInfo.ownerPid = INJECTOR_PID;
mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = ADISPLAY_ID_DEFAULT;
-
- return true;
}
protected:
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 7c7a16b..171f2b5 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -64,6 +64,7 @@
"libstatspull",
"libstatssocket",
"libui",
+ "libgui",
"libutils",
"lib-platform-compat-native-api",
"server_configurable_flags",
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 8f4527d..288068f 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -319,17 +319,4 @@
return seq;
}
-// --- CommandEntry ---
-
-CommandEntry::CommandEntry(Command command)
- : command(command),
- eventTime(0),
- keyEntry(nullptr),
- userActivityEventType(0),
- seq(0),
- handled(false),
- enabled(false) {}
-
-CommandEntry::~CommandEntry() {}
-
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 1b7fcf2..8feb982 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -245,55 +245,6 @@
VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry);
VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry);
-class InputDispatcher;
-// A command entry captures state and behavior for an action to be performed in the
-// dispatch loop after the initial processing has taken place. It is essentially
-// a kind of continuation used to postpone sensitive policy interactions to a point
-// in the dispatch loop where it is safe to release the lock (generally after finishing
-// the critical parts of the dispatch cycle).
-//
-// The special thing about commands is that they can voluntarily release and reacquire
-// the dispatcher lock at will. Initially when the command starts running, the
-// dispatcher lock is held. However, if the command needs to call into the policy to
-// do some work, it can release the lock, do the work, then reacquire the lock again
-// before returning.
-//
-// This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
-// never calls into the policy while holding its lock.
-//
-// Commands are implicitly 'LockedInterruptible'.
-struct CommandEntry;
-typedef std::function<void(InputDispatcher&, CommandEntry*)> Command;
-
-class Connection;
-struct CommandEntry {
- explicit CommandEntry(Command command);
- ~CommandEntry();
-
- Command command;
-
- // parameters for the command (usage varies by command)
- sp<Connection> connection;
- nsecs_t eventTime;
- std::shared_ptr<KeyEntry> keyEntry;
- std::shared_ptr<SensorEntry> sensorEntry;
- std::shared_ptr<InputApplicationHandle> inputApplicationHandle;
- std::string reason;
- int32_t userActivityEventType;
- uint32_t seq;
- bool handled;
- sp<IBinder> connectionToken;
- sp<IBinder> oldToken;
- sp<IBinder> newToken;
- std::string obscuringPackage;
- bool enabled;
- int32_t pid;
- nsecs_t consumeTime; // time when the event was consumed by InputConsumer
- int32_t displayId;
- float x;
- float y;
-};
-
} // namespace android::inputdispatcher
#endif // _UI_INPUT_INPUTDISPATCHER_ENTRY_H
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 07b4f30..1478a3c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -19,34 +19,6 @@
#define LOG_NDEBUG 1
-// Log detailed debug messages about each inbound event notification to the dispatcher.
-#define DEBUG_INBOUND_EVENT_DETAILS 0
-
-// Log detailed debug messages about each outbound event processed by the dispatcher.
-#define DEBUG_OUTBOUND_EVENT_DETAILS 0
-
-// Log debug messages about the dispatch cycle.
-#define DEBUG_DISPATCH_CYCLE 0
-
-// Log debug messages about channel creation
-#define DEBUG_CHANNEL_CREATION 0
-
-// Log debug messages about input event injection.
-#define DEBUG_INJECTION 0
-
-// Log debug messages about input focus tracking.
-static constexpr bool DEBUG_FOCUS = false;
-
-// Log debug messages about touch occlusion
-// STOPSHIP(b/169067926): Set to false
-static constexpr bool DEBUG_TOUCH_OCCLUSION = true;
-
-// Log debug messages about the app switch latency optimization.
-#define DEBUG_APP_SWITCH 0
-
-// Log debug messages about hover events.
-#define DEBUG_HOVER 0
-
#include <InputFlingerProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/properties.h>
@@ -55,6 +27,7 @@
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
#include <com/android/internal/compat/IPlatformCompatNative.h>
+#include <gui/SurfaceComposerClient.h>
#include <input/InputDevice.h>
#include <log/log.h>
#include <log/log_event_list.h>
@@ -93,9 +66,50 @@
namespace android::inputdispatcher {
+namespace {
+
+// Log detailed debug messages about each inbound event notification to the dispatcher.
+constexpr bool DEBUG_INBOUND_EVENT_DETAILS = false;
+
+// Log detailed debug messages about each outbound event processed by the dispatcher.
+constexpr bool DEBUG_OUTBOUND_EVENT_DETAILS = false;
+
+// Log debug messages about the dispatch cycle.
+constexpr bool DEBUG_DISPATCH_CYCLE = false;
+
+// Log debug messages about channel creation
+constexpr bool DEBUG_CHANNEL_CREATION = false;
+
+// Log debug messages about input event injection.
+constexpr bool DEBUG_INJECTION = false;
+
+// Log debug messages about input focus tracking.
+constexpr bool DEBUG_FOCUS = false;
+
+// Log debug messages about touch occlusion
+// STOPSHIP(b/169067926): Set to false
+constexpr bool DEBUG_TOUCH_OCCLUSION = true;
+
+// Log debug messages about the app switch latency optimization.
+constexpr bool DEBUG_APP_SWITCH = false;
+
+// Log debug messages about hover events.
+constexpr bool DEBUG_HOVER = false;
+
+// Temporarily releases a held mutex for the lifetime of the instance.
+// Named to match std::scoped_lock
+class scoped_unlock {
+public:
+ explicit scoped_unlock(std::mutex& mutex) : mMutex(mutex) { mMutex.unlock(); }
+ ~scoped_unlock() { mMutex.lock(); }
+
+private:
+ std::mutex& mMutex;
+};
+
// When per-window-input-rotation is enabled, InputFlinger works in the un-rotated display
// coordinates and SurfaceFlinger includes the display rotation in the input window transforms.
-static bool isPerWindowInputRotationEnabled() {
+bool isPerWindowInputRotationEnabled() {
static const bool PER_WINDOW_INPUT_ROTATION =
sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false);
@@ -135,27 +149,27 @@
constexpr int LOGTAG_INPUT_INTERACTION = 62000;
constexpr int LOGTAG_INPUT_FOCUS = 62001;
-static inline nsecs_t now() {
+inline nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
}
-static inline const char* toString(bool value) {
+inline const char* toString(bool value) {
return value ? "true" : "false";
}
-static inline const std::string toString(sp<IBinder> binder) {
+inline const std::string toString(const sp<IBinder>& binder) {
if (binder == nullptr) {
return "<null>";
}
return StringPrintf("%p", binder.get());
}
-static inline int32_t getMotionEventActionPointerIndex(int32_t action) {
+inline int32_t getMotionEventActionPointerIndex(int32_t action) {
return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
-static bool isValidKeyAction(int32_t action) {
+bool isValidKeyAction(int32_t action) {
switch (action) {
case AKEY_EVENT_ACTION_DOWN:
case AKEY_EVENT_ACTION_UP:
@@ -165,7 +179,7 @@
}
}
-static bool validateKeyEvent(int32_t action) {
+bool validateKeyEvent(int32_t action) {
if (!isValidKeyAction(action)) {
ALOGE("Key event has invalid action code 0x%x", action);
return false;
@@ -173,7 +187,7 @@
return true;
}
-static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
+bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP:
@@ -198,12 +212,12 @@
}
}
-static int64_t millis(std::chrono::nanoseconds t) {
+int64_t millis(std::chrono::nanoseconds t) {
return std::chrono::duration_cast<std::chrono::milliseconds>(t).count();
}
-static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
- const PointerProperties* pointerProperties) {
+bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
+ const PointerProperties* pointerProperties) {
if (!isValidMotionAction(action, actionButton, pointerCount)) {
ALOGE("Motion event has invalid action code 0x%x", action);
return false;
@@ -230,7 +244,7 @@
return true;
}
-static std::string dumpRegion(const Region& region) {
+std::string dumpRegion(const Region& region) {
if (region.isEmpty()) {
return "<empty>";
}
@@ -251,7 +265,7 @@
return dump;
}
-static std::string dumpQueue(const std::deque<DispatchEntry*>& queue, nsecs_t currentTime) {
+std::string dumpQueue(const std::deque<DispatchEntry*>& queue, nsecs_t currentTime) {
constexpr size_t maxEntries = 50; // max events to print
constexpr size_t skipBegin = maxEntries / 2;
const size_t skipEnd = queue.size() - maxEntries / 2;
@@ -290,12 +304,12 @@
* Also useful when the entries are sp<>. If an entry is not found, nullptr is returned.
*/
template <typename K, typename V>
-static V getValueByKey(const std::unordered_map<K, V>& map, K key) {
+V getValueByKey(const std::unordered_map<K, V>& map, K key) {
auto it = map.find(key);
return it != map.end() ? it->second : V{};
}
-static bool haveSameToken(const sp<WindowInfoHandle>& first, const sp<WindowInfoHandle>& second) {
+bool haveSameToken(const sp<WindowInfoHandle>& first, const sp<WindowInfoHandle>& second) {
if (first == second) {
return true;
}
@@ -307,7 +321,7 @@
return first->getToken() == second->getToken();
}
-static bool haveSameApplicationToken(const WindowInfo* first, const WindowInfo* second) {
+bool haveSameApplicationToken(const WindowInfo* first, const WindowInfo* second) {
if (first == nullptr || second == nullptr) {
return false;
}
@@ -315,13 +329,13 @@
first->applicationInfo.token == second->applicationInfo.token;
}
-static bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
+bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
}
-static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
- std::shared_ptr<EventEntry> eventEntry,
- int32_t inputTargetFlags) {
+std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
+ std::shared_ptr<EventEntry> eventEntry,
+ int32_t inputTargetFlags) {
if (eventEntry->type == EventEntry::Type::MOTION) {
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
if ((motionEntry.source & AINPUT_SOURCE_CLASS_JOYSTICK) ||
@@ -398,9 +412,9 @@
return dispatchEntry;
}
-static void addGestureMonitors(const std::vector<Monitor>& monitors,
- std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0,
- float yOffset = 0) {
+void addGestureMonitors(const std::vector<Monitor>& monitors,
+ std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0,
+ float yOffset = 0) {
if (monitors.empty()) {
return;
}
@@ -410,9 +424,8 @@
}
}
-static status_t openInputChannelPair(const std::string& name,
- std::shared_ptr<InputChannel>& serverChannel,
- std::unique_ptr<InputChannel>& clientChannel) {
+status_t openInputChannelPair(const std::string& name, std::shared_ptr<InputChannel>& serverChannel,
+ std::unique_ptr<InputChannel>& clientChannel) {
std::unique_ptr<InputChannel> uniqueServerChannel;
status_t result = InputChannel::openInputChannelPair(name, uniqueServerChannel, clientChannel);
@@ -421,7 +434,7 @@
}
template <typename T>
-static bool sharedPointersEqual(const std::shared_ptr<T>& lhs, const std::shared_ptr<T>& rhs) {
+bool sharedPointersEqual(const std::shared_ptr<T>& lhs, const std::shared_ptr<T>& rhs) {
if (lhs == nullptr && rhs == nullptr) {
return true;
}
@@ -431,7 +444,7 @@
return *lhs == *rhs;
}
-static sp<IPlatformCompatNative> getCompatService() {
+sp<IPlatformCompatNative> getCompatService() {
sp<IBinder> service(defaultServiceManager()->getService(String16("platform_compat_native")));
if (service == nullptr) {
ALOGE("Failed to link to compat service");
@@ -440,7 +453,7 @@
return interface_cast<IPlatformCompatNative>(service);
}
-static KeyEvent createKeyEvent(const KeyEntry& entry) {
+KeyEvent createKeyEvent(const KeyEntry& entry) {
KeyEvent event;
event.initialize(entry.id, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC,
entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState,
@@ -448,7 +461,7 @@
return event;
}
-static std::optional<int32_t> findMonitorPidByToken(
+std::optional<int32_t> findMonitorPidByToken(
const std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay,
const sp<IBinder>& token) {
for (const auto& it : monitorsByDisplay) {
@@ -462,7 +475,7 @@
return std::nullopt;
}
-static bool shouldReportMetricsForConnection(const Connection& connection) {
+bool shouldReportMetricsForConnection(const Connection& connection) {
// Do not keep track of gesture monitors. They receive every event and would disproportionately
// affect the statistics.
if (connection.monitor) {
@@ -475,8 +488,7 @@
return true;
}
-static bool shouldReportFinishedEvent(const DispatchEntry& dispatchEntry,
- const Connection& connection) {
+bool shouldReportFinishedEvent(const DispatchEntry& dispatchEntry, const Connection& connection) {
const EventEntry& eventEntry = *dispatchEntry.eventEntry;
const int32_t& inputEventId = eventEntry.id;
if (inputEventId != dispatchEntry.resolvedEventId) {
@@ -512,6 +524,22 @@
return true;
}
+/**
+ * Connection is responsive if it has no events in the waitQueue that are older than the
+ * current time.
+ */
+bool isConnectionResponsive(const Connection& connection) {
+ const nsecs_t currentTime = now();
+ for (const DispatchEntry* entry : connection.waitQueue) {
+ if (entry->timeoutTime < currentTime) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -545,20 +573,24 @@
}
InputDispatcher::~InputDispatcher() {
- { // acquire lock
- std::scoped_lock _l(mLock);
+ std::scoped_lock _l(mLock);
- resetKeyRepeatLocked();
- releasePendingEventLocked();
- drainInboundQueueLocked();
- }
+ resetKeyRepeatLocked();
+ releasePendingEventLocked();
+ drainInboundQueueLocked();
+ mCommandQueue.clear();
while (!mConnectionsByToken.empty()) {
sp<Connection> connection = mConnectionsByToken.begin()->second;
- removeInputChannel(connection->inputChannel->getConnectionToken());
+ removeInputChannelLocked(connection->inputChannel->getConnectionToken(),
+ false /* notify */);
}
}
+void InputDispatcher::onFirstRef() {
+ SurfaceComposerClient::getDefault()->addWindowInfosListener(this);
+}
+
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
@@ -591,7 +623,7 @@
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
- if (runCommandsLockedInterruptible()) {
+ if (runCommandsLockedInterruptable()) {
nextWakeupTime = LONG_LONG_MIN;
}
@@ -951,9 +983,9 @@
mAppSwitchSawKeyDown = true;
} else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
if (mAppSwitchSawKeyDown) {
-#if DEBUG_APP_SWITCH
- ALOGD("App switch is pending!");
-#endif
+ if (DEBUG_APP_SWITCH) {
+ ALOGD("App switch is pending!");
+ }
mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
mAppSwitchSawKeyDown = false;
needWake = true;
@@ -1048,9 +1080,9 @@
const char* reason;
switch (dropReason) {
case DropReason::POLICY:
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("Dropped event because policy consumed it.");
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("Dropped event because policy consumed it.");
+ }
reason = "inbound event was dropped because the policy consumed it";
break;
case DropReason::DISABLED:
@@ -1134,37 +1166,35 @@
void InputDispatcher::resetPendingAppSwitchLocked(bool handled) {
mAppSwitchDueTime = LONG_LONG_MAX;
-#if DEBUG_APP_SWITCH
- if (handled) {
- ALOGD("App switch has arrived.");
- } else {
- ALOGD("App switch was abandoned.");
+ if (DEBUG_APP_SWITCH) {
+ if (handled) {
+ ALOGD("App switch has arrived.");
+ } else {
+ ALOGD("App switch was abandoned.");
+ }
}
-#endif
}
bool InputDispatcher::haveCommandsLocked() const {
return !mCommandQueue.empty();
}
-bool InputDispatcher::runCommandsLockedInterruptible() {
+bool InputDispatcher::runCommandsLockedInterruptable() {
if (mCommandQueue.empty()) {
return false;
}
do {
- std::unique_ptr<CommandEntry> commandEntry = std::move(mCommandQueue.front());
+ auto command = std::move(mCommandQueue.front());
mCommandQueue.pop_front();
- Command command = commandEntry->command;
- command(*this, commandEntry.get()); // commands are implicitly 'LockedInterruptible'
-
- commandEntry->connection.clear();
+ // Commands are run with the lock held, but may release and re-acquire the lock from within.
+ command();
} while (!mCommandQueue.empty());
return true;
}
-void InputDispatcher::postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) {
- mCommandQueue.push_back(std::move(commandEntry));
+void InputDispatcher::postCommandLocked(Command&& command) {
+ mCommandQueue.push_back(command);
}
void InputDispatcher::drainInboundQueueLocked() {
@@ -1186,9 +1216,9 @@
void InputDispatcher::releaseInboundEventLocked(std::shared_ptr<EventEntry> entry) {
InjectionState* injectionState = entry->injectionState;
if (injectionState && injectionState->injectionResult == InputEventInjectionResult::PENDING) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("Injected inbound event was dropped.");
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("Injected inbound event was dropped.");
+ }
setInjectionResult(*entry, InputEventInjectionResult::FAILED);
}
if (entry == mNextUnblockedEvent) {
@@ -1223,27 +1253,28 @@
bool InputDispatcher::dispatchConfigurationChangedLocked(nsecs_t currentTime,
const ConfigurationChangedEntry& entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry.eventTime);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry.eventTime);
+ }
// Reset key repeating in case a keyboard device was added or removed or something.
resetKeyRepeatLocked();
// Enqueue a command to run outside the lock to tell the policy that the configuration changed.
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
- commandEntry->eventTime = entry.eventTime;
- postCommandLocked(std::move(commandEntry));
+ auto command = [this, eventTime = entry.eventTime]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyConfigurationChanged(eventTime);
+ };
+ postCommandLocked(std::move(command));
return true;
}
bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime,
const DeviceResetEntry& entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry.eventTime,
- entry.deviceId);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry.eventTime,
+ entry.deviceId);
+ }
// Reset key repeating in case a keyboard device was disabled or enabled.
if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->deviceId == entry.deviceId) {
@@ -1384,9 +1415,9 @@
} else if (entry->action == AKEY_EVENT_ACTION_UP && mKeyRepeatState.lastKeyEntry &&
mKeyRepeatState.lastKeyEntry->deviceId != entry->deviceId) {
// The key on device 'deviceId' is still down, do not stop key repeat
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
+ }
} else if (!entry->syntheticRepeat) {
resetKeyRepeatLocked();
}
@@ -1417,13 +1448,13 @@
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
sp<IBinder> focusedWindowToken =
mFocusResolver.getFocusedWindowToken(getTargetDisplayId(*entry));
- commandEntry->connectionToken = focusedWindowToken;
- commandEntry->keyEntry = entry;
- postCommandLocked(std::move(commandEntry));
+
+ auto command = [this, focusedWindowToken, entry]() REQUIRES(mLock) {
+ doInterceptKeyBeforeDispatchingCommand(focusedWindowToken, *entry);
+ };
+ postCommandLocked(std::move(command));
return false; // wait for the command to run
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
@@ -1465,47 +1496,42 @@
}
void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry& entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
- "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
- "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
- prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId, entry.policyFlags,
- entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState,
- entry.repeatCount, entry.downTime);
-#endif
-}
-
-void InputDispatcher::doNotifySensorLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- const std::shared_ptr<SensorEntry>& entry = commandEntry->sensorEntry;
- if (entry->accuracyChanged) {
- mPolicy->notifySensorAccuracy(entry->deviceId, entry->sensorType, entry->accuracy);
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
+ "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
+ "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
+ prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId,
+ entry.policyFlags, entry.action, entry.flags, entry.keyCode, entry.scanCode,
+ entry.metaState, entry.repeatCount, entry.downTime);
}
- mPolicy->notifySensorEvent(entry->deviceId, entry->sensorType, entry->accuracy,
- entry->hwTimestamp, entry->values);
- mLock.lock();
}
-void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime, std::shared_ptr<SensorEntry> entry,
+void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime,
+ const std::shared_ptr<SensorEntry>& entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, "
- "source=0x%x, sensorType=%s",
- entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source,
- NamedEnum::string(entry->sensorType).c_str());
-#endif
- std::unique_ptr<CommandEntry> commandEntry =
- std::make_unique<CommandEntry>(&InputDispatcher::doNotifySensorLockedInterruptible);
- commandEntry->sensorEntry = entry;
- postCommandLocked(std::move(commandEntry));
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, "
+ "source=0x%x, sensorType=%s",
+ entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source,
+ NamedEnum::string(entry->sensorType).c_str());
+ }
+ auto command = [this, entry]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+
+ if (entry->accuracyChanged) {
+ mPolicy->notifySensorAccuracy(entry->deviceId, entry->sensorType, entry->accuracy);
+ }
+ mPolicy->notifySensorEvent(entry->deviceId, entry->sensorType, entry->accuracy,
+ entry->hwTimestamp, entry->values);
+ };
+ postCommandLocked(std::move(command));
}
bool InputDispatcher::flushSensor(int deviceId, InputDeviceSensorType sensorType) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("flushSensor deviceId=%d, sensorType=%s", deviceId,
- NamedEnum::string(sensorType).c_str());
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("flushSensor deviceId=%d, sensorType=%s", deviceId,
+ NamedEnum::string(sensorType).c_str());
+ }
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -1616,42 +1642,43 @@
}
void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry& entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
- ", policyFlags=0x%x, "
- "action=0x%x, actionButton=0x%x, flags=0x%x, "
- "metaState=0x%x, buttonState=0x%x,"
- "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
- prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId, entry.policyFlags,
- entry.action, entry.actionButton, entry.flags, entry.metaState, entry.buttonState,
- entry.edgeFlags, entry.xPrecision, entry.yPrecision, entry.downTime);
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+ ", policyFlags=0x%x, "
+ "action=0x%x, actionButton=0x%x, flags=0x%x, "
+ "metaState=0x%x, buttonState=0x%x,"
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
+ prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId,
+ entry.policyFlags, entry.action, entry.actionButton, entry.flags, entry.metaState,
+ entry.buttonState, entry.edgeFlags, entry.xPrecision, entry.yPrecision,
+ entry.downTime);
- for (uint32_t i = 0; i < entry.pointerCount; i++) {
- ALOGD(" Pointer %d: id=%d, toolType=%d, "
- "x=%f, y=%f, pressure=%f, size=%f, "
- "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
- "orientation=%f",
- i, entry.pointerProperties[i].id, entry.pointerProperties[i].toolType,
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+ for (uint32_t i = 0; i < entry.pointerCount; i++) {
+ ALOGD(" Pointer %d: id=%d, toolType=%d, "
+ "x=%f, y=%f, pressure=%f, size=%f, "
+ "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
+ "orientation=%f",
+ i, entry.pointerProperties[i].id, entry.pointerProperties[i].toolType,
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+ }
}
-#endif
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
std::shared_ptr<EventEntry> eventEntry,
const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("dispatchEventToCurrentInputTargets");
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("dispatchEventToCurrentInputTargets");
+ }
updateInteractionTokensLocked(*eventEntry, inputTargets);
@@ -2015,7 +2042,7 @@
ALOGD("%s", log.c_str());
}
}
- onUntrustedTouchLocked(occlusionInfo.obscuringPackage);
+ sendUntrustedTouchCommandLocked(occlusionInfo.obscuringPackage);
if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
ALOGW("Dropping untrusted touch event due to %s/%d",
occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
@@ -2132,10 +2159,10 @@
if (mLastHoverWindowHandle != nullptr &&
(maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT ||
mLastHoverWindowHandle != newTouchedWindowHandle)) {
-#if DEBUG_HOVER
- ALOGD("Sending hover exit event to window %s.",
- mLastHoverWindowHandle->getName().c_str());
-#endif
+ if (DEBUG_HOVER) {
+ ALOGD("Sending hover exit event to window %s.",
+ mLastHoverWindowHandle->getName().c_str());
+ }
tempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
}
@@ -2145,10 +2172,10 @@
if (newHoverWindowHandle != nullptr &&
(maskedAction != AMOTION_EVENT_ACTION_HOVER_ENTER ||
newHoverWindowHandle != newTouchedWindowHandle)) {
-#if DEBUG_HOVER
- ALOGD("Sending hover enter event to window %s.",
- newHoverWindowHandle->getName().c_str());
-#endif
+ if (DEBUG_HOVER) {
+ ALOGD("Sending hover enter event to window %s.",
+ newHoverWindowHandle->getName().c_str());
+ }
tempTouchState.addOrUpdateWindow(newHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER,
BitSet32(0));
@@ -2341,9 +2368,9 @@
false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
if (dropWindow) {
vec2 local = dropWindow->getInfo()->transform.transform(x, y);
- notifyDropWindowLocked(dropWindow->getToken(), local.x, local.y);
+ sendDropWindowCommandLocked(dropWindow->getToken(), local.x, local.y);
} else {
- notifyDropWindowLocked(nullptr, 0, 0);
+ sendDropWindowCommandLocked(nullptr, 0, 0);
}
mDragState.reset();
}
@@ -2389,7 +2416,7 @@
} else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
finishDragAndDrop(entry.displayId, x, y);
} else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
- notifyDropWindowLocked(nullptr, 0, 0);
+ sendDropWindowCommandLocked(nullptr, 0, 0);
mDragState.reset();
}
}
@@ -2677,9 +2704,9 @@
if (focusedWindowHandle != nullptr) {
const WindowInfo* info = focusedWindowHandle->getInfo();
if (info->inputFeatures.test(WindowInfo::Feature::DISABLE_USER_ACTIVITY)) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
+ }
return;
}
}
@@ -2717,12 +2744,12 @@
}
}
- std::unique_ptr<CommandEntry> commandEntry =
- std::make_unique<CommandEntry>(&InputDispatcher::doPokeUserActivityLockedInterruptible);
- commandEntry->eventTime = eventEntry.eventTime;
- commandEntry->userActivityEventType = eventType;
- commandEntry->displayId = displayId;
- postCommandLocked(std::move(commandEntry));
+ auto command = [this, eventTime = eventEntry.eventTime, eventType, displayId]()
+ REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->pokeUserActivity(eventTime, eventType, displayId);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
@@ -2735,21 +2762,21 @@
connection->getInputChannelName().c_str(), eventEntry->id);
ATRACE_NAME(message.c_str());
}
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
- "globalScaleFactor=%f, pointerIds=0x%x %s",
- connection->getInputChannelName().c_str(), inputTarget.flags,
- inputTarget.globalScaleFactor, inputTarget.pointerIds.value,
- inputTarget.getPointerInfoString().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
+ "globalScaleFactor=%f, pointerIds=0x%x %s",
+ connection->getInputChannelName().c_str(), inputTarget.flags,
+ inputTarget.globalScaleFactor, inputTarget.pointerIds.value,
+ inputTarget.getPointerInfoString().c_str());
+ }
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
- connection->getInputChannelName().c_str(), connection->getStatusLabel());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
+ connection->getInputChannelName().c_str(), connection->getStatusLabel());
+ }
return;
}
@@ -2848,10 +2875,11 @@
if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags)) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
- connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key "
+ "event",
+ connection->getInputChannelName().c_str());
+ }
return; // skip the inconsistent event
}
break;
@@ -2881,11 +2909,11 @@
if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
!connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
motionEntry.displayId)) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter "
- "event",
- connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover "
+ "enter event",
+ connection->getInputChannelName().c_str());
+ }
// We keep the 'resolvedEventId' here equal to the original 'motionEntry.id' because
// this is a one-to-one event conversion.
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
@@ -2901,11 +2929,11 @@
if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags)) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion "
- "event",
- connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion "
+ "event",
+ connection->getInputChannelName().c_str());
+ }
return; // skip the inconsistent event
}
@@ -3037,10 +3065,11 @@
return;
}
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
- commandEntry->newToken = token;
- postCommandLocked(std::move(commandEntry));
+ auto command = [this, token]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->onPointerDownOutsideFocus(token);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -3050,9 +3079,9 @@
connection->getInputChannelName().c_str());
ATRACE_NAME(message.c_str());
}
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
+ }
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
@@ -3190,11 +3219,11 @@
} else {
// Pipe is full and we are waiting for the app to finish process some events
// before sending more events to it.
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
- "waiting for the application to catch up",
- connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
+ "waiting for the application to catch up",
+ connection->getInputChannelName().c_str());
+ }
}
} else {
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
@@ -3261,10 +3290,10 @@
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq,
bool handled, nsecs_t consumeTime) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
- connection->getInputChannelName().c_str(), seq, toString(handled));
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
+ connection->getInputChannelName().c_str(), seq, toString(handled));
+ }
if (connection->status == Connection::STATUS_BROKEN ||
connection->status == Connection::STATUS_ZOMBIE) {
@@ -3272,16 +3301,19 @@
}
// Notify other system components and prepare to start the next dispatch cycle.
- onDispatchCycleFinishedLocked(currentTime, connection, seq, handled, consumeTime);
+ auto command = [this, currentTime, connection, seq, handled, consumeTime]() REQUIRES(mLock) {
+ doDispatchCycleFinishedCommand(currentTime, connection, seq, handled, consumeTime);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
bool notify) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
- connection->getInputChannelName().c_str(), toString(notify));
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
+ connection->getInputChannelName().c_str(), toString(notify));
+ }
// Clear the dispatch queues.
drainDispatchQueue(connection->outboundQueue);
@@ -3296,7 +3328,15 @@
if (notify) {
// Notify other system components.
- onDispatchCycleBrokenLocked(currentTime, connection);
+ ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
+ connection->getInputChannelName().c_str());
+
+ auto command = [this, connection]() REQUIRES(mLock) {
+ if (connection->status == Connection::STATUS_ZOMBIE) return;
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyInputChannelBroken(connection->inputChannel->getConnectionToken());
+ };
+ postCommandLocked(std::move(command));
}
}
}
@@ -3363,7 +3403,7 @@
gotOne = true;
}
if (gotOne) {
- runCommandsLockedInterruptible();
+ runCommandsLockedInterruptable();
if (status == WOULD_BLOCK) {
return 1;
}
@@ -3440,12 +3480,12 @@
if (cancelationEvents.empty()) {
return;
}
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
- "with reality: %s, mode=%d.",
- connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,
- options.mode);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
+ "with reality: %s, mode=%d.",
+ connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,
+ options.mode);
+ }
InputTarget target;
sp<WindowInfoHandle> windowHandle =
@@ -3509,10 +3549,10 @@
return;
}
-#if DEBUG_OUTBOUND_EVENT_DETAILS
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
ALOGD("channel '%s' ~ Synthesized %zu down events to ensure consistent event stream.",
connection->getInputChannelName().c_str(), downEvents.size());
-#endif
+ }
InputTarget target;
sp<WindowInfoHandle> windowHandle =
@@ -3655,9 +3695,9 @@
}
void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
+ }
bool needWake;
{ // acquire lock
@@ -3711,14 +3751,14 @@
}
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyKey - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
- "policyFlags=0x%x, action=0x%x, "
- "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
- args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
- args->action, args->flags, args->keyCode, args->scanCode, args->metaState,
- args->downTime);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyKey - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+ "policyFlags=0x%x, action=0x%x, "
+ "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
+ args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
+ args->action, args->flags, args->keyCode, args->scanCode, args->metaState,
+ args->downTime);
+ }
if (!validateKeyEvent(args->action)) {
return;
}
@@ -3789,33 +3829,33 @@
}
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
- "displayId=%" PRId32 ", policyFlags=0x%x, "
- "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
- "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
- "yCursorPosition=%f, downTime=%" PRId64,
- args->id, args->eventTime, args->deviceId, args->source, args->displayId,
- args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
- args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
- args->xCursorPosition, args->yCursorPosition, args->downTime);
- for (uint32_t i = 0; i < args->pointerCount; i++) {
- ALOGD(" Pointer %d: id=%d, toolType=%d, "
- "x=%f, y=%f, pressure=%f, size=%f, "
- "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
- "orientation=%f",
- i, args->pointerProperties[i].id, args->pointerProperties[i].toolType,
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
+ "displayId=%" PRId32 ", policyFlags=0x%x, "
+ "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
+ "yCursorPosition=%f, downTime=%" PRId64,
+ args->id, args->eventTime, args->deviceId, args->source, args->displayId,
+ args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
+ args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
+ args->xCursorPosition, args->yCursorPosition, args->downTime);
+ for (uint32_t i = 0; i < args->pointerCount; i++) {
+ ALOGD(" Pointer %d: id=%d, toolType=%d, "
+ "x=%f, y=%f, pressure=%f, size=%f, "
+ "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
+ "orientation=%f",
+ i, args->pointerProperties[i].id, args->pointerProperties[i].toolType,
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+ }
}
-#endif
if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount,
args->pointerProperties)) {
return;
@@ -3885,12 +3925,12 @@
}
void InputDispatcher::notifySensor(const NotifySensorArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
- " sensorType=%s",
- args->id, args->eventTime, args->deviceId, args->source,
- NamedEnum::string(args->sensorType).c_str());
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
+ " sensorType=%s",
+ args->id, args->eventTime, args->deviceId, args->source,
+ NamedEnum::string(args->sensorType).c_str());
+ }
bool needWake;
{ // acquire lock
@@ -3913,10 +3953,10 @@
}
void InputDispatcher::notifyVibratorState(const NotifyVibratorStateArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyVibratorState - eventTime=%" PRId64 ", device=%d, isOn=%d", args->eventTime,
- args->deviceId, args->isOn);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyVibratorState - eventTime=%" PRId64 ", device=%d, isOn=%d", args->eventTime,
+ args->deviceId, args->isOn);
+ }
mPolicy->notifyVibratorState(args->deviceId, args->isOn);
}
@@ -3925,11 +3965,11 @@
}
void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
- "switchMask=0x%08x",
- args->eventTime, args->policyFlags, args->switchValues, args->switchMask);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
+ "switchMask=0x%08x",
+ args->eventTime, args->policyFlags, args->switchValues, args->switchMask);
+ }
uint32_t policyFlags = args->policyFlags;
policyFlags |= POLICY_FLAG_TRUSTED;
@@ -3937,10 +3977,10 @@
}
void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args->eventTime,
- args->deviceId);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args->eventTime,
+ args->deviceId);
+ }
bool needWake;
{ // acquire lock
@@ -3957,10 +3997,10 @@
}
void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime,
- args->enabled ? "true" : "false");
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime,
+ args->enabled ? "true" : "false");
+ }
bool needWake;
{ // acquire lock
@@ -3978,11 +4018,11 @@
InputEventInjectionResult InputDispatcher::injectInputEvent(
const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
- event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
+ "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
+ event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
+ }
nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
policyFlags |= POLICY_FLAG_INJECTED;
@@ -4160,10 +4200,10 @@
nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
-#if DEBUG_INJECTION
- ALOGD("injectInputEvent - Timed out waiting for injection result "
- "to become available.");
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("injectInputEvent - Timed out waiting for injection result "
+ "to become available.");
+ }
injectionResult = InputEventInjectionResult::TIMED_OUT;
break;
}
@@ -4174,16 +4214,16 @@
if (injectionResult == InputEventInjectionResult::SUCCEEDED &&
syncMode == InputEventInjectionSync::WAIT_FOR_FINISHED) {
while (injectionState->pendingForegroundDispatches != 0) {
-#if DEBUG_INJECTION
- ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.",
- injectionState->pendingForegroundDispatches);
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.",
+ injectionState->pendingForegroundDispatches);
+ }
nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
-#if DEBUG_INJECTION
- ALOGD("injectInputEvent - Timed out waiting for pending foreground "
- "dispatches to finish.");
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("injectInputEvent - Timed out waiting for pending foreground "
+ "dispatches to finish.");
+ }
injectionResult = InputEventInjectionResult::TIMED_OUT;
break;
}
@@ -4196,10 +4236,10 @@
injectionState->release();
} // release lock
-#if DEBUG_INJECTION
- ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
- injectionResult, injectorPid, injectorUid);
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
+ injectionResult, injectorPid, injectorUid);
+ }
return injectionResult;
}
@@ -4246,11 +4286,11 @@
InputEventInjectionResult injectionResult) {
InjectionState* injectionState = entry.injectionState;
if (injectionState) {
-#if DEBUG_INJECTION
- ALOGD("Setting input event injection result to %d. "
- "injectorPid=%d, injectorUid=%d",
- injectionResult, injectionState->injectorPid, injectionState->injectorUid);
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("Setting input event injection result to %d. "
+ "injectorPid=%d, injectorUid=%d",
+ injectionResult, injectionState->injectorPid, injectionState->injectorUid);
+ }
if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
// Log the outcome since the injector did not wait for the injection result.
@@ -4409,11 +4449,6 @@
std::vector<sp<WindowInfoHandle>> newHandles;
for (const sp<WindowInfoHandle>& handle : windowInfoHandles) {
- if (!handle->updateInfo()) {
- // handle no longer valid
- continue;
- }
-
const WindowInfo* info = handle->getInfo();
if (getInputChannelLocked(handle->getToken()) == nullptr) {
const bool noInputChannel =
@@ -4660,7 +4695,7 @@
// Find new focused window and validate
sp<IBinder> newFocusedWindowToken = mFocusResolver.getFocusedWindowToken(displayId);
- notifyFocusChangedLocked(oldFocusedWindowToken, newFocusedWindowToken);
+ sendFocusChangedCommandLocked(oldFocusedWindowToken, newFocusedWindowToken);
if (newFocusedWindowToken == nullptr) {
ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
@@ -5092,6 +5127,12 @@
dump += INDENT "ReplacedKeys: <empty>\n";
}
+ if (!mCommandQueue.empty()) {
+ dump += StringPrintf(INDENT "CommandQueue: size=%zu\n", mCommandQueue.size());
+ } else {
+ dump += INDENT "CommandQueue: <empty>\n";
+ }
+
if (!mConnectionsByToken.empty()) {
dump += INDENT "Connections:\n";
for (const auto& [token, connection] : mConnectionsByToken) {
@@ -5158,9 +5199,9 @@
};
Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
-#if DEBUG_CHANNEL_CREATION
- ALOGD("channel '%s' ~ createInputChannel", name.c_str());
-#endif
+ if (DEBUG_CHANNEL_CREATION) {
+ ALOGD("channel '%s' ~ createInputChannel", name.c_str());
+ }
std::unique_ptr<InputChannel> serverChannel;
std::unique_ptr<InputChannel> clientChannel;
@@ -5441,46 +5482,92 @@
mConnectionsByToken.erase(connection->inputChannel->getConnectionToken());
}
-void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
- const sp<Connection>& connection, uint32_t seq,
- bool handled, nsecs_t consumeTime) {
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
- commandEntry->connection = connection;
- commandEntry->eventTime = currentTime;
- commandEntry->seq = seq;
- commandEntry->handled = handled;
- commandEntry->consumeTime = consumeTime;
- postCommandLocked(std::move(commandEntry));
+void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
+ const sp<Connection>& connection, uint32_t seq,
+ bool handled, nsecs_t consumeTime) {
+ // Handle post-event policy actions.
+ std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
+ if (dispatchEntryIt == connection->waitQueue.end()) {
+ return;
+ }
+ DispatchEntry* dispatchEntry = *dispatchEntryIt;
+ const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
+ if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
+ ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
+ ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str());
+ }
+ if (shouldReportFinishedEvent(*dispatchEntry, *connection)) {
+ mLatencyTracker.trackFinishedEvent(dispatchEntry->eventEntry->id,
+ connection->inputChannel->getConnectionToken(),
+ dispatchEntry->deliveryTime, consumeTime, finishTime);
+ }
+
+ bool restartEvent;
+ if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
+ KeyEntry& keyEntry = static_cast<KeyEntry&>(*(dispatchEntry->eventEntry));
+ restartEvent =
+ afterKeyEventLockedInterruptable(connection, dispatchEntry, keyEntry, handled);
+ } else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
+ MotionEntry& motionEntry = static_cast<MotionEntry&>(*(dispatchEntry->eventEntry));
+ restartEvent = afterMotionEventLockedInterruptable(connection, dispatchEntry, motionEntry,
+ handled);
+ } else {
+ restartEvent = false;
+ }
+
+ // Dequeue the event and start the next cycle.
+ // Because the lock might have been released, it is possible that the
+ // contents of the wait queue to have been drained, so we need to double-check
+ // a few things.
+ dispatchEntryIt = connection->findWaitQueueEntry(seq);
+ if (dispatchEntryIt != connection->waitQueue.end()) {
+ dispatchEntry = *dispatchEntryIt;
+ connection->waitQueue.erase(dispatchEntryIt);
+ const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
+ mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);
+ if (!connection->responsive) {
+ connection->responsive = isConnectionResponsive(*connection);
+ if (connection->responsive) {
+ // The connection was unresponsive, and now it's responsive.
+ processConnectionResponsiveLocked(*connection);
+ }
+ }
+ traceWaitQueueLength(*connection);
+ if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
+ connection->outboundQueue.push_front(dispatchEntry);
+ traceOutboundQueueLength(*connection);
+ } else {
+ releaseDispatchEntry(dispatchEntry);
+ }
+ }
+
+ // Start the next dispatch cycle for this connection.
+ startDispatchCycleLocked(now(), connection);
}
-void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
- ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
- connection->getInputChannelName().c_str());
-
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
- commandEntry->connection = connection;
- postCommandLocked(std::move(commandEntry));
+void InputDispatcher::sendFocusChangedCommandLocked(const sp<IBinder>& oldToken,
+ const sp<IBinder>& newToken) {
+ auto command = [this, oldToken, newToken]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyFocusChanged(oldToken, newToken);
+ };
+ postCommandLocked(std::move(command));
}
-void InputDispatcher::notifyFocusChangedLocked(const sp<IBinder>& oldToken,
- const sp<IBinder>& newToken) {
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyFocusChangedLockedInterruptible);
- commandEntry->oldToken = oldToken;
- commandEntry->newToken = newToken;
- postCommandLocked(std::move(commandEntry));
+void InputDispatcher::sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) {
+ auto command = [this, token, x, y]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyDropWindow(token, x, y);
+ };
+ postCommandLocked(std::move(command));
}
-void InputDispatcher::notifyDropWindowLocked(const sp<IBinder>& token, float x, float y) {
- std::unique_ptr<CommandEntry> commandEntry =
- std::make_unique<CommandEntry>(&InputDispatcher::doNotifyDropWindowLockedInterruptible);
- commandEntry->newToken = token;
- commandEntry->x = x;
- commandEntry->y = y;
- postCommandLocked(std::move(commandEntry));
+void InputDispatcher::sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) {
+ auto command = [this, obscuringPackage]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyUntrustedTouch(obscuringPackage);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
@@ -5523,17 +5610,11 @@
StringPrintf("%s does not have a focused window", application->getName().c_str());
updateLastAnrStateLocked(*application, reason);
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible);
- commandEntry->inputApplicationHandle = std::move(application);
- postCommandLocked(std::move(commandEntry));
-}
-
-void InputDispatcher::onUntrustedTouchLocked(const std::string& obscuringPackage) {
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyUntrustedTouchLockedInterruptible);
- commandEntry->obscuringPackage = obscuringPackage;
- postCommandLocked(std::move(commandEntry));
+ auto command = [this, application = std::move(application)]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyNoFocusedWindowAnr(application);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::updateLastAnrStateLocked(const sp<WindowInfoHandle>& window,
@@ -5564,109 +5645,24 @@
dumpDispatchStateLocked(mLastAnrState);
}
-void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyConfigurationChanged(commandEntry->eventTime);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) {
- sp<Connection> connection = commandEntry->connection;
-
- if (connection->status != Connection::STATUS_ZOMBIE) {
- mLock.unlock();
-
- mPolicy->notifyInputChannelBroken(connection->inputChannel->getConnectionToken());
-
- mLock.lock();
- }
-}
-
-void InputDispatcher::doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) {
- sp<IBinder> oldToken = commandEntry->oldToken;
- sp<IBinder> newToken = commandEntry->newToken;
- mLock.unlock();
- mPolicy->notifyFocusChanged(oldToken, newToken);
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyDropWindowLockedInterruptible(CommandEntry* commandEntry) {
- sp<IBinder> newToken = commandEntry->newToken;
- mLock.unlock();
- mPolicy->notifyDropWindow(newToken, commandEntry->x, commandEntry->y);
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyNoFocusedWindowAnr(commandEntry->inputApplicationHandle);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyWindowUnresponsiveLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyWindowUnresponsive(commandEntry->connectionToken, commandEntry->reason);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyMonitorUnresponsiveLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyMonitorUnresponsive(commandEntry->pid, commandEntry->reason);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyWindowResponsiveLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyWindowResponsive(commandEntry->connectionToken);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyMonitorResponsiveLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyMonitorResponsive(commandEntry->pid);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyUntrustedTouchLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyUntrustedTouch(commandEntry->obscuringPackage);
-
- mLock.lock();
-}
-
-void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
- CommandEntry* commandEntry) {
- KeyEntry& entry = *(commandEntry->keyEntry);
- KeyEvent event = createKeyEvent(entry);
-
- mLock.unlock();
-
- android::base::Timer t;
- const sp<IBinder>& token = commandEntry->connectionToken;
- nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry.policyFlags);
- if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
- ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
- std::to_string(t.duration().count()).c_str());
- }
-
- mLock.lock();
+void InputDispatcher::doInterceptKeyBeforeDispatchingCommand(const sp<IBinder>& focusedWindowToken,
+ KeyEntry& entry) {
+ const KeyEvent event = createKeyEvent(entry);
+ nsecs_t delay = 0;
+ { // release lock
+ scoped_unlock unlock(mLock);
+ android::base::Timer t;
+ delay = mPolicy->interceptKeyBeforeDispatching(focusedWindowToken, &event,
+ entry.policyFlags);
+ if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+ ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
+ std::to_string(t.duration().count()).c_str());
+ }
+ } // acquire lock
if (delay < 0) {
entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
- } else if (!delay) {
+ } else if (delay == 0) {
entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
} else {
entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
@@ -5674,122 +5670,37 @@
}
}
-void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
- mPolicy->onPointerDownOutsideFocus(commandEntry->newToken);
- mLock.lock();
-}
-
-/**
- * Connection is responsive if it has no events in the waitQueue that are older than the
- * current time.
- */
-static bool isConnectionResponsive(const Connection& connection) {
- const nsecs_t currentTime = now();
- for (const DispatchEntry* entry : connection.waitQueue) {
- if (entry->timeoutTime < currentTime) {
- return false;
- }
- }
- return true;
-}
-
-void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {
- sp<Connection> connection = commandEntry->connection;
- const nsecs_t finishTime = commandEntry->eventTime;
- uint32_t seq = commandEntry->seq;
- const bool handled = commandEntry->handled;
-
- // Handle post-event policy actions.
- std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
- if (dispatchEntryIt == connection->waitQueue.end()) {
- return;
- }
- DispatchEntry* dispatchEntry = *dispatchEntryIt;
- const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
- if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
- ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
- ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str());
- }
- if (shouldReportFinishedEvent(*dispatchEntry, *connection)) {
- mLatencyTracker.trackFinishedEvent(dispatchEntry->eventEntry->id,
- connection->inputChannel->getConnectionToken(),
- dispatchEntry->deliveryTime, commandEntry->consumeTime,
- finishTime);
- }
-
- bool restartEvent;
- if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
- KeyEntry& keyEntry = static_cast<KeyEntry&>(*(dispatchEntry->eventEntry));
- restartEvent =
- afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
- } else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
- MotionEntry& motionEntry = static_cast<MotionEntry&>(*(dispatchEntry->eventEntry));
- restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
- handled);
- } else {
- restartEvent = false;
- }
-
- // Dequeue the event and start the next cycle.
- // Because the lock might have been released, it is possible that the
- // contents of the wait queue to have been drained, so we need to double-check
- // a few things.
- dispatchEntryIt = connection->findWaitQueueEntry(seq);
- if (dispatchEntryIt != connection->waitQueue.end()) {
- dispatchEntry = *dispatchEntryIt;
- connection->waitQueue.erase(dispatchEntryIt);
- const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
- mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);
- if (!connection->responsive) {
- connection->responsive = isConnectionResponsive(*connection);
- if (connection->responsive) {
- // The connection was unresponsive, and now it's responsive.
- processConnectionResponsiveLocked(*connection);
- }
- }
- traceWaitQueueLength(*connection);
- if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
- connection->outboundQueue.push_front(dispatchEntry);
- traceOutboundQueueLength(*connection);
- } else {
- releaseDispatchEntry(dispatchEntry);
- }
- }
-
- // Start the next dispatch cycle for this connection.
- startDispatchCycleLocked(now(), connection);
-}
-
void InputDispatcher::sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) {
- std::unique_ptr<CommandEntry> monitorUnresponsiveCommand = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyMonitorUnresponsiveLockedInterruptible);
- monitorUnresponsiveCommand->pid = pid;
- monitorUnresponsiveCommand->reason = std::move(reason);
- postCommandLocked(std::move(monitorUnresponsiveCommand));
+ auto command = [this, pid, reason = std::move(reason)]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyMonitorUnresponsive(pid, reason);
+ };
+ postCommandLocked(std::move(command));
}
-void InputDispatcher::sendWindowUnresponsiveCommandLocked(sp<IBinder> connectionToken,
+void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token,
std::string reason) {
- std::unique_ptr<CommandEntry> windowUnresponsiveCommand = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyWindowUnresponsiveLockedInterruptible);
- windowUnresponsiveCommand->connectionToken = std::move(connectionToken);
- windowUnresponsiveCommand->reason = std::move(reason);
- postCommandLocked(std::move(windowUnresponsiveCommand));
+ auto command = [this, token, reason = std::move(reason)]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyWindowUnresponsive(token, reason);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::sendMonitorResponsiveCommandLocked(int32_t pid) {
- std::unique_ptr<CommandEntry> monitorResponsiveCommand = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyMonitorResponsiveLockedInterruptible);
- monitorResponsiveCommand->pid = pid;
- postCommandLocked(std::move(monitorResponsiveCommand));
+ auto command = [this, pid]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyMonitorResponsive(pid);
+ };
+ postCommandLocked(std::move(command));
}
-void InputDispatcher::sendWindowResponsiveCommandLocked(sp<IBinder> connectionToken) {
- std::unique_ptr<CommandEntry> windowResponsiveCommand = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyWindowResponsiveLockedInterruptible);
- windowResponsiveCommand->connectionToken = std::move(connectionToken);
- postCommandLocked(std::move(windowResponsiveCommand));
+void InputDispatcher::sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) {
+ auto command = [this, connectionToken]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyWindowResponsive(connectionToken);
+ };
+ postCommandLocked(std::move(command));
}
/**
@@ -5837,7 +5748,7 @@
sendWindowResponsiveCommandLocked(connectionToken);
}
-bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
+bool InputDispatcher::afterKeyEventLockedInterruptable(const sp<Connection>& connection,
DispatchEntry* dispatchEntry,
KeyEntry& keyEntry, bool handled) {
if (keyEntry.flags & AKEY_EVENT_FLAG_FALLBACK) {
@@ -5862,11 +5773,12 @@
// then cancel the associated fallback key, if any.
if (fallbackKeyCode != -1) {
// Dispatch the unhandled key to the policy with the cancel flag.
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: Asking policy to cancel fallback action. "
- "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: Asking policy to cancel fallback action. "
+ "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
+ keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount,
+ keyEntry.policyFlags);
+ }
KeyEvent event = createKeyEvent(keyEntry);
event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
@@ -5894,21 +5806,21 @@
// Then ask the policy what to do with it.
bool initialDown = keyEntry.action == AKEY_EVENT_ACTION_DOWN && keyEntry.repeatCount == 0;
if (fallbackKeyCode == -1 && !initialDown) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: Skipping unhandled key event processing "
- "since this is not an initial down. "
- "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- originalKeyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: Skipping unhandled key event processing "
+ "since this is not an initial down. "
+ "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
+ originalKeyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
+ }
return false;
}
// Dispatch the unhandled key to the policy.
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: Asking policy to perform fallback action. "
- "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: Asking policy to perform fallback action. "
+ "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
+ keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
+ }
KeyEvent event = createKeyEvent(keyEntry);
mLock.unlock();
@@ -5942,19 +5854,19 @@
// longer dispatch a fallback key to the application.
if (fallbackKeyCode != AKEYCODE_UNKNOWN &&
(!fallback || fallbackKeyCode != event.getKeyCode())) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- if (fallback) {
- ALOGD("Unhandled key event: Policy requested to send key %d"
- "as a fallback for %d, but on the DOWN it had requested "
- "to send %d instead. Fallback canceled.",
- event.getKeyCode(), originalKeyCode, fallbackKeyCode);
- } else {
- ALOGD("Unhandled key event: Policy did not request fallback for %d, "
- "but on the DOWN it had requested to send %d. "
- "Fallback canceled.",
- originalKeyCode, fallbackKeyCode);
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ if (fallback) {
+ ALOGD("Unhandled key event: Policy requested to send key %d"
+ "as a fallback for %d, but on the DOWN it had requested "
+ "to send %d instead. Fallback canceled.",
+ event.getKeyCode(), originalKeyCode, fallbackKeyCode);
+ } else {
+ ALOGD("Unhandled key event: Policy did not request fallback for %d, "
+ "but on the DOWN it had requested to send %d. "
+ "Fallback canceled.",
+ originalKeyCode, fallbackKeyCode);
+ }
}
-#endif
CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS,
"canceling fallback, policy no longer desires it");
@@ -5968,18 +5880,18 @@
}
}
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- {
- std::string msg;
- const KeyedVector<int32_t, int32_t>& fallbackKeys =
- connection->inputState.getFallbackKeys();
- for (size_t i = 0; i < fallbackKeys.size(); i++) {
- msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i));
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ {
+ std::string msg;
+ const KeyedVector<int32_t, int32_t>& fallbackKeys =
+ connection->inputState.getFallbackKeys();
+ for (size_t i = 0; i < fallbackKeys.size(); i++) {
+ msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i));
+ }
+ ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.",
+ fallbackKeys.size(), msg.c_str());
}
- ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.",
- fallbackKeys.size(), msg.c_str());
}
-#endif
if (fallback) {
// Restart the dispatch cycle using the fallback key.
@@ -5995,16 +5907,16 @@
keyEntry.downTime = event.getDownTime();
keyEntry.syntheticRepeat = false;
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: Dispatching fallback key. "
- "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
- originalKeyCode, fallbackKeyCode, keyEntry.metaState);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: Dispatching fallback key. "
+ "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
+ originalKeyCode, fallbackKeyCode, keyEntry.metaState);
+ }
return true; // restart the event
} else {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: No fallback key.");
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: No fallback key.");
+ }
// Report the key as unhandled, since there is no fallback key.
mReporter->reportUnhandledKey(keyEntry.id);
@@ -6013,21 +5925,12 @@
return false;
}
-bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection,
+bool InputDispatcher::afterMotionEventLockedInterruptable(const sp<Connection>& connection,
DispatchEntry* dispatchEntry,
MotionEntry& motionEntry, bool handled) {
return false;
}
-void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType,
- commandEntry->displayId);
-
- mLock.lock();
-}
-
void InputDispatcher::traceInboundQueueLengthLocked() {
if (ATRACE_ENABLED()) {
ATRACE_INT("iq", mInboundQueue.size());
@@ -6139,7 +6042,7 @@
disablePointerCaptureForcedLocked();
if (mFocusedDisplayId == changes.displayId) {
- notifyFocusChangedLocked(changes.oldFocus, changes.newFocus);
+ sendFocusChangedCommandLocked(changes.oldFocus, changes.newFocus);
}
}
@@ -6173,19 +6076,11 @@
}
void InputDispatcher::setPointerCaptureLocked(bool enabled) {
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doSetPointerCaptureLockedInterruptible);
- commandEntry->enabled = enabled;
- postCommandLocked(std::move(commandEntry));
-}
-
-void InputDispatcher::doSetPointerCaptureLockedInterruptible(
- android::inputdispatcher::CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->setPointerCapture(commandEntry->enabled);
-
- mLock.lock();
+ auto command = [this, enabled]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->setPointerCapture(enabled);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::displayRemoved(int32_t displayId) {
@@ -6203,4 +6098,16 @@
mLooper->wake();
}
+void InputDispatcher::onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) {
+ // The listener sends the windows as a flattened array. Separate the windows by display for
+ // more convenient parsing.
+ std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
+
+ for (const auto& info : windowInfos) {
+ handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
+ handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));
+ }
+ setInputWindows(handlesPerDisplay);
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 32a467e..6df333a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -58,6 +58,7 @@
#include <InputListener.h>
#include <InputReporterInterface.h>
+#include <gui/WindowInfosListener.h>
namespace android::inputdispatcher {
@@ -80,7 +81,7 @@
*
* A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa.
*/
-class InputDispatcher : public android::InputDispatcherInterface {
+class InputDispatcher : public android::InputDispatcherInterface, public gui::WindowInfosListener {
protected:
~InputDispatcher() override;
@@ -142,6 +143,8 @@
void displayRemoved(int32_t displayId) override;
+ void onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) override;
+
private:
enum class DropReason {
NOT_DROPPED,
@@ -168,7 +171,26 @@
std::shared_ptr<EventEntry> mPendingEvent GUARDED_BY(mLock);
std::deque<std::shared_ptr<EventEntry>> mInboundQueue GUARDED_BY(mLock);
std::deque<std::shared_ptr<EventEntry>> mRecentQueue GUARDED_BY(mLock);
- std::deque<std::unique_ptr<CommandEntry>> mCommandQueue GUARDED_BY(mLock);
+
+ // A command entry captures state and behavior for an action to be performed in the
+ // dispatch loop after the initial processing has taken place. It is essentially
+ // a kind of continuation used to postpone sensitive policy interactions to a point
+ // in the dispatch loop where it is safe to release the lock (generally after finishing
+ // the critical parts of the dispatch cycle).
+ //
+ // The special thing about commands is that they can voluntarily release and reacquire
+ // the dispatcher lock at will. Initially when the command starts running, the
+ // dispatcher lock is held. However, if the command needs to call into the policy to
+ // do some work, it can release the lock, do the work, then reacquire the lock again
+ // before returning.
+ //
+ // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
+ // never calls into the policy while holding its lock.
+ //
+ // Commands are called with the lock held, but they can release and re-acquire the lock from
+ // within.
+ using Command = std::function<void()>;
+ std::deque<Command> mCommandQueue GUARDED_BY(mLock);
DropReason mLastDropReason GUARDED_BY(mLock);
@@ -292,8 +314,8 @@
// Deferred command processing.
bool haveCommandsLocked() const REQUIRES(mLock);
- bool runCommandsLockedInterruptible() REQUIRES(mLock);
- void postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) REQUIRES(mLock);
+ bool runCommandsLockedInterruptable() REQUIRES(mLock);
+ void postCommandLocked(Command&& command) REQUIRES(mLock);
nsecs_t processAnrsLocked() REQUIRES(mLock);
std::chrono::nanoseconds getDispatchingTimeoutLocked(const sp<IBinder>& token) REQUIRES(mLock);
@@ -401,7 +423,7 @@
DropReason& dropReason) REQUIRES(mLock);
void dispatchEventLocked(nsecs_t currentTime, std::shared_ptr<EventEntry> entry,
const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
- void dispatchSensorLocked(nsecs_t currentTime, std::shared_ptr<SensorEntry> entry,
+ void dispatchSensorLocked(nsecs_t currentTime, const std::shared_ptr<SensorEntry>& entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
void dispatchDragLocked(nsecs_t currentTime, std::shared_ptr<DragEntry> entry) REQUIRES(mLock);
void logOutboundKeyDetails(const char* prefix, const KeyEntry& entry);
@@ -448,24 +470,11 @@
*/
void processConnectionResponsiveLocked(const Connection& connection) REQUIRES(mLock);
- /**
- * Post `doNotifyMonitorUnresponsiveLockedInterruptible` command.
- */
void sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) REQUIRES(mLock);
- /**
- * Post `doNotifyWindowUnresponsiveLockedInterruptible` command.
- */
- void sendWindowUnresponsiveCommandLocked(sp<IBinder> connectionToken, std::string reason)
+ void sendWindowUnresponsiveCommandLocked(const sp<IBinder>& connectionToken, std::string reason)
REQUIRES(mLock);
- /**
- * Post `doNotifyMonitorResponsiveLockedInterruptible` command.
- */
void sendMonitorResponsiveCommandLocked(int32_t pid) REQUIRES(mLock);
- /**
- * Post `doNotifyWindowResponsiveLockedInterruptible` command.
- */
- void sendWindowResponsiveCommandLocked(sp<IBinder> connectionToken) REQUIRES(mLock);
-
+ void sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock);
// Optimization: AnrTracker is used to quickly find which connection is due for a timeout next.
// AnrTracker must be kept in-sync with all responsive connection.waitQueues.
@@ -599,53 +608,30 @@
REQUIRES(mLock);
// Interesting events that we might like to log or tell the framework about.
- void onDispatchCycleFinishedLocked(nsecs_t currentTime, const sp<Connection>& connection,
- uint32_t seq, bool handled, nsecs_t consumeTime)
+ void doDispatchCycleFinishedCommand(nsecs_t finishTime, const sp<Connection>& connection,
+ uint32_t seq, bool handled, nsecs_t consumeTime)
REQUIRES(mLock);
- void onDispatchCycleBrokenLocked(nsecs_t currentTime, const sp<Connection>& connection)
- REQUIRES(mLock);
+ void doInterceptKeyBeforeDispatchingCommand(const sp<IBinder>& focusedWindowToken,
+ KeyEntry& entry) REQUIRES(mLock);
void onFocusChangedLocked(const FocusResolver::FocusChanges& changes) REQUIRES(mLock);
- void notifyFocusChangedLocked(const sp<IBinder>& oldFocus, const sp<IBinder>& newFocus)
+ void sendFocusChangedCommandLocked(const sp<IBinder>& oldToken, const sp<IBinder>& newToken)
REQUIRES(mLock);
- void notifyDropWindowLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
+ void sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
+ void sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) REQUIRES(mLock);
void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
- void onUntrustedTouchLocked(const std::string& obscuringPackage) REQUIRES(mLock);
void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window,
const std::string& reason) REQUIRES(mLock);
void updateLastAnrStateLocked(const InputApplicationHandle& application,
const std::string& reason) REQUIRES(mLock);
void updateLastAnrStateLocked(const std::string& windowLabel, const std::string& reason)
REQUIRES(mLock);
-
- // Outbound policy interactions.
- void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry)
- REQUIRES(mLock);
- void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyDropWindowLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
-
- // ANR-related callbacks - start
- void doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyWindowUnresponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyMonitorUnresponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyWindowResponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyMonitorResponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- // ANR-related callbacks - end
- void doNotifySensorLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyUntrustedTouchLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry)
- REQUIRES(mLock);
- void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doSetPointerCaptureLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- bool afterKeyEventLockedInterruptible(const sp<Connection>& connection,
+ bool afterKeyEventLockedInterruptable(const sp<Connection>& connection,
DispatchEntry* dispatchEntry, KeyEntry& keyEntry,
bool handled) REQUIRES(mLock);
- bool afterMotionEventLockedInterruptible(const sp<Connection>& connection,
+ bool afterMotionEventLockedInterruptable(const sp<Connection>& connection,
DispatchEntry* dispatchEntry, MotionEntry& motionEntry,
bool handled) REQUIRES(mLock);
- void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
// Statistics gathering.
LatencyAggregator mLatencyAggregator GUARDED_BY(mLock);
@@ -656,6 +642,8 @@
sp<InputReporterInterface> mReporter;
sp<com::android::internal::compat::IPlatformCompatNative> mCompatService;
+
+ void onFirstRef() override;
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 80db035..a7dccf0 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -21,7 +21,6 @@
#include <android-base/result.h>
#include <android/gui/FocusRequest.h>
#include <android/os/BlockUntrustedTouchesMode.h>
-#include <android/os/ISetInputWindowsListener.h>
#include <android/os/InputEventInjectionResult.h>
#include <android/os/InputEventInjectionSync.h>
#include <gui/InputApplication.h>
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index c05ff39..3cf1b2b 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -23,7 +23,6 @@
#include "InputHost.h"
#include <android/os/BnInputFlinger.h>
-#include <android/os/ISetInputWindowsListener.h>
#include <binder/Binder.h>
#include <cutils/compiler.h>
#include <utils/String16.h>
@@ -31,9 +30,7 @@
#include <utils/StrongPointer.h>
using android::gui::FocusRequest;
-using android::gui::WindowInfo;
using android::os::BnInputFlinger;
-using android::os::ISetInputWindowsListener;
namespace android {
@@ -46,10 +43,6 @@
InputFlinger() ANDROID_API;
status_t dump(int fd, const Vector<String16>& args) override;
- binder::Status setInputWindows(const std::vector<WindowInfo>&,
- const sp<ISetInputWindowsListener>&) override {
- return binder::Status::ok();
- }
binder::Status createInputChannel(const std::string&, InputChannel*) override {
return binder::Status::ok();
}
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index 7ac2dec..a507632 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -303,7 +303,7 @@
* the device
*/
mDeviceEnabled = false;
- for (const auto& [sensorType, sensor] : mSensors) {
+ for (const auto& [_, sensor] : mSensors) {
// If any sensor is on we will turn on the device.
if (sensor.enabled) {
mDeviceEnabled = true;
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 4c5ff63..7347b2c 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -33,9 +33,7 @@
// projection are part of the input window's transform. This means InputReader should work in the
// un-rotated coordinate space.
static bool isPerWindowInputRotationEnabled() {
- static const bool PER_WINDOW_INPUT_ROTATION =
- sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false);
- return PER_WINDOW_INPUT_ROTATION;
+ return sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false);
}
static int32_t getInverseRotation(int32_t orientation) {
diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp
index 8c0edca..662be80 100644
--- a/services/inputflinger/tests/FocusResolver_test.cpp
+++ b/services/inputflinger/tests/FocusResolver_test.cpp
@@ -41,7 +41,6 @@
mInfo.focusable = focusable;
}
- bool updateInfo() { return true; }
void setFocusable(bool focusable) { mInfo.focusable = focusable; }
void setVisible(bool visible) { mInfo.visible = visible; }
};
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
index aff03bf..5aeb21f 100644
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -17,14 +17,11 @@
import android.InputChannel;
import android.gui.FocusRequest;
import android.gui.WindowInfo;
-import android.os.ISetInputWindowsListener;
/** @hide */
interface IInputFlingerQuery
{
/* Test interfaces */
- void getInputWindows(out WindowInfo[] inputHandles);
void getInputChannels(out InputChannel[] channels);
- void getLastFocusRequest(out FocusRequest request);
void resetInputManager();
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f03cf8b..50e1854 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -937,8 +937,6 @@
mInfo.displayId = displayId;
}
- virtual bool updateInfo() { return true; }
-
void setFocusable(bool focusable) { mInfo.focusable = focusable; }
void setVisible(bool visible) { mInfo.visible = visible; }
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index d2a98df..454e531 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -18,9 +18,7 @@
#include <IInputFlingerQuery.h>
#include <android/os/BnInputFlinger.h>
-#include <android/os/BnSetInputWindowsListener.h>
#include <android/os/IInputFlinger.h>
-#include <android/os/ISetInputWindowsListener.h>
#include <binder/Binder.h>
#include <binder/IPCThreadState.h>
@@ -28,7 +26,6 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
-#include <gui/WindowInfo.h>
#include <input/Input.h>
#include <input/InputTransport.h>
@@ -45,57 +42,17 @@
#define TAG "InputFlingerServiceTest"
using android::gui::FocusRequest;
-using android::gui::WindowInfo;
-using android::gui::WindowInfoHandle;
using android::os::BnInputFlinger;
-using android::os::BnSetInputWindowsListener;
using android::os::IInputFlinger;
-using android::os::ISetInputWindowsListener;
using std::chrono_literals::operator""ms;
using std::chrono_literals::operator""s;
namespace android {
-static const sp<IBinder> TestInfoToken = new BBinder();
-static const sp<IBinder> FocusedTestInfoToken = new BBinder();
-static constexpr int32_t TestInfoId = 1;
-static const std::string TestInfoName = "InputFlingerServiceTestInputWindowInfo";
-static constexpr Flags<WindowInfo::Flag> TestInfoFlags = WindowInfo::Flag::NOT_FOCUSABLE;
-static constexpr WindowInfo::Type TestInfoType = WindowInfo::Type::INPUT_METHOD;
-static constexpr std::chrono::duration TestInfoDispatchingTimeout = 2532ms;
-static constexpr int32_t TestInfoFrameLeft = 93;
-static constexpr int32_t TestInfoFrameTop = 34;
-static constexpr int32_t TestInfoFrameRight = 16;
-static constexpr int32_t TestInfoFrameBottom = 19;
-static constexpr int32_t TestInfoSurfaceInset = 17;
-static constexpr float TestInfoGlobalScaleFactor = 0.3;
-static constexpr float TestInfoWindowXScale = 0.4;
-static constexpr float TestInfoWindowYScale = 0.5;
-static const Rect TestInfoTouchableRegionRect = {100 /* left */, 150 /* top */, 400 /* right */,
- 450 /* bottom */};
-static const Region TestInfoTouchableRegion(TestInfoTouchableRegionRect);
-static constexpr bool TestInfoVisible = false;
-static constexpr bool TestInfoTrustedOverlay = true;
-static constexpr bool TestInfoFocusable = false;
-static constexpr bool TestInfoHasWallpaper = false;
-static constexpr bool TestInfoPaused = false;
-static constexpr int32_t TestInfoOwnerPid = 19;
-static constexpr int32_t TestInfoOwnerUid = 24;
-static constexpr WindowInfo::Feature TestInfoInputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL;
-static constexpr int32_t TestInfoDisplayId = 34;
-static constexpr int32_t TestInfoPortalToDisplayId = 2;
-static constexpr bool TestInfoReplaceTouchableRegionWithCrop = true;
-static const sp<IBinder> TestInfoTouchableRegionCropHandle = new BBinder();
-
-static const std::string TestAppInfoName = "InputFlingerServiceTestInputApplicationInfo";
-static const sp<IBinder> TestAppInfoToken = new BBinder();
-static constexpr std::chrono::duration TestAppInfoDispatchingTimeout = 12345678ms;
-
static const String16 kTestServiceName = String16("InputFlingerService");
static const String16 kQueryServiceName = String16("InputFlingerQueryService");
-struct SetInputWindowsListener;
// --- InputFlingerServiceTest ---
class InputFlingerServiceTest : public testing::Test {
public:
@@ -104,32 +61,15 @@
protected:
void InitializeInputFlinger();
- void setInputWindowsByInfos(const std::vector<WindowInfo>& infos);
- void setFocusedWindow(const sp<IBinder> token, const sp<IBinder> focusedToken,
- nsecs_t timestampNanos);
-
- void setInputWindowsFinished();
- void verifyInputWindowInfo(const WindowInfo& info) const;
- WindowInfo& getInfo() const { return const_cast<WindowInfo&>(mInfo); }
sp<IInputFlinger> mService;
sp<IInputFlingerQuery> mQuery;
private:
- sp<SetInputWindowsListener> mSetInputWindowsListener;
std::unique_ptr<InputChannel> mServerChannel, mClientChannel;
- WindowInfo mInfo;
std::mutex mLock;
- std::condition_variable mSetInputWindowsFinishedCondition;
};
-struct SetInputWindowsListener : BnSetInputWindowsListener {
- explicit SetInputWindowsListener(std::function<void()> cbFunc) : mCbFunc(cbFunc) {}
-
- binder::Status onSetInputWindowsFinished() override;
-
- std::function<void()> mCbFunc;
-};
class TestInputManager : public BnInputFlinger {
protected:
@@ -138,16 +78,10 @@
public:
TestInputManager(){};
- binder::Status getInputWindows(std::vector<WindowInfo>* inputHandles);
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
- binder::Status getLastFocusRequest(FocusRequest*);
status_t dump(int fd, const Vector<String16>& args) override;
- binder::Status setInputWindows(
- const std::vector<WindowInfo>& handles,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
-
binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
binder::Status setFocusedWindow(const FocusRequest&) override;
@@ -156,62 +90,28 @@
private:
mutable Mutex mLock;
- std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> mHandlesPerDisplay;
std::vector<std::shared_ptr<InputChannel>> mInputChannels;
- FocusRequest mFocusRequest;
};
class TestInputQuery : public BnInputFlingerQuery {
public:
TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){};
- binder::Status getInputWindows(std::vector<WindowInfo>* inputHandles) override;
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
- binder::Status getLastFocusRequest(FocusRequest*) override;
binder::Status resetInputManager() override;
private:
sp<android::TestInputManager> mManager;
};
-binder::Status TestInputQuery::getInputWindows(std::vector<WindowInfo>* inputHandles) {
- return mManager->getInputWindows(inputHandles);
-}
-
binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannel>* channels) {
return mManager->getInputChannels(channels);
}
-binder::Status TestInputQuery::getLastFocusRequest(FocusRequest* request) {
- return mManager->getLastFocusRequest(request);
-}
-
binder::Status TestInputQuery::resetInputManager() {
mManager->reset();
return binder::Status::ok();
}
-binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
- if (mCbFunc != nullptr) {
- mCbFunc();
- }
- return binder::Status::ok();
-}
-
-binder::Status TestInputManager::setInputWindows(
- const std::vector<WindowInfo>& infos,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) {
- AutoMutex _l(mLock);
-
- for (const auto& info : infos) {
- mHandlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
- mHandlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));
- }
- if (setInputWindowsListener) {
- setInputWindowsListener->onSetInputWindowsFinished();
- }
- return binder::Status::ok();
-}
-
binder::Status TestInputManager::createInputChannel(const std::string& name,
InputChannel* outChannel) {
AutoMutex _l(mLock);
@@ -249,15 +149,6 @@
return NO_ERROR;
}
-binder::Status TestInputManager::getInputWindows(std::vector<WindowInfo>* inputInfos) {
- for (auto& [displayId, inputHandles] : mHandlesPerDisplay) {
- for (auto& inputHandle : inputHandles) {
- inputInfos->push_back(*inputHandle->getInfo());
- }
- }
- return binder::Status::ok();
-}
-
binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannel>* channels) {
channels->clear();
for (std::shared_ptr<InputChannel>& channel : mInputChannels) {
@@ -266,64 +157,16 @@
return binder::Status::ok();
}
-binder::Status TestInputManager::getLastFocusRequest(FocusRequest* request) {
- *request = mFocusRequest;
- return binder::Status::ok();
-}
-
binder::Status TestInputManager::setFocusedWindow(const FocusRequest& request) {
- mFocusRequest = request;
return binder::Status::ok();
}
void TestInputManager::reset() {
- mHandlesPerDisplay.clear();
mInputChannels.clear();
- mFocusRequest = FocusRequest();
}
void InputFlingerServiceTest::SetUp() {
- mSetInputWindowsListener = new SetInputWindowsListener([&]() {
- std::unique_lock<std::mutex> lock(mLock);
- mSetInputWindowsFinishedCondition.notify_all();
- });
InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
-
- mInfo.token = TestInfoToken;
- mInfo.id = TestInfoId;
- mInfo.name = TestInfoName;
- mInfo.flags = TestInfoFlags;
- mInfo.type = TestInfoType;
- mInfo.dispatchingTimeout = TestInfoDispatchingTimeout;
- mInfo.frameLeft = TestInfoFrameLeft;
- mInfo.frameTop = TestInfoFrameTop;
- mInfo.frameRight = TestInfoFrameRight;
- mInfo.frameBottom = TestInfoFrameBottom;
- mInfo.surfaceInset = TestInfoSurfaceInset;
- mInfo.globalScaleFactor = TestInfoGlobalScaleFactor;
- mInfo.transform.set({TestInfoWindowXScale, 0, TestInfoFrameLeft, 0, TestInfoWindowYScale,
- TestInfoFrameTop, 0, 0, 1});
- mInfo.touchableRegion = TestInfoTouchableRegion;
- mInfo.visible = TestInfoVisible;
- mInfo.trustedOverlay = TestInfoTrustedOverlay;
- mInfo.focusable = TestInfoFocusable;
-
- mInfo.hasWallpaper = TestInfoHasWallpaper;
- mInfo.paused = TestInfoPaused;
- mInfo.ownerPid = TestInfoOwnerPid;
- mInfo.ownerUid = TestInfoOwnerUid;
- mInfo.inputFeatures = TestInfoInputFeatures;
- mInfo.displayId = TestInfoDisplayId;
- mInfo.portalToDisplayId = TestInfoPortalToDisplayId;
- mInfo.replaceTouchableRegionWithCrop = TestInfoReplaceTouchableRegionWithCrop;
- mInfo.touchableRegionCropHandle = TestInfoTouchableRegionCropHandle;
-
- mInfo.applicationInfo.name = TestAppInfoName;
- mInfo.applicationInfo.token = TestAppInfoToken;
- mInfo.applicationInfo.dispatchingTimeoutMillis =
- std::chrono::duration_cast<std::chrono::milliseconds>(TestAppInfoDispatchingTimeout)
- .count();
-
InitializeInputFlinger();
}
@@ -331,10 +174,6 @@
mQuery->resetInputManager();
}
-void InputFlingerServiceTest::verifyInputWindowInfo(const WindowInfo& info) const {
- EXPECT_EQ(mInfo, info);
-}
-
void InputFlingerServiceTest::InitializeInputFlinger() {
sp<IBinder> input(defaultServiceManager()->waitForService(kTestServiceName));
ASSERT_TRUE(input != nullptr);
@@ -345,40 +184,6 @@
mQuery = interface_cast<IInputFlingerQuery>(input);
}
-void InputFlingerServiceTest::setInputWindowsByInfos(const std::vector<WindowInfo>& infos) {
- std::unique_lock<std::mutex> lock(mLock);
- mService->setInputWindows(infos, mSetInputWindowsListener);
- // Verify listener call
- EXPECT_NE(mSetInputWindowsFinishedCondition.wait_for(lock, 1s), std::cv_status::timeout);
-}
-
-void InputFlingerServiceTest::setFocusedWindow(const sp<IBinder> token,
- const sp<IBinder> focusedToken,
- nsecs_t timestampNanos) {
- FocusRequest request;
- request.token = TestInfoToken;
- request.focusedToken = focusedToken;
- request.timestamp = timestampNanos;
- mService->setFocusedWindow(request);
- // call set input windows and wait for the callback to drain the queue.
- setInputWindowsByInfos(std::vector<WindowInfo>());
-}
-
-/**
- * Test InputFlinger service interface SetInputWindows
- */
-TEST_F(InputFlingerServiceTest, InputWindow_SetInputWindows) {
- std::vector<WindowInfo> infos = {getInfo()};
- setInputWindowsByInfos(infos);
-
- // Verify input windows from service
- std::vector<WindowInfo> windowInfos;
- mQuery->getInputWindows(&windowInfos);
- for (const WindowInfo& windowInfo : windowInfos) {
- verifyInputWindowInfo(windowInfo);
- }
-}
-
/**
* Test InputFlinger service interface createInputChannel
*/
@@ -397,7 +202,7 @@
EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
}
-TEST_F(InputFlingerServiceTest, InputWindow_CreateInputChannel) {
+TEST_F(InputFlingerServiceTest, CreateInputChannel) {
InputChannel channel;
ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
@@ -411,30 +216,6 @@
EXPECT_EQ(channels.size(), 0UL);
}
-TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindow) {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- setFocusedWindow(TestInfoToken, nullptr /* focusedToken */, now);
-
- FocusRequest request;
- mQuery->getLastFocusRequest(&request);
-
- EXPECT_EQ(request.token, TestInfoToken);
- EXPECT_EQ(request.focusedToken, nullptr);
- EXPECT_EQ(request.timestamp, now);
-}
-
-TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindowWithFocusedToken) {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- setFocusedWindow(TestInfoToken, FocusedTestInfoToken, now);
-
- FocusRequest request;
- mQuery->getLastFocusRequest(&request);
-
- EXPECT_EQ(request.token, TestInfoToken);
- EXPECT_EQ(request.focusedToken, FocusedTestInfoToken);
- EXPECT_EQ(request.timestamp, now);
-}
-
} // namespace android
int main(int argc, char** argv) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 778f6e6..43f14bd 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -16,6 +16,7 @@
#include <CursorInputMapper.h>
#include <InputDevice.h>
+#include <InputFlingerProperties.sysprop.h>
#include <InputMapper.h>
#include <InputReader.h>
#include <InputReaderBase.h>
@@ -95,6 +96,17 @@
{"green", LightColor::GREEN},
{"blue", LightColor::BLUE}};
+static int32_t getInverseRotation(int32_t orientation) {
+ switch (orientation) {
+ case DISPLAY_ORIENTATION_90:
+ return DISPLAY_ORIENTATION_270;
+ case DISPLAY_ORIENTATION_270:
+ return DISPLAY_ORIENTATION_90;
+ default:
+ return orientation;
+ }
+}
+
// --- FakePointerController ---
class FakePointerController : public PointerControllerInterface {
@@ -2660,6 +2672,7 @@
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const Flags<InputDeviceClass> DEVICE_CLASSES;
static const int32_t EVENTHUB_ID;
+ static const std::optional<bool> INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE;
std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
@@ -2676,11 +2689,19 @@
mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
}
- void SetUp() override { SetUp(DEVICE_CLASSES); }
+ void SetUp() override {
+ // Ensure per_window_input_rotation is enabled.
+ sysprop::InputFlingerProperties::per_window_input_rotation(true);
+
+ SetUp(DEVICE_CLASSES);
+ }
void TearDown() override {
mFakeListener.clear();
mFakePolicy.clear();
+
+ sysprop::InputFlingerProperties::per_window_input_rotation(
+ INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE);
}
void addConfigurationProperty(const char* key, const char* value) {
@@ -2792,6 +2813,8 @@
const Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
Flags<InputDeviceClass>(0); // not needed for current tests
const int32_t InputMapperTest::EVENTHUB_ID = 1;
+const std::optional<bool> InputMapperTest::INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE =
+ sysprop::InputFlingerProperties::per_window_input_rotation();
// --- SwitchInputMapperTest ---
@@ -4088,8 +4111,11 @@
ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f));
}
-TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) {
+TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotions) {
addConfigurationProperty("cursor.mode", "navigation");
+ // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
+ // need to be rotated.
+ addConfigurationProperty("cursor.orientationAware", "1");
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
prepareDisplay(DISPLAY_ORIENTATION_90);
@@ -4103,9 +4129,10 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
}
-TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) {
+TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotions) {
addConfigurationProperty("cursor.mode", "navigation");
- addConfigurationProperty("cursor.orientationAware", "1");
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
prepareDisplay(DISPLAY_ORIENTATION_0);
@@ -4119,14 +4146,14 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
prepareDisplay(DISPLAY_ORIENTATION_90);
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1));
prepareDisplay(DISPLAY_ORIENTATION_180);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1));
@@ -4139,14 +4166,14 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1));
prepareDisplay(DISPLAY_ORIENTATION_270);
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1));
- ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1));
+ ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1));
}
TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) {
@@ -5368,11 +5395,12 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
}
-TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) {
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_DoesNotRotateMotions) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareButtons();
prepareAxes(POSITION);
- addConfigurationProperty("touch.orientationAware", "0");
+ // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
+ // need to be rotated. Touchscreens are orientation-aware by default.
SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs args;
@@ -5391,10 +5419,13 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}
-TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) {
+TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_RotatesMotions) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareButtons();
prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs args;
@@ -5416,7 +5447,7 @@
// Rotation 90.
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_90);
- processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
+ processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
@@ -5444,7 +5475,7 @@
// Rotation 270.
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_270);
- processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
+ processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
@@ -7806,7 +7837,7 @@
ASSERT_EQ(std::vector<TouchVideoFrame>(), motionArgs.videoFrames);
}
-TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) {
+TEST_F(MultiTouchInputMapperTest, VideoFrames_AreNotRotated) {
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
@@ -7816,6 +7847,32 @@
// Test all 4 orientations
for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90,
+ DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) {
+ SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation));
+ clearViewports();
+ prepareDisplay(orientation);
+ std::vector<TouchVideoFrame> frames{frame};
+ mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}});
+ processPosition(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(frames, motionArgs.videoFrames);
+ }
+}
+
+TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_AreRotated) {
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+ // Unrotated video frame
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+ NotifyMotionArgs motionArgs;
+
+ // Test all 4 orientations
+ for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90,
DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) {
SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation));
clearViewports();
@@ -7825,12 +7882,16 @@
processPosition(mapper, 100, 200);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- frames[0].rotate(orientation);
+ // We expect the raw coordinates of the MotionEvent to be rotated in the inverse direction
+ // compared to the display. This is so that when the window transform (which contains the
+ // display rotation) is applied later by InputDispatcher, the coordinates end up in the
+ // window's coordinate space.
+ frames[0].rotate(getInverseRotation(orientation));
ASSERT_EQ(frames, motionArgs.videoFrames);
}
}
-TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) {
+TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreNotRotated) {
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
@@ -7847,8 +7908,36 @@
processPosition(mapper, 100, 200);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- std::for_each(frames.begin(), frames.end(),
- [](TouchVideoFrame& frame) { frame.rotate(DISPLAY_ORIENTATION_90); });
+ ASSERT_EQ(frames, motionArgs.videoFrames);
+}
+
+TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_MultipleFramesAreRotated) {
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+ // Unrotated video frames. There's no rule that they must all have the same dimensions,
+ // so mix these.
+ TouchVideoFrame frame1(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+ TouchVideoFrame frame2(3, 3, {0, 1, 2, 3, 4, 5, 6, 7, 8}, {1, 3});
+ TouchVideoFrame frame3(2, 2, {10, 20, 10, 0}, {1, 4});
+ std::vector<TouchVideoFrame> frames{frame1, frame2, frame3};
+ NotifyMotionArgs motionArgs;
+
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+ mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}});
+ processPosition(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ std::for_each(frames.begin(), frames.end(), [](TouchVideoFrame& frame) {
+ // We expect the raw coordinates of the MotionEvent to be rotated in the inverse direction
+ // compared to the display. This is so that when the window transform (which contains the
+ // display rotation) is applied later by InputDispatcher, the coordinates end up in the
+ // window's coordinate space.
+ frame.rotate(getInverseRotation(DISPLAY_ORIENTATION_90));
+ });
ASSERT_EQ(frames, motionArgs.videoFrames);
}
@@ -8402,18 +8491,25 @@
// Reset.
mapper.reset(ARBITRARY_TIME);
- // Let physical display be different to device, and make surface and physical could be 1:1.
- halfDisplayToCenterHorizontal(DISPLAY_ORIENTATION_0);
+ // Let physical display be different to device, and make surface and physical could be 1:1 in
+ // all four orientations.
+ for (int orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90, DISPLAY_ORIENTATION_180,
+ DISPLAY_ORIENTATION_270}) {
+ halfDisplayToCenterHorizontal(orientation);
- const int32_t xExpected = (x + 1) - (DISPLAY_WIDTH / 4);
- const int32_t yExpected = y;
- processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
+ const int32_t xExpected = (x + 1) - (DISPLAY_WIDTH / 4);
+ const int32_t yExpected = y;
+ processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
+ }
}
-TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_90) {
+TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_90_NotOrientationAware) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// Half display to (width/4, 0, width * 3/4, height) and rotate 90-degrees.
@@ -8422,34 +8518,40 @@
const int32_t x = DISPLAY_WIDTH / 4;
const int32_t y = DISPLAY_HEIGHT / 2;
- // expect x/y = swap x/y then reverse y.
- const int32_t xExpected = y;
- const int32_t yExpected = (DISPLAY_WIDTH * 3 / 4) - (x + 1);
- processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
-}
-
-TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_270) {
- addConfigurationProperty("touch.deviceType", "touchScreen");
- prepareDisplay(DISPLAY_ORIENTATION_0);
- prepareAxes(POSITION);
- MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
-
- // Half display to (width/4, 0, width * 3/4, height) and rotate 270-degrees.
- halfDisplayToCenterHorizontal(DISPLAY_ORIENTATION_270);
-
- const int32_t x = DISPLAY_WIDTH / 4;
- const int32_t y = DISPLAY_HEIGHT / 2;
-
// expect x/y = swap x/y then reverse x.
constexpr int32_t xExpected = DISPLAY_HEIGHT - y;
constexpr int32_t yExpected = (x + 1) - DISPLAY_WIDTH / 4;
processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
}
-TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner) {
+TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_270_NotOrientationAware) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ // Half display to (width/4, 0, width * 3/4, height) and rotate 270-degrees.
+ halfDisplayToCenterHorizontal(DISPLAY_ORIENTATION_270);
+
+ const int32_t x = DISPLAY_WIDTH / 4;
+ const int32_t y = DISPLAY_HEIGHT / 2;
+
+ // expect x/y = swap x/y then reverse y.
+ const int32_t xExpected = y;
+ const int32_t yExpected = (DISPLAY_WIDTH * 3 / 4) - (x + 1);
+ processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
+}
+
+TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner_NotOrientationAware) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
const int32_t x = 0;
@@ -8461,16 +8563,16 @@
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_90);
- // expect x/y = swap x/y then reverse y.
- const int32_t xExpected90 = y;
- const int32_t yExpected90 = DISPLAY_WIDTH - 1;
+ // expect x/y = swap x/y then reverse x.
+ const int32_t xExpected90 = DISPLAY_HEIGHT - 1;
+ const int32_t yExpected90 = x;
processPositionAndVerify(mapper, x - 1, y, x, y, xExpected90, yExpected90);
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_270);
- // expect x/y = swap x/y then reverse x.
- const int32_t xExpected270 = DISPLAY_HEIGHT - 1;
- const int32_t yExpected270 = x;
+ // expect x/y = swap x/y then reverse y.
+ const int32_t xExpected270 = y;
+ const int32_t yExpected270 = DISPLAY_WIDTH - 1;
processPositionAndVerify(mapper, x - 1, y, x, y, xExpected270, yExpected270);
}
diff --git a/services/memtrackproxy/Android.bp b/services/memtrackproxy/Android.bp
index 7d78f3b..3233cc9 100644
--- a/services/memtrackproxy/Android.bp
+++ b/services/memtrackproxy/Android.bp
@@ -32,7 +32,7 @@
"libcutils",
"libutils",
"android.hardware.memtrack@1.0",
- "android.hardware.memtrack-V1-ndk_platform",
+ "android.hardware.memtrack-V1-ndk",
],
srcs: [
"MemtrackProxy.cpp",
@@ -45,6 +45,6 @@
],
export_shared_lib_headers: [
"android.hardware.memtrack@1.0",
- "android.hardware.memtrack-V1-ndk_platform",
+ "android.hardware.memtrack-V1-ndk",
],
}
diff --git a/services/memtrackproxy/test/Android.bp b/services/memtrackproxy/test/Android.bp
index f943761..1dc21bf 100644
--- a/services/memtrackproxy/test/Android.bp
+++ b/services/memtrackproxy/test/Android.bp
@@ -29,7 +29,7 @@
shared_libs: [
"libbinder_ndk",
"libmemtrackproxy",
- "android.hardware.memtrack-V1-ndk_platform",
+ "android.hardware.memtrack-V1-ndk",
],
test_suites: ["general-tests"],
require_root: true,
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 5d6f8c7..c233bf0 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -915,7 +915,7 @@
if (activationIndex < 0) {
return false;
}
- return mActivationCount.valueAt(activationIndex).numActiveClients() > 0;
+ return mActivationCount.valueAt(activationIndex).isActive;
}
void SensorDevice::onMicSensorAccessChanged(void* ident, int handle, nsecs_t samplingPeriodNs) {
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index 560834f..c285c00 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -92,14 +92,16 @@
}
status_t ProximitySensor::activate(void* ident, bool enabled) {
- bool wasActive = mActive;
+ bool lastState = mSensorDevice.isSensorActive(mSensor.getHandle());
+
status_t status = HardwareSensor::activate(ident, enabled);
if (status != NO_ERROR) {
return status;
}
- mActive = enabled;
- if (wasActive != enabled) {
- mSensorService.onProximityActiveLocked(enabled);
+
+ bool currentState = mSensorDevice.isSensorActive(mSensor.getHandle());
+ if (currentState != lastState) {
+ mSensorService.onProximityActiveLocked(currentState);
}
return NO_ERROR;
}
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index ea181c9..4e9f7bf 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -119,7 +119,6 @@
void didEnableAllSensors() override;
private:
SensorService& mSensorService;
- bool mActive;
};
// ---------------------------------------------------------------------------
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
index a472c5f..7fea616 100644
--- a/services/stats/Android.bp
+++ b/services/stats/Android.bp
@@ -16,7 +16,7 @@
cflags: ["-Wall", "-Werror"],
shared_libs: [
"android.frameworks.stats@1.0",
- "android.frameworks.stats-V1-ndk_platform",
+ "android.frameworks.stats-V1-ndk",
"libbinder_ndk",
"libhidlbase",
"liblog",
@@ -29,7 +29,7 @@
],
export_shared_lib_headers: [
"android.frameworks.stats@1.0",
- "android.frameworks.stats-V1-ndk_platform",
+ "android.frameworks.stats-V1-ndk",
],
local_include_dirs: [
"include/stats",
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 63f7efc..eeb3f3a 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -146,6 +146,7 @@
"DisplayHardware/ComposerHal.cpp",
"DisplayHardware/DisplayIdentification.cpp",
"DisplayHardware/FramebufferSurface.cpp",
+ "DisplayHardware/Hash.cpp",
"DisplayHardware/HWC2.cpp",
"DisplayHardware/HWComposer.cpp",
"DisplayHardware/PowerAdvisor.cpp",
@@ -157,6 +158,7 @@
"FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
"HdrLayerInfoReporter.cpp",
+ "WindowInfosListenerInvoker.cpp",
"Layer.cpp",
"LayerProtoHelper.cpp",
"LayerRejecter.cpp",
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 2fa8936..81254ac 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -520,13 +520,10 @@
}
status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
- uint32_t const maxSurfaceDims =
- std::min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
-
// never allow a surface larger than what our underlying GL implementation
// can handle.
- if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
- ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
+ if (mFlinger->exceedsMaxRenderTargetSize(w, h)) {
+ ALOGE("dimensions too large %" PRIu32 " x %" PRIu32, w, h);
return BAD_VALUE;
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 032ff9a..8bc51df 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -425,7 +425,8 @@
if (mDrawingState.buffer) {
mReleasePreviousBuffer = true;
- if (mDrawingState.buffer != mBufferInfo.mBuffer) {
+ if (mDrawingState.buffer != mBufferInfo.mBuffer ||
+ mDrawingState.frameNumber != mBufferInfo.mFrameNumber) {
// If mDrawingState has a buffer, and we are about to update again
// before swapping to drawing state, then the first buffer will be
// dropped and we should decrement the pending buffer count and
@@ -890,7 +891,11 @@
mBufferInfo.mFenceTime = std::make_shared<FenceTime>(s.acquireFence);
mBufferInfo.mFence = s.acquireFence;
mBufferInfo.mTransform = s.bufferTransform;
+ auto lastDataspace = mBufferInfo.mDataspace;
mBufferInfo.mDataspace = translateDataspace(s.dataspace);
+ if (lastDataspace != mBufferInfo.mDataspace) {
+ mFlinger->mSomeDataspaceChanged = true;
+ }
mBufferInfo.mCrop = computeBufferCrop(s);
mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion;
@@ -959,22 +964,6 @@
ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers);
}
-void BufferStateLayer::bufferMayChange(const sp<GraphicBuffer>& newBuffer) {
- if (mDrawingState.buffer != nullptr &&
- (!mBufferInfo.mBuffer ||
- mDrawingState.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) &&
- newBuffer != mDrawingState.buffer->getBuffer()) {
- // If we are about to update mDrawingState.buffer but it has not yet latched
- // then we will drop a buffer and should decrement the pending buffer count and
- // call any release buffer callbacks if set.
- callReleaseBufferCallback(mDrawingState.releaseBufferListener,
- mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
- mDrawingState.acquireFence, mTransformHint,
- mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
- mOwnerUid));
- decrementPendingBufferCount();
- }
-}
/*
* We don't want to send the layer's transform to input, but rather the
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index e567478..cab4899 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -97,7 +97,6 @@
// See mPendingBufferTransactions
void decrementPendingBufferCount();
- void bufferMayChange(const sp<GraphicBuffer>& newBuffer) override;
std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; }
std::string getPendingBufferCounterName() override { return mBlastTransactionName; }
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index aac6c91..8da2e24 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#include <stdint.h>
#include <sys/types.h>
@@ -132,6 +128,3 @@
// ---------------------------------------------------------------------------
}; // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index e2b07f0..15a86af 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -166,6 +166,9 @@
// Enables (or disables) layer caching on this output
virtual void setLayerCachingEnabled(bool) = 0;
+ // Enables (or disables) layer caching texture pool on this output
+ virtual void setLayerCachingTexturePoolEnabled(bool) = 0;
+
// Sets the projection state to use
virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 2e40487..14f2163 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -41,6 +41,7 @@
std::optional<DisplayId> getDisplayId() const override;
void setCompositionEnabled(bool) override;
void setLayerCachingEnabled(bool) override;
+ void setLayerCachingTexturePoolEnabled(bool) override;
void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) override;
void setDisplaySize(const ui::Size&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 7534548..8ec15ed 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -80,6 +80,8 @@
void renderCachedSets(const OutputCompositionState& outputState,
std::optional<std::chrono::steady_clock::time_point> renderDeadline);
+ void setTexturePoolEnabled(bool enabled) { mTexturePool.setEnabled(enabled); }
+
void dump(std::string& result) const;
void dumpLayers(std::string& result) const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index be34153..76d5e81 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -64,6 +64,8 @@
void renderCachedSets(const OutputCompositionState& outputState,
std::optional<std::chrono::steady_clock::time_point> renderDeadline);
+ void setTexturePoolEnabled(bool enabled) { mFlattener.setTexturePoolEnabled(enabled); }
+
void dump(const Vector<String16>& args, std::string&);
private:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
index fb53ee0..d607c75 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
@@ -63,7 +63,8 @@
sp<Fence> mFence;
};
- TexturePool(renderengine::RenderEngine& renderEngine) : mRenderEngine(renderEngine) {}
+ TexturePool(renderengine::RenderEngine& renderEngine)
+ : mRenderEngine(renderEngine), mEnabled(false) {}
virtual ~TexturePool() = default;
@@ -78,6 +79,12 @@
// to the pool.
std::shared_ptr<AutoTexture> borrowTexture();
+ // Enables or disables the pool. When the pool is disabled, no buffers will
+ // be held by the pool. This is useful when the active display changes.
+ void setEnabled(bool enable);
+
+ void dump(std::string& out) const;
+
protected:
// Proteted visibility so that they can be used for testing
const static constexpr size_t kMinPoolSize = 3;
@@ -95,8 +102,10 @@
// Returns a previously borrowed texture to the pool.
void returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture,
const sp<Fence>& fence);
+ void allocatePool();
renderengine::RenderEngine& mRenderEngine;
ui::Size mSize;
+ bool mEnabled;
};
} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 60ff4b1..216019f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -37,6 +37,7 @@
MOCK_METHOD1(setCompositionEnabled, void(bool));
MOCK_METHOD1(setLayerCachingEnabled, void(bool));
+ MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool));
MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 3c3c7f3..6ac488b 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -146,6 +146,12 @@
}
}
+void Output::setLayerCachingTexturePoolEnabled(bool enabled) {
+ if (mPlanner) {
+ mPlanner->setTexturePoolEnabled(enabled);
+ }
+}
+
void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) {
auto& outputState = editState();
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index b82bdbc..ccacdfb 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -174,7 +174,7 @@
LayerFE::ClientCompositionTargetSettings targetSettings{
.clip = Region(viewport),
.needsFiltering = false,
- .isSecure = true,
+ .isSecure = outputState.isSecure,
.supportsProtectedContent = false,
.viewport = viewport,
.dataspace = outputDataspace,
@@ -216,6 +216,7 @@
}
renderengine::LayerSettings holePunchSettings;
+ renderengine::LayerSettings holePunchBackgroundSettings;
if (mHolePunchLayer) {
auto clientCompositionList =
mHolePunchLayer->getOutputLayer()->getLayerFE().prepareClientCompositionList(
@@ -230,6 +231,15 @@
holePunchSettings.alpha = 0.0f;
holePunchSettings.name = std::string("hole punch layer");
layerSettingsPointers.push_back(&holePunchSettings);
+
+ // Add a solid background as the first layer in case there is no opaque
+ // buffer behind the punch hole
+ holePunchBackgroundSettings.alpha = 1.0f;
+ holePunchBackgroundSettings.name = std::string("holePunchBackground");
+ holePunchBackgroundSettings.geometry.boundaries = holePunchSettings.geometry.boundaries;
+ holePunchBackgroundSettings.geometry.positionTransform =
+ holePunchSettings.geometry.positionTransform;
+ layerSettingsPointers.insert(layerSettingsPointers.begin(), &holePunchBackgroundSettings);
}
if (sDebugHighlighLayers) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index f033279..8e2c182 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -205,6 +205,9 @@
durationString(lastUpdate).c_str());
dumpLayers(result);
+
+ base::StringAppendF(&result, "\n");
+ mTexturePool.dump(result);
}
size_t Flattener::calculateDisplayCost(const std::vector<const LayerState*>& layers) const {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
index e3772a2..497c433 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
@@ -24,14 +24,22 @@
namespace android::compositionengine::impl::planner {
+void TexturePool::allocatePool() {
+ mPool.clear();
+ if (mEnabled && mSize.isValid()) {
+ mPool.resize(kMinPoolSize);
+ std::generate_n(mPool.begin(), kMinPoolSize, [&]() {
+ return Entry{genTexture(), nullptr};
+ });
+ }
+}
+
void TexturePool::setDisplaySize(ui::Size size) {
if (mSize == size) {
return;
}
mSize = size;
- mPool.clear();
- mPool.resize(kMinPoolSize);
- std::generate_n(mPool.begin(), kMinPoolSize, [&]() { return Entry{genTexture(), nullptr}; });
+ allocatePool();
}
std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() {
@@ -46,7 +54,12 @@
void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture,
const sp<Fence>& fence) {
- // Drop the texture on the floor if the pool is no longer tracking textures of the same size.
+ // Drop the texture on the floor if the pool is not enabled
+ if (!mEnabled) {
+ return;
+ }
+
+ // Or the texture on the floor if the pool is no longer tracking textures of the same size.
if (static_cast<int32_t>(texture->getBuffer()->getWidth()) != mSize.getWidth() ||
static_cast<int32_t>(texture->getBuffer()->getHeight()) != mSize.getHeight()) {
ALOGV("Deallocating texture from Planner's pool - display size changed (previous: (%dx%d), "
@@ -81,4 +94,15 @@
renderengine::ExternalTexture::Usage::WRITEABLE);
}
+void TexturePool::setEnabled(bool enabled) {
+ mEnabled = enabled;
+ allocatePool();
+}
+
+void TexturePool::dump(std::string& out) const {
+ base::StringAppendF(&out,
+ "TexturePool (%s) has %zu buffers of size [%" PRId32 ", %" PRId32 "]\n",
+ mEnabled ? "enabled" : "disabled", mPool.size(), mSize.width, mSize.height);
+}
+
} // namespace android::compositionengine::impl::planner
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 65c97b7..224dad1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -47,9 +47,7 @@
MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t());
MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t());
- MOCK_METHOD4(allocateVirtualDisplay,
- bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*,
- std::optional<PhysicalDisplayId>));
+ MOCK_METHOD3(allocateVirtualDisplay, bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*));
MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId));
MOCK_METHOD1(createLayer, std::shared_ptr<HWC2::Layer>(HalDisplayId));
@@ -113,11 +111,15 @@
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*());
- MOCK_CONST_METHOD1(getHwcDisplayId, std::optional<hal::HWDisplayId>(int32_t));
- MOCK_CONST_METHOD0(getInternalHwcDisplayId, std::optional<hal::HWDisplayId>());
- MOCK_CONST_METHOD0(getExternalHwcDisplayId, std::optional<hal::HWDisplayId>());
- MOCK_CONST_METHOD1(toPhysicalDisplayId, std::optional<PhysicalDisplayId>(hal::HWDisplayId));
- MOCK_CONST_METHOD1(fromPhysicalDisplayId, std::optional<hal::HWDisplayId>(PhysicalDisplayId));
+
+ MOCK_METHOD(hal::HWDisplayId, getPrimaryHwcDisplayId, (), (const, override));
+ MOCK_METHOD(PhysicalDisplayId, getPrimaryDisplayId, (), (const, override));
+ MOCK_METHOD(bool, isHeadless, (), (const, override));
+
+ MOCK_METHOD(std::optional<PhysicalDisplayId>, toPhysicalDisplayId, (hal::HWDisplayId),
+ (const, override));
+ MOCK_METHOD(std::optional<hal::HWDisplayId>, fromPhysicalDisplayId, (PhysicalDisplayId),
+ (const, override));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index b05a594..ec81322 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -51,6 +51,15 @@
return expectedBlurSetting == arg.blurSetting;
}
+
+MATCHER_P(ClientCompositionTargetSettingsSecureEq, expectedSecureSetting, "") {
+ *result_listener << "ClientCompositionTargetSettings' SecureSettings aren't equal \n";
+ *result_listener << "expected " << expectedSecureSetting << "\n";
+ *result_listener << "actual " << arg.isSecure << "\n";
+
+ return expectedSecureSetting == arg.isSecure;
+}
+
static const ui::Size kOutputSize = ui::Size(1, 1);
class CachedSetTest : public testing::Test {
@@ -315,7 +324,7 @@
EXPECT_EQ(0u, cachedSet.getAge());
}
-TEST_F(CachedSetTest, render) {
+TEST_F(CachedSetTest, renderUnsecureOutput) {
// Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
sp<mock::LayerFE> layerFE1 = mTestLayers[1]->layerFE;
@@ -348,9 +357,66 @@
return NO_ERROR;
};
- EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
- EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
+ EXPECT_CALL(*layerFE1,
+ prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(false)))
+ .WillOnce(Return(clientCompList1));
+ EXPECT_CALL(*layerFE2,
+ prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(false)))
+ .WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ mOutputState.isSecure = false;
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+ expectReadyBuffer(cachedSet);
+
+ EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
+ EXPECT_EQ(Rect(kOutputSize.width, kOutputSize.height), cachedSet.getTextureBounds());
+
+ // Now check that appending a new cached set properly cleans up RenderEngine resources.
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+ cachedSet.append(CachedSet(layer3));
+}
+
+TEST_F(CachedSetTest, renderSecureOutput) {
+ // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
+ CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE1 = mTestLayers[1]->layerFE;
+ CachedSet::Layer& layer2 = *mTestLayers[2]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE2 = mTestLayers[2]->layerFE;
+
+ CachedSet cachedSet(layer1);
+ cachedSet.append(CachedSet(layer2));
+
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1;
+ clientCompList1.push_back({});
+ clientCompList1[0].alpha = 0.5f;
+
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2;
+ clientCompList2.push_back({});
+ clientCompList2[0].alpha = 0.75f;
+
+ const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&, base::unique_fd*) -> size_t {
+ EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
+ EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
+ EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
+ displaySettings.orientation);
+ EXPECT_EQ(0.5f, layers[0]->alpha);
+ EXPECT_EQ(0.75f, layers[1]->alpha);
+ EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
+
+ return NO_ERROR;
+ };
+
+ EXPECT_CALL(*layerFE1,
+ prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(true)))
+ .WillOnce(Return(clientCompList1));
+ EXPECT_CALL(*layerFE2,
+ prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(true)))
+ .WillOnce(Return(clientCompList2));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ mOutputState.isSecure = true;
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
@@ -590,12 +656,22 @@
base::unique_fd&&, base::unique_fd*) -> size_t {
// If the highlight layer is enabled, it will increase the size by 1.
// We're interested in the third layer either way.
- EXPECT_GE(layers.size(), 3u);
- const auto* holePunchSettings = layers[2];
- EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
- EXPECT_TRUE(holePunchSettings->disableBlending);
- EXPECT_EQ(0.0f, holePunchSettings->alpha);
+ EXPECT_GE(layers.size(), 4u);
+ {
+ const auto* holePunchSettings = layers[3];
+ EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
+ EXPECT_TRUE(holePunchSettings->disableBlending);
+ EXPECT_EQ(0.0f, holePunchSettings->alpha);
+ }
+
+ {
+ const auto* holePunchBackgroundSettings = layers[0];
+ EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor);
+ EXPECT_FALSE(holePunchBackgroundSettings->disableBlending);
+ EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
+ }
return NO_ERROR;
};
@@ -640,12 +716,23 @@
base::unique_fd&&, base::unique_fd*) -> size_t {
// If the highlight layer is enabled, it will increase the size by 1.
// We're interested in the third layer either way.
- EXPECT_GE(layers.size(), 3u);
- const auto* holePunchSettings = layers[2];
- EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
- EXPECT_TRUE(holePunchSettings->disableBlending);
- EXPECT_EQ(0.0f, holePunchSettings->alpha);
+ EXPECT_GE(layers.size(), 4u);
+
+ {
+ const auto* holePunchSettings = layers[3];
+ EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
+ EXPECT_TRUE(holePunchSettings->disableBlending);
+ EXPECT_EQ(0.0f, holePunchSettings->alpha);
+ }
+
+ {
+ const auto* holePunchBackgroundSettings = layers[0];
+ EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor);
+ EXPECT_FALSE(holePunchBackgroundSettings->disableBlending);
+ EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
+ }
return NO_ERROR;
};
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
index b802e51..6fc90fe 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
@@ -42,6 +42,7 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ mTexturePool.setEnabled(true);
mTexturePool.setDisplaySize(kDisplaySize);
}
@@ -130,5 +131,44 @@
static_cast<int32_t>(texture->get()->getBuffer()->getHeight()));
}
+TEST_F(TexturePoolTest, freesBuffersWhenDisabled) {
+ EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
+
+ std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures;
+ for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) {
+ textures.emplace_back(mTexturePool.borrowTexture());
+ }
+
+ EXPECT_EQ(mTexturePool.getPoolSize(), 1u);
+ mTexturePool.setEnabled(false);
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+
+ textures.clear();
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+}
+
+TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) {
+ EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
+ mTexturePool.setEnabled(false);
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+
+ std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures;
+ for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) {
+ textures.emplace_back(mTexturePool.borrowTexture());
+ }
+
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+ textures.clear();
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+}
+
+TEST_F(TexturePoolTest, reallocatesWhenReEnabled) {
+ EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
+ mTexturePool.setEnabled(false);
+ EXPECT_EQ(mTexturePool.getPoolSize(), 0u);
+ mTexturePool.setEnabled(true);
+ EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize());
+}
+
} // namespace
} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index afd12b5..7db87d9 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -273,7 +273,7 @@
std::atomic<nsecs_t> mLastHwVsync = 0;
- // TODO(b/74619554): Remove special cases for primary display.
+ // TODO(b/182939859): Remove special cases for primary display.
const bool mIsPrimary;
uint32_t mFlags = 0;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index caf0294..09734c2 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -212,7 +212,7 @@
}
Error Composer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
- std::optional<Display>, Display* outDisplay) {
+ Display* outDisplay) {
const uint32_t bufferSlotCount = 1;
Error error = kDefaultError;
if (mClient_2_2) {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index b525e63..fe114b9 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -96,7 +96,7 @@
virtual uint32_t getMaxVirtualDisplayCount() = 0;
virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat*,
- std::optional<Display> mirror, Display* outDisplay) = 0;
+ Display* outDisplay) = 0;
virtual Error destroyVirtualDisplay(Display display) = 0;
virtual Error acceptDisplayChanges(Display display) = 0;
@@ -342,7 +342,7 @@
uint32_t getMaxVirtualDisplayCount() override;
Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
- std::optional<Display> mirror, Display* outDisplay) override;
+ Display* outDisplay) override;
Error destroyVirtualDisplay(Display display) override;
Error acceptDisplayChanges(Display display) override;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index 98209bb..83c2b2e 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -25,6 +25,7 @@
#include <log/log.h>
#include "DisplayIdentification.h"
+#include "Hash.h"
namespace android {
namespace {
@@ -262,8 +263,9 @@
}
// Hash model string instead of using product code or (integer) serial number, since the latter
- // have been observed to change on some displays with multiple inputs.
- const auto modelHash = static_cast<uint32_t>(std::hash<std::string_view>()(modelString));
+ // have been observed to change on some displays with multiple inputs. Use a stable hash instead
+ // of std::hash which is only required to be same within a single execution of a program.
+ const uint32_t modelHash = static_cast<uint32_t>(cityHash64Len0To16(modelString));
// Parse extension blocks.
std::optional<Cea861ExtensionBlock> cea861Block;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 7e45dab..256bca9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -212,8 +212,6 @@
RETURN_IF_INVALID_DISPLAY(*displayId, false);
auto& displayData = mDisplayData[*displayId];
- LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s",
- __FUNCTION__, to_string(*displayId).c_str());
{
// There have been reports of HWCs that signal several vsync events
@@ -245,8 +243,7 @@
}
bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size resolution,
- ui::PixelFormat* format,
- std::optional<PhysicalDisplayId> mirror) {
+ ui::PixelFormat* format) {
if (!resolution.isValid()) {
ALOGE("%s: Invalid resolution %dx%d", __func__, resolution.width, resolution.height);
return false;
@@ -262,14 +259,9 @@
return false;
}
- std::optional<hal::HWDisplayId> hwcMirrorId;
- if (mirror) {
- hwcMirrorId = fromPhysicalDisplayId(*mirror);
- }
-
hal::HWDisplayId hwcDisplayId;
const auto error = static_cast<hal::Error>(
- mComposer->createVirtualDisplay(width, height, format, hwcMirrorId, &hwcDisplayId));
+ mComposer->createVirtualDisplay(width, height, format, &hwcDisplayId));
RETURN_IF_HWC_ERROR_FOR("createVirtualDisplay", error, displayId, false);
auto display = std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities,
@@ -277,7 +269,6 @@
display->setConnected(true);
auto& displayData = mDisplayData[displayId];
displayData.hwcDisplay = std::move(display);
- displayData.isVirtual = true;
return true;
}
@@ -285,10 +276,8 @@
PhysicalDisplayId displayId) {
mPhysicalDisplayIdMap[hwcDisplayId] = displayId;
- if (!mInternalHwcDisplayId) {
- mInternalHwcDisplayId = hwcDisplayId;
- } else if (mInternalHwcDisplayId != hwcDisplayId && !mExternalHwcDisplayId) {
- mExternalHwcDisplayId = hwcDisplayId;
+ if (!mPrimaryHwcDisplayId) {
+ mPrimaryHwcDisplayId = hwcDisplayId;
}
auto& displayData = mDisplayData[displayId];
@@ -378,7 +367,7 @@
ui::DisplayConnectionType type;
const auto error = hwcDisplay->getConnectionType(&type);
- const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId
+ const auto FALLBACK_TYPE = hwcDisplay->getId() == mPrimaryHwcDisplayId
? ui::DisplayConnectionType::Internal
: ui::DisplayConnectionType::External;
@@ -434,9 +423,6 @@
RETURN_IF_INVALID_DISPLAY(displayId);
auto& displayData = mDisplayData[displayId];
- LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s",
- __FUNCTION__, to_string(displayId).c_str());
-
// NOTE: we use our own internal lock here because we have to call
// into the HWC with the lock held, and we want to make sure
// that even if HWC blocks (which it shouldn't), it won't
@@ -603,14 +589,11 @@
status_t HWComposer::setPowerMode(PhysicalDisplayId displayId, hal::PowerMode mode) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- const auto& displayData = mDisplayData[displayId];
- LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s",
- __FUNCTION__, to_string(displayId).c_str());
-
if (mode == hal::PowerMode::OFF) {
setVsyncEnabled(displayId, hal::Vsync::DISABLE);
}
+ const auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
switch (mode) {
case hal::PowerMode::OFF:
@@ -684,12 +667,6 @@
auto& displayData = mDisplayData[displayId];
const auto hwcDisplayId = displayData.hwcDisplay->getId();
- // TODO(b/74619554): Select internal/external display from remaining displays.
- if (hwcDisplayId == mInternalHwcDisplayId) {
- mInternalHwcDisplayId.reset();
- } else if (hwcDisplayId == mExternalHwcDisplayId) {
- mExternalHwcDisplayId.reset();
- }
mPhysicalDisplayIdMap.erase(hwcDisplayId);
mDisplayData.erase(displayId);
}
@@ -699,9 +676,6 @@
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto& displayData = mDisplayData[displayId];
- LOG_FATAL_IF(!displayData.isVirtual, "%s: Invalid operation on physical display with ID %s",
- __FUNCTION__, to_string(displayId).c_str());
-
auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence);
RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
return NO_ERROR;
@@ -859,8 +833,7 @@
std::optional<hal::HWDisplayId> HWComposer::fromPhysicalDisplayId(
PhysicalDisplayId displayId) const {
- if (const auto it = mDisplayData.find(displayId);
- it != mDisplayData.end() && !it->second.isVirtual) {
+ if (const auto it = mDisplayData.find(displayId); it != mDisplayData.end()) {
return it->second.hwcDisplay->getId();
}
return {};
@@ -874,7 +847,8 @@
return true;
}
- if (!mHasMultiDisplaySupport && mInternalHwcDisplayId && mExternalHwcDisplayId) {
+ // Legacy mode only supports IDs LEGACY_DISPLAY_TYPE_PRIMARY and LEGACY_DISPLAY_TYPE_EXTERNAL.
+ if (!mHasMultiDisplaySupport && mPhysicalDisplayIdMap.size() == 2) {
ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId);
return true;
}
@@ -915,7 +889,7 @@
}
info = [this, hwcDisplayId, &port, &data, hasDisplayIdentificationData] {
- const bool isPrimary = !mInternalHwcDisplayId;
+ const bool isPrimary = !mPrimaryHwcDisplayId;
if (mHasMultiDisplaySupport) {
if (const auto info = parseDisplayIdentificationData(port, data)) {
return *info;
@@ -928,8 +902,8 @@
}
return DisplayIdentificationInfo{.id = PhysicalDisplayId::fromPort(port),
- .name = isPrimary ? "Internal display"
- : "External display",
+ .name = isPrimary ? "Primary display"
+ : "Secondary display",
.deviceProductInfo = std::nullopt};
}();
}
@@ -942,9 +916,12 @@
std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect(
hal::HWDisplayId hwcDisplayId) {
+ LOG_ALWAYS_FATAL_IF(hwcDisplayId == mPrimaryHwcDisplayId,
+ "Primary display cannot be disconnected.");
+
const auto displayId = toPhysicalDisplayId(hwcDisplayId);
if (!displayId) {
- ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display");
return {};
}
@@ -953,7 +930,7 @@
if (isConnected(*displayId)) {
mDisplayData[*displayId].hwcDisplay->setConnected(false);
} else {
- ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId);
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Already disconnected");
}
// The cleanup of Disconnect is handled through HWComposer::disconnectDisplay
// via SurfaceFlinger's onHotplugReceived callback handling
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index b1849e8..0a090da 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_SF_HWCOMPOSER_H
-#define ANDROID_SF_HWCOMPOSER_H
+#pragma once
#include <cstdint>
#include <future>
@@ -113,11 +112,7 @@
// Attempts to allocate a virtual display on the HWC. The maximum number of virtual displays
// supported by the HWC can be queried in advance, but allocation may fail for other reasons.
- // For virtualized compositors, the PhysicalDisplayId is a hint that this virtual display is
- // a mirror of a physical display, and that the screen should be captured by the host rather
- // than guest compositor.
- virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*,
- std::optional<PhysicalDisplayId> mirror) = 0;
+ virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) = 0;
virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) = 0;
@@ -232,14 +227,18 @@
virtual const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata()
const = 0;
- // for debugging ----------------------------------------------------------
virtual void dump(std::string& out) const = 0;
virtual Hwc2::Composer* getComposer() const = 0;
- // TODO(b/74619554): Remove special cases for internal/external display.
- virtual std::optional<hal::HWDisplayId> getInternalHwcDisplayId() const = 0;
- virtual std::optional<hal::HWDisplayId> getExternalHwcDisplayId() const = 0;
+ // Returns the first display connected at boot. It cannot be disconnected, which implies an
+ // internal connection type. Its connection via HWComposer::onHotplug, which in practice is
+ // immediately after HWComposer construction, must occur before any call to this function.
+ //
+ // TODO(b/182939859): Remove special cases for primary display.
+ virtual hal::HWDisplayId getPrimaryHwcDisplayId() const = 0;
+ virtual PhysicalDisplayId getPrimaryDisplayId() const = 0;
+ virtual bool isHeadless() const = 0;
virtual std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const = 0;
virtual std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const = 0;
@@ -265,8 +264,7 @@
size_t getMaxVirtualDisplayCount() const override;
size_t getMaxVirtualDisplayDimension() const override;
- bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*,
- std::optional<PhysicalDisplayId>) override;
+ bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) override;
// Called from SurfaceFlinger, when the state for a new physical display needs to be recreated.
void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) override;
@@ -371,14 +369,19 @@
Hwc2::Composer* getComposer() const override { return mComposer.get(); }
- // TODO(b/74619554): Remove special cases for internal/external display.
- std::optional<hal::HWDisplayId> getInternalHwcDisplayId() const override {
- return mInternalHwcDisplayId;
+ hal::HWDisplayId getPrimaryHwcDisplayId() const override {
+ LOG_ALWAYS_FATAL_IF(!mPrimaryHwcDisplayId, "Missing HWC primary display");
+ return *mPrimaryHwcDisplayId;
}
- std::optional<hal::HWDisplayId> getExternalHwcDisplayId() const override {
- return mExternalHwcDisplayId;
+
+ PhysicalDisplayId getPrimaryDisplayId() const override {
+ const auto id = toPhysicalDisplayId(getPrimaryHwcDisplayId());
+ LOG_ALWAYS_FATAL_IF(!id, "Missing primary display");
+ return *id;
}
+ virtual bool isHeadless() const override { return !mPrimaryHwcDisplayId; }
+
std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const override;
std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const override;
@@ -387,12 +390,9 @@
friend TestableSurfaceFlinger;
struct DisplayData {
- bool isVirtual = false;
std::unique_ptr<HWC2::Display> hwcDisplay;
sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
- buffer_handle_t outbufHandle = nullptr;
- sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
bool validateWasSkipped;
hal::Error presentError;
@@ -423,8 +423,7 @@
bool mRegisteredCallback = false;
std::unordered_map<hal::HWDisplayId, PhysicalDisplayId> mPhysicalDisplayIdMap;
- std::optional<hal::HWDisplayId> mInternalHwcDisplayId;
- std::optional<hal::HWDisplayId> mExternalHwcDisplayId;
+ std::optional<hal::HWDisplayId> mPrimaryHwcDisplayId;
bool mHasMultiDisplaySupport = false;
const size_t mMaxVirtualDisplayDimension;
@@ -433,5 +432,3 @@
} // namespace impl
} // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/DisplayHardware/Hash.cpp b/services/surfaceflinger/DisplayHardware/Hash.cpp
new file mode 100644
index 0000000..6056c8d
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/Hash.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "DisplayIdentification"
+
+#include <cstring>
+#include <type_traits>
+
+#include <log/log.h>
+
+#include "Hash.h"
+
+namespace android {
+namespace {
+
+template <class T>
+inline T load(const void* p) {
+ static_assert(std::is_integral<T>::value, "T must be integral");
+
+ T r;
+ std::memcpy(&r, p, sizeof(r));
+ return r;
+}
+
+uint64_t rotateByAtLeast1(uint64_t val, uint8_t shift) {
+ return (val >> shift) | (val << (64 - shift));
+}
+
+uint64_t shiftMix(uint64_t val) {
+ return val ^ (val >> 47);
+}
+
+uint64_t hash64Len16(uint64_t u, uint64_t v) {
+ constexpr uint64_t kMul = 0x9ddfea08eb382d69;
+ uint64_t a = (u ^ v) * kMul;
+ a ^= (a >> 47);
+ uint64_t b = (v ^ a) * kMul;
+ b ^= (b >> 47);
+ b *= kMul;
+ return b;
+}
+
+uint64_t hash64Len0To16(const char* s, uint64_t len) {
+ constexpr uint64_t k2 = 0x9ae16a3b2f90404f;
+ constexpr uint64_t k3 = 0xc949d7c7509e6557;
+
+ if (len > 8) {
+ const uint64_t a = load<uint64_t>(s);
+ const uint64_t b = load<uint64_t>(s + len - 8);
+ return hash64Len16(a, rotateByAtLeast1(b + len, static_cast<uint8_t>(len))) ^ b;
+ }
+ if (len >= 4) {
+ const uint32_t a = load<uint32_t>(s);
+ const uint32_t b = load<uint32_t>(s + len - 4);
+ return hash64Len16(len + (a << 3), b);
+ }
+ if (len > 0) {
+ const unsigned char a = static_cast<unsigned char>(s[0]);
+ const unsigned char b = static_cast<unsigned char>(s[len >> 1]);
+ const unsigned char c = static_cast<unsigned char>(s[len - 1]);
+ const uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
+ const uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
+ return shiftMix(y * k2 ^ z * k3) * k2;
+ }
+ return k2;
+}
+
+} // namespace
+
+uint64_t cityHash64Len0To16(std::string_view sv) {
+ auto len = sv.length();
+ if (len > 16) {
+ ALOGE("%s called with length %zu. Only hashing the first 16 chars", __FUNCTION__, len);
+ len = 16;
+ }
+ return hash64Len0To16(sv.data(), len);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayHardware/Hash.h b/services/surfaceflinger/DisplayHardware/Hash.h
new file mode 100644
index 0000000..a7b6c71
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/Hash.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <string_view>
+
+namespace android {
+
+// CityHash64 implementation that only hashes at most the first 16 characters of the given string.
+uint64_t cityHash64Len0To16(std::string_view sv);
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 93c86d1..87b0dbc 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -819,11 +819,7 @@
}
bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
- sp<Handle> handle = static_cast<Handle*>(relativeToHandle.get());
- if (handle == nullptr) {
- return false;
- }
- sp<Layer> relative = handle->owner.promote();
+ sp<Layer> relative = fromHandle(relativeToHandle).promote();
if (relative == nullptr) {
return false;
}
@@ -851,6 +847,23 @@
return true;
}
+bool Layer::setTrustedOverlay(bool isTrustedOverlay) {
+ if (mDrawingState.isTrustedOverlay == isTrustedOverlay) return false;
+ mDrawingState.isTrustedOverlay = isTrustedOverlay;
+ mDrawingState.modified = true;
+ mFlinger->mInputInfoChanged = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::isTrustedOverlay() const {
+ if (getDrawingState().isTrustedOverlay) {
+ return true;
+ }
+ const auto& p = mDrawingParent.promote();
+ return (p != nullptr) && p->isTrustedOverlay();
+}
+
bool Layer::setSize(uint32_t w, uint32_t h) {
if (mDrawingState.requested_legacy.w == w && mDrawingState.requested_legacy.h == h)
return false;
@@ -958,7 +971,6 @@
}
bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) {
- mDrawingState.sequence++;
mDrawingState.blurRegions = blurRegions;
mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -1101,46 +1113,59 @@
return StretchEffect{};
}
+bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) {
+ // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate
+ const auto frameRate = [&] {
+ if (mDrawingState.frameRate.rate.isValid() ||
+ mDrawingState.frameRate.type == FrameRateCompatibility::NoVote) {
+ return mDrawingState.frameRate;
+ }
+
+ return parentFrameRate;
+ }();
+
+ *transactionNeeded |= setFrameRateForLayerTree(frameRate);
+
+ // The frame rate is propagated to the children
+ bool childrenHaveFrameRate = false;
+ for (const sp<Layer>& child : mCurrentChildren) {
+ childrenHaveFrameRate |=
+ child->propagateFrameRateForLayerTree(frameRate, transactionNeeded);
+ }
+
+ // If we don't have a valid frame rate, but the children do, we set this
+ // layer as NoVote to allow the children to control the refresh rate
+ if (!frameRate.rate.isValid() && frameRate.type != FrameRateCompatibility::NoVote &&
+ childrenHaveFrameRate) {
+ *transactionNeeded |=
+ setFrameRateForLayerTree(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote));
+ }
+
+ // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for
+ // the same reason we are allowing touch boost for those layers. See
+ // RefreshRateConfigs::getBestRefreshRate for more details.
+ const auto layerVotedWithDefaultCompatibility =
+ frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default;
+ const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote;
+ const auto layerVotedWithExactCompatibility =
+ frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Exact;
+ return layerVotedWithDefaultCompatibility || layerVotedWithNoVote ||
+ layerVotedWithExactCompatibility || childrenHaveFrameRate;
+}
+
void Layer::updateTreeHasFrameRateVote() {
- const auto traverseTree = [&](const LayerVector::Visitor& visitor) {
- auto parent = getParent();
- while (parent) {
- visitor(parent.get());
- parent = parent->getParent();
+ const auto root = [&]() -> sp<Layer> {
+ sp<Layer> layer = this;
+ while (auto parent = layer->getParent()) {
+ layer = parent;
}
+ return layer;
+ }();
- traverse(LayerVector::StateSet::Current, visitor);
- };
-
- // update parents and children about the vote
- // First traverse the tree and count how many layers has votes.
- int layersWithVote = 0;
- traverseTree([&layersWithVote](Layer* layer) {
- const auto layerVotedWithDefaultCompatibility =
- layer->mDrawingState.frameRate.rate.isValid() &&
- layer->mDrawingState.frameRate.type == FrameRateCompatibility::Default;
- const auto layerVotedWithNoVote =
- layer->mDrawingState.frameRate.type == FrameRateCompatibility::NoVote;
- const auto layerVotedWithExactCompatibility =
- layer->mDrawingState.frameRate.type == FrameRateCompatibility::Exact;
-
- // We do not count layers that are ExactOrMultiple for the same reason
- // we are allowing touch boost for those layers. See
- // RefreshRateConfigs::getBestRefreshRate for more details.
- if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote ||
- layerVotedWithExactCompatibility) {
- layersWithVote++;
- }
- });
-
- // Now we can update the tree frame rate vote for each layer in the tree
- const bool treeHasFrameRateVote = layersWithVote > 0;
bool transactionNeeded = false;
+ root->propagateFrameRateForLayerTree({}, &transactionNeeded);
- traverseTree([treeHasFrameRateVote, &transactionNeeded](Layer* layer) {
- transactionNeeded = layer->updateFrameRateForLayerTree(treeHasFrameRateVote);
- });
-
+ // TODO(b/195668952): we probably don't need eTraversalNeeded here
if (transactionNeeded) {
mFlinger->setTransactionFlags(eTraversalNeeded);
}
@@ -1267,42 +1292,23 @@
return surfaceFrame;
}
-bool Layer::updateFrameRateForLayerTree(bool treeHasFrameRateVote) {
- const auto updateDrawingState = [&](FrameRate frameRate) {
- if (mDrawingState.frameRateForLayerTree == frameRate) {
- return false;
- }
-
- mDrawingState.frameRateForLayerTree = frameRate;
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- mFlinger->mScheduler->recordLayerHistory(this, systemTime(),
- LayerHistory::LayerUpdateType::SetFrameRate);
-
- return true;
- };
-
- const auto frameRate = mDrawingState.frameRate;
- if (frameRate.rate.isValid() || frameRate.type == FrameRateCompatibility::NoVote) {
- return updateDrawingState(frameRate);
+bool Layer::setFrameRateForLayerTree(FrameRate frameRate) {
+ if (mDrawingState.frameRateForLayerTree == frameRate) {
+ return false;
}
- // This layer doesn't have a frame rate. Check if its ancestors have a vote
- for (sp<Layer> parent = getParent(); parent; parent = parent->getParent()) {
- if (parent->mDrawingState.frameRate.rate.isValid()) {
- return updateDrawingState(parent->mDrawingState.frameRate);
- }
- }
+ mDrawingState.frameRateForLayerTree = frameRate;
- // This layer and its ancestors don't have a frame rate. If one of successors
- // has a vote, return a NoVote for successors to set the vote
- if (treeHasFrameRateVote) {
- return updateDrawingState(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote));
- }
+ // TODO(b/195668952): we probably don't need to dirty visible regions here
+ // or even store frameRateForLayerTree in mDrawingState
+ mDrawingState.sequence++;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
- return updateDrawingState(frameRate);
+ mFlinger->mScheduler->recordLayerHistory(this, systemTime(),
+ LayerHistory::LayerUpdateType::SetFrameRate);
+
+ return true;
}
Layer::FrameRate Layer::getFrameRateForLayerTree() const {
@@ -1599,8 +1605,7 @@
bool Layer::reparent(const sp<IBinder>& newParentHandle) {
sp<Layer> newParent;
if (newParentHandle != nullptr) {
- auto handle = static_cast<Handle*>(newParentHandle.get());
- newParent = handle->owner.promote();
+ newParent = fromHandle(newParentHandle).promote();
if (newParent == nullptr) {
ALOGE("Unable to promote Layer handle");
return false;
@@ -1975,24 +1980,10 @@
mDrawingParent = mCurrentParent;
}
-static wp<Layer> extractLayerFromBinder(const wp<IBinder>& weakBinderHandle) {
- if (weakBinderHandle == nullptr) {
- return nullptr;
- }
- sp<IBinder> binderHandle = weakBinderHandle.promote();
- if (binderHandle == nullptr) {
- return nullptr;
- }
- sp<Layer::Handle> handle = static_cast<Layer::Handle*>(binderHandle.get());
- if (handle == nullptr) {
- return nullptr;
- }
- return handle->owner;
-}
void Layer::setInputInfo(const WindowInfo& info) {
mDrawingState.inputInfo = info;
- mDrawingState.touchableRegionCrop = extractLayerFromBinder(info.touchableRegionCropHandle);
+ mDrawingState.touchableRegionCrop = fromHandle(info.touchableRegionCropHandle.promote());
mDrawingState.modified = true;
mFlinger->mInputInfoChanged = true;
setTransactionFlags(eTransactionNeeded);
@@ -2042,6 +2033,7 @@
layerInfo->set_corner_radius(getRoundedCornerState().radius);
layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
+ layerInfo->set_is_trusted_overlay(isTrustedOverlay());
LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
[&]() { return layerInfo->mutable_position(); });
@@ -2332,6 +2324,11 @@
toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
}
+ // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
+ // if it was set by WM for a known system overlay
+ info.trustedOverlay = info.trustedOverlay || isTrustedOverlay();
+
+
// If the layer is a clone, we need to crop the input region to cloned root to prevent
// touches from going outside the cloned area.
if (isClone()) {
@@ -2549,6 +2546,23 @@
mFlinger->mNumClones++;
}
+const String16 Layer::Handle::kDescriptor = String16("android.Layer.Handle");
+
+wp<Layer> Layer::fromHandle(const sp<IBinder>& handleBinder) {
+ if (handleBinder == nullptr) {
+ return nullptr;
+ }
+
+ BBinder* b = handleBinder->localBinder();
+ if (b == nullptr || b->getInterfaceDescriptor() != Handle::kDescriptor) {
+ return nullptr;
+ }
+
+ // We can safely cast this binder since its local and we verified its interface descriptor.
+ sp<Handle> handle = static_cast<Handle*>(handleBinder.get());
+ return handle->owner;
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3aaa680..41bdebd 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -275,6 +275,9 @@
// Stretch effect to apply to this layer
StretchEffect stretchEffect;
+ // Whether or not this layer is a trusted overlay for input
+ bool isTrustedOverlay;
+
Rect bufferCrop;
Rect destinationFrame;
};
@@ -286,16 +289,17 @@
class LayerCleaner {
sp<SurfaceFlinger> mFlinger;
sp<Layer> mLayer;
+ BBinder* mHandle;
protected:
~LayerCleaner() {
// destroy client resources
- mFlinger->onHandleDestroyed(mLayer);
+ mFlinger->onHandleDestroyed(mHandle, mLayer);
}
public:
- LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
- : mFlinger(flinger), mLayer(layer) {}
+ LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer, BBinder* handle)
+ : mFlinger(flinger), mLayer(layer), mHandle(handle) {}
};
/*
@@ -309,11 +313,15 @@
class Handle : public BBinder, public LayerCleaner {
public:
Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
- : LayerCleaner(flinger, layer), owner(layer) {}
+ : LayerCleaner(flinger, layer, this), owner(layer) {}
+ const String16& getInterfaceDescriptor() const override { return kDescriptor; }
+ static const String16 kDescriptor;
wp<Layer> owner;
};
+ static wp<Layer> fromHandle(const sp<IBinder>& handle);
+
explicit Layer(const LayerCreationArgs& args);
virtual ~Layer();
@@ -393,6 +401,7 @@
virtual bool setBackgroundBlurRadius(int backgroundBlurRadius);
virtual bool setBlurRegions(const std::vector<BlurRegion>& effectRegions);
virtual bool setTransparentRegionHint(const Region& transparent);
+ virtual bool setTrustedOverlay(bool);
virtual bool setFlags(uint32_t flags, uint32_t mask);
virtual bool setLayerStack(uint32_t layerStack);
virtual uint32_t getLayerStack() const;
@@ -699,12 +708,6 @@
virtual uint32_t doTransaction(uint32_t transactionFlags);
/*
- * Called before updating the drawing state buffer. Used by BufferStateLayer to release any
- * unlatched buffers in the drawing state.
- */
- virtual void bufferMayChange(const sp<GraphicBuffer>& /* newBuffer */){};
-
- /*
* Remove relative z for the layer if its relative parent is not part of the
* provided layer tree.
*/
@@ -1049,7 +1052,10 @@
const std::vector<Layer*>& layersInTree);
void updateTreeHasFrameRateVote();
+ bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded);
+ bool setFrameRateForLayerTree(FrameRate);
void setZOrderRelativeOf(const wp<Layer>& relativeOf);
+ bool isTrustedOverlay() const;
// Find the root of the cloned hierarchy, this means the first non cloned parent.
// This will return null if first non cloned parent is not found.
@@ -1066,8 +1072,6 @@
// Fills in the frame and transform info for the gui::WindowInfo
void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& toPhysicalDisplay);
- bool updateFrameRateForLayerTree(bool treeHasFrameRateVote);
-
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
// a transform from the current layer coordinate space to display(screen) coordinate space.
diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp
index 9a6c853..5fea521 100644
--- a/services/surfaceflinger/RenderArea.cpp
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#include "RenderArea.h"
namespace android {
@@ -33,6 +29,3 @@
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 28be962..b805bf6 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -84,10 +84,13 @@
VSyncTracker& tracker, nsecs_t now) {
auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
+ auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
bool const wouldSkipAVsyncTarget =
mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
- if (wouldSkipAVsyncTarget) {
+ bool const wouldSkipAWakeup =
+ mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
+ if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
return getExpectedCallbackTime(nextVsyncTime, timing);
}
@@ -97,9 +100,9 @@
if (alreadyDispatchedForVsync) {
nextVsyncTime =
tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
+ nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
}
- auto const nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
mScheduleTiming = timing;
mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index 194d808..245db0f 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -46,27 +46,36 @@
return updateVsyncConfigLocked();
}
-VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(
- TransactionSchedule schedule) {
+VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(TransactionSchedule schedule,
+ const sp<IBinder>& token) {
+ std::lock_guard<std::mutex> lock(mMutex);
switch (schedule) {
case Schedule::EarlyStart:
- ALOGW_IF(mEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__);
- mEarlyWakeup = true;
+ if (token) {
+ mEarlyWakeupRequests.emplace(token);
+ token->linkToDeath(this);
+ } else {
+ ALOGW("%s: EarlyStart requested without a valid token", __func__);
+ }
break;
- case Schedule::EarlyEnd:
- ALOGW_IF(!mEarlyWakeup, "%s: Unexpected EarlyEnd", __FUNCTION__);
- mEarlyWakeup = false;
+ case Schedule::EarlyEnd: {
+ if (token && mEarlyWakeupRequests.erase(token) > 0) {
+ token->unlinkToDeath(this);
+ } else {
+ ALOGW("%s: Unexpected EarlyEnd", __func__);
+ }
break;
+ }
case Schedule::Late:
// No change to mEarlyWakeup for non-explicit states.
break;
}
if (mTraceDetailedInfo) {
- ATRACE_INT("mEarlyWakeup", mEarlyWakeup);
+ ATRACE_INT("mEarlyWakeup", static_cast<int>(mEarlyWakeupRequests.size()));
}
- if (!mEarlyWakeup && schedule == Schedule::EarlyEnd) {
+ if (mEarlyWakeupRequests.empty() && schedule == Schedule::EarlyEnd) {
mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES;
mEarlyTransactionStartTime = mNow();
}
@@ -76,7 +85,7 @@
return std::nullopt;
}
mTransactionSchedule = schedule;
- return updateVsyncConfig();
+ return updateVsyncConfigLocked();
}
VsyncModulator::VsyncConfigOpt VsyncModulator::onTransactionCommit() {
@@ -128,8 +137,8 @@
const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
- if (mEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 ||
- mRefreshRateChangePending) {
+ if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd ||
+ mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
return mVsyncConfigSet.early;
} else if (mEarlyGpuFrames > 0) {
return mVsyncConfigSet.earlyGpu;
@@ -160,4 +169,11 @@
return offsets;
}
+void VsyncModulator::binderDied(const wp<IBinder>& who) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mEarlyWakeupRequests.erase(who);
+
+ static_cast<void>(updateVsyncConfigLocked());
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index 9410768..b2b0451 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -19,8 +19,10 @@
#include <chrono>
#include <mutex>
#include <optional>
+#include <unordered_set>
#include <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
#include <utils/Timers.h>
namespace android::scheduler {
@@ -35,7 +37,7 @@
};
// Modulates VSYNC phase depending on transaction schedule and refresh rate changes.
-class VsyncModulator {
+class VsyncModulator : public IBinder::DeathRecipient {
public:
// Number of frames to keep early offsets after an early transaction or GPU composition.
// This acts as a low-pass filter in case subsequent transactions are delayed, or if the
@@ -91,7 +93,8 @@
[[nodiscard]] VsyncConfig setVsyncConfigSet(const VsyncConfigSet&) EXCLUDES(mMutex);
// Changes offsets in response to transaction flags or commit.
- [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule);
+ [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule,
+ const sp<IBinder>& = {}) EXCLUDES(mMutex);
[[nodiscard]] VsyncConfigOpt onTransactionCommit();
// Called when we send a refresh rate change to hardware composer, so that
@@ -104,6 +107,10 @@
[[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);
+protected:
+ // Called from unit tests as well
+ void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);
+
private:
const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex);
[[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex);
@@ -116,8 +123,14 @@
using Schedule = TransactionSchedule;
std::atomic<Schedule> mTransactionSchedule = Schedule::Late;
- std::atomic<bool> mEarlyWakeup = false;
+ struct WpHash {
+ size_t operator()(const wp<IBinder>& p) const {
+ return std::hash<IBinder*>()(p.unsafe_get());
+ }
+ };
+
+ std::unordered_set<wp<IBinder>, WpHash> mEarlyWakeupRequests GUARDED_BY(mMutex);
std::atomic<bool> mRefreshRateChangePending = false;
std::atomic<int> mEarlyTransactionFrames = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bc6e6fd..99d9bb3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -31,7 +31,6 @@
#include <android/hardware/configstore/1.1/types.h>
#include <android/hardware/power/Boost.h>
#include <android/native_window.h>
-#include <android/os/BnSetInputWindowsListener.h>
#include <android/os/IInputFlinger.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -133,6 +132,7 @@
#include "SurfaceInterceptor.h"
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
+#include "WindowInfosListenerInvoker.h"
#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -167,6 +167,7 @@
using android::hardware::power::Boost;
using base::StringAppendF;
+using gui::IWindowInfosListener;
using gui::WindowInfo;
using ui::ColorMode;
using ui::Dataspace;
@@ -275,21 +276,6 @@
} // namespace anonymous
-struct SetInputWindowsListener : os::BnSetInputWindowsListener {
- explicit SetInputWindowsListener(std::function<void()> listenerCb) : mListenerCb(listenerCb) {}
-
- binder::Status onSetInputWindowsFinished() override;
-
- std::function<void()> mListenerCb;
-};
-
-binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
- if (mListenerCb != nullptr) {
- mListenerCb();
- }
- return binder::Status::ok();
-}
-
// ---------------------------------------------------------------------------
const String16 sHardwareTest("android.permission.HARDWARE_TEST");
@@ -355,10 +341,9 @@
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
- mPowerAdvisor(*this) {
+ mPowerAdvisor(*this),
+ mWindowInfosListenerInvoker(new WindowInfosListenerInvoker(this)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
-
- mSetInputWindowsListener = new SetInputWindowsListener([&]() { setInputWindowsFinished(); });
}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
@@ -598,19 +583,11 @@
}
}
-VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui::PixelFormat format,
- ui::LayerStack layerStack) {
+VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution,
+ ui::PixelFormat format) {
if (auto& generator = mVirtualDisplayIdGenerators.hal) {
if (const auto id = generator->generateId()) {
- std::optional<PhysicalDisplayId> mirror;
-
- if (const auto display = findDisplay([layerStack](const auto& display) {
- return !display.isVirtual() && display.getLayerStack() == layerStack;
- })) {
- mirror = display->getPhysicalId();
- }
-
- if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format, mirror)) {
+ if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format)) {
return *id;
}
@@ -641,17 +618,14 @@
}
std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const {
- const auto internalDisplayId = getInternalDisplayIdLocked();
- if (!internalDisplayId) {
- return {};
- }
-
std::vector<PhysicalDisplayId> displayIds;
displayIds.reserve(mPhysicalDisplayTokens.size());
- displayIds.push_back(*internalDisplayId);
+
+ const auto internalDisplayId = getInternalDisplayIdLocked();
+ displayIds.push_back(internalDisplayId);
for (const auto& [id, token] : mPhysicalDisplayTokens) {
- if (id != *internalDisplayId) {
+ if (id != internalDisplayId) {
displayIds.push_back(id);
}
}
@@ -798,6 +772,8 @@
? renderengine::RenderEngine::ContextPriority::REALTIME
: renderengine::RenderEngine::ContextPriority::MEDIUM)
.build()));
+ mMaxRenderTargetSize =
+ std::min(getRenderEngine().getMaxTextureSize(), getRenderEngine().getMaxViewportDims());
// Set SF main policy after initializing RenderEngine which has its own policy.
if (!SetTaskProfiles(0, {"SFMainPolicy"})) {
@@ -816,10 +792,10 @@
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
- LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
+ LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback.");
const auto displayId = display->getPhysicalId();
LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId),
- "Internal display is disconnected.");
+ "Primary display is disconnected.");
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -885,14 +861,6 @@
}
}
-size_t SurfaceFlinger::getMaxTextureSize() const {
- return getRenderEngine().getMaxTextureSize();
-}
-
-size_t SurfaceFlinger::getMaxViewportDims() const {
- return getRenderEngine().getMaxViewportDims();
-}
-
// ----------------------------------------------------------------------------
bool SurfaceFlinger::authenticateSurfaceTexture(
@@ -996,6 +964,11 @@
return NAME_NOT_FOUND;
}
+ const auto displayId = PhysicalDisplayId::tryCast(display->getId());
+ if (!displayId) {
+ return INVALID_OPERATION;
+ }
+
info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value());
const auto& supportedModes = display->getSupportedModes();
@@ -1055,18 +1028,18 @@
}
info->activeColorMode = display->getCompositionDisplay()->getState().colorMode;
- const auto displayId = display->getPhysicalId();
- info->supportedColorModes = getDisplayColorModes(displayId);
-
+ info->supportedColorModes = getDisplayColorModes(*display);
info->hdrCapabilities = display->getHdrCapabilities();
+
info->autoLowLatencyModeSupported =
- getHwComposer().hasDisplayCapability(displayId,
+ getHwComposer().hasDisplayCapability(*displayId,
hal::DisplayCapability::AUTO_LOW_LATENCY_MODE);
std::vector<hal::ContentType> types;
- getHwComposer().getSupportedContentTypes(displayId, &types);
+ getHwComposer().getSupportedContentTypes(*displayId, &types);
info->gameContentTypeSupported = std::any_of(types.begin(), types.end(), [](auto type) {
return type == hal::ContentType::GAME;
});
+
return NO_ERROR;
}
@@ -1290,15 +1263,15 @@
}).wait();
}
-std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) {
- auto modes = getHwComposer().getColorModes(displayId);
- bool isInternalDisplay = displayId == getInternalDisplayIdLocked();
+std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) {
+ auto modes = getHwComposer().getColorModes(display.getPhysicalId());
- // If it's built-in display and the configuration claims it's not wide color capable,
+ // If the display is internal and the configuration claims it's not wide color capable,
// filter out all wide color modes. The typical reason why this happens is that the
// hardware is not good enough to support GPU composition of wide color, and thus the
// OEMs choose to disable this capability.
- if (isInternalDisplay && !hasWideColorDisplay) {
+ if (display.getConnectionType() == ui::DisplayConnectionType::Internal &&
+ !hasWideColorDisplay) {
const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode);
modes.erase(newEnd, modes.end());
}
@@ -1322,34 +1295,41 @@
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
- schedule([=]() MAIN_THREAD {
- const auto displayId = getPhysicalDisplayIdLocked(displayToken);
- if (!displayId) {
- ALOGE("Invalid display token %p", displayToken.get());
- return;
- }
- const auto modes = getDisplayColorModes(*displayId);
- bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
- if (mode < ColorMode::NATIVE || !exists) {
- ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
- decodeColorMode(mode).c_str(), mode, displayToken.get());
- return;
- }
+ if (!displayToken) {
+ return BAD_VALUE;
+ }
+
+ auto future = schedule([=]() MAIN_THREAD -> status_t {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
decodeColorMode(mode).c_str(), mode, displayToken.get());
- } else if (display->isVirtual()) {
+ return NAME_NOT_FOUND;
+ }
+
+ if (display->isVirtual()) {
ALOGW("Attempt to set active color mode %s (%d) for virtual display",
decodeColorMode(mode).c_str(), mode);
- } else {
- display->getCompositionDisplay()->setColorProfile(
- compositionengine::Output::ColorProfile{mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC,
- Dataspace::UNKNOWN});
+ return INVALID_OPERATION;
}
- }).wait();
+ const auto modes = getDisplayColorModes(*display);
+ const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end();
+
+ if (mode < ColorMode::NATIVE || !exists) {
+ ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
+ decodeColorMode(mode).c_str(), mode, displayToken.get());
+ return BAD_VALUE;
+ }
+
+ display->getCompositionDisplay()->setColorProfile(
+ {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN});
+
+ return NO_ERROR;
+ });
+
+ // TODO(b/195698395): Propagate error.
+ future.wait();
return NO_ERROR;
}
@@ -1639,6 +1619,9 @@
hdrInfoReporter = sp<HdrLayerInfoReporter>::make();
}
hdrInfoReporter->addListener(listener);
+
+
+ mAddingHDRLayerInfoListener = true;
return OK;
}
@@ -1763,8 +1746,8 @@
void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
hal::Connection connection) {
- ALOGI("%s(%" PRIu64 ", %s)", __func__, hwcDisplayId,
- connection == hal::Connection::CONNECTED ? "connected" : "disconnected");
+ const bool connected = connection == hal::Connection::CONNECTED;
+ ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId);
// Only lock if we're not on the main thread. This function is normally
// called on a hwbinder thread, but for the primary display it's called on
@@ -1956,13 +1939,9 @@
}
if (mRefreshRateOverlaySpinner) {
- if (Mutex::Autolock lock(mStateLock);
- const auto display = getDefaultDisplayDeviceLocked()) {
- if (display) {
- display->onInvalidate();
- } else {
- ALOGW("%s: default display is null", __func__);
- }
+ Mutex::Autolock lock(mStateLock);
+ if (const auto display = getDefaultDisplayDeviceLocked()) {
+ display->onInvalidate();
}
}
@@ -2142,6 +2121,8 @@
mTracing.notify("bufferLatched");
}
}
+
+ mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp
mVisibleRegionsDirty = false;
if (mCompositionEngine->needsAnotherUpdate()) {
@@ -2286,6 +2267,7 @@
std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>>
hdrInfoListeners;
+ bool haveNewListeners = false;
{
Mutex::Autolock lock(mStateLock);
if (mFpsReporter) {
@@ -2303,37 +2285,45 @@
}
}
}
+ haveNewListeners = mAddingHDRLayerInfoListener; // grab this with state lock
+ mAddingHDRLayerInfoListener = false;
}
- for (auto& [compositionDisplay, listener] : hdrInfoListeners) {
- HdrLayerInfoReporter::HdrLayerInfo info;
- int32_t maxArea = 0;
- mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
- const auto layerFe = layer->getCompositionEngineLayerFE();
- if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) {
- const Dataspace transfer =
+ if (haveNewListeners || mSomeDataspaceChanged || mVisibleRegionsWereDirtyThisFrame) {
+ for (auto& [compositionDisplay, listener] : hdrInfoListeners) {
+ HdrLayerInfoReporter::HdrLayerInfo info;
+ int32_t maxArea = 0;
+ mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
+ const auto layerFe = layer->getCompositionEngineLayerFE();
+ if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) {
+ const Dataspace transfer =
static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK);
- const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
- transfer == Dataspace::TRANSFER_HLG);
+ const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
+ transfer == Dataspace::TRANSFER_HLG);
- if (isHdr) {
- const auto* outputLayer = compositionDisplay->getOutputLayerForLayer(layerFe);
- if (outputLayer) {
- info.numberOfHdrLayers++;
- const auto displayFrame = outputLayer->getState().displayFrame;
- const int32_t area = displayFrame.width() * displayFrame.height();
- if (area > maxArea) {
- maxArea = area;
- info.maxW = displayFrame.width();
- info.maxH = displayFrame.height();
+ if (isHdr) {
+ const auto* outputLayer =
+ compositionDisplay->getOutputLayerForLayer(layerFe);
+ if (outputLayer) {
+ info.numberOfHdrLayers++;
+ const auto displayFrame = outputLayer->getState().displayFrame;
+ const int32_t area = displayFrame.width() * displayFrame.height();
+ if (area > maxArea) {
+ maxArea = area;
+ info.maxW = displayFrame.width();
+ info.maxH = displayFrame.height();
+ }
}
}
}
- }
- });
- listener->dispatchHdrLayerInfo(info);
+ });
+ listener->dispatchHdrLayerInfo(info);
+ }
}
+ mSomeDataspaceChanged = false;
+ mVisibleRegionsWereDirtyThisFrame = false;
+
mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
mTransactionCallbackInvoker.sendCallbacks();
@@ -2479,7 +2469,6 @@
handleTransactionLocked(transactionFlags);
mDebugInTransaction = 0;
- invalidateHwcGeometry();
// here the transaction has been committed
}
@@ -2745,7 +2734,7 @@
builder.setId(physical->id);
builder.setConnectionType(physical->type);
} else {
- builder.setId(acquireVirtualDisplay(resolution, pixelFormat, state.layerStack));
+ builder.setId(acquireVirtualDisplay(resolution, pixelFormat));
}
builder.setPixels(resolution);
@@ -2856,7 +2845,7 @@
setPowerModeInternal(display, hal::PowerMode::ON);
// TODO(b/175678251) Call a listener instead.
- if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
+ if (currentState.physical->hwcDisplayId == getHwComposer().getPrimaryHwcDisplayId()) {
updateInternalDisplayVsyncLocked(display);
}
}
@@ -3056,11 +3045,11 @@
if (mVisibleRegionsDirty || mInputInfoChanged) {
mInputInfoChanged = false;
- updateInputWindowInfo();
+ notifyWindowInfos();
} else if (mInputWindowCommands.syncInputWindows) {
// If the caller requested to sync input windows, but there are no
// changes to input windows, notify immediately.
- setInputWindowsFinished();
+ windowInfosReported();
}
for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
@@ -3075,8 +3064,8 @@
return value;
}
-void SurfaceFlinger::updateInputWindowInfo() {
- std::vector<WindowInfo> inputInfos;
+void SurfaceFlinger::notifyWindowInfos() {
+ std::vector<WindowInfo> windowInfos;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
@@ -3085,12 +3074,10 @@
: nullptr;
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- inputInfos.push_back(layer->fillInputInfo(display));
+ windowInfos.push_back(layer->fillInputInfo(display));
});
-
- mInputFlinger->setInputWindows(inputInfos,
- mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
- : nullptr);
+ mWindowInfosListenerInvoker->windowInfosChanged(windowInfos,
+ mInputWindowCommands.syncInputWindows);
}
void SurfaceFlinger::updateCursorAsync() {
@@ -3124,9 +3111,11 @@
void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) {
if (mScheduler) {
- // In practice it's not allowed to hotplug in/out the primary display once it's been
- // connected during startup, but some tests do it, so just warn and return.
- ALOGW("Can't re-init scheduler");
+ // If the scheduler is already initialized, this means that we received
+ // a hotplug(connected) on the primary display. In that case we should
+ // update the scheduler with the most recent display information.
+ ALOGW("Scheduler already initialized, updating instead");
+ mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
return;
}
const auto currRefreshRate = display->getActiveMode()->getFps();
@@ -3134,7 +3123,7 @@
hal::PowerMode::OFF);
mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate);
- mVsyncModulator.emplace(mVsyncConfiguration->getCurrentConfigs());
+ mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs());
// start the EventThread
mScheduler = getFactory().createScheduler(display->holdRefreshRateConfigs(), *this);
@@ -3357,7 +3346,7 @@
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle,
- const sp<Layer>& parentLayer, bool addToCurrentState,
+ const sp<Layer>& parentLayer, bool addToRoot,
uint32_t* outTransformHint) {
if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
@@ -3369,7 +3358,7 @@
if (gbc != nullptr) {
initialProducer = IInterface::asBinder(gbc);
}
- setLayerCreatedState(handle, lbc, parentHandle, parentLayer, initialProducer);
+ setLayerCreatedState(handle, lbc, parentHandle, parentLayer, initialProducer, addToRoot);
// Create a transaction includes the initial parent and producer.
Vector<ComposerState> states;
@@ -3412,9 +3401,10 @@
return setTransactionFlags(flags, TransactionSchedule::Late);
}
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule) {
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule,
+ const sp<IBinder>& token) {
uint32_t old = mTransactionFlags.fetch_or(flags);
- modulateVsync(&VsyncModulator::setTransactionSchedule, schedule);
+ modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token);
if ((old & flags) == 0) signalTransaction();
return old;
}
@@ -3572,7 +3562,7 @@
sp<Layer> layer = nullptr;
if (s.surface) {
- layer = fromHandleLocked(s.surface).promote();
+ layer = fromHandle(s.surface).promote();
} else if (s.hasBufferChanges()) {
ALOGW("Transaction with buffer, but no Layer?");
continue;
@@ -3634,7 +3624,7 @@
return TransactionSchedule::Late;
}(state.flags);
- setTransactionFlags(eTransactionFlushNeeded, schedule);
+ setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken);
}
void SurfaceFlinger::waitForSynchronousTransaction(
@@ -3739,7 +3729,7 @@
setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp,
postTime, permissions, listenerCallbacksWithSurfaces);
if ((flags & eAnimation) && state.state.surface) {
- if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) {
+ if (const auto layer = fromHandle(state.state.surface).promote(); layer) {
mScheduler->recordLayerHistory(layer.get(),
isAutoTimestamp ? 0 : desiredPresentTime,
LayerHistory::LayerUpdateType::AnimationTX);
@@ -3898,15 +3888,13 @@
sp<Layer> layer = nullptr;
if (s.surface) {
if (what & layer_state_t::eLayerCreated) {
- layer = handleLayerCreatedLocked(s.surface, privileged);
+ layer = handleLayerCreatedLocked(s.surface);
if (layer) {
- // put the created layer into mLayersByLocalBinderToken.
- mLayersByLocalBinderToken.emplace(s.surface->localBinder(), layer);
flags |= eTransactionNeeded | eTraversalNeeded;
mLayersAdded = true;
}
} else {
- layer = fromHandleLocked(s.surface).promote();
+ layer = fromHandle(s.surface).promote();
}
} else {
// The client may provide us a null handle. Treat it as if the layer was removed.
@@ -4136,6 +4124,15 @@
if (what & layer_state_t::eAutoRefreshChanged) {
layer->setAutoRefresh(s.autoRefresh);
}
+ if (what & layer_state_t::eTrustedOverlayChanged) {
+ if (privileged) {
+ if (layer->setTrustedOverlay(s.isTrustedOverlay)) {
+ flags |= eTraversalNeeded;
+ }
+ } else {
+ ALOGE("Attempt to set trusted overlay without permission ACCESS_SURFACE_FLINGER");
+ }
+ }
if (what & layer_state_t::eStretchChanged) {
if (layer->setStretchEffect(s.stretchEffect)) {
flags |= eTraversalNeeded;
@@ -4176,17 +4173,30 @@
}
bool bufferChanged = what & layer_state_t::eBufferChanged;
bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
+ bool bufferSizeExceedsLimit = false;
std::shared_ptr<renderengine::ExternalTexture> buffer;
if (bufferChanged && cacheIdChanged && s.buffer != nullptr) {
- ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
- buffer = ClientCache::getInstance().get(s.cachedBuffer);
+ bufferSizeExceedsLimit =
+ exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight());
+ if (!bufferSizeExceedsLimit) {
+ ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
+ buffer = ClientCache::getInstance().get(s.cachedBuffer);
+ }
} else if (cacheIdChanged) {
buffer = ClientCache::getInstance().get(s.cachedBuffer);
} else if (bufferChanged && s.buffer != nullptr) {
- buffer = std::make_shared<
- renderengine::ExternalTexture>(s.buffer, getRenderEngine(),
- renderengine::ExternalTexture::Usage::READABLE);
+ bufferSizeExceedsLimit =
+ exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight());
+ if (!bufferSizeExceedsLimit) {
+ buffer = std::make_shared<
+ renderengine::ExternalTexture>(s.buffer, getRenderEngine(),
+ renderengine::ExternalTexture::Usage::READABLE);
+ }
}
+ ALOGE_IF(bufferSizeExceedsLimit,
+ "Attempted to create an ExternalTexture for layer %s that exceeds render target size "
+ "limit.",
+ layer->getDebugName());
if (buffer) {
const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged;
const uint64_t frameNumber = frameNumberChanged
@@ -4225,7 +4235,7 @@
{
Mutex::Autolock _l(mStateLock);
- mirrorFrom = fromHandleLocked(mirrorFromHandle).promote();
+ mirrorFrom = fromHandle(mirrorFromHandle).promote();
if (!mirrorFrom) {
return NAME_NOT_FOUND;
}
@@ -4308,9 +4318,9 @@
return result;
}
- bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
- result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer,
- addToCurrentState, outTransformHint);
+ bool addToRoot = callingThreadHasUnscopedSurfaceFlingerAccess();
+ result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer, addToRoot,
+ outTransformHint);
if (result != NO_ERROR) {
return result;
}
@@ -4423,7 +4433,7 @@
setTransactionFlags(eTransactionNeeded);
}
-void SurfaceFlinger::onHandleDestroyed(sp<Layer>& layer) {
+void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer) {
Mutex::Autolock lock(mStateLock);
// If a layer has a parent, we allow it to out-live it's handle
// with the idea that the parent holds a reference and will eventually
@@ -4434,17 +4444,7 @@
mCurrentState.layersSortedByZ.remove(layer);
}
markLayerPendingRemovalLocked(layer);
-
- auto it = mLayersByLocalBinderToken.begin();
- while (it != mLayersByLocalBinderToken.end()) {
- if (it->second == layer) {
- mBufferCountTracker.remove(it->first->localBinder());
- it = mLayersByLocalBinderToken.erase(it);
- } else {
- it++;
- }
- }
-
+ mBufferCountTracker.remove(handle);
layer.clear();
}
@@ -4537,8 +4537,7 @@
if (currentMode == hal::PowerMode::OFF) {
const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken);
if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
- mActiveDisplayToken = display->getDisplayToken();
- onActiveDisplayChangedLocked(getDisplayDeviceLocked(mActiveDisplayToken));
+ onActiveDisplayChangedLocked(display);
}
// Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315.
// We can merge the syscall later.
@@ -5327,6 +5326,14 @@
}
return PERMISSION_DENIED;
}
+ case ADD_WINDOW_INFOS_LISTENER:
+ case REMOVE_WINDOW_INFOS_LISTENER: {
+ const int uid = IPCThreadState::self()->getCallingUid();
+ if (uid == AID_SYSTEM || uid == AID_GRAPHICS) {
+ return OK;
+ }
+ return PERMISSION_DENIED;
+ }
}
// These codes are used for the IBinder protocol to either interrogate the recipient
@@ -5689,12 +5696,10 @@
// Inject a hotplug connected event for the primary display. This will deallocate and
// reallocate the display state including framebuffers.
case 1037: {
- std::optional<hal::HWDisplayId> hwcId;
- {
- Mutex::Autolock lock(mStateLock);
- hwcId = getHwComposer().getInternalHwcDisplayId();
- }
- onComposerHalHotplug(*hwcId, hal::Connection::CONNECTED);
+ const hal::HWDisplayId hwcId =
+ (Mutex::Autolock(mStateLock), getHwComposer().getPrimaryHwcDisplayId());
+
+ onComposerHalHotplug(hwcId, hal::Connection::CONNECTED);
return NO_ERROR;
}
// Modify the max number of display frames stored within FrameTimeline
@@ -6057,7 +6062,7 @@
{
Mutex::Autolock lock(mStateLock);
- parent = fromHandleLocked(args.layerHandle).promote();
+ parent = fromHandle(args.layerHandle).promote();
if (parent == nullptr || parent->isRemovedFromCurrentState()) {
ALOGE("captureLayers called with an invalid or removed parent");
return NAME_NOT_FOUND;
@@ -6088,7 +6093,7 @@
reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY);
for (const auto& handle : args.excludeHandles) {
- sp<Layer> excludeLayer = fromHandleLocked(handle).promote();
+ sp<Layer> excludeLayer = fromHandle(handle).promote();
if (excludeLayer != nullptr) {
excludeLayers.emplace(excludeLayer);
} else {
@@ -6170,6 +6175,13 @@
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
+ if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) {
+ ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
+ ") that exceeds render target size limit.",
+ bufferSize.getWidth(), bufferSize.getHeight());
+ return BAD_VALUE;
+ }
+
// Loop over all visible layers to see whether there's any protected layer. A protected layer is
// typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer.
// A protected layer has no implication on whether it's secure, which is explicitly set by
@@ -6381,7 +6393,7 @@
return NO_ERROR;
}
-void SurfaceFlinger::setInputWindowsFinished() {
+void SurfaceFlinger::windowInfosReported() {
Mutex::Autolock _l(mStateLock);
signalSynchronousTransactions(CountDownLatch::eSyncInputWindows);
}
@@ -6552,24 +6564,8 @@
return NO_ERROR;
}
-wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
- Mutex::Autolock _l(mStateLock);
- return fromHandleLocked(handle);
-}
-
-wp<Layer> SurfaceFlinger::fromHandleLocked(const sp<IBinder>& handle) const {
- BBinder* b = nullptr;
- if (handle) {
- b = handle->localBinder();
- }
- if (b == nullptr) {
- return nullptr;
- }
- auto it = mLayersByLocalBinderToken.find(b);
- if (it != mLayersByLocalBinderToken.end()) {
- return it->second;
- }
- return nullptr;
+wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) const {
+ return Layer::fromHandle(handle);
}
void SurfaceFlinger::onLayerFirstRef(Layer* layer) {
@@ -6785,33 +6781,29 @@
}
status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
- const auto maxSupportedRefreshRate = [&] {
- const auto display = getDefaultDisplayDevice();
- if (display) {
- return display->refreshRateConfigs().getSupportedRefreshRateRange().max;
+ Fps maxRefreshRate(60.f);
+
+ if (!getHwComposer().isHeadless()) {
+ if (const auto display = getDefaultDisplayDevice()) {
+ maxRefreshRate = display->refreshRateConfigs().getSupportedRefreshRateRange().max;
}
- ALOGW("%s: default display is null", __func__);
- return Fps(60);
- }();
- *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate);
+ }
+
+ *buffers = getMaxAcquiredBufferCountForRefreshRate(maxRefreshRate);
return NO_ERROR;
}
int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const {
- const auto refreshRate = [&] {
- const auto frameRateOverride = mScheduler->getFrameRateOverride(uid);
- if (frameRateOverride.has_value()) {
- return frameRateOverride.value();
- }
+ Fps refreshRate(60.f);
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
- if (display) {
- return display->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) {
+ refreshRate = *frameRateOverride;
+ } else if (!getHwComposer().isHeadless()) {
+ if (const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked())) {
+ refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps();
}
+ }
- ALOGW("%s: default display is null", __func__);
- return Fps(60);
- }();
return getMaxAcquiredBufferCountForRefreshRate(refreshRate);
}
@@ -6832,10 +6824,10 @@
void SurfaceFlinger::setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer,
const wp<IBinder>& parent, const wp<Layer> parentLayer,
- const wp<IBinder>& producer) {
+ const wp<IBinder>& producer, bool addToRoot) {
Mutex::Autolock lock(mCreatedLayersLock);
mCreatedLayers[handle->localBinder()] =
- std::make_unique<LayerCreatedState>(layer, parent, parentLayer, producer);
+ std::make_unique<LayerCreatedState>(layer, parent, parentLayer, producer, addToRoot);
}
auto SurfaceFlinger::getLayerCreatedState(const sp<IBinder>& handle) {
@@ -6860,7 +6852,7 @@
return state;
}
-sp<Layer> SurfaceFlinger::handleLayerCreatedLocked(const sp<IBinder>& handle, bool privileged) {
+sp<Layer> SurfaceFlinger::handleLayerCreatedLocked(const sp<IBinder>& handle) {
const auto& state = getLayerCreatedState(handle);
if (!state) {
return nullptr;
@@ -6873,9 +6865,9 @@
}
sp<Layer> parent;
- bool allowAddRoot = privileged;
+ bool allowAddRoot = state->addToRoot;
if (state->initialParent != nullptr) {
- parent = fromHandleLocked(state->initialParent.promote()).promote();
+ parent = fromHandle(state->initialParent.promote()).promote();
if (parent == nullptr) {
ALOGE("Invalid parent %p", state->initialParent.unsafe_get());
allowAddRoot = false;
@@ -6935,16 +6927,35 @@
void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) {
ATRACE_CALL();
+ if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
+ display->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false);
+ }
+
if (!activeDisplay) {
ALOGE("%s: activeDisplay is null", __func__);
return;
}
+ mActiveDisplayToken = activeDisplay->getDisplayToken();
+
+ activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
updateInternalDisplayVsyncLocked(activeDisplay);
mScheduler->setModeChangePending(false);
mScheduler->setRefreshRateConfigs(activeDisplay->holdRefreshRateConfigs());
onActiveDisplaySizeChanged(activeDisplay);
}
+status_t SurfaceFlinger::addWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) const {
+ mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) const {
+ mWindowInfosListenerInvoker->removeWindowInfosListener(windowInfosListener);
+ return NO_ERROR;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 80f3f9c..0ac6438 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -93,7 +93,6 @@
class TunnelModeEnabledReporter;
class HdrLayerInfoReporter;
class HWComposer;
-struct SetInputWindowsListener;
class IGraphicBufferProducer;
class Layer;
class MessageBase;
@@ -102,6 +101,7 @@
class RenderArea;
class TimeStats;
class FrameTracer;
+class WindowInfosListenerInvoker;
using gui::ScreenCaptureResults;
@@ -327,13 +327,12 @@
// Returns nullptr if the handle does not point to an existing layer.
// Otherwise, returns a weak reference so that callers off the main-thread
// won't accidentally hold onto the last strong reference.
- wp<Layer> fromHandle(const sp<IBinder>& handle);
- wp<Layer> fromHandleLocked(const sp<IBinder>& handle) const REQUIRES(mStateLock);
+ wp<Layer> fromHandle(const sp<IBinder>& handle) const;
// If set, disables reusing client composition buffers. This can be set by
// debug.sf.disable_client_composition_cache
bool mDisableClientCompositionCache = false;
- void setInputWindowsFinished();
+ void windowInfosReported();
// Disables expensive rendering for all displays
// This is scheduled on the main thread
@@ -358,6 +357,15 @@
// display.
virtual FloatRect getLayerClipBoundsForDisplay(const DisplayDevice&) const;
+ virtual void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&)
+ REQUIRES(mStateLock);
+
+ // Returns true if any display matches a `bool(const DisplayDevice&)` predicate.
+ template <typename Predicate>
+ bool hasDisplay(Predicate p) const REQUIRES(mStateLock) {
+ return static_cast<bool>(findDisplay(p));
+ }
+
private:
friend class BufferLayer;
friend class BufferQueueLayer;
@@ -715,6 +723,11 @@
status_t getMaxAcquiredBufferCount(int* buffers) const override;
+ status_t addWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& windowInfosListener) const override;
+ status_t removeWindowInfosListener(
+ const sp<gui::IWindowInfosListener>& windowInfosListener) const override;
+
// Implements IBinder::DeathRecipient.
void binderDied(const wp<IBinder>& who) override;
@@ -805,7 +818,7 @@
void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
void updateInputFlinger();
- void updateInputWindowInfo();
+ void notifyWindowInfos();
void commitInputWindowCommands() REQUIRES(mStateLock);
void updateCursorAsync();
@@ -845,7 +858,7 @@
// but there is no need to try and wake up immediately to do it. Rather we rely on
// onFrameAvailable or another layer update to wake us up.
void setTraversalNeeded();
- uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule);
+ uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule, const sp<IBinder>& = {});
void commitTransaction() REQUIRES(mStateLock);
void commitOffscreenLayers();
bool transactionIsReadyToBeApplied(
@@ -892,14 +905,14 @@
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
// resources associated to this layer.
- void onHandleDestroyed(sp<Layer>& layer);
+ void onHandleDestroyed(BBinder* handle, sp<Layer>& layer);
void markLayerPendingRemovalLocked(const sp<Layer>& layer);
// add a layer to SurfaceFlinger
status_t addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer,
- bool addToCurrentState, uint32_t* outTransformHint);
+ bool addToRoot, uint32_t* outTransformHint);
// Traverse through all the layers and compute and cache its bounds.
void computeLayerBounds();
@@ -925,8 +938,9 @@
void readPersistentProperties();
- size_t getMaxTextureSize() const;
- size_t getMaxViewportDims() const;
+ bool exceedsMaxRenderTargetSize(uint32_t width, uint32_t height) const {
+ return width > mMaxRenderTargetSize || height > mMaxRenderTargetSize;
+ }
int getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
@@ -1042,8 +1056,6 @@
const sp<compositionengine::DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer) REQUIRES(mStateLock);
void processDisplayChangesLocked() REQUIRES(mStateLock);
- void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&)
- REQUIRES(mStateLock);
void processDisplayRemoved(const wp<IBinder>& displayToken) REQUIRES(mStateLock);
void processDisplayChanged(const wp<IBinder>& displayToken,
const DisplayDeviceState& currentState,
@@ -1106,23 +1118,26 @@
return {};
}
- // TODO(b/74619554): Remove special cases for primary display.
+ // TODO(b/182939859): SF conflates the primary (a.k.a. default) display with the first display
+ // connected at boot, which is typically internal. (Theoretically, it must be internal because
+ // SF does not support disconnecting it, though in practice HWC may circumvent this limitation.)
+ //
+ // SF inherits getInternalDisplayToken and getInternalDisplayId from ISurfaceComposer, so these
+ // locked counterparts are named consistently. Once SF supports headless mode and can designate
+ // any display as primary, the "internal" misnomer will be phased out.
sp<IBinder> getInternalDisplayTokenLocked() const REQUIRES(mStateLock) {
- const auto displayId = getInternalDisplayIdLocked();
- return displayId ? getPhysicalDisplayTokenLocked(*displayId) : nullptr;
+ return getPhysicalDisplayTokenLocked(getInternalDisplayIdLocked());
}
- std::optional<PhysicalDisplayId> getInternalDisplayIdLocked() const REQUIRES(mStateLock) {
- const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
- return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+ PhysicalDisplayId getInternalDisplayIdLocked() const REQUIRES(mStateLock) {
+ return getHwComposer().getPrimaryDisplayId();
}
// Toggles use of HAL/GPU virtual displays.
void enableHalVirtualDisplays(bool);
// Virtual display lifecycle for ID generation and HAL allocation.
- VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, ui::LayerStack)
- REQUIRES(mStateLock);
+ VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock);
void releaseVirtualDisplay(VirtualDisplayId);
void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) REQUIRES(mStateLock);
@@ -1194,8 +1209,7 @@
/*
* Misc
*/
- std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId)
- REQUIRES(mStateLock);
+ std::vector<ui::ColorMode> getDisplayColorModes(const DisplayDevice&) REQUIRES(mStateLock);
static int calculateMaxAcquiredBufferCount(Fps refreshRate,
std::chrono::nanoseconds presentLatency);
@@ -1249,11 +1263,19 @@
State mDrawingState{LayerVector::StateSet::Drawing};
bool mVisibleRegionsDirty = false;
+ // VisibleRegions dirty is already cleared by postComp, but we need to track it to prevent
+ // extra work in the HDR layer info listener.
+ bool mVisibleRegionsWereDirtyThisFrame = false;
+ // Used to ensure we omit a callback when HDR layer info listener is newly added but the
+ // scene hasn't changed
+ bool mAddingHDRLayerInfoListener = false;
+
// Set during transaction application stage to track if the input info or children
// for a layer has changed.
// TODO: Also move visibleRegions over to a boolean system.
bool mInputInfoChanged = false;
bool mSomeChildrenChanged;
+ bool mSomeDataspaceChanged = false;
bool mForceTransactionDisplayChange = false;
bool mGeometryInvalid = false;
@@ -1291,8 +1313,6 @@
std::optional<DisplayIdGenerator<HalVirtualDisplayId>> hal;
} mVirtualDisplayIdGenerators;
- std::unordered_map<BBinder*, wp<Layer>> mLayersByLocalBinderToken GUARDED_BY(mStateLock);
-
// don't use a lock for these, we don't care
int mDebugRegion = 0;
bool mDebugDisableHWC = false;
@@ -1382,6 +1402,9 @@
SurfaceFlingerBE mBE;
std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
+ // mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by
+ // any mutex.
+ size_t mMaxRenderTargetSize{1};
const std::string mHwcServiceName;
@@ -1398,7 +1421,7 @@
std::unique_ptr<scheduler::VsyncConfiguration> mVsyncConfiguration;
// Optional to defer construction until PhaseConfiguration is created.
- std::optional<scheduler::VsyncModulator> mVsyncModulator;
+ sp<VsyncModulator> mVsyncModulator;
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
@@ -1422,8 +1445,6 @@
// Should only be accessed by the main thread.
InputWindowCommands mInputWindowCommands;
- sp<SetInputWindowsListener> mSetInputWindowsListener;
-
Hwc2::impl::PowerAdvisor mPowerAdvisor;
// This should only be accessed on the main thread.
@@ -1451,11 +1472,12 @@
mutable Mutex mCreatedLayersLock;
struct LayerCreatedState {
LayerCreatedState(const wp<Layer>& layer, const wp<IBinder>& parent,
- const wp<Layer> parentLayer, const wp<IBinder>& producer)
+ const wp<Layer> parentLayer, const wp<IBinder>& producer, bool addToRoot)
: layer(layer),
initialParent(parent),
initialParentLayer(parentLayer),
- initialProducer(producer) {}
+ initialProducer(producer),
+ addToRoot(addToRoot) {}
wp<Layer> layer;
// Indicates the initial parent of the created layer, only used for creating layer in
// SurfaceFlinger. If nullptr, it may add the created layer into the current root layers.
@@ -1464,6 +1486,10 @@
// Indicates the initial graphic buffer producer of the created layer, only used for
// creating layer in SurfaceFlinger.
wp<IBinder> initialProducer;
+ // Indicates whether the layer getting created should be added at root if there's no parent
+ // and has permission ACCESS_SURFACE_FLINGER. If set to false and no parent, the layer will
+ // be added offscreen.
+ bool addToRoot;
};
// A temporay pool that store the created layers and will be added to current state in main
@@ -1471,10 +1497,9 @@
std::unordered_map<BBinder*, std::unique_ptr<LayerCreatedState>> mCreatedLayers;
void setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer,
const wp<IBinder>& parent, const wp<Layer> parentLayer,
- const wp<IBinder>& producer);
+ const wp<IBinder>& producer, bool addToRoot);
auto getLayerCreatedState(const sp<IBinder>& handle);
- sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle, bool privileged)
- REQUIRES(mStateLock);
+ sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle) REQUIRES(mStateLock);
std::atomic<ui::Transform::RotationFlags> mDefaultDisplayTransformHint;
@@ -1489,6 +1514,8 @@
}
wp<IBinder> mActiveDisplayToken GUARDED_BY(mStateLock);
+
+ const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 2084bb6..9be3abe 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -149,6 +149,7 @@
getLayerIdFromWeakRef(layer->mDrawingState.zOrderRelativeOf),
layer->mDrawingState.z);
addShadowRadiusLocked(transaction, layerId, layer->mDrawingState.shadowRadius);
+ addTrustedOverlayLocked(transaction, layerId, layer->mDrawingState.isTrustedOverlay);
}
void SurfaceInterceptor::addInitialDisplayStateLocked(Increment* increment,
@@ -183,12 +184,9 @@
return NO_ERROR;
}
-const sp<const Layer> SurfaceInterceptor::getLayer(const wp<const IBinder>& weakHandle) const {
- const sp<const IBinder>& handle(weakHandle.promote());
- const auto layerHandle(static_cast<const Layer::Handle*>(handle.get()));
- const sp<const Layer> layer(layerHandle->owner.promote());
- // layer could be a nullptr at this point
- return layer;
+const sp<const Layer> SurfaceInterceptor::getLayer(const wp<IBinder>& weakHandle) const {
+ sp<IBinder> handle = weakHandle.promote();
+ return Layer::fromHandle(handle).promote();
}
int32_t SurfaceInterceptor::getLayerId(const sp<const Layer>& layer) const {
@@ -203,12 +201,11 @@
return strongLayer == nullptr ? -1 : getLayerId(strongLayer);
}
-int32_t SurfaceInterceptor::getLayerIdFromHandle(const sp<const IBinder>& handle) const {
+int32_t SurfaceInterceptor::getLayerIdFromHandle(const sp<IBinder>& handle) const {
if (handle == nullptr) {
return -1;
}
- const auto layerHandle(static_cast<const Layer::Handle*>(handle.get()));
- const sp<const Layer> layer(layerHandle->owner.promote());
+ const sp<const Layer> layer = Layer::fromHandle(handle).promote();
return layer == nullptr ? -1 : getLayerId(layer);
}
@@ -398,6 +395,13 @@
overrideChange->set_radius(shadowRadius);
}
+void SurfaceInterceptor::addTrustedOverlayLocked(Transaction* transaction, int32_t layerId,
+ bool isTrustedOverlay) {
+ SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+ TrustedOverlayChange* overrideChange(change->mutable_trusted_overlay());
+ overrideChange->set_is_trusted_overlay(isTrustedOverlay);
+}
+
void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction,
const layer_state_t& state)
{
@@ -461,6 +465,9 @@
if (state.what & layer_state_t::eShadowRadiusChanged) {
addShadowRadiusLocked(transaction, layerId, state.shadowRadius);
}
+ if (state.what & layer_state_t::eTrustedOverlayChanged) {
+ addTrustedOverlayLocked(transaction, layerId, state.isTrustedOverlay);
+ }
if (state.what & layer_state_t::eStretchChanged) {
ALOGW("SurfaceInterceptor not implemented for eStretchChanged");
}
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index e498e7d..7b331b9 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -48,7 +48,7 @@
using Increment = surfaceflinger::Increment;
using DisplayChange = surfaceflinger::DisplayChange;
-constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope";
class SurfaceInterceptor : public IBinder::DeathRecipient {
public:
@@ -133,10 +133,10 @@
void addInitialDisplayStateLocked(Increment* increment, const DisplayDeviceState& display);
status_t writeProtoFileLocked();
- const sp<const Layer> getLayer(const wp<const IBinder>& weakHandle) const;
+ const sp<const Layer> getLayer(const wp<IBinder>& weakHandle) const;
int32_t getLayerId(const sp<const Layer>& layer) const;
int32_t getLayerIdFromWeakRef(const wp<const Layer>& layer) const;
- int32_t getLayerIdFromHandle(const sp<const IBinder>& weakHandle) const;
+ int32_t getLayerIdFromHandle(const sp<IBinder>& weakHandle) const;
Increment* createTraceIncrementLocked();
void addSurfaceCreationLocked(Increment* increment, const sp<const Layer>& layer);
@@ -177,6 +177,7 @@
void addRelativeParentLocked(Transaction* transaction, int32_t layerId, int32_t parentId,
int z);
void addShadowRadiusLocked(Transaction* transaction, int32_t layerId, float shadowRadius);
+ void addTrustedOverlayLocked(Transaction* transaction, int32_t layerId, bool isTrustedOverlay);
// Add display transactions to the trace
DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId);
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 15a503d..42a16c6 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -77,7 +77,7 @@
private:
class Runner;
static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB;
- static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb";
+ static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope";
SurfaceFlinger& mFlinger;
mutable std::mutex mTraceLock;
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
new file mode 100644
index 0000000..dc2aa58
--- /dev/null
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "WindowInfosListenerInvoker.h"
+#include <gui/ISurfaceComposer.h>
+#include <unordered_set>
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+using gui::IWindowInfosListener;
+using gui::WindowInfo;
+
+struct WindowInfosReportedListener : gui::BnWindowInfosReportedListener {
+ explicit WindowInfosReportedListener(std::function<void()> listenerCb)
+ : mListenerCb(listenerCb) {}
+
+ binder::Status onWindowInfosReported() override {
+ if (mListenerCb != nullptr) {
+ mListenerCb();
+ }
+ return binder::Status::ok();
+ }
+
+ std::function<void()> mListenerCb;
+};
+
+WindowInfosListenerInvoker::WindowInfosListenerInvoker(const sp<SurfaceFlinger>& sf) : mSf(sf) {
+ mWindowInfosReportedListener =
+ new WindowInfosReportedListener([&]() { windowInfosReported(); });
+}
+
+void WindowInfosListenerInvoker::addWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) {
+ sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener);
+
+ asBinder->linkToDeath(this);
+ std::scoped_lock lock(mListenersMutex);
+ mWindowInfosListeners.emplace(asBinder, windowInfosListener);
+}
+
+void WindowInfosListenerInvoker::removeWindowInfosListener(
+ const sp<IWindowInfosListener>& windowInfosListener) {
+ sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener);
+
+ std::scoped_lock lock(mListenersMutex);
+ asBinder->unlinkToDeath(this);
+ mWindowInfosListeners.erase(asBinder);
+}
+
+void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) {
+ std::scoped_lock lock(mListenersMutex);
+ mWindowInfosListeners.erase(who);
+}
+
+void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
+ bool shouldSync) {
+ std::unordered_set<sp<IWindowInfosListener>, ISurfaceComposer::SpHash<IWindowInfosListener>>
+ windowInfosListeners;
+
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (const auto& [_, listener] : mWindowInfosListeners) {
+ windowInfosListeners.insert(listener);
+ }
+ }
+
+ mCallbacksPending = windowInfosListeners.size();
+
+ for (const auto& listener : windowInfosListeners) {
+ listener->onWindowInfosChanged(windowInfos,
+ shouldSync ? mWindowInfosReportedListener : nullptr);
+ }
+}
+
+void WindowInfosListenerInvoker::windowInfosReported() {
+ mCallbacksPending--;
+ if (mCallbacksPending == 0) {
+ mSf->windowInfosReported();
+ }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
new file mode 100644
index 0000000..5e5796f
--- /dev/null
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/gui/BnWindowInfosReportedListener.h>
+#include <android/gui/IWindowInfosListener.h>
+#include <android/gui/IWindowInfosReportedListener.h>
+#include <binder/IBinder.h>
+#include <utils/Mutex.h>
+#include <unordered_map>
+
+namespace android {
+
+class SurfaceFlinger;
+
+class WindowInfosListenerInvoker : public IBinder::DeathRecipient {
+public:
+ WindowInfosListenerInvoker(const sp<SurfaceFlinger>& sf);
+ void addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
+ void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
+
+ void windowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos, bool shouldSync);
+
+protected:
+ void binderDied(const wp<IBinder>& who) override;
+
+private:
+ void windowInfosReported();
+
+ struct WpHash {
+ size_t operator()(const wp<IBinder>& p) const {
+ return std::hash<IBinder*>()(p.unsafe_get());
+ }
+ };
+
+ const sp<SurfaceFlinger> mSf;
+ std::mutex mListenersMutex;
+ std::unordered_map<wp<IBinder>, const sp<gui::IWindowInfosListener>, WpHash>
+ mWindowInfosListeners GUARDED_BY(mListenersMutex);
+ sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener;
+ std::atomic<size_t> mCallbacksPending{0};
+};
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index aef670d..2841f7c 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -105,6 +105,7 @@
layer.queuedFrames = layerProto.queued_frames();
layer.refreshPending = layerProto.refresh_pending();
layer.isProtected = layerProto.is_protected();
+ layer.isTrustedOverlay = layerProto.is_trusted_overlay();
layer.cornerRadius = layerProto.corner_radius();
layer.backgroundBlurRadius = layerProto.background_blur_radius();
for (const auto& entry : layerProto.metadata()) {
@@ -289,6 +290,7 @@
StringAppendF(&result, "crop=%s, ", crop.to_string().c_str());
StringAppendF(&result, "cornerRadius=%f, ", cornerRadius);
StringAppendF(&result, "isProtected=%1d, ", isProtected);
+ StringAppendF(&result, "isTrustedOverlay=%1d, ", isTrustedOverlay);
StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate);
StringAppendF(&result, "dataspace=%s, ", dataspace.c_str());
StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str());
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index c48354f..52503ba 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -109,6 +109,7 @@
int32_t queuedFrames;
bool refreshPending;
bool isProtected;
+ bool isTrustedOverlay;
float cornerRadius;
int backgroundBlurRadius;
LayerMetadata metadata;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 9f25674..dddc677 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -128,6 +128,8 @@
// Regions of a layer, where blur should be applied.
repeated BlurRegion blur_regions = 54;
+
+ bool is_trusted_overlay = 55;
}
message PositionProto {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index b96725f..32ad873 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -51,6 +51,7 @@
"Stress_test.cpp",
"SurfaceInterceptor_test.cpp",
"VirtualDisplay_test.cpp",
+ "WindowInfosListener_test.cpp",
],
data: ["SurfaceFlinger_test.filter"],
static_libs: [
@@ -59,7 +60,7 @@
"android.hardware.graphics.composer@2.1",
],
shared_libs: [
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.common@1.2",
"libandroid",
"libbase",
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index ccf434d..d027865 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -18,7 +18,9 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#include <private/android_filesystem_config.h>
#include "LayerTransactionTest.h"
+#include "utils/TransactionUtils.h"
namespace android {
@@ -227,6 +229,50 @@
}
}
+// Test that the mirror layer is initially offscreen.
+TEST_F(MirrorLayerTest, InitialMirrorState) {
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ui::DisplayMode mode;
+ SurfaceComposerClient::getActiveDisplayMode(display, &mode);
+ const ui::Size& size = mode.resolution;
+
+ sp<SurfaceControl> mirrorLayer = nullptr;
+ {
+ // Run as system to get the ACCESS_SURFACE_FLINGER permission when mirroring
+ UIDFaker f(AID_SYSTEM);
+ // Mirror mChildLayer
+ mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ ASSERT_NE(mirrorLayer, nullptr);
+ }
+
+ // Show the mirror layer, but don't reparent to a layer on screen.
+ Transaction()
+ .setPosition(mirrorLayer, 500, 500)
+ .show(mirrorLayer)
+ .setLayer(mirrorLayer, INT32_MAX - 1)
+ .apply();
+
+ {
+ SCOPED_TRACE("Offscreen Mirror");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, size.getWidth(), 50), Color::RED);
+ shot->expectColor(Rect(0, 0, 50, size.getHeight()), Color::RED);
+ shot->expectColor(Rect(450, 0, size.getWidth(), size.getHeight()), Color::RED);
+ shot->expectColor(Rect(0, 450, size.getWidth(), size.getHeight()), Color::RED);
+ shot->expectColor(Rect(50, 50, 450, 450), Color::GREEN);
+ }
+
+ // Add mirrorLayer as child of mParentLayer so it's shown on the display
+ Transaction().reparent(mirrorLayer, mParentLayer).apply();
+
+ {
+ SCOPED_TRACE("On Screen Mirror");
+ auto shot = screenshot();
+ // Child mirror
+ shot->expectColor(Rect(550, 550, 950, 950), Color::GREEN);
+ }
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 6912fcf..ab2064e 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -515,7 +515,8 @@
}
TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
@@ -532,6 +533,21 @@
ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
}
+TEST_F(ScreenCaptureTest, CaptureTooLargeLayer) {
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60);
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+
+ Transaction().show(redLayer).setLayer(redLayer, INT32_MAX).apply(true);
+
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = redLayer->getHandle();
+ captureArgs.frameScaleX = INT32_MAX / 60;
+ captureArgs.frameScaleY = INT32_MAX / 60;
+
+ ScreenCaptureResults captureResults;
+ ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(captureArgs, captureResults));
+}
+
TEST_F(ScreenCaptureTest, CaptureSecureLayer) {
sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
ISurfaceComposerClient::eFXSurfaceBufferState);
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index ee4e863..a424059 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -61,7 +61,7 @@
constexpr auto LAYER_NAME = "Layer Create and Delete Test";
constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
-constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope";
// Fill an RGBA_8888 formatted surface with a single color.
static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
@@ -193,6 +193,7 @@
bool reparentUpdateFound(const SurfaceChange& change, bool found);
bool relativeParentUpdateFound(const SurfaceChange& change, bool found);
bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found);
+ bool trustedOverlayUpdateFound(const SurfaceChange& change, bool found);
bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase);
// Find all of the updates in the single trace
@@ -228,6 +229,7 @@
void reparentUpdate(Transaction&);
void relativeParentUpdate(Transaction&);
void shadowRadiusUpdate(Transaction&);
+ void trustedOverlayUpdate(Transaction&);
void surfaceCreation(Transaction&);
void displayCreation(Transaction&);
void displayDeletion(Transaction&);
@@ -405,6 +407,10 @@
t.setShadowRadius(mBGSurfaceControl, SHADOW_RADIUS_UPDATE);
}
+void SurfaceInterceptorTest::trustedOverlayUpdate(Transaction& t) {
+ t.setTrustedOverlay(mBGSurfaceControl, true);
+}
+
void SurfaceInterceptorTest::displayCreation(Transaction&) {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
SurfaceComposerClient::destroyDisplay(testDisplay);
@@ -433,6 +439,7 @@
runInTransaction(&SurfaceInterceptorTest::reparentUpdate);
runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate);
runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate);
+ runInTransaction(&SurfaceInterceptorTest::trustedOverlayUpdate);
}
void SurfaceInterceptorTest::surfaceCreation(Transaction&) {
@@ -644,6 +651,17 @@
return foundShadowRadius;
}
+bool SurfaceInterceptorTest::trustedOverlayUpdateFound(const SurfaceChange& change,
+ bool foundTrustedOverlay) {
+ bool hasTrustedOverlay(change.trusted_overlay().is_trusted_overlay());
+ if (hasTrustedOverlay && !foundTrustedOverlay) {
+ foundTrustedOverlay = true;
+ } else if (hasTrustedOverlay && foundTrustedOverlay) {
+ []() { FAIL(); }();
+ }
+ return foundTrustedOverlay;
+}
+
bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace,
SurfaceChange::SurfaceChangeCase changeCase) {
bool foundUpdate = false;
@@ -704,6 +722,9 @@
case SurfaceChange::SurfaceChangeCase::kShadowRadius:
foundUpdate = shadowRadiusUpdateFound(change, foundUpdate);
break;
+ case SurfaceChange::SurfaceChangeCase::kTrustedOverlay:
+ foundUpdate = trustedOverlayUpdateFound(change, foundUpdate);
+ break;
case SurfaceChange::SurfaceChangeCase::SURFACECHANGE_NOT_SET:
break;
}
@@ -897,6 +918,11 @@
SurfaceChange::SurfaceChangeCase::kShadowRadius);
}
+TEST_F(SurfaceInterceptorTest, InterceptTrustedOverlayUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::trustedOverlayUpdate,
+ SurfaceChange::SurfaceChangeCase::kTrustedOverlay);
+}
+
TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) {
captureTest(&SurfaceInterceptorTest::runAllUpdates,
&SurfaceInterceptorTest::assertAllUpdatesFound);
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
new file mode 100644
index 0000000..89228d5
--- /dev/null
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/android_filesystem_config.h>
+#include <future>
+#include "utils/TransactionUtils.h"
+
+namespace android {
+using Transaction = SurfaceComposerClient::Transaction;
+using gui::WindowInfo;
+
+class WindowInfosListenerTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ seteuid(AID_SYSTEM);
+ mClient = new SurfaceComposerClient;
+ mWindowInfosListener = new SyncWindowInfosListener();
+ mClient->addWindowInfosListener(mWindowInfosListener);
+ }
+
+ void TearDown() override {
+ mClient->removeWindowInfosListener(mWindowInfosListener);
+ seteuid(AID_ROOT);
+ }
+
+ struct SyncWindowInfosListener : public gui::WindowInfosListener {
+ public:
+ void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos) override {
+ windowInfosPromise.set_value(windowInfos);
+ }
+
+ std::vector<WindowInfo> waitForWindowInfos() {
+ std::future<std::vector<WindowInfo>> windowInfosFuture =
+ windowInfosPromise.get_future();
+ std::vector<WindowInfo> windowInfos = windowInfosFuture.get();
+ windowInfosPromise = std::promise<std::vector<WindowInfo>>();
+ return windowInfos;
+ }
+
+ private:
+ std::promise<std::vector<WindowInfo>> windowInfosPromise;
+ };
+
+ sp<SurfaceComposerClient> mClient;
+ sp<SyncWindowInfosListener> mWindowInfosListener;
+};
+
+std::optional<WindowInfo> findMatchingWindowInfo(WindowInfo targetWindowInfo,
+ std::vector<WindowInfo> windowInfos) {
+ std::optional<WindowInfo> foundWindowInfo = std::nullopt;
+ for (WindowInfo windowInfo : windowInfos) {
+ if (windowInfo.token == targetWindowInfo.token) {
+ foundWindowInfo = std::make_optional<>(windowInfo);
+ break;
+ }
+ }
+
+ return foundWindowInfo;
+}
+
+TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) {
+ std::string name = "Test Layer";
+ sp<IBinder> token = new BBinder();
+ WindowInfo windowInfo;
+ windowInfo.name = name;
+ windowInfo.token = token;
+ sp<SurfaceControl> surfaceControl =
+ mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+
+ Transaction()
+ .setLayerStack(surfaceControl, 0)
+ .show(surfaceControl)
+ .setLayer(surfaceControl, INT32_MAX - 1)
+ .setInputWindowInfo(surfaceControl, windowInfo)
+ .apply();
+
+ std::vector<WindowInfo> windowInfos = mWindowInfosListener->waitForWindowInfos();
+ std::optional<WindowInfo> foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ ASSERT_NE(std::nullopt, foundWindowInfo);
+
+ Transaction().reparent(surfaceControl, nullptr).apply();
+
+ windowInfos = mWindowInfosListener->waitForWindowInfos();
+ foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ ASSERT_EQ(std::nullopt, foundWindowInfo);
+}
+
+TEST_F(WindowInfosListenerTest, WindowInfoChanged) {
+ std::string name = "Test Layer";
+ sp<IBinder> token = new BBinder();
+ WindowInfo windowInfo;
+ windowInfo.name = name;
+ windowInfo.token = token;
+ sp<SurfaceControl> surfaceControl =
+ mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+
+ Transaction()
+ .setLayerStack(surfaceControl, 0)
+ .show(surfaceControl)
+ .setLayer(surfaceControl, INT32_MAX - 1)
+ .setInputWindowInfo(surfaceControl, windowInfo)
+ .apply();
+
+ std::vector<WindowInfo> windowInfos = mWindowInfosListener->waitForWindowInfos();
+ std::optional<WindowInfo> foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ ASSERT_NE(std::nullopt, foundWindowInfo);
+ ASSERT_TRUE(foundWindowInfo->touchableRegion.isEmpty());
+
+ Rect touchableRegions(0, 0, 50, 50);
+ windowInfo.addTouchableRegion(Rect(0, 0, 50, 50));
+ Transaction().setInputWindowInfo(surfaceControl, windowInfo).apply();
+
+ windowInfos = mWindowInfosListener->waitForWindowInfos();
+ foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos);
+ ASSERT_NE(std::nullopt, foundWindowInfo);
+ ASSERT_TRUE(foundWindowInfo->touchableRegion.hasSameRects(windowInfo.touchableRegion));
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index fca3bfc..98c1889 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -108,6 +108,8 @@
mComposer = new Hwc2::mock::Composer();
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ mFlinger.mutableMaxRenderTargetSize() = 16384;
}
~CompositionTest() {
@@ -519,8 +521,6 @@
static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) {
// TODO: Eliminate the complexity of actually creating a buffer
- EXPECT_CALL(*test->mRenderEngine, getMaxTextureSize()).WillOnce(Return(16384));
- EXPECT_CALL(*test->mRenderEngine, getMaxViewportDims()).WillOnce(Return(16384));
status_t err =
layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT,
LayerProperties::FORMAT);
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index dc04b6d..cd4a5c9 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -25,6 +25,7 @@
#include <gtest/gtest.h>
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/Hash.h"
using ::testing::ElementsAre;
@@ -134,7 +135,7 @@
}
uint32_t hash(const char* str) {
- return static_cast<uint32_t>(std::hash<std::string_view>()(str));
+ return static_cast<uint32_t>(cityHash64Len0To16(str));
}
} // namespace
@@ -309,9 +310,9 @@
ASSERT_TRUE(tertiaryInfo);
// Display IDs should be unique.
- EXPECT_NE(primaryInfo->id, secondaryInfo->id);
- EXPECT_NE(primaryInfo->id, tertiaryInfo->id);
- EXPECT_NE(secondaryInfo->id, tertiaryInfo->id);
+ EXPECT_EQ(4633257497453176576, primaryInfo->id.value);
+ EXPECT_EQ(4621520285560261121, secondaryInfo->id.value);
+ EXPECT_EQ(4633127902230889474, tertiaryInfo->id.value);
}
TEST(DisplayIdentificationTest, deviceProductInfo) {
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 6ce281d..de058a4 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -615,8 +615,8 @@
}
static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _, _))
- .WillOnce(DoAll(SetArgPointee<4>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
}
};
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 8e7554b..a4e9d20 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -487,5 +487,40 @@
EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate));
}
+TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ const auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ const auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ const auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ const auto childOfChild1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, childOfChild1);
+
+ childOfChild1->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+
+ addChild(parent, child2);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+
+ childOfChild1->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, childOfChild1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
index b713334..313ab03 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
@@ -282,7 +282,8 @@
}
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
- processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
+ EXPECT_EXIT(processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>(),
+ testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
@@ -290,96 +291,106 @@
}
TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) {
- using Case = SimplePrimaryDisplayCase;
+ EXPECT_EXIT(
+ [this] {
+ using Case = SimplePrimaryDisplayCase;
- // --------------------------------------------------------------------
- // Preconditions
+ // --------------------------------------------------------------------
+ // Preconditions
- setupCommonPreconditions<Case>();
+ setupCommonPreconditions<Case>();
- // A hotplug connect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
- // A hotplug disconnect event is also enqueued for the same display
- Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+ // A hotplug connect event is enqueued for a display
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+ // A hotplug disconnect event is also enqueued for the same display
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
- // --------------------------------------------------------------------
- // Call Expectations
+ // --------------------------------------------------------------------
+ // Call Expectations
- setupCommonCallExpectationsForConnectProcessing<Case>();
- setupCommonCallExpectationsForDisconnectProcessing<Case>();
+ setupCommonCallExpectationsForConnectProcessing<Case>();
+ setupCommonCallExpectationsForDisconnectProcessing<Case>();
- EXPECT_CALL(*mComposer,
- setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
- .WillOnce(Return(Error::NONE));
- EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(Case::Display::HWC_DISPLAY_ID,
+ IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+ EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
- // --------------------------------------------------------------------
- // Invocation
+ // --------------------------------------------------------------------
+ // Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
- // --------------------------------------------------------------------
- // Postconditions
+ // --------------------------------------------------------------------
+ // Postconditions
- // HWComposer should not have an entry for the display
- EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ // HWComposer should not have an entry for the display
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // SF should not have a display token.
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+ }(),
+ testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
- using Case = SimplePrimaryDisplayCase;
+ EXPECT_EXIT(
+ [this] {
+ using Case = SimplePrimaryDisplayCase;
- // --------------------------------------------------------------------
- // Preconditions
+ // --------------------------------------------------------------------
+ // Preconditions
- setupCommonPreconditions<Case>();
+ setupCommonPreconditions<Case>();
- // The display is already completely set up.
- Case::Display::injectHwcDisplay(this);
- auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
- existing.inject();
+ // The display is already completely set up.
+ Case::Display::injectHwcDisplay(this);
+ auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+ existing.inject();
- // A hotplug disconnect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
- // A hotplug connect event is also enqueued for the same display
- Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+ // A hotplug disconnect event is enqueued for a display
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+ // A hotplug connect event is also enqueued for the same display
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
- // --------------------------------------------------------------------
- // Call Expectations
+ // --------------------------------------------------------------------
+ // Call Expectations
- setupCommonCallExpectationsForConnectProcessing<Case>();
- setupCommonCallExpectationsForDisconnectProcessing<Case>();
+ setupCommonCallExpectationsForConnectProcessing<Case>();
+ setupCommonCallExpectationsForDisconnectProcessing<Case>();
- // --------------------------------------------------------------------
- // Invocation
+ // --------------------------------------------------------------------
+ // Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
- // --------------------------------------------------------------------
- // Postconditions
+ // --------------------------------------------------------------------
+ // Postconditions
- // The existing token should have been removed
- verifyDisplayIsNotConnected(existing.token());
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
- EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
+ // The existing token should have been removed
+ verifyDisplayIsNotConnected(existing.token());
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
+ EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
- // A new display should be connected in its place
+ // A new display should be connected in its place
- verifyPhysicalDisplayIsConnected<Case>();
+ verifyPhysicalDisplayIsConnected<Case>();
- // --------------------------------------------------------------------
- // Cleanup conditions
+ // --------------------------------------------------------------------
+ // Cleanup conditions
- EXPECT_CALL(*mComposer,
- setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
- .WillOnce(Return(Error::NONE));
- EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(Case::Display::HWC_DISPLAY_ID,
+ IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+ EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+ }(),
+ testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index e32c4bf..7ead0af 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -292,7 +292,9 @@
}
TEST_F(SetupNewDisplayDeviceInternalTest, createSimpleExternalDisplay) {
- setupNewDisplayDeviceInternalTest<SimpleExternalDisplayCase>();
+ // External displays must be secondary, as the primary display cannot be disconnected.
+ EXPECT_EXIT(setupNewDisplayDeviceInternalTest<SimpleExternalDisplayCase>(),
+ testing::KilledBySignal(SIGABRT), "Missing primary display");
}
TEST_F(SetupNewDisplayDeviceInternalTest, createNonHwcVirtualDisplay) {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index ad284e3..e036f4d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -227,7 +227,8 @@
mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, currMode);
const auto currFps = mRefreshRateConfigs->getCurrentRefreshRate().getFps();
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps);
- mFlinger->mVsyncModulator.emplace(mFlinger->mVsyncConfiguration->getCurrentConfigs());
+ mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
+ mFlinger->mVsyncConfiguration->getCurrentConfigs());
mFlinger->mRefreshRateStats =
std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
/*powerMode=*/hal::PowerMode::OFF);
@@ -434,11 +435,11 @@
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
+ auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; }
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
- auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
- auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
+ auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; }
auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
auto fromHandle(const sp<IBinder>& handle) {
@@ -598,13 +599,12 @@
LOG_ALWAYS_FATAL_IF(!physicalId);
flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, *physicalId);
if (mIsPrimary) {
- flinger->mutableInternalHwcDisplayId() = mHwcDisplayId;
+ flinger->mutablePrimaryHwcDisplayId() = mHwcDisplayId;
} else {
- // If there is an external HWC display there should always be an internal ID
+ // If there is an external HWC display, there should always be a primary ID
// as well. Set it to some arbitrary value.
- auto& internalId = flinger->mutableInternalHwcDisplayId();
- if (!internalId) internalId = mHwcDisplayId - 1;
- flinger->mutableExternalHwcDisplayId() = mHwcDisplayId;
+ auto& primaryId = flinger->mutablePrimaryHwcDisplayId();
+ if (!primaryId) primaryId = mHwcDisplayId - 1;
}
}
}
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index d59d64b..ddc02bf 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -942,6 +942,27 @@
EXPECT_THAT(cb.mReadyTime[0], 970);
}
+TEST_F(VSyncDispatchTimerQueueTest, updatesVsyncTimeForCloseWakeupTime) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+
+ CountingCallback cb(mDispatch);
+
+ mDispatch.schedule(cb, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb, {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000});
+
+ advanceToNextCallback();
+
+ advanceToNextCallback();
+
+ ASSERT_THAT(cb.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb.mCalls[0], Eq(2000));
+ ASSERT_THAT(cb.mWakeupTime.size(), Eq(1));
+ EXPECT_THAT(cb.mWakeupTime[0], Eq(600));
+ ASSERT_THAT(cb.mReadyTime.size(), Eq(1));
+ EXPECT_THAT(cb.mReadyTime[0], Eq(2000));
+}
+
class VSyncDispatchTimerQueueEntryTest : public testing::Test {
protected:
nsecs_t const mPeriod = 1000;
diff --git a/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
index 60952bf..b519582 100644
--- a/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <binder/Binder.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -21,6 +22,13 @@
namespace android::scheduler {
+class TestableVsyncModulator : public VsyncModulator {
+public:
+ TestableVsyncModulator(const VsyncConfigSet& config, Now now) : VsyncModulator(config, now) {}
+
+ void binderDied(const wp<IBinder>& token) { VsyncModulator::binderDied(token); }
+};
+
class VsyncModulatorTest : public testing::Test {
enum {
SF_OFFSET_LATE,
@@ -60,30 +68,31 @@
const VsyncModulator::VsyncConfigSet mOffsets = {kEarly, kEarlyGpu, kLate,
nanos(HWC_MIN_WORK_DURATION)};
- VsyncModulator mVsyncModulator{mOffsets, Now};
+ sp<TestableVsyncModulator> mVsyncModulator = sp<TestableVsyncModulator>::make(mOffsets, Now);
- void SetUp() override { EXPECT_EQ(kLate, mVsyncModulator.setVsyncConfigSet(mOffsets)); }
+ void SetUp() override { EXPECT_EQ(kLate, mVsyncModulator->setVsyncConfigSet(mOffsets)); }
};
-#define CHECK_COMMIT(result, configs) \
- EXPECT_EQ(result, mVsyncModulator.onTransactionCommit()); \
- EXPECT_EQ(configs, mVsyncModulator.getVsyncConfig());
+#define CHECK_COMMIT(result, configs) \
+ EXPECT_EQ(result, mVsyncModulator->onTransactionCommit()); \
+ EXPECT_EQ(configs, mVsyncModulator->getVsyncConfig());
-#define CHECK_REFRESH(N, result, configs) \
- for (int i = 0; i < N; i++) { \
- EXPECT_EQ(result, mVsyncModulator.onDisplayRefresh(false)); \
- EXPECT_EQ(configs, mVsyncModulator.getVsyncConfig()); \
+#define CHECK_REFRESH(N, result, configs) \
+ for (int i = 0; i < N; i++) { \
+ EXPECT_EQ(result, mVsyncModulator->onDisplayRefresh(false)); \
+ EXPECT_EQ(configs, mVsyncModulator->getVsyncConfig()); \
}
TEST_F(VsyncModulatorTest, Late) {
- EXPECT_FALSE(mVsyncModulator.setTransactionSchedule(Schedule::Late));
+ EXPECT_FALSE(mVsyncModulator->setTransactionSchedule(Schedule::Late));
CHECK_COMMIT(std::nullopt, kLate);
CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kLate);
}
TEST_F(VsyncModulatorTest, EarlyEnd) {
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+ const auto token = sp<BBinder>::make();
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyEnd, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
@@ -91,12 +100,13 @@
}
TEST_F(VsyncModulatorTest, EarlyStart) {
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
+ const auto token = sp<BBinder>::make();
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyStart, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyEnd, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
@@ -104,16 +114,17 @@
}
TEST_F(VsyncModulatorTest, EarlyStartWithMoreTransactions) {
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
+ const auto token = sp<BBinder>::make();
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyStart, token));
CHECK_COMMIT(kEarly, kEarly);
for (int i = 0; i < 5 * MIN_EARLY_TRANSACTION_FRAMES; i++) {
- EXPECT_FALSE(mVsyncModulator.setTransactionSchedule(Schedule::Late));
+ EXPECT_FALSE(mVsyncModulator->setTransactionSchedule(Schedule::Late));
CHECK_REFRESH(1, std::nullopt, kEarly);
}
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyEnd, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
@@ -121,18 +132,19 @@
}
TEST_F(VsyncModulatorTest, EarlyStartAfterEarlyEnd) {
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+ const auto token = sp<BBinder>::make();
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyEnd, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyStart, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(1, kEarly, kEarly);
CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyEnd, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
@@ -140,26 +152,64 @@
}
TEST_F(VsyncModulatorTest, EarlyStartAfterEarlyEndWithMoreTransactions) {
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+ const auto token = sp<BBinder>::make();
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyEnd, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyStart, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(1, kEarly, kEarly);
for (int i = 0; i < 5 * MIN_EARLY_TRANSACTION_FRAMES; i++) {
- EXPECT_FALSE(mVsyncModulator.setTransactionSchedule(Schedule::Late));
+ EXPECT_FALSE(mVsyncModulator->setTransactionSchedule(Schedule::Late));
CHECK_REFRESH(1, std::nullopt, kEarly);
}
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyEnd, token));
CHECK_COMMIT(kEarly, kEarly);
CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
CHECK_REFRESH(1, kLate, kLate);
}
+TEST_F(VsyncModulatorTest, EarlyStartDifferentClients) {
+ const auto token1 = sp<BBinder>::make();
+ const auto token2 = sp<BBinder>::make();
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyStart, token1));
+
+ CHECK_COMMIT(kEarly, kEarly);
+ CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
+
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyStart, token2));
+
+ CHECK_COMMIT(kEarly, kEarly);
+ CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
+
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyEnd, token1));
+
+ CHECK_COMMIT(kEarly, kEarly);
+ CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
+
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyEnd, token2));
+
+ CHECK_COMMIT(kEarly, kEarly);
+ CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
+ CHECK_REFRESH(1, kLate, kLate);
+}
+
+TEST_F(VsyncModulatorTest, EarlyStartWithBinderDeath) {
+ const auto token = sp<BBinder>::make();
+ EXPECT_EQ(kEarly, mVsyncModulator->setTransactionSchedule(Schedule::EarlyStart, token));
+
+ CHECK_COMMIT(kEarly, kEarly);
+ CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
+
+ mVsyncModulator->binderDied(token);
+
+ CHECK_COMMIT(std::nullopt, kLate);
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index cb3bd73..1ba3c0f 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -54,8 +54,7 @@
MOCK_METHOD0(resetCommands, void());
MOCK_METHOD0(executeCommands, Error());
MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t());
- MOCK_METHOD5(createVirtualDisplay,
- Error(uint32_t, uint32_t, PixelFormat*, std::optional<Display>, Display*));
+ MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*));
MOCK_METHOD1(destroyVirtualDisplay, Error(Display));
MOCK_METHOD1(acceptDisplayChanges, Error(Display));
MOCK_METHOD2(createLayer, Error(Display, Layer* outLayer));
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index d7fdab5..cf774fd 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -979,6 +979,8 @@
void QueryPresentationProperties(
VkPhysicalDevice physicalDevice,
VkPhysicalDevicePresentationPropertiesANDROID* presentation_properties) {
+ ATRACE_CALL();
+
// Request the android-specific presentation properties via GPDP2
VkPhysicalDeviceProperties2 properties = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
@@ -994,7 +996,17 @@
presentation_properties->pNext = nullptr;
presentation_properties->sharedImage = VK_FALSE;
- GetPhysicalDeviceProperties2(physicalDevice, &properties);
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceProperties2) {
+ // >= 1.1 driver, supports core GPDP2 entrypoint.
+ driver.GetPhysicalDeviceProperties2(physicalDevice, &properties);
+ } else if (driver.GetPhysicalDeviceProperties2KHR) {
+ // Old driver, but may support presentation properties
+ // if we have the GPDP2 extension. Otherwise, no presentation
+ // properties supported.
+ driver.GetPhysicalDeviceProperties2KHR(physicalDevice, &properties);
+ }
}
VkResult EnumerateDeviceExtensionProperties(