Merge "sf: send sideband frame to hwc when recieve a buffer"
diff --git a/cmds/cmd/fuzzer/Android.bp b/cmds/cmd/fuzzer/Android.bp
index 0c78c5a..8262bc2 100644
--- a/cmds/cmd/fuzzer/Android.bp
+++ b/cmds/cmd/fuzzer/Android.bp
@@ -14,6 +14,15 @@
* 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: [
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index f8fdaa0..3d2bdf1 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -21,7 +21,9 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <binder/BpBinder.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <binder/Stability.h>
@@ -58,27 +60,30 @@
}
static void usage() {
- fprintf(stderr,
- "usage: dumpsys\n"
- " To dump all services.\n"
- "or:\n"
- " 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"
- " --priority LEVEL: filter services based on specified priority\n"
- " LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
- " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
- " --stability: dump binder stability information instead of usual dump\n"
- " --thread: dump thread usage instead of usual dump\n"
- " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
+ fprintf(
+ stderr,
+ "usage: dumpsys\n"
+ " To dump all services.\n"
+ "or:\n"
+ " dumpsys [-t TIMEOUT] [--priority LEVEL] [--clients] [--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"
+ " --clients: dump client PIDs instead of usual dump\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"
+ " --priority LEVEL: filter services based on specified priority\n"
+ " LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
+ " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
+ " --stability: dump binder stability information instead of usual dump\n"
+ " --thread: dump thread usage instead of usual dump\n"
+ " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
}
static bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
@@ -131,15 +136,12 @@
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},
- {"skip", no_argument, 0, 0},
- {"stability", no_argument, 0, 0},
- {"thread", no_argument, 0, 0},
- {0, 0, 0, 0}};
+ static struct option longOptions[] = {
+ {"help", no_argument, 0, 0}, {"clients", no_argument, 0, 0},
+ {"dump", no_argument, 0, 0}, {"pid", no_argument, 0, 0},
+ {"priority", required_argument, 0, 0}, {"proto", no_argument, 0, 0},
+ {"skip", no_argument, 0, 0}, {"stability", no_argument, 0, 0},
+ {"thread", no_argument, 0, 0}, {0, 0, 0, 0}};
// Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
// happens on test cases).
@@ -178,6 +180,8 @@
dumpTypeFlags |= TYPE_STABILITY;
} else if (!strcmp(longOptions[optionIndex].name, "thread")) {
dumpTypeFlags |= TYPE_THREAD;
+ } else if (!strcmp(longOptions[optionIndex].name, "clients")) {
+ dumpTypeFlags |= TYPE_CLIENTS;
}
break;
@@ -373,6 +377,35 @@
return OK;
}
+static status_t dumpClientsToFd(const sp<IBinder>& service, const unique_fd& fd) {
+ std::string clientPids;
+ const auto remoteBinder = service->remoteBinder();
+ if (remoteBinder == nullptr) {
+ WriteStringToFd("Client PIDs are not available for local binders.\n", fd.get());
+ return OK;
+ }
+ const auto handle = remoteBinder->getDebugBinderHandle();
+ if (handle == std::nullopt) {
+ return OK;
+ }
+ std::vector<pid_t> pids;
+ pid_t myPid = getpid();
+ pid_t servicePid;
+ status_t status = service->getDebugPid(&servicePid);
+ if (status != OK) {
+ return status;
+ }
+ status =
+ getBinderClientPids(BinderDebugContext::BINDER, myPid, servicePid, handle.value(), &pids);
+ if (status != OK) {
+ return status;
+ }
+ pids.erase(std::remove_if(pids.begin(), pids.end(), [&](pid_t pid) { return pid == myPid; }),
+ pids.end());
+ WriteStringToFd("Client PIDs: " + ::android::base::Join(pids, ", ") + "\n", fd.get());
+ return OK;
+}
+
static void reportDumpError(const String16& serviceName, status_t error, const char* context) {
if (error == OK) return;
@@ -413,6 +446,10 @@
status_t err = dumpThreadsToFd(service, remote_end);
reportDumpError(serviceName, err, "dumping thread info");
}
+ if (dumpTypeFlags & TYPE_CLIENTS) {
+ status_t err = dumpClientsToFd(service, remote_end);
+ reportDumpError(serviceName, err, "dumping clients info");
+ }
// other types always act as a header, this is usually longer
if (dumpTypeFlags & TYPE_DUMP) {
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 05c5d5e..6ab1a7d 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -52,10 +52,11 @@
static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
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
+ 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
+ TYPE_CLIENTS = 0x10, // dump pid of clients
};
/**
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 312f4d7..fa63db5 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -627,6 +627,29 @@
AssertOutputFormat(format);
}
+// Tests 'dumpsys --clients'
+TEST_F(DumpsysTest, ListAllServicesWithClients) {
+ ExpectListServices({"Locksmith", "Valet"});
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet");
+
+ CallMain({"--clients"});
+
+ AssertRunningServices({"Locksmith", "Valet"});
+
+ const std::string format("(.|\n)*((Client PIDs are not available for local binders.)(.|\n)*){2}");
+ AssertOutputFormat(format);
+}
+
+// Tests 'dumpsys --clients service_name'
+TEST_F(DumpsysTest, ListServiceWithClients) {
+ ExpectCheckService("Locksmith");
+
+ CallMain({"--clients", "Locksmith"});
+
+ const std::string format("Client PIDs are not available for local binders.\n");
+ AssertOutputFormat(format);
+}
// Tests 'dumpsys --thread --stability'
TEST_F(DumpsysTest, ListAllServicesWithMultipleOptions) {
ExpectListServices({"Locksmith", "Valet"});
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/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index cfd42fe..3f7c7d6 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -528,7 +528,7 @@
void Replayer::setLayerStack(SurfaceComposerClient::Transaction& t,
layer_id id, const LayerStackChange& lsc) {
ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack());
- t.setLayerStack(mLayers[id], lsc.layer_stack());
+ t.setLayerStack(mLayers[id], ui::LayerStack::fromValue(lsc.layer_stack()));
}
void Replayer::setHiddenFlag(SurfaceComposerClient::Transaction& t,
@@ -566,7 +566,7 @@
void Replayer::setDisplayLayerStack(SurfaceComposerClient::Transaction& t,
display_id id, const LayerStackChange& lsc) {
- t.setDisplayLayerStack(mDisplays[id], lsc.layer_stack());
+ t.setDisplayLayerStack(mDisplays[id], ui::LayerStack::fromValue(lsc.layer_stack()));
}
void Replayer::setDisplaySize(SurfaceComposerClient::Transaction& t,
diff --git a/include/ftl/NamedEnum.h b/include/ftl/NamedEnum.h
index f50ff46..6e98fee 100644
--- a/include/ftl/NamedEnum.h
+++ b/include/ftl/NamedEnum.h
@@ -49,6 +49,10 @@
// Example (cont'd): V = android::test::TestEnums::ONE
view = view.substr(valStart);
+ // Check invalid enum values with cast, like V = (android::test::TestEnums)8.
+ if (view.find('(') != std::string::npos) {
+ return std::nullopt;
+ }
size_t nameStart = view.rfind("::");
if (nameStart == std::string::npos) {
return std::nullopt;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index d7112b5..20bf301 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -101,6 +101,7 @@
"BpBinder.cpp",
"BufferedTextOutput.cpp",
"Debug.cpp",
+ "FdTrigger.cpp",
"IInterface.cpp",
"IMemory.cpp",
"IPCThreadState.cpp",
@@ -120,6 +121,7 @@
"RpcSession.cpp",
"RpcServer.cpp",
"RpcState.cpp",
+ "RpcTransportRaw.cpp",
"Static.cpp",
"Stability.cpp",
"Status.cpp",
@@ -144,9 +146,6 @@
enabled: false,
},
host: {
- static_libs: [
- "libbase",
- ],
srcs: [
"ServiceManagerHost.cpp",
"UtilsHost.cpp",
@@ -187,6 +186,10 @@
"libutils",
],
+ static_libs: [
+ "libbase",
+ ],
+
header_libs: [
"libbinder_headers",
"libandroid_runtime_vm_headers",
@@ -229,6 +232,42 @@
},
}
+cc_defaults {
+ name: "libbinder_tls_shared_deps",
+ shared_libs: [
+ "libbinder",
+ "libcrypto",
+ "liblog",
+ "libssl",
+ "libutils",
+ ],
+}
+
+cc_defaults {
+ name: "libbinder_tls_defaults",
+ defaults: ["libbinder_tls_shared_deps"],
+ host_supported: true,
+
+ header_libs: [
+ "libbinder_headers",
+ ],
+ export_header_lib_headers: [
+ "libbinder_headers",
+ ],
+ export_include_dirs: ["include_tls"],
+ static_libs: [
+ "libbase",
+ ],
+ srcs: [
+ "RpcTransportTls.cpp",
+ ],
+}
+
+cc_library_shared {
+ name: "libbinder_tls",
+ defaults: ["libbinder_tls_defaults"],
+}
+
// AIDL interface between libbinder and framework.jar
filegroup {
name: "libbinder_aidl",
@@ -247,6 +286,9 @@
"aidl/android/content/pm/IPackageChangeObserver.aidl",
"aidl/android/content/pm/IPackageManagerNative.aidl",
"aidl/android/content/pm/PackageChangeEvent.aidl",
+ "aidl/android/content/pm/IStagedApexObserver.aidl",
+ "aidl/android/content/pm/ApexStagedEvent.aidl",
+ "aidl/android/content/pm/StagedApexInfo.aidl",
],
path: "aidl",
}
@@ -354,5 +396,6 @@
"libbinder",
"liblog",
"libutils",
+ "android.debug_aidl-cpp",
],
}
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 628381c..d3eef4e 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -555,7 +555,9 @@
return status;
}
rpcServer->setRootObjectWeak(weakThis);
- rpcServer->setupExternalServer(std::move(socketFd));
+ if (auto status = rpcServer->setupExternalServer(std::move(socketFd)); status != OK) {
+ return status;
+ }
rpcServer->setMaxThreads(binderThreadPoolMaxCount);
rpcServer->start();
e->mRpcServerLinks.emplace(link);
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 765e21c..55566e2 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -188,6 +188,14 @@
return std::get<BinderHandle>(mHandle).handle;
}
+std::optional<int32_t> BpBinder::getDebugBinderHandle() const {
+ if (!isRpcBinder()) {
+ return binderHandle();
+ } else {
+ return std::nullopt;
+ }
+}
+
bool BpBinder::isDescriptorCached() const {
Mutex::Autolock _l(mLock);
return mDescriptorCache.size() ? true : false;
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/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
new file mode 100644
index 0000000..b197a6a
--- /dev/null
+++ b/libs/binder/FdTrigger.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 "FdTrigger"
+#include <log/log.h>
+
+#include <poll.h>
+
+#include <android-base/macros.h>
+
+#include "FdTrigger.h"
+namespace android {
+
+std::unique_ptr<FdTrigger> FdTrigger::make() {
+ auto ret = std::make_unique<FdTrigger>();
+ if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
+ ALOGE("Could not create pipe %s", strerror(errno));
+ return nullptr;
+ }
+ return ret;
+}
+
+void FdTrigger::trigger() {
+ mWrite.reset();
+}
+
+bool FdTrigger::isTriggered() {
+ return mWrite == -1;
+}
+
+status_t FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
+ while (true) {
+ pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
+ {.fd = mRead.get(), .events = 0, .revents = 0}};
+ int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
+ if (ret < 0) {
+ return -errno;
+ }
+ if (ret == 0) {
+ continue;
+ }
+ if (pfd[1].revents & POLLHUP) {
+ return -ECANCELED;
+ }
+ return pfd[0].revents & event ? OK : DEAD_OBJECT;
+ }
+}
+
+android::base::Result<bool> FdTrigger::isTriggeredPolled() {
+ pollfd pfd{.fd = mRead.get(), .events = 0, .revents = 0};
+ int ret = TEMP_FAILURE_RETRY(poll(&pfd, 1, 0));
+ if (ret < 0) {
+ return android::base::ErrnoError() << "FdTrigger::isTriggeredPolled: Error in poll()";
+ }
+ if (ret == 0) {
+ return false;
+ }
+ if (pfd.revents & POLLHUP) {
+ return true;
+ }
+ return android::base::Error() << "FdTrigger::isTriggeredPolled: poll() returns " << pfd.revents;
+}
+
+} // namespace android
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
new file mode 100644
index 0000000..a428417
--- /dev/null
+++ b/libs/binder/FdTrigger.h
@@ -0,0 +1,67 @@
+/*
+ * 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 <memory>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+/** This is not a pipe. */
+class FdTrigger {
+public:
+ /** Returns nullptr for error case */
+ static std::unique_ptr<FdTrigger> make();
+
+ /**
+ * Close the write end of the pipe so that the read end receives POLLHUP.
+ * Not threadsafe.
+ */
+ void trigger();
+
+ /**
+ * Check whether this has been triggered by checking the write end.
+ */
+ bool isTriggered();
+
+ /**
+ * Poll for a read event.
+ *
+ * event - for pollfd
+ *
+ * Return:
+ * true - time to read!
+ * false - trigger happened
+ */
+ status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
+
+ /**
+ * Check whether this has been triggered by poll()ing the read end.
+ *
+ * Return:
+ * true - triggered
+ * false - not triggered
+ * error - error when polling
+ */
+ android::base::Result<bool> isTriggeredPolled();
+
+private:
+ base::unique_fd mWrite;
+ base::unique_fd mRead;
+};
+} // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 650a108..52a6cf1 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -409,7 +409,7 @@
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
if (result == -1) {
- ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+ ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
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 62ea187..a20445b 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -26,8 +26,10 @@
#include <android-base/scopeguard.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
+#include <binder/RpcTransportRaw.h>
#include <log/log.h>
+#include "FdTrigger.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
#include "RpcWireFormat.h"
@@ -37,39 +39,42 @@
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() {
mAgreedExperimental = true;
}
-bool RpcServer::setupUnixDomainServer(const char* path) {
+status_t RpcServer::setupUnixDomainServer(const char* path) {
return setupSocketServer(UnixSocketAddress(path));
}
-bool RpcServer::setupVsockServer(unsigned int port) {
+status_t RpcServer::setupVsockServer(unsigned int port) {
// realizing value w/ this type at compile time to avoid ubsan abort
constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
return setupSocketServer(VsockSocketAddress(kAnyCid, port));
}
-bool RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) {
- const char* kAddr = "127.0.0.1";
-
+status_t RpcServer::setupInetServer(const char* address, unsigned int port,
+ unsigned int* assignedPort) {
if (assignedPort != nullptr) *assignedPort = 0;
- auto aiStart = InetSocketAddress::getAddrInfo(kAddr, port);
- if (aiStart == nullptr) return false;
+ auto aiStart = InetSocketAddress::getAddrInfo(address, port);
+ if (aiStart == nullptr) return UNKNOWN_ERROR;
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
- InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
- if (!setupSocketServer(socketAddress)) {
+ InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, address, port);
+ if (status_t status = setupSocketServer(socketAddress); status != OK) {
continue;
}
@@ -80,7 +85,7 @@
int savedErrno = errno;
ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
strerror(savedErrno));
- return false;
+ return -savedErrno;
}
LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu",
static_cast<size_t>(len), sizeof(addr));
@@ -93,11 +98,11 @@
*assignedPort = realPort;
}
- return true;
+ return OK;
}
- 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;
+ return UNKNOWN_ERROR;
}
void RpcServer::setMaxThreads(size_t threads) {
@@ -152,14 +157,18 @@
LOG_ALWAYS_FATAL_IF(!mServer.ok(), "RpcServer must be setup to join.");
LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
mJoinThreadRunning = true;
- mShutdownTrigger = RpcSession::FdTrigger::make();
+ mShutdownTrigger = 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;
while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
unique_fd clientFd(TEMP_FAILURE_RETRY(
- accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC)));
+ accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC | SOCK_NONBLOCK)));
if (clientFd < 0) {
ALOGE("Could not accept4 socket: %s", strerror(errno));
@@ -220,6 +229,7 @@
LOG_RPC_DETAIL("Finished waiting on shutdown.");
mShutdownTrigger = nullptr;
+ mCtx = nullptr;
return true;
}
@@ -245,14 +255,29 @@
// 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), server->mShutdownTrigger.get());
+ 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));
- 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
+ if (status == OK) {
+ status = client->interruptableReadFully(server->mShutdownTrigger.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 = false;
@@ -272,8 +297,8 @@
.version = protocolVersion,
};
- status = server->mShutdownTrigger->interruptableWriteFully(clientFd.get(), &response,
- sizeof(response));
+ status = client->interruptableWriteFully(server->mShutdownTrigger.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
@@ -342,7 +367,7 @@
}
if (incoming) {
- LOG_ALWAYS_FATAL_IF(!session->addOutgoingConnection(std::move(clientFd), true),
+ LOG_ALWAYS_FATAL_IF(OK != session->addOutgoingConnection(std::move(client), true),
"server state must already be initialized");
return;
}
@@ -351,7 +376,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;
@@ -359,21 +384,22 @@
RpcSession::join(std::move(session), std::move(setupResult));
}
-bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
+status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
- unique_fd serverFd(
- TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ unique_fd serverFd(TEMP_FAILURE_RETRY(
+ socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
if (serverFd == -1) {
- ALOGE("Could not create socket: %s", strerror(errno));
- return false;
+ int savedErrno = errno;
+ ALOGE("Could not create socket: %s", strerror(savedErrno));
+ return -savedErrno;
}
if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
int savedErrno = errno;
ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
- return false;
+ return -savedErrno;
}
// Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
@@ -383,16 +409,16 @@
if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 50 /*backlog*/))) {
int savedErrno = errno;
ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
- return false;
+ return -savedErrno;
}
LOG_RPC_DETAIL("Successfully setup socket server %s", addr.toString().c_str());
- if (!setupExternalServer(std::move(serverFd))) {
+ if (status_t status = setupExternalServer(std::move(serverFd)); status != OK) {
ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
- return false;
+ return status;
}
- return true;
+ return OK;
}
void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
@@ -425,15 +451,15 @@
return std::move(mServer);
}
-bool RpcServer::setupExternalServer(base::unique_fd serverFd) {
+status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
std::lock_guard<std::mutex> _l(mLock);
if (mServer.ok()) {
ALOGE("Each RpcServer can only have one server.");
- return false;
+ return INVALID_OPERATION;
}
mServer = std::move(serverFd);
- return true;
+ return OK;
}
} // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 254b99c..4c47005 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -30,13 +30,16 @@
#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>
+#include "FdTrigger.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
#include "RpcWireFormat.h"
+#include "Utils.h"
#ifdef __GLIBC__
extern "C" pid_t gettid();
@@ -46,7 +49,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 +63,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) {
@@ -102,34 +109,63 @@
return mProtocolVersion;
}
-bool RpcSession::setupUnixDomainClient(const char* path) {
+status_t RpcSession::setupUnixDomainClient(const char* path) {
return setupSocketClient(UnixSocketAddress(path));
}
-bool RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
+status_t RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
return setupSocketClient(VsockSocketAddress(cid, port));
}
-bool RpcSession::setupInetClient(const char* addr, unsigned int port) {
+status_t RpcSession::setupInetClient(const char* addr, unsigned int port) {
auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
- if (aiStart == nullptr) return false;
+ if (aiStart == nullptr) return UNKNOWN_ERROR;
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
- if (setupSocketClient(socketAddress)) return true;
+ if (status_t status = setupSocketClient(socketAddress); status == OK) return OK;
}
ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
- return false;
+ return NAME_NOT_FOUND;
}
-bool RpcSession::addNullDebuggingClient() {
+status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
+ return setupClient([&](const RpcAddress& sessionId, bool incoming) -> status_t {
+ // std::move'd from fd becomes -1 (!ok())
+ if (!fd.ok()) {
+ fd = request();
+ if (!fd.ok()) return BAD_VALUE;
+ }
+ if (auto res = setNonBlocking(fd); !res.ok()) {
+ ALOGE("setupPreconnectedClient: %s", res.error().message().c_str());
+ return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code();
+ }
+ return initAndAddConnection(std::move(fd), sessionId, incoming);
+ });
+}
+
+status_t RpcSession::addNullDebuggingClient() {
+ // Note: only works on raw sockets.
+ if (auto status = initShutdownTrigger(); status != OK) return status;
+
unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
if (serverFd == -1) {
- ALOGE("Could not connect to /dev/null: %s", strerror(errno));
- return false;
+ int savedErrno = errno;
+ ALOGE("Could not connect to /dev/null: %s", strerror(savedErrno));
+ return -savedErrno;
}
- return addOutgoingConnection(std::move(serverFd), false);
+ auto ctx = mRpcTransportCtxFactory->newClientCtx();
+ if (ctx == nullptr) {
+ ALOGE("Unable to create RpcTransportCtx for null debugging client");
+ return NO_MEMORY;
+ }
+ auto server = ctx->newTransport(std::move(serverFd), mShutdownTrigger.get());
+ if (server == nullptr) {
+ ALOGE("Unable to set up RpcTransport");
+ return UNKNOWN_ERROR;
+ }
+ return addOutgoingConnection(std::move(server), false);
}
sp<IBinder> RpcSession::getRootObject() {
@@ -188,83 +224,6 @@
return state()->sendDecStrong(connection.get(), sp<RpcSession>::fromExisting(this), address);
}
-std::unique_ptr<RpcSession::FdTrigger> RpcSession::FdTrigger::make() {
- auto ret = std::make_unique<RpcSession::FdTrigger>();
- if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
- ALOGE("Could not create pipe %s", strerror(errno));
- return nullptr;
- }
- return ret;
-}
-
-void RpcSession::FdTrigger::trigger() {
- mWrite.reset();
-}
-
-bool RpcSession::FdTrigger::isTriggered() {
- return mWrite == -1;
-}
-
-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), .revents = 0},
- {.fd = mRead.get(), .events = POLLHUP, .revents = 0}};
- int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
- if (ret < 0) {
- return -errno;
- }
- if (ret == 0) {
- continue;
- }
- if (pfd[1].revents & POLLHUP) {
- return -ECANCELED;
- }
- return pfd[0].revents & event ? OK : DEAD_OBJECT;
- }
-}
-
-status_t RpcSession::FdTrigger::interruptableWriteFully(base::borrowed_fd fd, 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;
- }
- buffer += writeSize;
- if (buffer == end) return OK;
- }
- return status;
-}
-
-status_t RpcSession::FdTrigger::interruptableReadFully(base::borrowed_fd fd, void* data,
- size_t size) {
- uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
- uint8_t* end = buffer + size;
-
- 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;
- }
- buffer += readSize;
- if (buffer == end) return OK;
- }
- return status;
-}
-
status_t RpcSession::readId() {
{
std::lock_guard<std::mutex> _l(mMutex);
@@ -312,10 +271,11 @@
}
}
-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;
@@ -439,48 +399,48 @@
return server;
}
-bool RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+status_t RpcSession::setupClient(
+ const std::function<status_t(const RpcAddress& sessionId, bool incoming)>& connectAndInit) {
{
std::lock_guard<std::mutex> _l(mMutex);
LOG_ALWAYS_FATAL_IF(mOutgoingConnections.size() != 0,
"Must only setup session once, but already has %zu clients",
mOutgoingConnections.size());
}
+ if (auto status = initShutdownTrigger(); status != OK) return status;
- if (!setupOneSocketConnection(addr, RpcAddress::zero(), false /*incoming*/)) return false;
+ if (status_t status = connectAndInit(RpcAddress::zero(), false /*incoming*/); status != OK)
+ return status;
{
ExclusiveConnection connection;
- status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
- ConnectionUse::CLIENT, &connection);
- if (status != OK) return false;
+ if (status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+ ConnectionUse::CLIENT, &connection);
+ status != OK)
+ return status;
uint32_t version;
- status = state()->readNewSessionResponse(connection.get(),
- sp<RpcSession>::fromExisting(this), &version);
- if (!setProtocolVersion(version)) return false;
+ if (status_t status =
+ state()->readNewSessionResponse(connection.get(),
+ sp<RpcSession>::fromExisting(this), &version);
+ status != OK)
+ return status;
+ if (!setProtocolVersion(version)) return BAD_VALUE;
}
// 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;
+ return status;
}
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;
+ return status;
}
// TODO(b/189955605): we should add additional sessions dynamically
@@ -489,25 +449,38 @@
// requested to be set) in order to allow the other side to reliably make
// any requests at all.
- for (size_t i = 0; i < mMaxThreads; i++) {
- if (!setupOneSocketConnection(addr, mId.value(), true /*incoming*/)) return false;
+ // we've already setup one client
+ for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
+ if (status_t status = connectAndInit(mId.value(), false /*incoming*/); status != OK)
+ return status;
}
- return true;
+ for (size_t i = 0; i < mMaxThreads; i++) {
+ if (status_t status = connectAndInit(mId.value(), true /*incoming*/); status != OK)
+ return status;
+ }
+
+ return OK;
}
-bool RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, const RpcAddress& id,
- bool incoming) {
+status_t RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+ return setupClient([&](const RpcAddress& sessionId, bool incoming) {
+ return setupOneSocketConnection(addr, sessionId, incoming);
+ });
+}
+
+status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
+ const RpcAddress& sessionId, bool incoming) {
for (size_t tries = 0; tries < 5; tries++) {
if (tries > 0) usleep(10000);
- unique_fd serverFd(
- TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ unique_fd serverFd(TEMP_FAILURE_RETRY(
+ socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
if (serverFd == -1) {
int savedErrno = errno;
ALOGE("Could not create socket at %s: %s", addr.toString().c_str(),
strerror(savedErrno));
- return false;
+ return -savedErrno;
}
if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
@@ -515,41 +488,87 @@
ALOGW("Connection reset on %s", addr.toString().c_str());
continue;
}
- int savedErrno = errno;
- ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
- strerror(savedErrno));
- return false;
+ if (errno != EAGAIN && errno != EINPROGRESS) {
+ int savedErrno = errno;
+ ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
+ strerror(savedErrno));
+ return -savedErrno;
+ }
+ // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
+ // EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
+ status_t pollStatus = mShutdownTrigger->triggerablePoll(serverFd, POLLOUT);
+ if (pollStatus != OK) {
+ ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
+ statusToString(pollStatus).c_str());
+ return pollStatus;
+ }
+ int soError;
+ socklen_t soErrorLen = sizeof(soError);
+ int ret = getsockopt(serverFd.get(), SOL_SOCKET, SO_ERROR, &soError, &soErrorLen);
+ if (ret == -1) {
+ int savedErrno = errno;
+ ALOGE("Could not getsockopt() after connect() on non-blocking socket: %s",
+ strerror(savedErrno));
+ return -savedErrno;
+ }
+ if (soError != 0) {
+ ALOGE("After connect(), getsockopt() returns error for socket at %s: %s",
+ addr.toString().c_str(), strerror(soError));
+ return -soError;
+ }
}
-
- RpcConnectionHeader header{
- .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
- .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;
+ return UNKNOWN_ERROR;
}
-bool RpcSession::addIncomingConnection(unique_fd fd) {
+status_t RpcSession::initAndAddConnection(unique_fd fd, const RpcAddress& sessionId,
+ bool incoming) {
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr);
+ auto ctx = mRpcTransportCtxFactory->newClientCtx();
+ if (ctx == nullptr) {
+ ALOGE("Unable to create client RpcTransportCtx with %s sockets",
+ mRpcTransportCtxFactory->toCString());
+ return NO_MEMORY;
+ }
+ auto server = ctx->newTransport(std::move(fd), mShutdownTrigger.get());
+ if (server == nullptr) {
+ ALOGE("Unable to set up RpcTransport in %s context", mRpcTransportCtxFactory->toCString());
+ return UNKNOWN_ERROR;
+ }
+
+ 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 sendHeaderStatus =
+ server->interruptableWriteFully(mShutdownTrigger.get(), &header, sizeof(header));
+ if (sendHeaderStatus != OK) {
+ ALOGE("Could not write connection header to socket: %s",
+ statusToString(sendHeaderStatus).c_str());
+ return sendHeaderStatus;
+ }
+
+ LOG_RPC_DETAIL("Socket at client: header sent");
+
+ if (incoming) {
+ return addIncomingConnection(std::move(server));
+ } else {
+ return addOutgoingConnection(std::move(server), true /*init*/);
+ }
+}
+
+status_t RpcSession::addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport) {
std::mutex mutex;
std::condition_variable joinCv;
std::unique_lock<std::mutex> lock(mutex);
@@ -558,13 +577,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();
@@ -575,23 +594,25 @@
});
joinCv.wait(lock, [&] { return ownershipTransferred; });
LOG_ALWAYS_FATAL_IF(!ownershipTransferred);
- return true;
+ return OK;
}
-bool RpcSession::addOutgoingConnection(unique_fd fd, bool init) {
+status_t RpcSession::initShutdownTrigger() {
+ // first client connection added, but setForServer not called, so
+ // initializaing for a client.
+ if (mShutdownTrigger == nullptr) {
+ mShutdownTrigger = FdTrigger::make();
+ mEventListener = mShutdownListener = sp<WaitForShutdownListener>::make();
+ if (mShutdownTrigger == nullptr) return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t RpcSession::addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport, bool init) {
sp<RpcConnection> connection = sp<RpcConnection>::make();
{
std::lock_guard<std::mutex> _l(mMutex);
-
- // first client connection added, but setForServer not called, so
- // initializaing for a client.
- if (mShutdownTrigger == nullptr) {
- mShutdownTrigger = FdTrigger::make();
- mEventListener = mShutdownListener = sp<WaitForShutdownListener>::make();
- if (mShutdownTrigger == nullptr) return false;
- }
-
- connection->fd = std::move(fd);
+ connection->rpcTransport = std::move(rpcTransport);
connection->exclusiveTid = gettid();
mOutgoingConnections.push_back(connection);
}
@@ -606,7 +627,7 @@
connection->exclusiveTid = std::nullopt;
}
- return status == OK;
+ return status;
}
bool RpcSession::setForServer(const wp<RpcServer>& server, const wp<EventListener>& eventListener,
@@ -626,9 +647,16 @@
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
@@ -638,7 +666,7 @@
}
sp<RpcConnection> session = sp<RpcConnection>::make();
- session->fd = std::move(fd);
+ session->rpcTransport = std::move(rpcTransport);
session->exclusiveTid = gettid();
mIncomingConnections.push_back(session);
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index f3406bb..b58f1b3 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 =
+ connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.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,16 @@
}
if (status_t status =
- session->mShutdownTrigger->interruptableReadFully(connection->fd.get(), data, size);
+ connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.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;
}
@@ -489,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,
@@ -584,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));
@@ -597,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/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
new file mode 100644
index 0000000..d77fc52
--- /dev/null
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 <poll.h>
+
+#include <binder/RpcTransportRaw.h>
+
+#include "FdTrigger.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) {
+ 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) {
+ 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));
+ if (ret < 0) {
+ return ErrnoError() << "recv(MSG_PEEK)";
+ }
+ return ret;
+ }
+
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size) override {
+ 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 = fdTrigger->triggerablePoll(mSocket.get(), POLLOUT)) == OK) {
+ auto writeSize = this->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();
+ }
+
+ if (*writeSize == 0) return DEAD_OBJECT;
+
+ buffer += *writeSize;
+ if (buffer == end) return OK;
+ }
+ return status;
+ }
+
+ status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) override {
+ uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
+ uint8_t* end = buffer + size;
+
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ status_t status;
+ while ((status = fdTrigger->triggerablePoll(mSocket.get(), POLLIN)) == OK) {
+ auto readSize = this->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();
+ }
+
+ if (*readSize == 0) return DEAD_OBJECT; // EOF
+
+ buffer += *readSize;
+ if (buffer == end) return OK;
+ }
+ return status;
+ }
+
+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, FdTrigger*) 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/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
new file mode 100644
index 0000000..a102913
--- /dev/null
+++ b/libs/binder/RpcTransportTls.cpp
@@ -0,0 +1,535 @@
+/*
+ * 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 "RpcTransportTls"
+#include <log/log.h>
+
+#include <poll.h>
+
+#include <openssl/bn.h>
+#include <openssl/ssl.h>
+
+#include <binder/RpcTransportTls.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+#define SHOULD_LOG_TLS_DETAIL false
+
+#if SHOULD_LOG_TLS_DETAIL
+#define LOG_TLS_DETAIL(...) ALOGI(__VA_ARGS__)
+#else
+#define LOG_TLS_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
+#endif
+
+#define TEST_AND_RETURN(value, expr) \
+ do { \
+ if (!(expr)) { \
+ ALOGE("Failed to call: %s", #expr); \
+ return value; \
+ } \
+ } while (0)
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+
+namespace android {
+namespace {
+
+constexpr const int kCertValidDays = 30;
+
+// Implement BIO for socket that ignores SIGPIPE.
+int socketNew(BIO* bio) {
+ BIO_set_data(bio, reinterpret_cast<void*>(-1));
+ BIO_set_init(bio, 0);
+ return 1;
+}
+int socketFree(BIO* bio) {
+ LOG_ALWAYS_FATAL_IF(bio == nullptr);
+ return 1;
+}
+int socketRead(BIO* bio, char* buf, int size) {
+ android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio))));
+ int ret = TEMP_FAILURE_RETRY(::recv(fd.get(), buf, size, MSG_NOSIGNAL));
+ BIO_clear_retry_flags(bio);
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ BIO_set_retry_read(bio);
+ }
+ return ret;
+}
+
+int socketWrite(BIO* bio, const char* buf, int size) {
+ android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio))));
+ int ret = TEMP_FAILURE_RETRY(::send(fd.get(), buf, size, MSG_NOSIGNAL));
+ BIO_clear_retry_flags(bio);
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ BIO_set_retry_write(bio);
+ }
+ return ret;
+}
+
+long socketCtrl(BIO* bio, int cmd, long num, void*) { // NOLINT
+ android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio))));
+ if (cmd == BIO_CTRL_FLUSH) return 1;
+ LOG_ALWAYS_FATAL("sockCtrl(fd=%d, %d, %ld)", fd.get(), cmd, num);
+ return 0;
+}
+
+bssl::UniquePtr<BIO> newSocketBio(android::base::borrowed_fd fd) {
+ static const BIO_METHOD* gMethods = ([] {
+ auto methods = BIO_meth_new(BIO_get_new_index(), "socket_no_signal");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_write(methods, socketWrite), "BIO_meth_set_write");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_read(methods, socketRead), "BIO_meth_set_read");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_ctrl(methods, socketCtrl), "BIO_meth_set_ctrl");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_create(methods, socketNew), "BIO_meth_set_create");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_destroy(methods, socketFree), "BIO_meth_set_destroy");
+ return methods;
+ })();
+ bssl::UniquePtr<BIO> ret(BIO_new(gMethods));
+ if (ret == nullptr) return nullptr;
+ BIO_set_data(ret.get(), reinterpret_cast<void*>(fd.get()));
+ BIO_set_init(ret.get(), 1);
+ return ret;
+}
+
+bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert() {
+ bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+ if (ec_key == nullptr || !EC_KEY_generate_key(ec_key.get())) {
+ ALOGE("Failed to generate key pair.");
+ return nullptr;
+ }
+ bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new());
+ // Use set1 instead of assign to avoid leaking ec_key when assign fails. set1 increments
+ // the refcount of the ec_key, so it is okay to release it at the end of this function.
+ if (evp_pkey == nullptr || !EVP_PKEY_set1_EC_KEY(evp_pkey.get(), ec_key.get())) {
+ ALOGE("Failed to assign key pair.");
+ return nullptr;
+ }
+ return evp_pkey;
+}
+
+bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* evp_pkey, const int valid_days) {
+ bssl::UniquePtr<X509> x509(X509_new());
+ bssl::UniquePtr<BIGNUM> serial(BN_new());
+ bssl::UniquePtr<BIGNUM> serialLimit(BN_new());
+ TEST_AND_RETURN(nullptr, BN_lshift(serialLimit.get(), BN_value_one(), 128));
+ TEST_AND_RETURN(nullptr, BN_rand_range(serial.get(), serialLimit.get()));
+ TEST_AND_RETURN(nullptr, BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get())));
+ TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notBefore(x509.get()), 0));
+ TEST_AND_RETURN(nullptr,
+ X509_gmtime_adj(X509_getm_notAfter(x509.get()), 60 * 60 * 24 * valid_days));
+
+ X509_NAME* subject = X509_get_subject_name(x509.get());
+ TEST_AND_RETURN(nullptr,
+ X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>("Android"), -1, -1,
+ 0));
+ TEST_AND_RETURN(nullptr,
+ X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>("BinderRPC"), -1,
+ -1, 0));
+ TEST_AND_RETURN(nullptr, X509_set_issuer_name(x509.get(), subject));
+
+ TEST_AND_RETURN(nullptr, X509_set_pubkey(x509.get(), evp_pkey));
+ TEST_AND_RETURN(nullptr, X509_sign(x509.get(), evp_pkey, EVP_sha256()));
+ return x509;
+}
+
+[[maybe_unused]] void sslDebugLog(const SSL* ssl, int type, int value) {
+ switch (type) {
+ case SSL_CB_HANDSHAKE_START:
+ LOG_TLS_DETAIL("Handshake started.");
+ break;
+ case SSL_CB_HANDSHAKE_DONE:
+ LOG_TLS_DETAIL("Handshake done.");
+ break;
+ case SSL_CB_ACCEPT_LOOP:
+ LOG_TLS_DETAIL("Handshake progress: %s", SSL_state_string_long(ssl));
+ break;
+ default:
+ LOG_TLS_DETAIL("SSL Debug Log: type = %d, value = %d", type, value);
+ break;
+ }
+}
+
+// Handles libssl's error queue.
+//
+// Call into any of its member functions to ensure the error queue is properly handled or cleared.
+// If the error queue is not handled or cleared, the destructor will abort.
+class ErrorQueue {
+public:
+ ~ErrorQueue() { LOG_ALWAYS_FATAL_IF(!mHandled); }
+
+ // Clear the error queue.
+ void clear() {
+ ERR_clear_error();
+ mHandled = true;
+ }
+
+ // Stores the error queue in |ssl| into a string, then clears the error queue.
+ std::string toString() {
+ std::stringstream ss;
+ ERR_print_errors_cb(
+ [](const char* str, size_t len, void* ctx) {
+ auto ss = (std::stringstream*)ctx;
+ (*ss) << std::string_view(str, len) << "\n";
+ return 1; // continue
+ },
+ &ss);
+ // Though ERR_print_errors_cb should have cleared it, it is okay to clear again.
+ clear();
+ return ss.str();
+ }
+
+ // |sslError| should be from Ssl::getError().
+ // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
+ // return error. Also return error if |fdTrigger| is triggered before or during poll().
+ status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
+ const char* fnString, int additionalEvent = 0) {
+ switch (sslError) {
+ case SSL_ERROR_WANT_READ:
+ return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString);
+ case SSL_ERROR_WANT_WRITE:
+ return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString);
+ case SSL_ERROR_SYSCALL: {
+ auto queue = toString();
+ LOG_TLS_DETAIL("%s(): %s. Treating as DEAD_OBJECT. Error queue: %s", fnString,
+ SSL_error_description(sslError), queue.c_str());
+ return DEAD_OBJECT;
+ }
+ default: {
+ auto queue = toString();
+ ALOGE("%s(): %s. Error queue: %s", fnString, SSL_error_description(sslError),
+ queue.c_str());
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+
+private:
+ bool mHandled = false;
+
+ status_t handlePoll(int event, android::base::borrowed_fd fd, FdTrigger* fdTrigger,
+ const char* fnString) {
+ status_t ret = fdTrigger->triggerablePoll(fd, event);
+ if (ret != OK && ret != DEAD_OBJECT && ret != -ECANCELED) {
+ ALOGE("triggerablePoll error while poll()-ing after %s(): %s", fnString,
+ statusToString(ret).c_str());
+ }
+ clear();
+ return ret;
+ }
+};
+
+// Helper to call a function, with its return value instantiable.
+template <typename Fn, typename... Args>
+struct FuncCaller {
+ struct Monostate {};
+ static constexpr bool sIsVoid = std::is_void_v<std::invoke_result_t<Fn, Args...>>;
+ using Result = std::conditional_t<sIsVoid, Monostate, std::invoke_result_t<Fn, Args...>>;
+ static inline Result call(Fn fn, Args&&... args) {
+ if constexpr (std::is_void_v<std::invoke_result_t<Fn, Args...>>) {
+ std::invoke(fn, std::forward<Args>(args)...);
+ return {};
+ } else {
+ return std::invoke(fn, std::forward<Args>(args)...);
+ }
+ }
+};
+
+// Helper to Ssl::call(). Returns the result to the SSL_* function as well as an ErrorQueue object.
+template <typename Fn, typename... Args>
+struct SslCaller {
+ using RawCaller = FuncCaller<Fn, SSL*, Args...>;
+ struct ResultAndErrorQueue {
+ typename RawCaller::Result result;
+ ErrorQueue errorQueue;
+ };
+ static inline ResultAndErrorQueue call(Fn fn, SSL* ssl, Args&&... args) {
+ LOG_ALWAYS_FATAL_IF(ssl == nullptr);
+ auto result = RawCaller::call(fn, std::forward<SSL*>(ssl), std::forward<Args>(args)...);
+ return ResultAndErrorQueue{std::move(result), ErrorQueue()};
+ }
+};
+
+// A wrapper over bssl::UniquePtr<SSL>. This class ensures that all SSL_* functions are called
+// through call(), which returns an ErrorQueue object that requires the caller to either handle
+// or clear it.
+// Example:
+// auto [ret, errorQueue] = ssl.call(SSL_read, buf, size);
+// if (ret >= 0) errorQueue.clear();
+// else ALOGE("%s", errorQueue.toString().c_str());
+class Ssl {
+public:
+ explicit Ssl(bssl::UniquePtr<SSL> ssl) : mSsl(std::move(ssl)) {
+ LOG_ALWAYS_FATAL_IF(mSsl == nullptr);
+ }
+
+ template <typename Fn, typename... Args>
+ inline typename SslCaller<Fn, Args...>::ResultAndErrorQueue call(Fn fn, Args&&... args) {
+ return SslCaller<Fn, Args...>::call(fn, mSsl.get(), std::forward<Args>(args)...);
+ }
+
+ int getError(int ret) {
+ LOG_ALWAYS_FATAL_IF(mSsl == nullptr);
+ return SSL_get_error(mSsl.get(), ret);
+ }
+
+private:
+ bssl::UniquePtr<SSL> mSsl;
+};
+
+class RpcTransportTls : public RpcTransport {
+public:
+ RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
+ : mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
+ Result<size_t> peek(void* buf, size_t size) override;
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size) override;
+ status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) override;
+
+private:
+ android::base::unique_fd mSocket;
+ Ssl mSsl;
+
+ static status_t isTriggered(FdTrigger* fdTrigger);
+};
+
+// Error code is errno.
+Result<size_t> RpcTransportTls::peek(void* buf, size_t size) {
+ size_t todo = std::min<size_t>(size, std::numeric_limits<int>::max());
+ auto [ret, errorQueue] = mSsl.call(SSL_peek, buf, static_cast<int>(todo));
+ if (ret < 0) {
+ int err = mSsl.getError(ret);
+ if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
+ // Seen EAGAIN / EWOULDBLOCK on recv(2) / send(2).
+ // Like RpcTransportRaw::peek(), don't handle it here.
+ return Error(EWOULDBLOCK) << "SSL_peek(): " << errorQueue.toString();
+ }
+ return Error() << "SSL_peek(): " << errorQueue.toString();
+ }
+ errorQueue.clear();
+ LOG_TLS_DETAIL("TLS: Peeked %d bytes!", ret);
+ return ret;
+}
+
+status_t RpcTransportTls::isTriggered(FdTrigger* fdTrigger) {
+ auto ret = fdTrigger->isTriggeredPolled();
+ if (!ret.ok()) {
+ ALOGE("%s: %s", __PRETTY_FUNCTION__, ret.error().message().c_str());
+ return ret.error().code() == 0 ? UNKNOWN_ERROR : -ret.error().code();
+ }
+ return OK;
+}
+
+status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, const void* data,
+ size_t size) {
+ auto buffer = reinterpret_cast<const uint8_t*>(data);
+ const uint8_t* end = buffer + size;
+
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
+ // once. The trigger is also checked via triggerablePoll() after every SSL_write().
+ if (status_t status = isTriggered(fdTrigger); status != OK) return status;
+
+ while (buffer < end) {
+ size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
+ auto [writeSize, errorQueue] = mSsl.call(SSL_write, buffer, todo);
+ if (writeSize > 0) {
+ buffer += writeSize;
+ errorQueue.clear();
+ continue;
+ }
+ // SSL_write() should never return 0 unless BIO_write were to return 0.
+ int sslError = mSsl.getError(writeSize);
+ // TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be
+ // triggerablePoll()-ed. Then additionalEvent is no longer necessary.
+ status_t pollStatus =
+ errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, "SSL_write", POLLIN);
+ if (pollStatus != OK) return pollStatus;
+ // Do not advance buffer. Try SSL_write() again.
+ }
+ LOG_TLS_DETAIL("TLS: Sent %zu bytes!", size);
+ return OK;
+}
+
+status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) {
+ auto buffer = reinterpret_cast<uint8_t*>(data);
+ uint8_t* end = buffer + size;
+
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
+ // once. The trigger is also checked via triggerablePoll() after every SSL_write().
+ if (status_t status = isTriggered(fdTrigger); status != OK) return status;
+
+ while (buffer < end) {
+ size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
+ auto [readSize, errorQueue] = mSsl.call(SSL_read, buffer, todo);
+ if (readSize > 0) {
+ buffer += readSize;
+ errorQueue.clear();
+ continue;
+ }
+ if (readSize == 0) {
+ // SSL_read() only returns 0 on EOF.
+ errorQueue.clear();
+ return DEAD_OBJECT;
+ }
+ int sslError = mSsl.getError(readSize);
+ status_t pollStatus =
+ errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, "SSL_read");
+ if (pollStatus != OK) return pollStatus;
+ // Do not advance buffer. Try SSL_read() again.
+ }
+ LOG_TLS_DETAIL("TLS: Received %zu bytes!", size);
+ return OK;
+}
+
+// For |ssl|, set internal FD to |fd|, and do handshake. Handshake is triggerable by |fdTrigger|.
+bool setFdAndDoHandshake(Ssl* ssl, android::base::borrowed_fd fd, FdTrigger* fdTrigger) {
+ bssl::UniquePtr<BIO> bio = newSocketBio(fd);
+ TEST_AND_RETURN(false, bio != nullptr);
+ auto [_, errorQueue] = ssl->call(SSL_set_bio, bio.get(), bio.get());
+ (void)bio.release(); // SSL_set_bio takes ownership.
+ errorQueue.clear();
+
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ while (true) {
+ auto [ret, errorQueue] = ssl->call(SSL_do_handshake);
+ if (ret > 0) {
+ errorQueue.clear();
+ return true;
+ }
+ if (ret == 0) {
+ // SSL_do_handshake() only returns 0 on EOF.
+ ALOGE("SSL_do_handshake(): EOF: %s", errorQueue.toString().c_str());
+ return false;
+ }
+ int sslError = ssl->getError(ret);
+ status_t pollStatus =
+ errorQueue.pollForSslError(fd, sslError, fdTrigger, "SSL_do_handshake");
+ if (pollStatus != OK) return false;
+ }
+}
+
+class RpcTransportCtxTlsServer : public RpcTransportCtx {
+public:
+ static std::unique_ptr<RpcTransportCtxTlsServer> create();
+ std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd acceptedFd,
+ FdTrigger* fdTrigger) const override;
+
+private:
+ bssl::UniquePtr<SSL_CTX> mCtx;
+};
+
+std::unique_ptr<RpcTransportCtxTlsServer> RpcTransportCtxTlsServer::create() {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ TEST_AND_RETURN(nullptr, ctx != nullptr);
+
+ // Server use self-signing cert
+ auto evp_pkey = makeKeyPairForSelfSignedCert();
+ TEST_AND_RETURN(nullptr, evp_pkey != nullptr);
+ auto cert = makeSelfSignedCert(evp_pkey.get(), kCertValidDays);
+ TEST_AND_RETURN(nullptr, cert != nullptr);
+ TEST_AND_RETURN(nullptr, SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get()));
+ TEST_AND_RETURN(nullptr, SSL_CTX_use_certificate(ctx.get(), cert.get()));
+ // Require at least TLS 1.3
+ TEST_AND_RETURN(nullptr, SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
+
+ if constexpr (SHOULD_LOG_TLS_DETAIL) { // NOLINT
+ SSL_CTX_set_info_callback(ctx.get(), sslDebugLog);
+ }
+
+ auto rpcTransportTlsServerCtx = std::make_unique<RpcTransportCtxTlsServer>();
+ rpcTransportTlsServerCtx->mCtx = std::move(ctx);
+ return rpcTransportTlsServerCtx;
+}
+
+std::unique_ptr<RpcTransport> RpcTransportCtxTlsServer::newTransport(
+ android::base::unique_fd acceptedFd, FdTrigger* fdTrigger) const {
+ bssl::UniquePtr<SSL> ssl(SSL_new(mCtx.get()));
+ TEST_AND_RETURN(nullptr, ssl != nullptr);
+ Ssl wrapped(std::move(ssl));
+
+ wrapped.call(SSL_set_accept_state).errorQueue.clear();
+ TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, acceptedFd, fdTrigger));
+ return std::make_unique<RpcTransportTls>(std::move(acceptedFd), std::move(wrapped));
+}
+
+class RpcTransportCtxTlsClient : public RpcTransportCtx {
+public:
+ static std::unique_ptr<RpcTransportCtxTlsClient> create();
+ std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd connectedFd,
+ FdTrigger* fdTrigger) const override;
+
+private:
+ bssl::UniquePtr<SSL_CTX> mCtx;
+};
+
+std::unique_ptr<RpcTransportCtxTlsClient> RpcTransportCtxTlsClient::create() {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ TEST_AND_RETURN(nullptr, ctx != nullptr);
+
+ // TODO(b/195166979): server should send certificate in a different channel, and client
+ // should verify it here.
+ SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER,
+ [](SSL*, uint8_t*) -> ssl_verify_result_t { return ssl_verify_ok; });
+
+ // Require at least TLS 1.3
+ TEST_AND_RETURN(nullptr, SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
+
+ if constexpr (SHOULD_LOG_TLS_DETAIL) { // NOLINT
+ SSL_CTX_set_info_callback(ctx.get(), sslDebugLog);
+ }
+
+ auto rpcTransportTlsClientCtx = std::make_unique<RpcTransportCtxTlsClient>();
+ rpcTransportTlsClientCtx->mCtx = std::move(ctx);
+ return rpcTransportTlsClientCtx;
+}
+
+std::unique_ptr<RpcTransport> RpcTransportCtxTlsClient::newTransport(
+ android::base::unique_fd connectedFd, FdTrigger* fdTrigger) const {
+ bssl::UniquePtr<SSL> ssl(SSL_new(mCtx.get()));
+ TEST_AND_RETURN(nullptr, ssl != nullptr);
+ Ssl wrapped(std::move(ssl));
+
+ wrapped.call(SSL_set_connect_state).errorQueue.clear();
+ TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, connectedFd, fdTrigger));
+ return std::make_unique<RpcTransportTls>(std::move(connectedFd), std::move(wrapped));
+}
+
+} // namespace
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const {
+ return android::RpcTransportCtxTlsServer::create();
+}
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newClientCtx() const {
+ return android::RpcTransportCtxTlsClient::create();
+}
+
+const char* RpcTransportCtxFactoryTls::toCString() const {
+ return "tls";
+}
+
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTls::make() {
+ return std::unique_ptr<RpcTransportCtxFactoryTls>(new RpcTransportCtxFactoryTls());
+}
+
+} // namespace android
diff --git a/libs/binder/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
index 1c2f9b4..59334b7 100644
--- a/libs/binder/ServiceManagerHost.cpp
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -158,8 +158,10 @@
LOG_ALWAYS_FATAL_IF(!forwardResult->hostPort().has_value());
auto rpcSession = RpcSession::make();
- if (!rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort())) {
- ALOGE("Unable to set up inet client on host port %u", *forwardResult->hostPort());
+ if (status_t status = rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort());
+ status != OK) {
+ ALOGE("Unable to set up inet client on host port %u: %s", *forwardResult->hostPort(),
+ statusToString(status).c_str());
return nullptr;
}
auto binder = rpcSession->getRootObject();
diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp
index 90a4502..d2a5be1 100644
--- a/libs/binder/Utils.cpp
+++ b/libs/binder/Utils.cpp
@@ -18,10 +18,24 @@
#include <string.h>
+using android::base::ErrnoError;
+using android::base::Result;
+
namespace android {
void zeroMemory(uint8_t* data, size_t size) {
memset(data, 0, size);
}
-} // namespace android
+Result<void> setNonBlocking(android::base::borrowed_fd fd) {
+ int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
+ if (flags == -1) {
+ return ErrnoError() << "Could not get flags for fd";
+ }
+ if (int ret = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_SETFL, flags | O_NONBLOCK)); ret == -1) {
+ return ErrnoError() << "Could not set non-blocking flag for fd";
+ }
+ return {};
+}
+
+} // namespace android
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index f94b158..1e383da 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -17,9 +17,14 @@
#include <cstdint>
#include <stddef.h>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+
namespace android {
// avoid optimizations
void zeroMemory(uint8_t* data, size_t size);
+android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
+
} // namespace android
diff --git a/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl
new file mode 100644
index 0000000..75f8753
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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 android.content.pm;
+
+/**
+ * This event is designed for notification to native code listener about
+ * any changes to set of apex packages staged for installation on next boot.
+ *
+ * @hide
+ */
+parcelable ApexStagedEvent {
+ @utf8InCpp String[] stagedApexModuleNames;
+}
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index c20d9f6..d71f496 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -18,6 +18,8 @@
package android.content.pm;
import android.content.pm.IPackageChangeObserver;
+import android.content.pm.IStagedApexObserver;
+import android.content.pm.StagedApexInfo;
/**
* Parallel implementation of certain {@link PackageManager} APIs that need to
@@ -123,4 +125,24 @@
* requested version.
*/
boolean hasSystemFeature(in String featureName, in int version);
+
+ /** Register a observer for change in set of staged APEX ready for installation */
+ void registerStagedApexObserver(in IStagedApexObserver observer);
+
+ /**
+ * Unregister an existing staged apex observer.
+ * This does nothing if this observer was not already registered.
+ */
+ void unregisterStagedApexObserver(in IStagedApexObserver observer);
+
+ /**
+ * Get APEX module names of all APEX that are staged ready for installation
+ */
+ @utf8InCpp String[] getStagedApexModuleNames();
+
+ /**
+ * Get information of APEX which is staged ready for installation.
+ * Returns null if no such APEX is found.
+ */
+ StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName);
}
diff --git a/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl b/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl
new file mode 100644
index 0000000..9906436
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl
@@ -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.
+ */
+
+package android.content.pm;
+
+import android.content.pm.ApexStagedEvent;
+
+/**
+ * This is a non-blocking notification when set of staged apex has changed
+ *
+ * @hide
+ */
+oneway interface IStagedApexObserver {
+ void onApexStaged(in ApexStagedEvent event);
+}
diff --git a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
new file mode 100644
index 0000000..ece7989
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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 android.content.pm;
+
+/**
+ * This object is designed for returning information regarding
+ * staged APEX that are ready to be installed on next reboot.
+ *
+ * @hide
+ */
+parcelable StagedApexInfo {
+ @utf8InCpp String moduleName;
+ @utf8InCpp String diskImagePath;
+ long versionCode;
+ @utf8InCpp String versionName;
+}
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index c69bb9e..a6d35c7 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -90,6 +90,8 @@
static void setLimitCallback(binder_proxy_limit_callback cb);
static void setBinderProxyCountWatermarks(int high, int low);
+ std::optional<int32_t> getDebugBinderHandle() const;
+
class ObjectManager {
public:
ObjectManager();
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 02052ad..fd8ac62 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -245,9 +245,10 @@
template<typename T>
status_t writeNullableParcelable(const std::optional<T>& parcelable)
{ return writeData(parcelable); }
- template<typename T>
- status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")))
- { return writeData(parcelable); }
+ template <typename T>
+ status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
+ return writeData(parcelable);
+ }
status_t writeParcelable(const Parcelable& parcelable);
@@ -401,9 +402,10 @@
template<typename T>
status_t readParcelable(std::optional<T>* parcelable) const
{ return readData(parcelable); }
- template<typename T>
- status_t readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")))
- { return readData(parcelable); }
+ template <typename T>
+ status_t readParcelable(std::unique_ptr<T>* parcelable) const {
+ return readData(parcelable);
+ }
// If strong binder would be nullptr, readStrongBinder() returns an error.
// TODO: T must be derived from IInterface, fix for clarity.
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 40ff78c..bf3e7e0 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>
@@ -31,6 +32,7 @@
namespace android {
+class FdTrigger;
class RpcSocketAddress;
/**
@@ -47,7 +49,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.:
@@ -57,12 +60,12 @@
* process B makes binder b and sends it to A
* A uses this 'back session' to send things back to B
*/
- [[nodiscard]] bool setupUnixDomainServer(const char* path);
+ [[nodiscard]] status_t setupUnixDomainServer(const char* path);
/**
* Creates an RPC server at the current port.
*/
- [[nodiscard]] bool setupVsockServer(unsigned int port);
+ [[nodiscard]] status_t setupVsockServer(unsigned int port);
/**
* Creates an RPC server at the current port using IPv4.
@@ -72,8 +75,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]] status_t setupInetServer(const char* address, unsigned int port,
+ unsigned int* assignedPort);
/**
* If setup*Server has been successful, return true. Otherwise return false.
@@ -89,7 +98,7 @@
* Set up server using an external FD previously set up by releaseServer().
* Return false if there's already a server.
*/
- bool setupExternalServer(base::unique_fd serverFd);
+ [[nodiscard]] status_t setupExternalServer(base::unique_fd serverFd);
void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
@@ -161,14 +170,15 @@
private:
friend sp<RpcServer>;
- RpcServer();
+ explicit RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
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);
+ status_t setupSocketServer(const RpcSocketAddress& address);
+ const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
bool mAgreedExperimental = false;
size_t mMaxThreads = 1;
std::optional<uint32_t> mProtocolVersion;
@@ -181,8 +191,9 @@
sp<IBinder> mRootObject;
wp<IBinder> mRootObjectWeak;
std::map<RpcAddress, sp<RpcSession>> mSessions;
- std::unique_ptr<RpcSession::FdTrigger> mShutdownTrigger;
+ std::unique_ptr<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 1f7c029..6e6eb74 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -18,6 +18,7 @@
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
#include <binder/RpcAddress.h>
+#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -36,6 +37,8 @@
class RpcServer;
class RpcSocketAddress;
class RpcState;
+class RpcTransport;
+class FdTrigger;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 0;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
@@ -48,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).
@@ -74,17 +78,30 @@
* This should be called once per thread, matching 'join' in the remote
* process.
*/
- [[nodiscard]] bool setupUnixDomainClient(const char* path);
+ [[nodiscard]] status_t setupUnixDomainClient(const char* path);
/**
* Connects to an RPC server at the CVD & port.
*/
- [[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port);
+ [[nodiscard]] status_t setupVsockClient(unsigned int cvd, unsigned int port);
/**
* Connects to an RPC server at the given address and port.
*/
- [[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
+ [[nodiscard]] status_t 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]] status_t setupPreconnectedClient(base::unique_fd fd,
+ std::function<base::unique_fd()>&& request);
/**
* For debugging!
@@ -93,7 +110,7 @@
* response will never be satisfied. All data sent here will be
* unceremoniously cast down the bottomless pit, /dev/null.
*/
- [[nodiscard]] bool addNullDebuggingClient();
+ [[nodiscard]] status_t addNullDebuggingClient();
/**
* Query the other side of the session for the root object hosted by that
@@ -142,49 +159,7 @@
friend sp<RpcSession>;
friend RpcServer;
friend RpcState;
- RpcSession();
-
- /** This is not a pipe. */
- struct FdTrigger {
- /** Returns nullptr for error case */
- static std::unique_ptr<FdTrigger> make();
-
- /**
- * Close the write end of the pipe so that the read end receives POLLHUP.
- * Not threadsafe.
- */
- void trigger();
-
- /**
- * Whether this has been triggered.
- */
- bool isTriggered();
-
- /**
- * Poll for a read event.
- *
- * event - for pollfd
- *
- * Return:
- * true - time to read!
- * false - trigger happened
- */
- status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
-
- /**
- * Read (or write), but allow to be interrupted by this trigger.
- *
- * Return:
- * 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);
-
- private:
- base::unique_fd mWrite;
- base::unique_fd mRead;
- };
+ explicit RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
class EventListener : public virtual RefBase {
public:
@@ -204,7 +179,7 @@
};
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.
@@ -230,21 +205,30 @@
// 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 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);
+ [[nodiscard]] status_t setupClient(
+ const std::function<status_t(const RpcAddress& sessionId, bool incoming)>&
+ connectAndInit);
+ [[nodiscard]] status_t setupSocketClient(const RpcSocketAddress& address);
+ [[nodiscard]] status_t setupOneSocketConnection(const RpcSocketAddress& address,
+ const RpcAddress& sessionId, bool incoming);
+ [[nodiscard]] status_t initAndAddConnection(base::unique_fd fd, const RpcAddress& sessionId,
+ bool incoming);
+ [[nodiscard]] status_t addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport);
+ [[nodiscard]] status_t 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);
+ status_t initShutdownTrigger();
+
enum class ConnectionUse {
CLIENT,
CLIENT_ASYNC,
@@ -275,6 +259,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).
//
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
new file mode 100644
index 0000000..1b69519
--- /dev/null
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -0,0 +1,89 @@
+/*
+ * 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>
+#include <utils/Errors.h>
+
+namespace android {
+
+class FdTrigger;
+
+// Represents a socket connection.
+class RpcTransport {
+public:
+ virtual ~RpcTransport() = default;
+
+ // replacement of ::recv(MSG_PEEK). Error code may not be set if TLS is enabled.
+ virtual android::base::Result<size_t> peek(void *buf, size_t size) = 0;
+
+ /**
+ * Read (or write), but allow to be interrupted by a trigger.
+ *
+ * Return:
+ * OK - succeeded in completely processing 'size'
+ * error - interrupted (failure or trigger)
+ */
+ virtual status_t interruptableWriteFully(FdTrigger *fdTrigger, const void *buf,
+ size_t size) = 0;
+ virtual status_t interruptableReadFully(FdTrigger *fdTrigger, void *buf, size_t size) = 0;
+
+protected:
+ RpcTransport() = default;
+};
+
+// Represents the context that generates the socket connection.
+class RpcTransportCtx {
+public:
+ virtual ~RpcTransportCtx() = default;
+
+ // Create a new RpcTransport object.
+ //
+ // Implemenion details: for TLS, this function may incur I/O. |fdTrigger| may be used
+ // to interrupt I/O. This function blocks until handshake is finished.
+ [[nodiscard]] virtual std::unique_ptr<RpcTransport> newTransport(
+ android::base::unique_fd fd, FdTrigger *fdTrigger) 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_tls/binder/RpcTransportTls.h b/libs/binder/include_tls/binder/RpcTransportTls.h
new file mode 100644
index 0000000..531aaa9
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcTransportTls.h
@@ -0,0 +1,38 @@
+/*
+ * 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 TLS.
+
+#pragma once
+
+#include <binder/RpcTransport.h>
+
+namespace android {
+
+// RpcTransportCtxFactory with TLS enabled with self-signed certificate.
+class RpcTransportCtxFactoryTls : 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:
+ RpcTransportCtxFactoryTls() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 68ec669..bcb13ae 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -19,16 +19,20 @@
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+using android::OK;
using android::RpcServer;
using android::RpcSession;
+using android::status_t;
+using android::statusToString;
extern "C" {
bool RunRpcServer(AIBinder* service, unsigned int port) {
auto server = RpcServer::make();
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- if (!server->setupVsockServer(port)) {
- LOG(ERROR) << "Failed to set up vsock server with port " << port;
+ if (status_t status = server->setupVsockServer(port); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock server with port " << port
+ << " error: " << statusToString(status).c_str();
return false;
}
server->setRootObject(AIBinder_toPlatformBinder(service));
@@ -41,8 +45,9 @@
AIBinder* RpcClient(unsigned int cid, unsigned int port) {
auto session = RpcSession::make();
- if (!session->setupVsockClient(cid, port)) {
- LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port;
+ if (status_t status = session->setupVsockClient(cid, port); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port
+ << " error: " << statusToString(status).c_str();
return nullptr;
}
return AIBinder_fromPlatformBinder(session->getRootObject());
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 785e032..717beec 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -82,8 +82,8 @@
const String16& currentDescriptor = mClazz->getInterfaceDescriptor();
if (newDescriptor == currentDescriptor) {
LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
- << "' match during associateClass, but they are different class objects. "
- "Class descriptor collision?";
+ << "' match during associateClass, but they are different class objects ("
+ << clazz << " vs " << mClazz << "). Class descriptor collision?";
} else {
LOG(ERROR) << __func__
<< ": Class cannot be associated on object which already has a class. "
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 6c44726..5de64f8 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -55,6 +55,12 @@
std::call_once(mFlagThis, [&]() {
__assert(__FILE__, __LINE__, "SharedRefBase: no ref created during lifetime");
});
+
+ if (ref() != nullptr) {
+ __assert(__FILE__, __LINE__,
+ "SharedRefBase: destructed but still able to lock weak_ptr. Is this object "
+ "double-owned?");
+ }
}
/**
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 5092d87..563d011 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -469,6 +469,22 @@
}
/**
+ * Convenience API for writing a nullable parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
+ const std::unique_ptr<P>& p) {
+ if (!p) {
+ return AParcel_writeInt32(parcel, 0); // null
+ }
+ binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
+ if (status != STATUS_OK) {
+ return status;
+ }
+ return p->writeToParcel(parcel);
+}
+
+/**
* Convenience API for reading a nullable parcelable.
*/
template <typename P>
@@ -488,6 +504,25 @@
}
/**
+ * Convenience API for reading a nullable parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
+ std::unique_ptr<P>* p) {
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ p->reset();
+ return STATUS_OK;
+ }
+ *p = std::make_unique<P>();
+ return (*p)->readFromParcel(parcel);
+}
+
+/**
* Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
*/
template <typename P>
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/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index ce12ccf..4b36530 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -224,6 +224,17 @@
return true;
}
+TEST(NdkBinder, DetectDoubleOwn) {
+ auto badService = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+ EXPECT_DEATH(std::shared_ptr<MyBinderNdkUnitTest>(badService.get()),
+ "Is this object double-owned?");
+}
+
+TEST(NdkBinder, DetectNoSharedRefBaseCreated) {
+ EXPECT_DEATH(std::make_shared<MyBinderNdkUnitTest>(),
+ "SharedRefBase: no ref created during lifetime");
+}
+
TEST(NdkBinder, GetServiceThatDoesntExist) {
sp<IFoo> foo = IFoo::getService("asdfghkl;");
EXPECT_EQ(nullptr, foo.get());
diff --git a/libs/binder/run_rpc_tests.sh b/libs/binder/run_rpc_tests.sh
new file mode 100755
index 0000000..7ba682d
--- /dev/null
+++ b/libs/binder/run_rpc_tests.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+set -ex
+
+if [ $# -eq 0 ]; then
+ :
+elif [ $# -eq 1 ] && [[ "$1" =~ ^host|device$ ]]; then
+ :
+else
+ echo "usage: $0 [device|host]"
+ false
+fi
+
+# Script maintained for RPC development, while it is active, to quickly run
+# tests. Generally, to match VTS/presubmit behavior, 'atest' should be used.
+
+function dtest () { adb shell /data/nativetest64/$1/$@; }
+function hbench () { $AT/out/host/linux-x86/benchmarktest/$1/$@; }
+function hfuzz () { time $ANDROID_HOST_OUT/fuzz/x86_64/$1/$@; }
+function htest () { time $ANDROID_BUILD_TOP/out/host/linux-x86/nativetest/$1/$@; }
+function pdtest () { adb wait-for-device && adb shell mkdir -p /data/nativetest64/$1 && adb push $OUT/data/nativetest64/$1/$1 /data/nativetest64/$1/$1 && dtest $@; }
+function dbench () { adb shell /data/benchmarktest64/$1/$@; }
+function pdbench () { adb wait-for-device && adb shell mkdir -p /data/benchmarktest64/$1 && adb push $OUT/data/benchmarktest64/$1/$1 /data/benchmarktest64/$1/$1 && dbench $@; }
+
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
+ binderRpcTest \
+ binder_rpc_fuzzer \
+ binder_parcel_fuzzer \
+ binderLibTest \
+ binderRpcBenchmark
+
+if ! [ "$1" = "device" ]; then
+ htest binderRpcTest
+ hbench binderRpcBenchmark
+ hfuzz binder_rpc_fuzzer -max_total_time=30
+ hfuzz binder_parcel_fuzzer -max_total_time=30
+fi
+
+if ! [ "$1" = "host" ]; then
+ pdtest binderRpcTest
+ pdtest binderLibTest
+ pdbench binderRpcBenchmark
+fi
+
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 20e9178..179b7c8 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -23,7 +23,7 @@
use crate::sys;
use std::fs::File;
-use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
/// Rust version of the Java class android.os.ParcelFileDescriptor
#[derive(Debug)]
@@ -48,6 +48,12 @@
}
}
+impl AsRawFd for ParcelFileDescriptor {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
+ }
+}
+
impl Serialize for ParcelFileDescriptor {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
let fd = self.0.as_raw_fd();
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 956ecfe..56c6165 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -764,6 +764,30 @@
}
}
+impl<T: Serialize> Serialize for Box<T> {
+ fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ Serialize::serialize(&**self, parcel)
+ }
+}
+
+impl<T: Deserialize> Deserialize for Box<T> {
+ fn deserialize(parcel: &Parcel) -> Result<Self> {
+ Deserialize::deserialize(parcel).map(Box::new)
+ }
+}
+
+impl<T: SerializeOption> SerializeOption for Box<T> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ SerializeOption::serialize_option(this.map(|inner| &**inner), parcel)
+ }
+}
+
+impl<T: DeserializeOption> DeserializeOption for Box<T> {
+ fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ DeserializeOption::deserialize_option(parcel).map(|t| t.map(Box::new))
+ }
+}
+
#[test]
fn test_custom_parcelable() {
use crate::binder::Interface;
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..9811cdf 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -23,9 +23,12 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android/debug/BnAdbCallback.h>
+#include <android/debug/IAdbManager.h>
#include <android/os/BnServiceManager.h>
#include <android/os/IServiceManager.h>
#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <binder/RpcServer.h>
using android::BBinder;
@@ -33,6 +36,7 @@
using android::OK;
using android::RpcServer;
using android::sp;
+using android::status_t;
using android::statusToString;
using android::String16;
using android::base::Basename;
@@ -47,7 +51,9 @@
namespace {
+const char* kLocalInetAddress = "127.0.0.1";
using ServiceRetriever = decltype(&android::IServiceManager::checkService);
+using android::debug::IAdbManager;
int Usage(const char* program) {
auto basename = Basename(program);
@@ -86,8 +92,8 @@
}
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
- if (!rpcServer->setupInetServer(0, &port)) {
- LOG(ERROR) << "setupInetServer failed";
+ if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+ LOG(ERROR) << "setupInetServer failed: " << statusToString(status);
return EX_SOFTWARE;
}
auto socket = rpcServer->releaseServer();
@@ -199,8 +205,8 @@
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
rpcServer->setRootObject(service);
unsigned int port;
- if (!rpcServer->setupInetServer(0, &port)) {
- LOG(ERROR) << "Unable to set up inet server";
+ if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+ LOG(ERROR) << "Unable to set up inet server: " << statusToString(status);
return EX_SOFTWARE;
}
LOG(INFO) << "Finish wrapping servicemanager with RPC on port " << port;
@@ -211,6 +217,25 @@
__builtin_unreachable();
}
+class AdbCallback : public android::debug::BnAdbCallback {
+public:
+ android::binder::Status onDebuggingChanged(bool enabled,
+ android::debug::AdbTransportType) override {
+ if (!enabled) {
+ LOG(ERROR) << "ADB debugging disabled, exiting.";
+ exit(EX_SOFTWARE);
+ }
+ return android::binder::Status::ok();
+ }
+};
+
+void exitOnAdbDebuggingDisabled() {
+ auto adb = android::waitForService<IAdbManager>(String16("adb"));
+ CHECK(adb != nullptr) << "Unable to retrieve service adb";
+ auto status = adb->registerCallback(sp<AdbCallback>::make());
+ CHECK(status.isOk()) << "Unable to call IAdbManager::registerCallback: " << status;
+}
+
// Log to logd. For warning and more severe messages, also log to stderr.
class ServiceDispatcherLogger {
public:
@@ -251,6 +276,10 @@
}
}
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ android::ProcessState::self()->startThreadPool();
+ exitOnAdbDebuggingDisabled();
+
if (optind + 1 != argc) return Usage(argv[0]);
auto name = argv[optind];
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/IBinderRpcBenchmark.aidl b/libs/binder/tests/IBinderRpcBenchmark.aidl
index 1457422..2baf680 100644
--- a/libs/binder/tests/IBinderRpcBenchmark.aidl
+++ b/libs/binder/tests/IBinderRpcBenchmark.aidl
@@ -17,4 +17,5 @@
interface IBinderRpcBenchmark {
@utf8InCpp String repeatString(@utf8InCpp String str);
IBinder repeatBinder(IBinder binder);
+ byte[] repeatBytes(in byte[] bytes);
}
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/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
index 5dd9212..3f72b8f 100644
--- a/libs/binder/tests/binderHostDeviceTest.cpp
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -101,8 +101,9 @@
[[nodiscard]] static sp<IBinder> get(unsigned int hostPort) {
auto rpcSession = RpcSession::make();
- if (!rpcSession->setupInetClient("127.0.0.1", hostPort)) {
- ADD_FAILURE() << "Failed to setupInetClient on " << hostPort;
+ if (status_t status = rpcSession->setupInetClient("127.0.0.1", hostPort); status != OK) {
+ ADD_FAILURE() << "Failed to setupInetClient on " << hostPort << ": "
+ << statusToString(status);
return nullptr;
}
return rpcSession->getRootObject();
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 4c3225f..eea7d8c 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1192,8 +1192,8 @@
if (rpcServer == nullptr) return {};
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
- if (!rpcServer->setupInetServer(0, &port)) {
- ADD_FAILURE() << "setupInetServer failed";
+ if (status_t status = rpcServer->setupInetServer("127.0.0.1", 0, &port); status != OK) {
+ ADD_FAILURE() << "setupInetServer failed" << statusToString(status);
return {};
}
return {rpcServer->releaseServer(), port};
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index 5f4a7b5..e430c28 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -42,6 +42,8 @@
using android::RpcServer;
using android::RpcSession;
using android::sp;
+using android::status_t;
+using android::statusToString;
using android::String16;
using android::binder::Status;
@@ -50,8 +52,12 @@
*out = str;
return Status::ok();
}
- Status repeatBinder(const sp<IBinder>& str, sp<IBinder>* out) override {
- *out = str;
+ Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
+ *out = binder;
+ return Status::ok();
+ }
+ Status repeatBytes(const std::vector<uint8_t>& bytes, std::vector<uint8_t>* out) override {
+ *out = bytes;
return Status::ok();
}
};
@@ -61,12 +67,11 @@
RPC,
};
-static void EachTransport(benchmark::internal::Benchmark* b) {
+static const std::initializer_list<int64_t> kTransportList = {
#ifdef __BIONIC__
- b->Args({Transport::KERNEL});
+ Transport::KERNEL,
#endif
- b->Args({Transport::RPC});
-}
+ Transport::RPC};
static sp<RpcSession> gSession = RpcSession::make();
#ifdef __BIONIC__
@@ -96,9 +101,9 @@
CHECK_EQ(OK, binder->pingBinder());
}
}
-BENCHMARK(BM_pingTransaction)->Apply(EachTransport);
+BENCHMARK(BM_pingTransaction)->ArgsProduct({kTransportList});
-void BM_repeatString(benchmark::State& state) {
+void BM_repeatTwoPageString(benchmark::State& state) {
sp<IBinder> binder = getBinderForOptions(state);
sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
@@ -125,10 +130,30 @@
CHECK(ret.isOk()) << ret;
}
}
-BENCHMARK(BM_repeatString)->Apply(EachTransport);
+BENCHMARK(BM_repeatTwoPageString)->ArgsProduct({kTransportList});
+
+void BM_throughputForTransportAndBytes(benchmark::State& state) {
+ sp<IBinder> binder = getBinderForOptions(state);
+ sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
+ CHECK(iface != nullptr);
+
+ std::vector<uint8_t> bytes = std::vector<uint8_t>(state.range(1));
+ for (size_t i = 0; i < bytes.size(); i++) {
+ bytes[i] = i % 256;
+ }
+
+ while (state.KeepRunning()) {
+ std::vector<uint8_t> out;
+ Status ret = iface->repeatBytes(bytes, &out);
+ CHECK(ret.isOk()) << ret;
+ }
+}
+BENCHMARK(BM_throughputForTransportAndBytes)
+ ->ArgsProduct({kTransportList,
+ {64, 1024, 2048, 4096, 8182, 16364, 32728, 65535, 65536, 65537}});
void BM_repeatBinder(benchmark::State& state) {
- sp<IBinder> binder = gSession->getRootObject();
+ sp<IBinder> binder = getBinderForOptions(state);
CHECK(binder != nullptr);
sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
CHECK(iface != nullptr);
@@ -142,7 +167,7 @@
CHECK(ret.isOk()) << ret;
}
}
-BENCHMARK(BM_repeatBinder)->Apply(EachTransport);
+BENCHMARK(BM_repeatBinder)->ArgsProduct({kTransportList});
int main(int argc, char** argv) {
::benchmark::Initialize(&argc, argv);
@@ -152,15 +177,15 @@
(void)unlink(addr.c_str());
std::cerr << "Tests suffixes:" << std::endl;
- std::cerr << "\t\\" << Transport::KERNEL << " is KERNEL" << std::endl;
- std::cerr << "\t\\" << Transport::RPC << " is RPC" << 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()));
+ CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
server->join();
exit(1);
}
@@ -182,11 +207,13 @@
CHECK_NE(nullptr, gKernelBinder.get());
#endif
+ status_t status;
for (size_t tries = 0; tries < 5; tries++) {
usleep(10000);
- if (gSession->setupUnixDomainClient(addr.c_str())) goto success;
+ status = gSession->setupUnixDomainClient(addr.c_str());
+ if (status == OK) goto success;
}
- LOG(FATAL) << "Could not connect.";
+ LOG(FATAL) << "Could not connect: " << statusToString(status).c_str();
success:
::benchmark::RunSpecifiedBenchmarks();
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index d5786bc..15ccae9 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_*
@@ -49,6 +52,22 @@
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;
@@ -57,13 +76,20 @@
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)));
+ ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
ASSERT_TRUE(server->hasServer());
base::unique_fd retrieved = server->releaseServer();
ASSERT_FALSE(server->hasServer());
@@ -384,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:
@@ -402,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;
@@ -410,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();
@@ -424,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);
@@ -432,14 +481,16 @@
unsigned int outPort = 0;
switch (socketType) {
+ case SocketType::PRECONNECTED:
+ [[fallthrough]];
case SocketType::UNIX:
- CHECK(server->setupUnixDomainServer(addr.c_str())) << addr;
+ CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())) << addr;
break;
case SocketType::VSOCK:
- CHECK(server->setupVsockServer(vsockPort));
+ CHECK_EQ(OK, server->setupVsockServer(vsockPort));
break;
case SocketType::INET: {
- CHECK(server->setupInetServer(0, &outPort));
+ CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
CHECK_NE(0, outPort);
break;
}
@@ -465,24 +516,35 @@
CHECK_NE(0, outPort);
}
+ status_t status;
+
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:
+ status = session->setupPreconnectedClient({}, [=]() {
+ return connectToUds(addr.c_str());
+ });
+ if (status == OK) goto success;
+ break;
case SocketType::UNIX:
- if (session->setupUnixDomainClient(addr.c_str())) goto success;
+ status = session->setupUnixDomainClient(addr.c_str());
+ if (status == OK) goto success;
break;
case SocketType::VSOCK:
- if (session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
+ status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+ if (status == OK) goto success;
break;
case SocketType::INET:
- if (session->setupInetClient("127.0.0.1", outPort)) goto success;
+ status = session->setupInetClient("127.0.0.1", outPort);
+ if (status == OK) goto success;
break;
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
- LOG_ALWAYS_FATAL("Could not connect");
+ LOG_ALWAYS_FATAL("Could not connect %s", statusToString(status).c_str());
success:
ret.sessions.push_back({session, session->getRootObject()});
}
@@ -1130,21 +1192,27 @@
}
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));
+ if (status_t status = server->setupVsockServer(vsockPort); status != OK) {
+ if (status == -EAFNOSUPPORT) {
+ return false;
+ }
+ LOG_ALWAYS_FATAL("Could not setup vsock server: %s", statusToString(status).c_str());
+ }
server->start();
- sp<RpcSession> session = RpcSession::make();
- bool okay = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+ sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
while (!server->shutdown()) usleep(10000);
- ALOGE("Detected vsock loopback supported: %d", okay);
- return okay;
+ ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
+ return status == OK;
}
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();
@@ -1155,10 +1223,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>)>;
@@ -1166,8 +1237,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);
@@ -1184,7 +1255,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:
@@ -1207,12 +1279,12 @@
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()));
+ ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
auto joinEnds = std::make_shared<OneOffSignal>();
// If things are broken and the thread never stops, don't block other tests. Because the thread
@@ -1253,14 +1325,14 @@
auto rpcServer = RpcServer::make();
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
- ASSERT_TRUE(rpcServer->setupInetServer(0, &port));
+ ASSERT_EQ(OK, rpcServer->setupInetServer(kLocalInetAddress, 0, &port));
auto socket = rpcServer->releaseServer();
auto keepAlive = sp<BBinder>::make();
ASSERT_EQ(OK, binder->setRpcClientDebug(std::move(socket), keepAlive));
auto rpcSession = RpcSession::make();
- ASSERT_TRUE(rpcSession->setupInetClient("127.0.0.1", port));
+ ASSERT_EQ(OK, rpcSession->setupInetClient("127.0.0.1", port));
auto rpcBinder = rpcSession->getRootObject();
ASSERT_NE(nullptr, rpcBinder);
@@ -1271,6 +1343,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..8bf04cc 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,8 +36,8 @@
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
if (provider.ConsumeBool()) {
- auto session = sp<RpcSession>::make();
- CHECK(session->addNullDebuggingClient());
+ auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ CHECK_EQ(OK, session->addNullDebuggingClient());
p->markForRpc(session);
fillRandomParcelData(p, std::move(provider));
return;
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/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index 9fc496f..230f5c7 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -60,7 +60,7 @@
sp<RpcServer> server = RpcServer::make();
server->setRootObject(sp<SomeBinder>::make());
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- CHECK(server->setupUnixDomainServer(kSock.c_str()));
+ CHECK_EQ(OK, server->setupUnixDomainServer(kSock.c_str()));
std::thread serverThread([=] { (void)server->join(); });
diff --git a/libs/binderdebug/BinderDebug.cpp b/libs/binderdebug/BinderDebug.cpp
index b435dba..d086b49 100644
--- a/libs/binderdebug/BinderDebug.cpp
+++ b/libs/binderdebug/BinderDebug.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <binder/Binder.h>
@@ -116,4 +117,60 @@
return ret;
}
+status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servicePid,
+ int32_t handle, std::vector<pid_t>* pids) {
+ std::smatch match;
+ static const std::regex kNodeNumber("^\\s+ref \\d+:\\s+desc\\s+(\\d+)\\s+node\\s+(\\d+).*");
+ std::string contextStr = contextToString(context);
+ int32_t node;
+ status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
+ if (std::regex_search(line, match, kNodeNumber)) {
+ const std::string& descString = match.str(1);
+ int32_t desc;
+ if (!::android::base::ParseInt(descString.c_str(), &desc)) {
+ LOG(ERROR) << "Failed to parse desc int: " << descString;
+ return;
+ }
+ if (handle != desc) {
+ return;
+ }
+ const std::string& nodeString = match.str(2);
+ if (!::android::base::ParseInt(nodeString.c_str(), &node)) {
+ LOG(ERROR) << "Failed to parse node int: " << nodeString;
+ return;
+ }
+ return;
+ }
+ return;
+ });
+ if (ret != OK) {
+ return ret;
+ }
+ static const std::regex kClients("^\\s+node\\s+(\\d+).*proc\\s+([\\d+\\s*]*)");
+ ret = scanBinderContext(servicePid, contextStr, [&](const std::string& line) {
+ if (std::regex_search(line, match, kClients)) {
+ const std::string nodeString = match.str(1);
+ int32_t matchedNode;
+ if (!::android::base::ParseInt(nodeString.c_str(), &matchedNode)) {
+ LOG(ERROR) << "Failed to parse node int: " << nodeString;
+ return;
+ }
+ if (node != matchedNode) {
+ return;
+ }
+ const std::string clients = match.str(2);
+ for (const std::string& pidStr : base::Split(clients, " ")) {
+ int32_t pid;
+ if (!::android::base::ParseInt(pidStr, &pid)) {
+ return;
+ }
+ pids->push_back(pid);
+ }
+ return;
+ }
+ return;
+ });
+ return ret;
+}
+
} // namespace android
diff --git a/libs/binderdebug/include/binderdebug/BinderDebug.h b/libs/binderdebug/include/binderdebug/BinderDebug.h
index 14a0ef3..dfd5a7c 100644
--- a/libs/binderdebug/include/binderdebug/BinderDebug.h
+++ b/libs/binderdebug/include/binderdebug/BinderDebug.h
@@ -32,6 +32,14 @@
VNDBINDER,
};
+/**
+ * pid is the pid of the service
+ */
status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo);
+/**
+ * pid is typically the pid of this process that is making the query
+ */
+status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servicePid,
+ int32_t handle, std::vector<pid_t>* pids);
} // namespace android
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 5cf7a5f..326da3a 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -68,6 +68,7 @@
"android/gui/FocusRequest.aidl",
"android/gui/InputApplicationInfo.aidl",
"android/gui/IWindowInfosListener.aidl",
+ "android/gui/IWindowInfosReportedListener.aidl",
"android/gui/WindowInfo.aidl",
"WindowInfo.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/LayerState.cpp b/libs/gui/LayerState.cpp
index 23895c0..1fd9d13 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -41,7 +41,6 @@
z(0),
w(0),
h(0),
- layerStack(0),
alpha(0),
flags(0),
mask(0),
@@ -86,7 +85,7 @@
SAFE_PARCEL(output.writeInt32, z);
SAFE_PARCEL(output.writeUint32, w);
SAFE_PARCEL(output.writeUint32, h);
- SAFE_PARCEL(output.writeUint32, layerStack);
+ SAFE_PARCEL(output.writeUint32, layerStack.id);
SAFE_PARCEL(output.writeFloat, alpha);
SAFE_PARCEL(output.writeUint32, flags);
SAFE_PARCEL(output.writeUint32, mask);
@@ -174,6 +173,7 @@
SAFE_PARCEL(output.write, destinationFrame);
SAFE_PARCEL(output.writeBool, isTrustedOverlay);
+ SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint);
return NO_ERROR;
}
@@ -187,7 +187,7 @@
SAFE_PARCEL(input.readInt32, &z);
SAFE_PARCEL(input.readUint32, &w);
SAFE_PARCEL(input.readUint32, &h);
- SAFE_PARCEL(input.readUint32, &layerStack);
+ SAFE_PARCEL(input.readUint32, &layerStack.id);
SAFE_PARCEL(input.readFloat, &alpha);
SAFE_PARCEL(input.readUint32, &flags);
@@ -303,6 +303,7 @@
SAFE_PARCEL(input.read, destinationFrame);
SAFE_PARCEL(input.readBool, &isTrustedOverlay);
+ SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint);
return NO_ERROR;
}
@@ -314,21 +315,14 @@
return state.read(input);
}
-DisplayState::DisplayState()
- : what(0),
- layerStack(0),
- flags(0),
- layerStackSpaceRect(Rect::EMPTY_RECT),
- orientedDisplaySpaceRect(Rect::EMPTY_RECT),
- width(0),
- height(0) {}
+DisplayState::DisplayState() = default;
status_t DisplayState::write(Parcel& output) const {
SAFE_PARCEL(output.writeStrongBinder, token);
SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(surface));
SAFE_PARCEL(output.writeUint32, what);
- SAFE_PARCEL(output.writeUint32, layerStack);
SAFE_PARCEL(output.writeUint32, flags);
+ SAFE_PARCEL(output.writeUint32, layerStack.id);
SAFE_PARCEL(output.writeUint32, toRotationInt(orientation));
SAFE_PARCEL(output.write, layerStackSpaceRect);
SAFE_PARCEL(output.write, orientedDisplaySpaceRect);
@@ -344,8 +338,8 @@
surface = interface_cast<IGraphicBufferProducer>(tmpBinder);
SAFE_PARCEL(input.readUint32, &what);
- SAFE_PARCEL(input.readUint32, &layerStack);
SAFE_PARCEL(input.readUint32, &flags);
+ SAFE_PARCEL(input.readUint32, &layerStack.id);
uint32_t tmpUint = 0;
SAFE_PARCEL(input.readUint32, &tmpUint);
orientation = ui::toRotation(tmpUint);
@@ -461,6 +455,7 @@
if (other.what & eBufferChanged) {
what |= eBufferChanged;
buffer = other.buffer;
+ releaseBufferEndpoint = other.releaseBufferEndpoint;
}
if (other.what & eAcquireFenceChanged) {
what |= eAcquireFenceChanged;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index f620f5a..05554ca 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -147,8 +147,16 @@
return mCallbackIdCounter++;
}
+sp<TransactionCompletedListener> TransactionCompletedListener::sInstance = nullptr;
+
+void TransactionCompletedListener::setInstance(const sp<TransactionCompletedListener>& listener) {
+ sInstance = listener;
+}
+
sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
- static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener;
+ if (sInstance == nullptr) {
+ sInstance = new TransactionCompletedListener;
+ }
return sInstance;
}
@@ -1087,7 +1095,7 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack(
- const sp<SurfaceControl>& sc, uint32_t layerStack) {
+ const sp<SurfaceControl>& sc, ui::LayerStack layerStack) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
@@ -1274,6 +1282,7 @@
removeReleaseBufferCallback(s);
s->what |= layer_state_t::eBufferChanged;
s->buffer = buffer;
+ s->releaseBufferEndpoint = IInterface::asBinder(TransactionCompletedListener::getIInstance());
if (mIsAutoTimestamp) {
mDesiredPresentTime = systemTime();
}
@@ -1751,7 +1760,7 @@
}
void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& token,
- uint32_t layerStack) {
+ ui::LayerStack layerStack) {
DisplayState& s(getDisplayState(token));
s.layerStack = layerStack;
s.what |= DisplayState::eLayerStackChanged;
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index ff0bb8a..b2ef7aa 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -54,8 +54,8 @@
info.frameLeft == frameLeft && info.frameTop == frameTop &&
info.frameRight == frameRight && info.frameBottom == frameBottom &&
info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor &&
- info.transform == transform && info.displayWidth == displayWidth &&
- info.displayHeight == displayHeight &&
+ info.transform == transform && info.displayOrientation == displayOrientation &&
+ info.displayWidth == displayWidth && info.displayHeight == displayHeight &&
info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible &&
info.trustedOverlay == trustedOverlay && info.focusable == focusable &&
info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper &&
@@ -97,6 +97,7 @@
parcel->writeFloat(transform.dtdy()) ?:
parcel->writeFloat(transform.dsdy()) ?:
parcel->writeFloat(transform.ty()) ?:
+ parcel->writeUint32(displayOrientation) ?:
parcel->writeInt32(displayWidth) ?:
parcel->writeInt32(displayHeight) ?:
parcel->writeBool(visible) ?:
@@ -114,7 +115,8 @@
applicationInfo.writeToParcel(parcel) ?:
parcel->write(touchableRegion) ?:
parcel->writeBool(replaceTouchableRegionWithCrop) ?:
- parcel->writeStrongBinder(touchableRegionCropHandle.promote());
+ parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
+ parcel->writeStrongBinder(windowToken);
// clang-format on
return status;
}
@@ -153,6 +155,7 @@
parcel->readFloat(&dtdy) ?:
parcel->readFloat(&dsdy) ?:
parcel->readFloat(&ty) ?:
+ parcel->readUint32(&displayOrientation) ?:
parcel->readInt32(&displayWidth) ?:
parcel->readInt32(&displayHeight) ?:
parcel->readBool(&visible) ?:
@@ -188,7 +191,8 @@
touchableRegionCropHandle = parcel->readStrongBinder();
transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1});
- return OK;
+ status = parcel->readNullableStrongBinder(&windowToken);
+ return status;
}
// --- WindowInfoHandle ---
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index 834e2b8..c00a438 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -19,6 +19,7 @@
namespace android {
+using gui::IWindowInfosReportedListener;
using gui::WindowInfo;
using gui::WindowInfosListener;
@@ -64,7 +65,8 @@
}
binder::Status WindowInfosListenerReporter::onWindowInfosChanged(
- const std::vector<WindowInfo>& windowInfos) {
+ const std::vector<WindowInfo>& windowInfos,
+ const sp<IWindowInfosReportedListener>& windowInfosReportedListener) {
std::unordered_set<sp<WindowInfosListener>, ISurfaceComposer::SpHash<WindowInfosListener>>
windowInfosListeners;
@@ -79,6 +81,10 @@
listener->onWindowInfosChanged(windowInfos);
}
+ if (windowInfosReportedListener) {
+ windowInfosReportedListener->onWindowInfosReported();
+ }
+
return binder::Status::ok();
}
diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl
index 500d928..d4553ca 100644
--- a/libs/gui/android/gui/IWindowInfosListener.aidl
+++ b/libs/gui/android/gui/IWindowInfosListener.aidl
@@ -16,10 +16,11 @@
package android.gui;
+import android.gui.IWindowInfosReportedListener;
import android.gui.WindowInfo;
/** @hide */
oneway interface IWindowInfosListener
{
- void onWindowInfosChanged(in WindowInfo[] windowInfos);
+ 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/LayerState.h b/libs/gui/include/gui/LayerState.h
index b27d9cf..f14127c 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -35,6 +35,7 @@
#include <math/vec3.h>
#include <ui/BlurRegion.h>
#include <ui/GraphicTypes.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Rotation.h>
@@ -143,7 +144,7 @@
int32_t z;
uint32_t w;
uint32_t h;
- uint32_t layerStack;
+ ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK;
float alpha;
uint32_t flags;
uint32_t mask;
@@ -242,6 +243,11 @@
// is used to remove the old callback from the client process map if it is
// overwritten by another setBuffer call.
ReleaseCallbackId releaseCallbackId;
+
+ // Stores which endpoint the release information should be sent to. We don't want to send the
+ // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer
+ // was called with.
+ sp<IBinder> releaseBufferEndpoint;
};
struct ComposerState {
@@ -262,11 +268,12 @@
DisplayState();
void merge(const DisplayState& other);
- uint32_t what;
+ uint32_t what = 0;
+ uint32_t flags = 0;
sp<IBinder> token;
sp<IGraphicBufferProducer> surface;
- uint32_t layerStack;
- uint32_t flags;
+
+ ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK;
// These states define how layers are projected onto the physical display.
//
@@ -280,10 +287,11 @@
// will be additionally rotated by 90 degrees around the origin clockwise and translated by (W,
// 0).
ui::Rotation orientation = ui::ROTATION_0;
- Rect layerStackSpaceRect;
- Rect orientedDisplaySpaceRect;
+ Rect layerStackSpaceRect = Rect::EMPTY_RECT;
+ Rect orientedDisplaySpaceRect = Rect::EMPTY_RECT;
- uint32_t width, height;
+ uint32_t width = 0;
+ uint32_t height = 0;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 869cef6..a980ce2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -456,7 +456,7 @@
int backgroundBlurRadius);
Transaction& setBlurRegions(const sp<SurfaceControl>& sc,
const std::vector<BlurRegion>& regions);
- Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
+ Transaction& setLayerStack(const sp<SurfaceControl>&, ui::LayerStack);
Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
/// Reparents the current layer to the new parent handle. The new parent must not be null.
@@ -566,7 +566,7 @@
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
- void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
+ void setDisplayLayerStack(const sp<IBinder>& token, ui::LayerStack);
void setDisplayFlags(const sp<IBinder>& token, uint32_t flags);
@@ -652,8 +652,10 @@
};
class TransactionCompletedListener : public BnTransactionCompletedListener {
+public:
TransactionCompletedListener();
+protected:
int64_t getNextIdLocked() REQUIRES(mMutex);
std::mutex mMutex;
@@ -731,8 +733,12 @@
void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t transformHint,
uint32_t currentMaxAcquiredBufferCount) override;
+ // For Testing Only
+ static void setInstance(const sp<TransactionCompletedListener>&);
+
private:
ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&);
+ static sp<TransactionCompletedListener> sInstance;
};
} // namespace android
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 7af1f0e..f090c63 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -132,6 +132,10 @@
// This value should NOT be used to uniquely identify the window. There may be different
// input windows that have the same token.
sp<IBinder> token;
+
+ // The token that identifies which client window this WindowInfo was created for.
+ sp<IBinder> windowToken;
+
// This uniquely identifies the input window.
int32_t id = -1;
std::string name;
@@ -164,7 +168,7 @@
// Transform applied to individual windows.
ui::Transform transform;
- // Display orientation. Used for compatibility raw coordinates.
+ // Display orientation as ui::Transform::RotationFlags. Used for compatibility raw coordinates.
uint32_t displayOrientation = ui::Transform::ROT_0;
// Display size in its natural rotation. Used to rotate raw coordinates for compatibility.
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
index 3e346de..7cb96e0 100644
--- a/libs/gui/include/gui/WindowInfosListenerReporter.h
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/gui/BnWindowInfosListener.h>
+#include <android/gui/IWindowInfosReportedListener.h>
#include <binder/IBinder.h>
#include <gui/ISurfaceComposer.h>
#include <gui/WindowInfosListener.h>
@@ -29,8 +30,8 @@
class WindowInfosListenerReporter : public gui::BnWindowInfosListener {
public:
static sp<WindowInfosListenerReporter> getInstance();
-
- binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) override;
+ 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>&);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 9082d27..26d902d 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -128,7 +128,7 @@
mDisplayToken = mClient->getInternalDisplayToken();
ASSERT_NE(nullptr, mDisplayToken.get());
Transaction t;
- t.setDisplayLayerStack(mDisplayToken, 0);
+ t.setDisplayLayerStack(mDisplayToken, ui::DEFAULT_LAYER_STACK);
t.apply();
t.clear();
@@ -142,7 +142,7 @@
mDisplayHeight, PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceBufferState,
/*parent*/ nullptr);
- t.setLayerStack(mSurfaceControl, 0)
+ t.setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
.show(mSurfaceControl)
.setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB)
@@ -490,7 +490,7 @@
ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_NE(nullptr, bg.get());
Transaction t;
- t.setLayerStack(bg, 0)
+ t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK)
.setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
.setColor(bg, half3{0, 0, 0})
.setLayer(bg, 0)
@@ -545,7 +545,7 @@
ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_NE(nullptr, bg.get());
Transaction t;
- t.setLayerStack(bg, 0)
+ t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK)
.setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
.setColor(bg, half3{0, 0, 0})
.setLayer(bg, 0)
@@ -612,7 +612,7 @@
ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_NE(nullptr, bg.get());
Transaction t;
- t.setLayerStack(bg, 0)
+ t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK)
.setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
.setColor(bg, half3{0, 0, 0})
.setLayer(bg, 0)
@@ -733,7 +733,7 @@
ISurfaceComposerClient::eFXSurfaceBufferState);
ASSERT_NE(nullptr, bgSurface.get());
Transaction t;
- t.setLayerStack(bgSurface, 0)
+ t.setLayerStack(bgSurface, ui::DEFAULT_LAYER_STACK)
.show(bgSurface)
.setDataspace(bgSurface, ui::Dataspace::V0_SRGB)
.setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1)
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index 58f3981..a4f436c 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -46,6 +46,7 @@
sp<IBinder> touchableRegionCropHandle = new BBinder();
WindowInfo i;
i.token = new BBinder();
+ i.windowToken = new BBinder();
i.id = 1;
i.name = "Foobar";
i.flags = WindowInfo::Flag::SLIPPERY;
@@ -85,6 +86,7 @@
WindowInfo i2;
i2.readFromParcel(&p);
ASSERT_EQ(i.token, i2.token);
+ ASSERT_EQ(i.windowToken, i2.windowToken);
ASSERT_EQ(i.id, i2.id);
ASSERT_EQ(i.name, i2.name);
ASSERT_EQ(i.flags, i2.flags);
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 02cf9eb..e73c3b8 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -83,7 +83,6 @@
"android/os/IInputFlinger.aidl",
"android/os/InputEventInjectionResult.aidl",
"android/os/InputEventInjectionSync.aidl",
- "android/os/ISetInputWindowsListener.aidl",
],
export_shared_lib_headers: ["libbinder"],
@@ -119,7 +118,6 @@
"InputTransport.cpp",
"android/os/IInputConstants.aidl",
"android/os/IInputFlinger.aidl",
- "android/os/ISetInputWindowsListener.aidl",
],
static_libs: [
"libhostgraphics",
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/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
index 6eaa84e..bac44c9 100644
--- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
+++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
@@ -272,10 +272,11 @@
status_t attachToContext(uint32_t tex);
sp<GraphicBuffer> dequeueBuffer(int* outSlotid, android_dataspace* outDataspace,
- float* outTransformMatrix, bool* outQueueEmpty,
+ float* outTransformMatrix, uint32_t* outTransform,
+ bool* outQueueEmpty,
SurfaceTexture_createReleaseFence createFence,
SurfaceTexture_fenceWait fenceWait,
- void* fencePassThroughHandle);
+ void* fencePassThroughHandle, ARect* currentCrop);
/**
* takeConsumerOwnership attaches a SurfaceTexture that is currently in the
diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
index 85fe42f..e85009c 100644
--- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
+++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
@@ -84,10 +84,11 @@
*/
AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid,
android_dataspace* outDataspace,
- float* outTransformMatrix, bool* outNewContent,
+ float* outTransformMatrix, uint32_t* outTransform,
+ bool* outNewContent,
ASurfaceTexture_createReleaseFence createFence,
ASurfaceTexture_fenceWait fenceWait,
- void* fencePassThroughHandle);
+ void* fencePassThroughHandle, ARect* currentCrop);
} // namespace android
diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
index 62db6d0..3535e67 100644
--- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
+++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
@@ -464,10 +464,11 @@
}
sp<GraphicBuffer> SurfaceTexture::dequeueBuffer(int* outSlotid, android_dataspace* outDataspace,
- float* outTransformMatrix, bool* outQueueEmpty,
+ float* outTransformMatrix, uint32_t* outTransform,
+ bool* outQueueEmpty,
SurfaceTexture_createReleaseFence createFence,
SurfaceTexture_fenceWait fenceWait,
- void* fencePassThroughHandle) {
+ void* fencePassThroughHandle, ARect* currentCrop) {
Mutex::Autolock _l(mMutex);
sp<GraphicBuffer> buffer;
@@ -484,6 +485,8 @@
buffer = mImageConsumer.dequeueBuffer(outSlotid, outDataspace, outQueueEmpty, *this,
createFence, fenceWait, fencePassThroughHandle);
memcpy(outTransformMatrix, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
+ *outTransform = mCurrentTransform;
+ *currentCrop = mCurrentCrop;
return buffer;
}
diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp
index c214ab7..cc0a12d 100644
--- a/libs/nativedisplay/surfacetexture/surface_texture.cpp
+++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp
@@ -194,15 +194,18 @@
AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid,
android_dataspace* outDataspace,
- float* outTransformMatrix, bool* outNewContent,
+ float* outTransformMatrix, uint32_t* outTransform,
+ bool* outNewContent,
ASurfaceTexture_createReleaseFence createFence,
- ASurfaceTexture_fenceWait fenceWait, void* handle) {
+ ASurfaceTexture_fenceWait fenceWait, void* handle,
+ ARect* currentCrop) {
sp<GraphicBuffer> buffer;
*outNewContent = false;
bool queueEmpty;
do {
buffer = st->consumer->dequeueBuffer(outSlotid, outDataspace, outTransformMatrix,
- &queueEmpty, createFence, fenceWait, handle);
+ outTransform, &queueEmpty, createFence, fenceWait,
+ handle, currentCrop);
if (!queueEmpty) {
*outNewContent = true;
}
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index c478506..5d23a5e 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,3 +1,4 @@
+adyabr@google.com
alecmouri@google.com
djsollen@google.com
jreck@google.com
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 0c5a851..2174df5 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -95,5 +95,16 @@
"output buffer not gpu writeable");
}
+std::future<RenderEngineResult> RenderEngine::drawLayers(
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) {
+ const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
+ std::future<RenderEngineResult> resultFuture = resultPromise->get_future();
+ drawLayersInternal(std::move(resultPromise), display, layers, buffer, useFramebufferCache,
+ std::move(bufferFence));
+ return resultFuture;
+}
+
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index b1e1014..2375cb7 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1078,15 +1078,16 @@
return image;
}
-status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) {
+void GLESRenderEngine::drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) {
ATRACE_CALL();
if (layers.empty()) {
ALOGV("Drawing empty layer stack");
- return NO_ERROR;
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ return;
}
if (bufferFence.get() >= 0) {
@@ -1100,7 +1101,8 @@
if (buffer == nullptr) {
ALOGE("No output buffer provided. Aborting GPU composition.");
- return BAD_VALUE;
+ resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+ return;
}
validateOutputBufferUsage(buffer->getBuffer());
@@ -1128,7 +1130,8 @@
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors();
- return fbo->getStatus();
+ resultPromise->set_value({fbo->getStatus(), base::unique_fd()});
+ return;
}
setViewportAndProjection(display.physicalDisplay, display.clip);
} else {
@@ -1139,7 +1142,8 @@
ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors();
- return status;
+ resultPromise->set_value({status, base::unique_fd()});
+ return;
}
}
@@ -1172,7 +1176,8 @@
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors("Can't render first blur pass");
- return status;
+ resultPromise->set_value({status, base::unique_fd()});
+ return;
}
if (blurLayers.size() == 0) {
@@ -1194,7 +1199,8 @@
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors("Can't bind native framebuffer");
- return status;
+ resultPromise->set_value({status, base::unique_fd()});
+ return;
}
status = mBlurFilter->render(blurLayersSize > 1);
@@ -1202,7 +1208,8 @@
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors("Can't render blur filter");
- return status;
+ resultPromise->set_value({status, base::unique_fd()});
+ return;
}
}
@@ -1289,30 +1296,31 @@
}
}
- if (drawFence != nullptr) {
- *drawFence = flush();
- }
+ base::unique_fd drawFence = flush();
+
// If flush failed or we don't support native fences, we need to force the
// gl command stream to be executed.
- if (drawFence == nullptr || drawFence->get() < 0) {
+ if (drawFence.get() < 0) {
bool success = finish();
if (!success) {
ALOGE("Failed to flush RenderEngine commands");
checkErrors();
// Chances are, something illegal happened (either the caller passed
// us bad parameters, or we messed up our shader generation).
- return INVALID_OPERATION;
+ resultPromise->set_value({INVALID_OPERATION, std::move(drawFence)});
+ return;
}
mLastDrawFence = nullptr;
} else {
// The caller takes ownership of drawFence, so we need to duplicate the
// fd here.
- mLastDrawFence = new Fence(dup(drawFence->get()));
+ mLastDrawFence = new Fence(dup(drawFence.get()));
}
mPriorResourcesCleaned = false;
checkErrors();
- return NO_ERROR;
+ resultPromise->set_value({NO_ERROR, std::move(drawFence)});
+ return;
}
void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 14627ce..c4adfdf 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -63,11 +63,6 @@
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
void useProtectedContext(bool useProtectedContext) override;
- status_t drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) override;
void cleanupPostRender() override;
int getContextPriority() override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
@@ -107,6 +102,11 @@
EXCLUDES(mRenderingMutex);
void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
bool canSkipPostRenderCleanup() const override;
+ void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
private:
friend class BindNativeBufferAsFramebuffer;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 967cf5d..701c1f2 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -68,6 +68,7 @@
class Mesh;
class Texture;
struct RenderEngineCreationArgs;
+struct RenderEngineResult;
namespace threaded {
class RenderEngineThreaded;
@@ -156,17 +157,12 @@
// parameter does nothing.
// @param bufferFence Fence signalling that the buffer is ready to be drawn
// to.
- // @param drawFence A pointer to a fence, which will fire when the buffer
- // has been drawn to and is ready to be examined. The fence will be
- // initialized by this method. The caller will be responsible for owning the
- // fence.
- // @return An error code indicating whether drawing was successful. For
- // now, this always returns NO_ERROR.
- virtual status_t drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) = 0;
+ // @return A future object of RenderEngineResult struct indicating whether
+ // drawing was successful in async mode.
+ virtual std::future<RenderEngineResult> drawLayers(
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence);
// Clean-up method that should be called on the main thread after the
// drawFence returned by drawLayers fires. This method will free up
@@ -232,6 +228,12 @@
friend class threaded::RenderEngineThreaded;
friend class RenderEngineTest_cleanupPostRender_cleansUpOnce_Test;
const RenderEngineType mRenderEngineType;
+
+ virtual void drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) = 0;
};
struct RenderEngineCreationArgs {
@@ -318,6 +320,13 @@
RenderEngine::RenderEngineType::SKIA_GL_THREADED;
};
+struct RenderEngineResult {
+ // status indicates if drawing is successful
+ status_t status;
+ // drawFence will fire when the buffer has been drawn to and is ready to be examined.
+ base::unique_fd drawFence;
+};
+
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 0be3ba6..a7e6809 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -47,10 +47,15 @@
MOCK_METHOD1(useProtectedContext, void(bool));
MOCK_METHOD0(cleanupPostRender, void());
MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool());
- MOCK_METHOD6(drawLayers,
- status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&,
- const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&,
- base::unique_fd*));
+ MOCK_METHOD5(drawLayers,
+ std::future<RenderEngineResult>(const DisplaySettings&,
+ const std::vector<const LayerSettings*>&,
+ const std::shared_ptr<ExternalTexture>&,
+ const bool, base::unique_fd&&));
+ MOCK_METHOD6(drawLayersInternal,
+ void(const std::shared_ptr<std::promise<RenderEngineResult>>&&,
+ const DisplaySettings&, const std::vector<const LayerSettings*>&,
+ const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&));
MOCK_METHOD0(cleanFramebufferCache, void());
MOCK_METHOD0(getContextPriority, int());
MOCK_METHOD0(supportsBackgroundBlur, bool());
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 01df6a6..e796f66 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -95,7 +95,6 @@
.alpha = 1,
};
- base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer, &caster};
// Four combinations of settings are used (two transforms here, and drawShadowLayers is
// called with two different destination data spaces) They're all rounded rect.
@@ -116,7 +115,7 @@
layer.geometry.positionTransform = transform;
caster.geometry.positionTransform = transform;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), &drawFence);
+ base::unique_fd());
}
}
@@ -141,7 +140,6 @@
}},
};
- base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
layer.sourceDataspace = dataspace;
@@ -155,7 +153,7 @@
for (auto alpha : {half(.2f), half(1.0f)}) {
layer.alpha = alpha;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), &drawFence);
+ base::unique_fd());
}
}
}
@@ -178,14 +176,13 @@
.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(), &drawFence);
+ base::unique_fd());
}
}
}
@@ -204,13 +201,12 @@
.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(), &drawFence);
+ base::unique_fd());
}
}
@@ -246,7 +242,6 @@
},
};
- base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
layer.source = pixelSource;
@@ -258,7 +253,7 @@
for (float alpha : {0.5f, 1.f}) {
layer.alpha = alpha,
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), &drawFence);
+ base::unique_fd());
}
}
}
@@ -294,10 +289,8 @@
};
- base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), &drawFence);
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd());
}
static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
@@ -324,10 +317,8 @@
};
- base::unique_fd drawFence;
auto layers = std::vector<const LayerSettings*>{&layer};
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), &drawFence);
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd());
}
//
@@ -436,8 +427,10 @@
.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
+ // call get() to make it synchronous
+ renderengine
+ ->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd())
+ .get();
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 9fbbdc3..052c61f 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -713,17 +713,18 @@
return roundedRect;
}
-status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool /*useFramebufferCache*/,
- base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
+void SkiaGLRenderEngine::drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
+ base::unique_fd&& bufferFence) {
ATRACE_NAME("SkiaGL::drawLayers");
std::lock_guard<std::mutex> lock(mRenderingMutex);
if (layers.empty()) {
ALOGV("Drawing empty layer stack");
- return NO_ERROR;
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ return;
}
if (bufferFence.get() >= 0) {
@@ -736,7 +737,8 @@
}
if (buffer == nullptr) {
ALOGE("No output buffer provided. Aborting GPU composition.");
- return BAD_VALUE;
+ resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+ return;
}
validateOutputBufferUsage(buffer->getBuffer());
@@ -765,7 +767,8 @@
SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
if (dstCanvas == nullptr) {
ALOGE("Cannot acquire canvas from Skia.");
- return BAD_VALUE;
+ resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+ return;
}
// setup color filter if necessary
@@ -1094,13 +1097,11 @@
activeSurface->flush();
}
- if (drawFence != nullptr) {
- *drawFence = flush();
- }
+ base::unique_fd drawFence = flush();
// If flush failed or we don't support native fences, we need to force the
// gl command stream to be executed.
- bool requireSync = drawFence == nullptr || drawFence->get() < 0;
+ bool requireSync = drawFence.get() < 0;
if (requireSync) {
ATRACE_BEGIN("Submit(sync=true)");
} else {
@@ -1112,11 +1113,13 @@
ALOGE("Failed to flush RenderEngine commands");
// Chances are, something illegal happened (either the caller passed
// us bad parameters, or we messed up our shader generation).
- return INVALID_OPERATION;
+ resultPromise->set_value({INVALID_OPERATION, std::move(drawFence)});
+ return;
}
// checkErrors();
- return NO_ERROR;
+ resultPromise->set_value({NO_ERROR, std::move(drawFence)});
+ return;
}
inline SkRect SkiaGLRenderEngine::getSkRect(const FloatRect& rect) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index cc91948..0b46705 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -54,11 +54,6 @@
~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex);
std::future<void> primeCache() override;
- status_t drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) override;
void cleanupPostRender() override;
void cleanFramebufferCache() override{};
int getContextPriority() override;
@@ -77,6 +72,11 @@
void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
bool canSkipPostRenderCleanup() const override;
+ void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
private:
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 7cd9eca..f61653b 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -44,14 +44,6 @@
virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{};
virtual bool isProtected() const override { return false; } // mInProtectedContext; }
virtual bool supportsProtectedContent() const override { return false; };
- virtual status_t drawLayers(const DisplaySettings& /*display*/,
- const std::vector<const LayerSettings*>& /*layers*/,
- const std::shared_ptr<ExternalTexture>& /*buffer*/,
- const bool /*useFramebufferCache*/,
- base::unique_fd&& /*bufferFence*/,
- base::unique_fd* /*drawFence*/) override {
- return 0;
- };
virtual int getContextPriority() override { return 0; }
virtual void assertShadersCompiled(int numShaders) {}
virtual int reportShadersCompiled() { return 0; }
@@ -60,6 +52,14 @@
virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/,
bool /*isRenderable*/) override = 0;
virtual void unmapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/) override = 0;
+
+ virtual void drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) override {
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ };
};
} // namespace skia
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 33053a0..b3b726d 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -419,9 +419,10 @@
void invokeDraw(renderengine::DisplaySettings settings,
std::vector<const renderengine::LayerSettings*> layers) {
- base::unique_fd fence;
- status_t status =
- mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence);
+ std::future<renderengine::RenderEngineResult> result =
+ mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
+ ASSERT_TRUE(result.valid());
+ auto [status, fence] = result.get();
int fd = fence.release();
if (fd >= 0) {
@@ -1312,9 +1313,11 @@
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layers.push_back(&layer);
- base::unique_fd fence;
- status_t status = mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
+ std::future<renderengine::RenderEngineResult> result =
+ mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd());
+ ASSERT_TRUE(result.valid());
+ auto [status, _] = result.get();
ASSERT_EQ(BAD_VALUE, status);
}
@@ -1333,7 +1336,10 @@
layer.alpha = 1.0;
layers.push_back(&layer);
- status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr);
+ std::future<renderengine::RenderEngineResult> result =
+ mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
+ ASSERT_TRUE(result.valid());
+ auto [status, _] = result.get();
ASSERT_EQ(NO_ERROR, status);
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
@@ -1360,7 +1366,10 @@
layer.alpha = 1.0;
layers.push_back(&layer);
- status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr);
+ std::future<renderengine::RenderEngineResult> result =
+ mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd());
+ ASSERT_TRUE(result.valid());
+ auto [status, _] = result.get();
ASSERT_EQ(NO_ERROR, status);
ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
@@ -1760,10 +1769,17 @@
layer.alpha = 1.0;
layers.push_back(&layer);
- base::unique_fd fenceOne;
- mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fenceOne);
- base::unique_fd fenceTwo;
- mRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne), &fenceTwo);
+ std::future<renderengine::RenderEngineResult> resultOne =
+ mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
+ ASSERT_TRUE(resultOne.valid());
+ auto [statusOne, fenceOne] = resultOne.get();
+ ASSERT_EQ(NO_ERROR, statusOne);
+
+ std::future<renderengine::RenderEngineResult> resultTwo =
+ mRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne));
+ ASSERT_TRUE(resultTwo.valid());
+ auto [statusTwo, fenceTwo] = resultTwo.get();
+ ASSERT_EQ(NO_ERROR, statusTwo);
const int fd = fenceTwo.get();
if (fd >= 0) {
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 830f463..99250c1 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -169,6 +169,7 @@
status_t result = mThreadedRE->supportsBackgroundBlur();
ASSERT_EQ(true, result);
}
+
TEST_F(RenderEngineThreadedTest, drawLayers) {
renderengine::DisplaySettings settings;
std::vector<const renderengine::LayerSettings*> layers;
@@ -177,17 +178,22 @@
renderengine::ExternalTexture::Usage::READABLE |
renderengine::ExternalTexture::Usage::WRITEABLE);
base::unique_fd bufferFence;
- base::unique_fd drawFence;
- EXPECT_CALL(*mRenderEngine, drawLayers)
- .WillOnce([](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>&,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> status_t { return NO_ERROR; });
+ EXPECT_CALL(*mRenderEngine, drawLayersInternal)
+ .WillOnce([&](const std::shared_ptr<std::promise<renderengine::RenderEngineResult>>&&
+ resultPromise,
+ const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> void {
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ });
- status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false,
- std::move(bufferFence), &drawFence);
- ASSERT_EQ(NO_ERROR, result);
+ std::future<renderengine::RenderEngineResult> result =
+ mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence));
+ ASSERT_TRUE(result.valid());
+ auto [status, _] = result.get();
+ ASSERT_EQ(NO_ERROR, status);
}
} // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 8e666d5..9a8201f 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -304,27 +304,33 @@
return mRenderEngine->canSkipPostRenderCleanup();
}
-status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache,
- base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) {
+void RenderEngineThreaded::drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) {
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ return;
+}
+
+std::future<RenderEngineResult> RenderEngineThreaded::drawLayers(
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) {
ATRACE_CALL();
- std::promise<status_t> resultPromise;
- std::future<status_t> resultFuture = resultPromise.get_future();
+ const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
+ std::future<RenderEngineResult> resultFuture = resultPromise->get_future();
{
std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise, &display, &layers, &buffer, useFramebufferCache,
- &bufferFence, &drawFence](renderengine::RenderEngine& instance) {
+ mFunctionCalls.push([resultPromise, &display, &layers, &buffer, useFramebufferCache,
+ &bufferFence](renderengine::RenderEngine& instance) {
ATRACE_NAME("REThreaded::drawLayers");
- status_t status = instance.drawLayers(display, layers, buffer, useFramebufferCache,
- std::move(bufferFence), drawFence);
- resultPromise.set_value(status);
+ instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer,
+ useFramebufferCache, std::move(bufferFence));
});
}
mCondition.notify_one();
- return resultFuture.get();
+ return resultFuture;
}
void RenderEngineThreaded::cleanFramebufferCache() {
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index b197df7..2303caa 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -56,11 +56,11 @@
void useProtectedContext(bool useProtectedContext) override;
void cleanupPostRender() override;
- status_t drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) override;
+ std::future<RenderEngineResult> drawLayers(const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) override;
void cleanFramebufferCache() override;
int getContextPriority() override;
@@ -71,6 +71,11 @@
void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
bool canSkipPostRenderCleanup() const override;
+ void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
private:
void threadMain(CreateInstanceFactory factory);
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/libs/ui/include/ui/DisplayState.h b/libs/ui/include/ui/DisplayState.h
index 70a0d50..98ee356 100644
--- a/libs/ui/include/ui/DisplayState.h
+++ b/libs/ui/include/ui/DisplayState.h
@@ -16,21 +16,18 @@
#pragma once
+#include <ui/LayerStack.h>
#include <ui/Rotation.h>
#include <ui/Size.h>
-#include <cstdint>
#include <type_traits>
namespace android::ui {
-using LayerStack = uint32_t;
-constexpr LayerStack NO_LAYER_STACK = static_cast<LayerStack>(-1);
-
// Transactional state of physical or virtual display. Note that libgui defines
// android::DisplayState as a superset of android::ui::DisplayState.
struct DisplayState {
- LayerStack layerStack = NO_LAYER_STACK;
+ LayerStack layerStack;
Rotation orientation = ROTATION_0;
Size layerStackSpaceRect;
};
diff --git a/libs/ui/include/ui/LayerStack.h b/libs/ui/include/ui/LayerStack.h
new file mode 100644
index 0000000..d6ffeb7
--- /dev/null
+++ b/libs/ui/include/ui/LayerStack.h
@@ -0,0 +1,78 @@
+/*
+ * 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 <ftl/cast.h>
+#include <ftl/string.h>
+#include <log/log.h>
+
+namespace android::ui {
+
+// A LayerStack identifies a Z-ordered group of layers. A layer can only be associated to a single
+// LayerStack, but a LayerStack can be associated to multiple displays, mirroring the same content.
+struct LayerStack {
+ uint32_t id = UINT32_MAX;
+
+ template <typename T>
+ static constexpr LayerStack fromValue(T v) {
+ if (ftl::cast_safety<uint32_t>(v) == ftl::CastSafety::kSafe) {
+ return {static_cast<uint32_t>(v)};
+ }
+
+ ALOGW("Invalid layer stack %s", ftl::to_string(v).c_str());
+ return {};
+ }
+};
+
+constexpr LayerStack INVALID_LAYER_STACK;
+constexpr LayerStack DEFAULT_LAYER_STACK{0u};
+
+inline bool operator==(LayerStack lhs, LayerStack rhs) {
+ return lhs.id == rhs.id;
+}
+
+inline bool operator!=(LayerStack lhs, LayerStack rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator>(LayerStack lhs, LayerStack rhs) {
+ return lhs.id > rhs.id;
+}
+
+// A LayerFilter determines if a layer is included for output to a display.
+struct LayerFilter {
+ LayerStack layerStack;
+
+ // True if the layer is only output to internal displays, i.e. excluded from screenshots, screen
+ // recordings, and mirroring to virtual or external displays. Used for display cutout overlays.
+ bool toInternalDisplay = false;
+
+ // Returns true if the input filter can be output to this filter.
+ bool includes(LayerFilter other) const {
+ // The layer stacks must match.
+ if (other.layerStack == INVALID_LAYER_STACK || other.layerStack != layerStack) {
+ return false;
+ }
+
+ // The output must be to an internal display if the input filter has that constraint.
+ return !other.toInternalDisplay || toInternalDisplay;
+ }
+};
+
+} // namespace android::ui
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 693b1f9..7b3658d 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -114,24 +114,6 @@
return mDispatcher;
}
-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 WindowInfoHandle(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/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 1478a3c..59cb419 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -5047,12 +5047,13 @@
windowInfo->inputFeatures.string().c_str());
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
"ms, trustedOverlay=%s, hasToken=%s, "
- "touchOcclusionMode=%s\n",
+ "touchOcclusionMode=%s, displayOrientation=%d\n",
windowInfo->ownerPid, windowInfo->ownerUid,
millis(windowInfo->dispatchingTimeout),
toString(windowInfo->trustedOverlay),
toString(windowInfo->token != nullptr),
- toString(windowInfo->touchOcclusionMode).c_str());
+ toString(windowInfo->touchOcclusionMode).c_str(),
+ windowInfo->displayOrientation);
windowInfo->transform.dump(dump, "transform", INDENT4);
}
} else {
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/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/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index af02844..a9f0247 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -896,6 +896,13 @@
mTiltXScale = M_PI / 180;
mTiltYScale = M_PI / 180;
+ if (mRawPointerAxes.tiltX.resolution) {
+ mTiltXScale = 1.0 / mRawPointerAxes.tiltX.resolution;
+ }
+ if (mRawPointerAxes.tiltY.resolution) {
+ mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution;
+ }
+
mOrientedRanges.haveTilt = true;
mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
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 50e1854..0fc4708 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -16,6 +16,7 @@
#include "../dispatcher/InputDispatcher.h"
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <binder/Binder.h>
@@ -678,7 +679,11 @@
// --- InputDispatcherTest SetInputWindowTest ---
static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
-static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 5s;
+// Default input dispatching timeout if there is no focused application or paused window
+// from which to determine an appropriate dispatching timeout.
+static const std::chrono::duration DISPATCHING_TIMEOUT = std::chrono::milliseconds(
+ android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
+ android::base::HwTimeoutMultiplier());
class FakeApplicationHandle : public InputApplicationHandle {
public:
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..c351676 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -168,7 +168,7 @@
}
}
- // Sanity check and clamp power if it is 0 (or close)
+ // Check and clamp power if it is 0 (or close)
constexpr float MIN_POWER_MA = 0.001; // 1 microAmp
if (sensor.power < MIN_POWER_MA) {
ALOGI("%s's reported power %f invalid, clamped to %f",
@@ -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/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 9ce8d9b..c58e992 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -867,7 +867,7 @@
} else if (numBytesRead == sizeof(uint32_t)) {
uint32_t numAcks = 0;
memcpy(&numAcks, buf, numBytesRead);
- // Sanity check to ensure there are no read errors in recv, numAcks is always
+ // Check to ensure there are no read errors in recv, numAcks is always
// within the range and not zero. If any of the above don't hold reset
// mWakeLockRefCount to zero.
if (numAcks > 0 && numAcks < mWakeLockRefCount) {
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/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 726fe8e..3081b1a 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1197,7 +1197,7 @@
// We have a dynamic sensor.
if (!sHmacGlobalKeyIsValid) {
- // Rather than risk exposing UUIDs, we cripple dynamic sensors.
+ // Rather than risk exposing UUIDs, we slow down dynamic sensors.
ALOGW("HMAC key failure; dynamic sensor getId() will be wrong.");
return 0;
}
@@ -1223,7 +1223,7 @@
sHmacGlobalKey, sizeof(sHmacGlobalKey),
uuidAndApp, sizeof(uuidAndApp),
hash, &hashLen) == nullptr) {
- // Rather than risk exposing UUIDs, we cripple dynamic sensors.
+ // Rather than risk exposing UUIDs, we slow down dynamic sensors.
ALOGW("HMAC failure; dynamic sensor getId() will be wrong.");
return 0;
}
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 eeb3f3a..af012cd 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -66,6 +66,7 @@
"libinput",
"libutils",
"libSurfaceFlingerProp",
+ "server_configurable_flags",
],
static_libs: [
"libcompositionengine",
@@ -154,6 +155,7 @@
"DisplayRenderArea.cpp",
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
+ "FlagManager.cpp",
"FpsReporter.cpp",
"FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e329aa0..7466c06 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -14,11 +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"
-#pragma clang diagnostic ignored "-Wextra"
-
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "BufferStateLayer"
@@ -158,7 +153,8 @@
// transaction doesn't need a previous release fence.
sp<CallbackHandle> ch;
for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
ch = handle;
break;
}
@@ -199,14 +195,9 @@
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
}
- // If there are multiple transactions in this frame, set the previous id on the earliest
- // transacton. We don't need to pass in the released buffer id to multiple transactions.
- // The buffer id does not have to correspond to any particular transaction as long as the
- // listening end point is the same but the client expects the first transaction callback that
- // replaces the presented buffer to contain the release fence. This follows the same logic.
- // see BufferStateLayer::onLayerDisplayed.
for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
handle->previousReleaseCallbackId = mPreviousReleaseCallbackId;
break;
}
@@ -420,12 +411,14 @@
nsecs_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& clientCacheId, uint64_t frameNumber,
std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
- const sp<ITransactionCompletedListener>& releaseBufferListener) {
+ const sp<ITransactionCompletedListener>& releaseBufferListener,
+ const sp<IBinder>& releaseBufferEndpoint) {
ATRACE_CALL();
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
@@ -484,6 +477,7 @@
mDrawingState.width = mDrawingState.buffer->getBuffer()->getWidth();
mDrawingState.height = mDrawingState.buffer->getBuffer()->getHeight();
+ mDrawingState.releaseBufferEndpoint = releaseBufferEndpoint;
return true;
}
@@ -597,7 +591,7 @@
return true;
}
-Rect BufferStateLayer::getBufferSize(const State& s) const {
+Rect BufferStateLayer::getBufferSize(const State& /*s*/) const {
// for buffer state layers we use the display frame size as the buffer size.
if (mBufferInfo.mBuffer == nullptr) {
@@ -619,7 +613,7 @@
}
}
- return Rect(0, 0, bufWidth, bufHeight);
+ return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight));
}
FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const {
@@ -818,7 +812,7 @@
eraseBufferLocked(clientCacheId);
}
-uint32_t BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) {
+int BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) {
std::lock_guard<std::mutex> lock(mMutex);
auto itr = mCachedBuffers.find(clientCacheId);
if (itr == mCachedBuffers.end()) {
@@ -829,7 +823,7 @@
return hwcCacheSlot;
}
-uint32_t BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId)
+int BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId)
REQUIRES(mMutex) {
if (!clientCacheId.isValid()) {
ALOGE("invalid process, returning invalid slot");
@@ -838,17 +832,17 @@
ClientCache::getInstance().registerErasedRecipient(clientCacheId, wp<ErasedRecipient>(this));
- uint32_t hwcCacheSlot = getFreeHwcCacheSlot();
+ int hwcCacheSlot = getFreeHwcCacheSlot();
mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++};
return hwcCacheSlot;
}
-uint32_t BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) {
+int BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) {
if (mFreeHwcCacheSlots.empty()) {
evictLeastRecentlyUsed();
}
- uint32_t hwcCacheSlot = mFreeHwcCacheSlots.top();
+ int hwcCacheSlot = mFreeHwcCacheSlots.top();
mFreeHwcCacheSlots.pop();
return hwcCacheSlot;
}
@@ -935,8 +929,8 @@
return false;
}
- uint32_t bufferWidth = s.buffer->getBuffer()->width;
- uint32_t bufferHeight = s.buffer->getBuffer()->height;
+ int32_t bufferWidth = s.buffer->getBuffer()->width;
+ int32_t bufferHeight = s.buffer->getBuffer()->height;
// Undo any transformations on the buffer and return the result.
if (s.bufferTransform & ui::Transform::ROT_90) {
@@ -963,22 +957,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
@@ -1011,6 +989,3 @@
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index e567478..124e91a 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -59,7 +59,8 @@
const sp<Fence>& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime,
bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber,
std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
- const sp<ITransactionCompletedListener>& transactionListener) override;
+ const sp<ITransactionCompletedListener>& transactionListener,
+ const sp<IBinder>& releaseBufferEndpoint) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
@@ -97,7 +98,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; }
@@ -178,19 +178,19 @@
class HwcSlotGenerator : public ClientCache::ErasedRecipient {
public:
HwcSlotGenerator() {
- for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
mFreeHwcCacheSlots.push(i);
}
}
void bufferErased(const client_cache_t& clientCacheId);
- uint32_t getHwcCacheSlot(const client_cache_t& clientCacheId);
+ int getHwcCacheSlot(const client_cache_t& clientCacheId);
private:
friend class SlotGenerationTest;
- uint32_t addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex);
- uint32_t getFreeHwcCacheSlot() REQUIRES(mMutex);
+ int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex);
+ int getFreeHwcCacheSlot() REQUIRES(mMutex);
void evictLeastRecentlyUsed() REQUIRES(mMutex);
void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex);
@@ -202,11 +202,10 @@
std::mutex mMutex;
- std::unordered_map<client_cache_t,
- std::pair<uint32_t /*HwcCacheSlot*/, uint32_t /*counter*/>,
+ std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>,
CachedBufferHash>
mCachedBuffers GUARDED_BY(mMutex);
- std::stack<uint32_t /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex);
+ std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex);
// The cache increments this counter value when a slot is updated or used.
// Used to track the least recently-used buffer
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/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index 554e2f4..95d553d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -47,9 +47,6 @@
// All the layers that have queued updates.
Layers layersWithQueuedFrames;
- // If true, forces the entire display to be considered dirty and repainted
- bool repaintEverything{false};
-
// Controls how the color mode is chosen for an output
OutputColorSetting outputColorSetting{OutputColorSetting::kEnhanced};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 526e7da..98c4af4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -36,18 +36,12 @@
struct DisplayCreationArgs {
DisplayId id;
- // Unset for virtual displays
- std::optional<ui::DisplayConnectionType> connectionType;
-
// Size of the display in pixels
ui::Size pixels = ui::kInvalidSize;
// True if this display should be considered secure
bool isSecure = false;
- // Gives the initial layer stack id to be used for the display
- uint32_t layerStackId = ~0u;
-
// Optional pointer to the power advisor interface, if one is needed for
// this display.
Hwc2::PowerAdvisor* powerAdvisor = nullptr;
@@ -69,11 +63,6 @@
return *this;
}
- DisplayCreationArgsBuilder& setConnectionType(ui::DisplayConnectionType connectionType) {
- mArgs.connectionType = connectionType;
- return *this;
- }
-
DisplayCreationArgsBuilder& setPixels(ui::Size pixels) {
mArgs.pixels = pixels;
return *this;
@@ -84,11 +73,6 @@
return *this;
}
- DisplayCreationArgsBuilder& setLayerStackId(uint32_t layerStackId) {
- mArgs.layerStackId = layerStackId;
- return *this;
- }
-
DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
mArgs.powerAdvisor = powerAdvisor;
return *this;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 2221280..a000661 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -22,6 +22,7 @@
#include <math/mat4.h>
#include <ui/BlurRegion.h>
#include <ui/FloatRect.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -93,11 +94,9 @@
/*
* Visibility state
*/
- // the layer stack this layer belongs to
- std::optional<uint32_t> layerStackId;
- // If true, this layer should be only visible on the internal display
- bool internalOnly{false};
+ // The filter that determines which outputs include this layer
+ ui::LayerFilter outputFilter;
// If false, this layer should not be considered visible
bool isVisible{true};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 15a86af..a33b57d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -28,6 +28,7 @@
#include <renderengine/LayerSettings.h>
#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
+#include <ui/LayerStack.h>
#include <ui/Region.h>
#include <ui/Transform.h>
#include <utils/StrongPointer.h>
@@ -180,9 +181,8 @@
// output.
virtual ui::Transform::RotationFlags getTransformHint() const = 0;
- // Sets the layer stack filtering settings for this output. See
- // belongsInOutput for full details.
- virtual void setLayerStackFilter(uint32_t layerStackId, bool isInternal) = 0;
+ // Sets the filter for this output. See Output::includesLayer.
+ virtual void setLayerFilter(ui::LayerFilter) = 0;
// Sets the output color mode
virtual void setColorProfile(const ColorProfile&) = 0;
@@ -221,20 +221,12 @@
virtual OutputCompositionState& editState() = 0;
// Gets the dirty region in layer stack space.
- // If repaintEverything is true, this will be the full display bounds.
- virtual Region getDirtyRegion(bool repaintEverything) const = 0;
+ virtual Region getDirtyRegion() const = 0;
- // Tests whether a given layerStackId belongs in this output.
- // A layer belongs to the output if its layerStackId matches the of the output layerStackId,
- // unless the layer should display on the primary output only and this is not the primary output
-
- // A layer belongs to the output if its layerStackId matches. Additionally
- // if the layer should only show in the internal (primary) display only and
- // this output allows that.
- virtual bool belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const = 0;
-
- // Determines if a layer belongs to the output.
- virtual bool belongsInOutput(const sp<LayerFE>&) const = 0;
+ // Returns whether the output includes a layer, based on their respective filters.
+ // See Output::setLayerFilter.
+ virtual bool includesLayer(ui::LayerFilter) const = 0;
+ virtual bool includesLayer(const sp<LayerFE>&) const = 0;
// Returns a pointer to the output layer corresponding to the given layer on
// this output, or nullptr if the layer does not have one
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index bb540ea..b407267 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -83,9 +83,8 @@
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
private:
- bool mIsVirtual = false;
- bool mIsDisconnected = false;
DisplayId mId;
+ bool mIsDisconnected = false;
Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
index 6b9597b..7521324 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -22,6 +22,7 @@
#include <math/mat4.h>
#include <ui/FloatRect.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/StretchEffect.h>
@@ -52,13 +53,14 @@
dumpVal(out, name, valueName, static_cast<std::underlying_type_t<EnumType>>(value));
}
-void dumpVal(std::string& out, const char* name, const FloatRect& rect);
-void dumpVal(std::string& out, const char* name, const Rect& rect);
-void dumpVal(std::string& out, const char* name, const Region& region);
-void dumpVal(std::string& out, const char* name, const ui::Transform&);
-void dumpVal(std::string& out, const char* name, const ui::Size&);
+void dumpVal(std::string& out, const char* name, ui::LayerFilter);
+void dumpVal(std::string& out, const char* name, ui::Size);
-void dumpVal(std::string& out, const char* name, const mat4& tr);
+void dumpVal(std::string& out, const char* name, const FloatRect&);
+void dumpVal(std::string& out, const char* name, const Rect&);
+void dumpVal(std::string& out, const char* name, const Region&);
+void dumpVal(std::string& out, const char* name, const ui::Transform&);
+void dumpVal(std::string& out, const char* name, const mat4&);
void dumpVal(std::string& out, const char* name, const StretchEffect&);
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 14f2163..6d49ce6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -23,6 +23,7 @@
#include <compositionengine/impl/planner/Planner.h>
#include <renderengine/DisplaySettings.h>
#include <renderengine/LayerSettings.h>
+
#include <memory>
#include <utility>
#include <vector>
@@ -45,7 +46,7 @@
void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) override;
void setDisplaySize(const ui::Size&) override;
- void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
+ void setLayerFilter(ui::LayerFilter) override;
ui::Transform::RotationFlags getTransformHint() const override;
void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
@@ -64,9 +65,10 @@
compositionengine::RenderSurface* getRenderSurface() const override;
void setRenderSurface(std::unique_ptr<compositionengine::RenderSurface>) override;
- Region getDirtyRegion(bool repaintEverything) const override;
- bool belongsInOutput(std::optional<uint32_t>, bool) const override;
- bool belongsInOutput(const sp<LayerFE>&) const override;
+ Region getDirtyRegion() const override;
+
+ bool includesLayer(ui::LayerFilter) const override;
+ bool includesLayer(const sp<LayerFE>&) const override;
compositionengine::OutputLayer* getOutputLayerForLayer(const sp<LayerFE>&) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index f34cb94..44f754f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -32,6 +32,7 @@
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include <compositionengine/ProjectionSpace.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -59,11 +60,8 @@
// If true, the current frame reused the buffer from a previous client composition
bool reusedClientComposition{false};
- // If true, this output displays layers that are internal-only
- bool layerStackInternal{false};
-
- // The layer stack to display on this display
- uint32_t layerStackId{~0u};
+ // The conditions for including a layer on this output
+ ui::LayerFilter layerFilter;
// The common space for all layers in the layer stack. layerStackSpace.content is the Rect
// which gets projected on the display. The orientation of this space is always ROTATION_0.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 8ec15ed..cff6527 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -38,35 +38,56 @@
class Flattener {
public:
- struct CachedSetRenderSchedulingTunables {
- // This default assumes that rendering a cached set takes about 3ms. That time is then cut
- // in half - the next frame using the cached set would have the same workload, meaning that
- // composition cost is the same. This is best illustrated with the following example:
- //
- // Suppose we're at a 120hz cadence so SurfaceFlinger is budgeted 8.3ms per-frame. If
- // renderCachedSets costs 3ms, then two consecutive frames have timings:
- //
- // First frame: Start at 0ms, end at 6.8ms.
- // renderCachedSets: Start at 6.8ms, end at 9.8ms.
- // Second frame: Start at 9.8ms, end at 16.6ms.
- //
- // Now the second frame won't render a cached set afterwards, but the first frame didn't
- // really steal time from the second frame.
- static const constexpr std::chrono::nanoseconds kDefaultCachedSetRenderDuration = 1500us;
+ // Collection of tunables which are backed by sysprops
+ struct Tunables {
+ // Tunables that are specific to scheduling when a cached set should be rendered
+ struct RenderScheduling {
+ // This default assumes that rendering a cached set takes about 3ms. That time is then
+ // cut in half - the next frame using the cached set would have the same workload,
+ // meaning that composition cost is the same. This is best illustrated with the
+ // following example:
+ //
+ // Suppose we're at a 120hz cadence so SurfaceFlinger is budgeted 8.3ms per-frame. If
+ // renderCachedSets costs 3ms, then two consecutive frames have timings:
+ //
+ // First frame: Start at 0ms, end at 6.8ms.
+ // renderCachedSets: Start at 6.8ms, end at 9.8ms.
+ // Second frame: Start at 9.8ms, end at 16.6ms.
+ //
+ // Now the second frame won't render a cached set afterwards, but the first frame didn't
+ // really steal time from the second frame.
+ static const constexpr std::chrono::nanoseconds kDefaultCachedSetRenderDuration =
+ 1500us;
- static const constexpr size_t kDefaultMaxDeferRenderAttempts = 240;
+ static const constexpr size_t kDefaultMaxDeferRenderAttempts = 240;
- // Duration allocated for rendering a cached set. If we don't have enough time for rendering
- // a cached set, then rendering is deferred to another frame.
- const std::chrono::nanoseconds cachedSetRenderDuration;
- // Maximum of times that we defer rendering a cached set. If we defer rendering a cached set
- // too many times, then render it anyways so that future frames would benefit from the
- // flattened cached set.
- const size_t maxDeferRenderAttempts;
+ // Duration allocated for rendering a cached set. If we don't have enough time for
+ // rendering a cached set, then rendering is deferred to another frame.
+ const std::chrono::nanoseconds cachedSetRenderDuration;
+ // Maximum of times that we defer rendering a cached set. If we defer rendering a cached
+ // set too many times, then render it anyways so that future frames would benefit from
+ // the flattened cached set.
+ const size_t maxDeferRenderAttempts;
+ };
+
+ static const constexpr std::chrono::milliseconds kDefaultActiveLayerTimeout = 150ms;
+
+ static const constexpr bool kDefaultEnableHolePunch = true;
+
+ // Threshold for determing whether a layer is active. A layer whose properties, including
+ // the buffer, have not changed in at least this time is considered inactive and is
+ // therefore a candidate for flattening.
+ const std::chrono::milliseconds mActiveLayerTimeout;
+
+ // Toggles for scheduling when it's safe to render a cached set.
+ // See: RenderScheduling
+ const std::optional<RenderScheduling> mRenderScheduling;
+
+ // True if the hole punching feature should be enabled.
+ const bool mEnableHolePunch;
};
- Flattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch = false,
- std::optional<CachedSetRenderSchedulingTunables> cachedSetRenderSchedulingTunables =
- std::nullopt);
+
+ Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables);
void setDisplaySize(ui::Size size) {
mDisplaySize = size;
@@ -98,8 +119,8 @@
std::chrono::steady_clock::time_point now);
// A Run is a sequence of CachedSets, which is a candidate for flattening into a single
- // CachedSet. Because it is wasteful to flatten 1 CachedSet, a Run must contain more than 1
- // CachedSet
+ // CachedSet. Because it is wasteful to flatten 1 CachedSet, a run must contain more than
+ // 1 CachedSet or be used for a hole punch.
class Run {
public:
// A builder for a Run, to aid in construction
@@ -133,7 +154,13 @@
// Builds a Run instance, if a valid Run may be built.
std::optional<Run> validateAndBuild() {
- if (mLengths.size() <= 1) {
+ if (mLengths.size() == 0) {
+ return std::nullopt;
+ }
+ // Runs of length 1 which are hole punch candidates are allowed if the candidate is
+ // going to be used.
+ if (mLengths.size() == 1 &&
+ (!mHolePunchCandidate || !(mHolePunchCandidate->requiresHolePunch()))) {
return std::nullopt;
}
@@ -177,8 +204,7 @@
void buildCachedSets(std::chrono::steady_clock::time_point now);
renderengine::RenderEngine& mRenderEngine;
- const bool mEnableHolePunch;
- const std::optional<CachedSetRenderSchedulingTunables> mCachedSetRenderSchedulingTunables;
+ const Tunables mTunables;
TexturePool mTexturePool;
@@ -202,9 +228,6 @@
size_t mCachedSetCreationCount = 0;
size_t mCachedSetCreationCost = 0;
std::unordered_map<size_t, size_t> mInvalidatedCachedSetAges;
- std::chrono::nanoseconds mActiveLayerTimeout = kActiveLayerTimeout;
-
- static constexpr auto kActiveLayerTimeout = std::chrono::nanoseconds(150ms);
};
} // namespace compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index 76d5e81..b7ebca6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -39,6 +39,9 @@
// heuristically determining the composition strategy of the current layer stack,
// and flattens inactive layers into an override buffer so it can be used
// as a more efficient representation of parts of the layer stack.
+// Implicitly, layer caching must also be enabled for the Planner to have any effect
+// E.g., setprop debug.sf.enable_layer_caching 1, or
+// adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
class Planner {
public:
Planner(renderengine::RenderEngine& renderengine);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 216019f..344b2f9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -40,9 +40,12 @@
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));
MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags());
+ MOCK_METHOD(void, setLayerFilter, (ui::LayerFilter));
+ MOCK_METHOD(bool, includesLayer, (ui::LayerFilter), (const));
+ MOCK_METHOD(bool, includesLayer, (const sp<compositionengine::LayerFE>&), (const));
+
MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD1(setColorProfile, void(const ColorProfile&));
MOCK_METHOD2(setDisplayBrightness, void(float, float));
@@ -62,9 +65,7 @@
MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
MOCK_METHOD0(editState, OutputCompositionState&());
- MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
- MOCK_CONST_METHOD2(belongsInOutput, bool(std::optional<uint32_t>, bool));
- MOCK_CONST_METHOD1(belongsInOutput, bool(const sp<compositionengine::LayerFE>&));
+ MOCK_METHOD(Region, getDirtyRegion, (), (const));
MOCK_CONST_METHOD1(getOutputLayerForLayer,
compositionengine::OutputLayer*(const sp<compositionengine::LayerFE>&));
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 2f2c686..6b9ea87 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -51,12 +51,9 @@
void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) {
mId = args.id;
- mIsVirtual = !args.connectionType;
mPowerAdvisor = args.powerAdvisor;
editState().isSecure = args.isSecure;
editState().displaySpace.bounds = Rect(args.pixels);
- setLayerStackFilter(args.layerStackId,
- args.connectionType == ui::DisplayConnectionType::Internal);
setName(args.name);
}
@@ -73,7 +70,7 @@
}
bool Display::isVirtual() const {
- return mIsVirtual;
+ return VirtualDisplayId::tryCast(mId).has_value();
}
std::optional<DisplayId> Display::getDisplayId() const {
@@ -117,8 +114,8 @@
return;
}
- if (mIsVirtual) {
- ALOGW("%s: Invalid operation on virtual display", __FUNCTION__);
+ if (isVirtual()) {
+ ALOGW("%s: Invalid operation on virtual display", __func__);
return;
}
@@ -136,7 +133,7 @@
StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str());
out.append("\n ");
- dumpVal(out, "isVirtual", mIsVirtual);
+ dumpVal(out, "isVirtual", isVirtual());
dumpVal(out, "DisplayId", to_string(mId));
out.append("\n");
@@ -364,8 +361,7 @@
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
- if (GpuVirtualDisplayId::tryCast(mId) &&
- getDirtyRegion(refreshArgs.repaintEverything).isEmpty()) {
+ if (GpuVirtualDisplayId::tryCast(mId) && getDirtyRegion().isEmpty()) {
ALOGV("Skipping display composition");
return;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index 5565396..01c368d 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -63,6 +63,18 @@
dumpVal(out, name, valueName.c_str(), value);
}
+void dumpVal(std::string& out, const char* name, ui::LayerFilter filter) {
+ out.append(name);
+ out.append("={");
+ dumpVal(out, "layerStack", filter.layerStack.id);
+ dumpVal(out, "toInternalDisplay", filter.toInternalDisplay);
+ out.push_back('}');
+}
+
+void dumpVal(std::string& out, const char* name, ui::Size size) {
+ StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height);
+}
+
void dumpVal(std::string& out, const char* name, const FloatRect& rect) {
StringAppendF(&out, "%s=[%f %f %f %f] ", name, rect.left, rect.top, rect.right, rect.bottom);
}
@@ -80,10 +92,6 @@
out.append(" ");
}
-void dumpVal(std::string& out, const char* name, const ui::Size& size) {
- StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height);
-}
-
void dumpVal(std::string& out, const char* name, const mat4& tr) {
StringAppendF(&out,
"%s=["
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6ac488b..1747294 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -227,11 +227,8 @@
return static_cast<ui::Transform::RotationFlags>(getState().transform.getOrientation());
}
-void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) {
- auto& outputState = editState();
- outputState.layerStackId = layerStackId;
- outputState.layerStackInternal = isInternal;
-
+void Output::setLayerFilter(ui::LayerFilter filter) {
+ editState().layerFilter = filter;
dirtyEntireOutput();
}
@@ -371,26 +368,18 @@
mRenderSurface = std::move(surface);
}
-Region Output::getDirtyRegion(bool repaintEverything) const {
+Region Output::getDirtyRegion() const {
const auto& outputState = getState();
- Region dirty(outputState.layerStackSpace.content);
- if (!repaintEverything) {
- dirty.andSelf(outputState.dirtyRegion);
- }
- return dirty;
+ return outputState.dirtyRegion.intersect(outputState.layerStackSpace.content);
}
-bool Output::belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const {
- // The layerStackId's must match, and also the layer must not be internal
- // only when not on an internal output.
- const auto& outputState = getState();
- return layerStackId && (*layerStackId == outputState.layerStackId) &&
- (!internalOnly || outputState.layerStackInternal);
+bool Output::includesLayer(ui::LayerFilter filter) const {
+ return getState().layerFilter.includes(filter);
}
-bool Output::belongsInOutput(const sp<compositionengine::LayerFE>& layerFE) const {
+bool Output::includesLayer(const sp<LayerFE>& layerFE) const {
const auto* layerFEState = layerFE->getCompositionState();
- return layerFEState && belongsInOutput(layerFEState->layerStackId, layerFEState->internalOnly);
+ return layerFEState && includesLayer(layerFEState->outputFilter);
}
std::unique_ptr<compositionengine::OutputLayer> Output::createOutputLayer(
@@ -496,8 +485,8 @@
layerFE->prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry);
}
- // Only consider the layers on the given layer stack
- if (!belongsInOutput(layerFE)) {
+ // Only consider the layers on this output
+ if (!includesLayer(layerFE)) {
return;
}
@@ -908,7 +897,7 @@
void Output::beginFrame() {
auto& outputState = editState();
- const bool dirty = !getDirtyRegion(false).isEmpty();
+ const bool dirty = !getDirtyRegion().isEmpty();
const bool empty = getOutputLayerCount() == 0;
const bool wasEmpty = !outputState.lastCompositionHadVisibleLayers;
@@ -960,14 +949,9 @@
}
if (getState().isEnabled) {
- // transform the dirty region into this screen's coordinate space
- const Region dirtyRegion = getDirtyRegion(refreshArgs.repaintEverything);
- if (!dirtyRegion.isEmpty()) {
- base::unique_fd readyFence;
- // redraw the whole screen
+ if (const auto dirtyRegion = getDirtyRegion(); !dirtyRegion.isEmpty()) {
static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs));
-
- mRenderSurface->queueBuffer(std::move(readyFence));
+ mRenderSurface->queueBuffer(base::unique_fd());
}
}
@@ -1046,10 +1030,9 @@
}
}
- base::unique_fd readyFence;
if (!hasClientComposition) {
setExpensiveRenderingExpected(false);
- return readyFence;
+ return base::unique_fd();
}
ALOGV("hasClientComposition");
@@ -1089,7 +1072,7 @@
clientCompositionLayers)) {
outputCompositionState.reusedClientComposition = true;
setExpensiveRenderingExpected(false);
- return readyFence;
+ return base::unique_fd();
}
mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
clientCompositionLayers);
@@ -1122,10 +1105,12 @@
// bounds its framebuffer cache but Skia RenderEngine has no current policy. The best fix is
// probably to encapsulate the output buffer into a structure that dispatches resource cleanup
// over to RenderEngine, in which case this flag can be removed from the drawLayers interface.
- const bool useFramebufferCache = outputState.layerStackInternal;
- status_t status =
- renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex,
- useFramebufferCache, std::move(fd), &readyFence);
+ const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay;
+ auto [status, drawFence] =
+ renderEngine
+ .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex,
+ useFramebufferCache, std::move(fd))
+ .get();
if (status != NO_ERROR && mClientCompositionRequestCache) {
// If rendering was not successful, remove the request from the cache.
@@ -1133,15 +1118,15 @@
}
auto& timeStats = getCompositionEngine().getTimeStats();
- if (readyFence.get() < 0) {
+ if (drawFence.get() < 0) {
timeStats.recordRenderEngineDuration(renderEngineStart, systemTime());
} else {
timeStats.recordRenderEngineDuration(renderEngineStart,
std::make_shared<FenceTime>(
- new Fence(dup(readyFence.get()))));
+ new Fence(dup(drawFence.get()))));
}
- return readyFence;
+ return std::move(drawFence);
}
std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests(
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index ee30ad8..acc9216 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -28,9 +28,7 @@
dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
dumpVal(out, "flipClientTarget", flipClientTarget);
dumpVal(out, "reusedClientComposition", reusedClientComposition);
-
- dumpVal(out, "layerStack", layerStackId);
- dumpVal(out, "layerStackInternal", layerStackInternal);
+ dumpVal(out, "layerFilter", layerFilter);
out.append("\n ");
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index ccacdfb..5bbd58e 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -272,12 +272,12 @@
bufferFence.reset(texture->getReadyFence()->dup());
}
- base::unique_fd drawFence;
- status_t result =
- renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture->get(), false,
- std::move(bufferFence), &drawFence);
+ auto [status, drawFence] = renderEngine
+ .drawLayers(displaySettings, layerSettingsPointers,
+ texture->get(), false, std::move(bufferFence))
+ .get();
- if (result == NO_ERROR) {
+ if (status == NO_ERROR) {
mDrawFence = new Fence(drawFence.release());
mOutputSpace = outputState.framebufferSpace;
mTexture = texture;
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 8e2c182..ad5e931 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -60,19 +60,8 @@
} // namespace
-Flattener::Flattener(
- renderengine::RenderEngine& renderEngine, bool enableHolePunch,
- std::optional<CachedSetRenderSchedulingTunables> cachedSetRenderSchedulingTunables)
- : mRenderEngine(renderEngine),
- mEnableHolePunch(enableHolePunch),
- mCachedSetRenderSchedulingTunables(cachedSetRenderSchedulingTunables),
- mTexturePool(mRenderEngine) {
- const int timeoutInMs =
- base::GetIntProperty(std::string("debug.sf.layer_caching_active_layer_timeout_ms"), 0);
- if (timeoutInMs != 0) {
- mActiveLayerTimeout = std::chrono::milliseconds(timeoutInMs);
- }
-}
+Flattener::Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables)
+ : mRenderEngine(renderEngine), mTunables(tunables), mTexturePool(mRenderEngine) {}
NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers,
NonBufferHash hash, time_point now) {
@@ -128,14 +117,14 @@
// If we have a render deadline, and the flattener is configured to skip rendering if we don't
// have enough time, then we skip rendering the cached set if we think that we'll steal too much
// time from the next frame.
- if (renderDeadline && mCachedSetRenderSchedulingTunables) {
+ if (renderDeadline && mTunables.mRenderScheduling) {
if (const auto estimatedRenderFinish =
- now + mCachedSetRenderSchedulingTunables->cachedSetRenderDuration;
+ now + mTunables.mRenderScheduling->cachedSetRenderDuration;
estimatedRenderFinish > *renderDeadline) {
mNewCachedSet->incrementSkipCount();
if (mNewCachedSet->getSkipCount() <=
- mCachedSetRenderSchedulingTunables->maxDeferRenderAttempts) {
+ mTunables.mRenderScheduling->maxDeferRenderAttempts) {
ATRACE_FORMAT("DeadlinePassed: exceeded deadline by: %d us",
std::chrono::duration_cast<std::chrono::microseconds>(
estimatedRenderFinish - *renderDeadline)
@@ -420,8 +409,10 @@
bool runHasFirstLayer = false;
for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) {
- const bool layerIsInactive = now - currentSet->getLastUpdate() > mActiveLayerTimeout;
+ const bool layerIsInactive =
+ now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout;
const bool layerHasBlur = currentSet->hasBlurBehind();
+
if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
!currentSet->hasUnsupportedDataspace()) {
if (isPartOfRun) {
@@ -522,7 +513,7 @@
mNewCachedSet->addBackgroundBlurLayer(*bestRun->getBlurringLayer());
}
- if (mEnableHolePunch && bestRun->getHolePunchCandidate() &&
+ if (mTunables.mEnableHolePunch && bestRun->getHolePunchCandidate() &&
bestRun->getHolePunchCandidate()->requiresHolePunch()) {
// Add the pip layer to mNewCachedSet, but in a special way - it should
// replace the buffer with a clear round rect.
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index f077470..f5b1cee 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -32,36 +32,46 @@
namespace {
-std::optional<Flattener::CachedSetRenderSchedulingTunables> buildFlattenerTuneables() {
+std::optional<Flattener::Tunables::RenderScheduling> buildRenderSchedulingTunables() {
if (!base::GetBoolProperty(std::string("debug.sf.enable_cached_set_render_scheduling"), true)) {
return std::nullopt;
}
- auto renderDuration = std::chrono::nanoseconds(
+ const auto renderDuration = std::chrono::nanoseconds(
base::GetUintProperty<uint64_t>(std::string("debug.sf.cached_set_render_duration_ns"),
- Flattener::CachedSetRenderSchedulingTunables::
+ Flattener::Tunables::RenderScheduling::
kDefaultCachedSetRenderDuration.count()));
- auto maxDeferRenderAttempts = base::GetUintProperty<
+ const auto maxDeferRenderAttempts = base::GetUintProperty<
size_t>(std::string("debug.sf.cached_set_max_defer_render_attmpts"),
- Flattener::CachedSetRenderSchedulingTunables::kDefaultMaxDeferRenderAttempts);
+ Flattener::Tunables::RenderScheduling::kDefaultMaxDeferRenderAttempts);
- return std::make_optional<Flattener::CachedSetRenderSchedulingTunables>(
- Flattener::CachedSetRenderSchedulingTunables{
+ return std::make_optional<Flattener::Tunables::RenderScheduling>(
+ Flattener::Tunables::RenderScheduling{
.cachedSetRenderDuration = renderDuration,
.maxDeferRenderAttempts = maxDeferRenderAttempts,
});
}
+Flattener::Tunables buildFlattenerTuneables() {
+ const auto activeLayerTimeout = std::chrono::milliseconds(
+ base::GetIntProperty<int32_t>(std::string(
+ "debug.sf.layer_caching_active_layer_timeout_ms"),
+ Flattener::Tunables::kDefaultActiveLayerTimeout.count()));
+ const auto enableHolePunch =
+ base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"),
+ Flattener::Tunables::kDefaultEnableHolePunch);
+ return Flattener::Tunables{
+ .mActiveLayerTimeout = activeLayerTimeout,
+ .mRenderScheduling = buildRenderSchedulingTunables(),
+ .mEnableHolePunch = enableHolePunch,
+ };
+}
+
} // namespace
Planner::Planner(renderengine::RenderEngine& renderEngine)
- // Implicitly, layer caching must also be enabled for the hole punch or
- // predictor to have any effect.
- // E.g., setprop debug.sf.enable_layer_caching 1, or
- // adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
: mFlattener(renderEngine,
- base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true),
buildFlattenerTuneables()) {
mPredictorEnabled =
base::GetBoolProperty(std::string("debug.sf.enable_planner_prediction"), false);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 72b16e0..f2978f9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -61,7 +61,6 @@
constexpr GpuVirtualDisplayId GPU_VIRTUAL_DISPLAY_ID{789u};
constexpr ui::Size DEFAULT_RESOLUTION{1920, 1080};
-constexpr uint32_t DEFAULT_LAYER_STACK = 42;
struct Layer {
Layer() {
@@ -161,13 +160,11 @@
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
}
- DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
+ DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() {
return DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::Internal)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(true)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.build();
}
@@ -177,7 +174,6 @@
.setId(GPU_VIRTUAL_DISPLAY_ID)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(false)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.build();
}
@@ -193,14 +189,13 @@
using Display = DisplayTestCommon::PartialMockDisplay;
std::shared_ptr<Display> mDisplay =
createPartialMockDisplay<Display>(mCompositionEngine,
- getDisplayCreationArgsForPhysicalHWCDisplay());
+ getDisplayCreationArgsForPhysicalDisplay());
};
struct FullDisplayImplTestCommon : public DisplayTestCommon {
using Display = DisplayTestCommon::FullImplDisplay;
std::shared_ptr<Display> mDisplay =
- createDisplay<Display>(mCompositionEngine,
- getDisplayCreationArgsForPhysicalHWCDisplay());
+ createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
};
struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon {
@@ -218,8 +213,7 @@
LayerNoHWC2Layer mLayer3;
StrictMock<HWC2::mock::Layer> hwc2LayerUnknown;
std::shared_ptr<Display> mDisplay =
- createDisplay<Display>(mCompositionEngine,
- getDisplayCreationArgsForPhysicalHWCDisplay());
+ createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
};
/*
@@ -232,7 +226,7 @@
TEST_F(DisplayCreationTest, createPhysicalInternalDisplay) {
auto display =
- impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalHWCDisplay());
+ impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
EXPECT_TRUE(display->isSecure());
EXPECT_FALSE(display->isVirtual());
EXPECT_EQ(DEFAULT_DISPLAY_ID, display->getId());
@@ -252,13 +246,11 @@
using DisplaySetConfigurationTest = PartialMockDisplayTestCommon;
-TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) {
+TEST_F(DisplaySetConfigurationTest, configuresPhysicalDisplay) {
mDisplay->setConfiguration(DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::Internal)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(true)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.setName(getDisplayNameFromCurrentTest())
.build());
@@ -266,28 +258,11 @@
EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId());
EXPECT_TRUE(mDisplay->isSecure());
EXPECT_FALSE(mDisplay->isVirtual());
- EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
- EXPECT_TRUE(mDisplay->getState().layerStackInternal);
EXPECT_FALSE(mDisplay->isValid());
-}
-TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) {
- mDisplay->setConfiguration(DisplayCreationArgsBuilder()
- .setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::External)
- .setPixels(DEFAULT_RESOLUTION)
- .setIsSecure(false)
- .setLayerStackId(DEFAULT_LAYER_STACK)
- .setPowerAdvisor(&mPowerAdvisor)
- .setName(getDisplayNameFromCurrentTest())
- .build());
-
- EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId());
- EXPECT_FALSE(mDisplay->isSecure());
- EXPECT_FALSE(mDisplay->isVirtual());
- EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
- EXPECT_FALSE(mDisplay->getState().layerStackInternal);
- EXPECT_FALSE(mDisplay->isValid());
+ const auto& filter = mDisplay->getState().layerFilter;
+ EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack);
+ EXPECT_FALSE(filter.toInternalDisplay);
}
TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) {
@@ -295,7 +270,6 @@
.setId(HAL_VIRTUAL_DISPLAY_ID)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(false)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.setName(getDisplayNameFromCurrentTest())
.build());
@@ -303,9 +277,11 @@
EXPECT_EQ(HAL_VIRTUAL_DISPLAY_ID, mDisplay->getId());
EXPECT_FALSE(mDisplay->isSecure());
EXPECT_TRUE(mDisplay->isVirtual());
- EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
- EXPECT_FALSE(mDisplay->getState().layerStackInternal);
EXPECT_FALSE(mDisplay->isValid());
+
+ const auto& filter = mDisplay->getState().layerFilter;
+ EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack);
+ EXPECT_FALSE(filter.toInternalDisplay);
}
TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) {
@@ -313,7 +289,6 @@
.setId(GPU_VIRTUAL_DISPLAY_ID)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(false)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.setName(getDisplayNameFromCurrentTest())
.build());
@@ -321,9 +296,11 @@
EXPECT_EQ(GPU_VIRTUAL_DISPLAY_ID, mDisplay->getId());
EXPECT_FALSE(mDisplay->isSecure());
EXPECT_TRUE(mDisplay->isVirtual());
- EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
- EXPECT_FALSE(mDisplay->getState().layerStackInternal);
EXPECT_FALSE(mDisplay->isValid());
+
+ const auto& filter = mDisplay->getState().layerFilter;
+ EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack);
+ EXPECT_FALSE(filter.toInternalDisplay);
}
/*
@@ -902,10 +879,7 @@
mDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
mDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- CompositionRefreshArgs refreshArgs;
- refreshArgs.repaintEverything = false;
-
- mDisplay->finishFrame(refreshArgs);
+ mDisplay->finishFrame({});
}
TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) {
@@ -923,10 +897,7 @@
gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- CompositionRefreshArgs refreshArgs;
- refreshArgs.repaintEverything = false;
-
- gpuDisplay->finishFrame(refreshArgs);
+ gpuDisplay->finishFrame({});
}
TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) {
@@ -944,31 +915,7 @@
gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
- CompositionRefreshArgs refreshArgs;
- refreshArgs.repaintEverything = false;
-
- gpuDisplay->finishFrame(refreshArgs);
-}
-
-TEST_F(DisplayFinishFrameTest, performsCompositionIfRepaintEverything) {
- auto args = getDisplayCreationArgsForGpuVirtualDisplay();
- std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
-
- mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
- gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
-
- // We expect a single call to queueBuffer when composition is not skipped.
- EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
-
- gpuDisplay->editState().isEnabled = true;
- gpuDisplay->editState().usesClientComposition = false;
- gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
- gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
-
- CompositionRefreshArgs refreshArgs;
- refreshArgs.repaintEverything = true;
-
- gpuDisplay->finishFrame(refreshArgs);
+ gpuDisplay->finishFrame({});
}
/*
@@ -998,10 +945,8 @@
Display>(mCompositionEngine,
DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::Internal)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(true)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.build());
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 58c6628..224dad1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -111,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/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index c3185e9..a904c7d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -35,6 +35,7 @@
#include "CallOrderStateMachineHelper.h"
#include "MockHWC2.h"
#include "RegionMatcher.h"
+#include "TestUtils.h"
#include "renderengine/ExternalTexture.h"
namespace android::compositionengine {
@@ -403,17 +404,18 @@
}
/*
- * Output::setLayerStackFilter()
+ * Output::setLayerFilter()
*/
-TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
- const uint32_t layerStack = 123u;
- mOutput->setLayerStackFilter(layerStack, true);
+TEST_F(OutputTest, setLayerFilterSetsFilterAndDirtiesEntireOutput) {
+ constexpr ui::LayerFilter kFilter{ui::LayerStack{123u}, true};
+ mOutput->setLayerFilter(kFilter);
- EXPECT_TRUE(mOutput->getState().layerStackInternal);
- EXPECT_EQ(layerStack, mOutput->getState().layerStackId);
+ const auto& state = mOutput->getState();
+ EXPECT_EQ(kFilter.layerStack, state.layerFilter.layerStack);
+ EXPECT_TRUE(state.layerFilter.toInternalDisplay);
- EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+ EXPECT_THAT(state.dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
/*
@@ -567,126 +569,100 @@
* Output::getDirtyRegion()
*/
-TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) {
+TEST_F(OutputTest, getDirtyRegion) {
const Rect viewport{100, 200};
mOutput->editState().layerStackSpace.content = viewport;
mOutput->editState().dirtyRegion.set(50, 300);
- {
- Region result = mOutput->getDirtyRegion(true);
-
- EXPECT_THAT(result, RegionEq(Region(viewport)));
- }
-}
-
-TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) {
- const Rect viewport{100, 200};
- mOutput->editState().layerStackSpace.content = viewport;
- mOutput->editState().dirtyRegion.set(50, 300);
-
- {
- Region result = mOutput->getDirtyRegion(false);
-
- // The dirtyRegion should be clipped to the display bounds.
- EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
- }
+ // The dirty region should be clipped to the display bounds.
+ EXPECT_THAT(mOutput->getDirtyRegion(), RegionEq(Region(Rect(50, 200))));
}
/*
- * Output::belongsInOutput()
+ * Output::includesLayer()
*/
-TEST_F(OutputTest, belongsInOutputFiltersAsExpected) {
- const uint32_t layerStack1 = 123u;
- const uint32_t layerStack2 = 456u;
+TEST_F(OutputTest, layerFiltering) {
+ const ui::LayerStack layerStack1{123u};
+ const ui::LayerStack layerStack2{456u};
- // If the output accepts layerStack1 and internal-only layers....
- mOutput->setLayerStackFilter(layerStack1, true);
+ // If the output is associated to layerStack1 and to an internal display...
+ mOutput->setLayerFilter({layerStack1, true});
- // A layer with no layerStack does not belong to it, internal-only or not.
- EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, false));
- EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, true));
+ // It excludes layers with no layer stack, internal-only or not.
+ EXPECT_FALSE(mOutput->includesLayer({ui::INVALID_LAYER_STACK, false}));
+ EXPECT_FALSE(mOutput->includesLayer({ui::INVALID_LAYER_STACK, true}));
- // Any layer with layerStack1 belongs to it, internal-only or not.
- EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false));
- EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, true));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false));
+ // It includes layers on layerStack1, internal-only or not.
+ EXPECT_TRUE(mOutput->includesLayer({layerStack1, false}));
+ EXPECT_TRUE(mOutput->includesLayer({layerStack1, true}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack2, true}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack2, false}));
- // If the output accepts layerStack21 but not internal-only layers...
- mOutput->setLayerStackFilter(layerStack1, false);
+ // If the output is associated to layerStack1 but not to an internal display...
+ mOutput->setLayerFilter({layerStack1, false});
- // Only non-internal layers with layerStack1 belong to it.
- EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack1, true));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false));
+ // It includes layers on layerStack1, unless they are internal-only.
+ EXPECT_TRUE(mOutput->includesLayer({layerStack1, false}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack1, true}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack2, true}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack2, false}));
}
-TEST_F(OutputTest, belongsInOutputHandlesLayerWithNoCompositionState) {
+TEST_F(OutputTest, layerFilteringWithoutCompositionState) {
NonInjectedLayer layer;
sp<LayerFE> layerFE(layer.layerFE);
- // If the layer has no composition state, it does not belong to any output.
+ // Layers without composition state are excluded.
EXPECT_CALL(*layer.layerFE, getCompositionState).WillOnce(Return(nullptr));
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
}
-TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) {
+TEST_F(OutputTest, layerFilteringWithCompositionState) {
NonInjectedLayer layer;
sp<LayerFE> layerFE(layer.layerFE);
- const uint32_t layerStack1 = 123u;
- const uint32_t layerStack2 = 456u;
+ const ui::LayerStack layerStack1{123u};
+ const ui::LayerStack layerStack2{456u};
- // If the output accepts layerStack1 and internal-only layers....
- mOutput->setLayerStackFilter(layerStack1, true);
+ // If the output is associated to layerStack1 and to an internal display...
+ mOutput->setLayerFilter({layerStack1, true});
- // A layer with no layerStack does not belong to it, internal-only or not.
- layer.layerFEState.layerStackId = std::nullopt;
- layer.layerFEState.internalOnly = false;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ // It excludes layers with no layer stack, internal-only or not.
+ layer.layerFEState.outputFilter = {ui::INVALID_LAYER_STACK, false};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = std::nullopt;
- layer.layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {ui::INVALID_LAYER_STACK, true};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- // Any layer with layerStack1 belongs to it, internal-only or not.
- layer.layerFEState.layerStackId = layerStack1;
- layer.layerFEState.internalOnly = false;
- EXPECT_TRUE(mOutput->belongsInOutput(layerFE));
+ // It includes layers on layerStack1, internal-only or not.
+ layer.layerFEState.outputFilter = {layerStack1, false};
+ EXPECT_TRUE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack1;
- layer.layerFEState.internalOnly = true;
- EXPECT_TRUE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack1, true};
+ EXPECT_TRUE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack2;
- layer.layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack2, true};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack2;
- layer.layerFEState.internalOnly = false;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack2, false};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- // If the output accepts layerStack1 but not internal-only layers...
- mOutput->setLayerStackFilter(layerStack1, false);
+ // If the output is associated to layerStack1 but not to an internal display...
+ mOutput->setLayerFilter({layerStack1, false});
- // Only non-internal layers with layerStack1 belong to it.
- layer.layerFEState.layerStackId = layerStack1;
- layer.layerFEState.internalOnly = false;
- EXPECT_TRUE(mOutput->belongsInOutput(layerFE));
+ // It includes layers on layerStack1, unless they are internal-only.
+ layer.layerFEState.outputFilter = {layerStack1, false};
+ EXPECT_TRUE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack1;
- layer.layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack1, true};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack2;
- layer.layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack2, true};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack2;
- layer.layerFEState.internalOnly = false;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack2, false};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
}
/*
@@ -1268,14 +1244,15 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_CONST_METHOD1(belongsInOutput, bool(const sp<compositionengine::LayerFE>&));
+ MOCK_METHOD(bool, includesLayer, (const sp<compositionengine::LayerFE>&),
+ (const, override));
MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, OutputLayer*(size_t));
MOCK_METHOD2(ensureOutputLayer,
compositionengine::OutputLayer*(std::optional<size_t>, const sp<LayerFE>&));
};
OutputEnsureOutputLayerIfVisibleTest() {
- EXPECT_CALL(mOutput, belongsInOutput(sp<LayerFE>(mLayer.layerFE)))
+ EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE)))
.WillRepeatedly(Return(true));
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
@@ -1326,8 +1303,8 @@
const Region OutputEnsureOutputLayerIfVisibleTest::kFullBounds90Rotation =
Region(Rect(0, 0, 200, 100));
-TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerBelongs) {
- EXPECT_CALL(mOutput, belongsInOutput(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) {
+ EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
EXPECT_CALL(*mLayer.layerFE,
prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry));
@@ -1337,8 +1314,8 @@
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
- skipsLatchIfAlreadyLatchedBeforeCheckingIfLayerBelongs) {
- EXPECT_CALL(mOutput, belongsInOutput(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
+ skipsLatchIfAlreadyLatchedBeforeCheckingIfLayerIncluded) {
+ EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
ensureOutputLayerIfVisible();
}
@@ -2530,7 +2507,7 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
+ MOCK_METHOD(Region, getDirtyRegion, (), (const));
};
OutputBeginFrameTest() {
@@ -2542,8 +2519,7 @@
struct IfGetDirtyRegionExpectationState
: public CallOrderStateMachineHelper<TestType, IfGetDirtyRegionExpectationState> {
[[nodiscard]] auto ifGetDirtyRegionReturns(Region dirtyRegion) {
- EXPECT_CALL(getInstance()->mOutput, getDirtyRegion(false))
- .WillOnce(Return(dirtyRegion));
+ EXPECT_CALL(getInstance()->mOutput, getDirtyRegion()).WillOnce(Return(dirtyRegion));
return nextState<AndIfGetOutputLayerCountExpectationState>();
}
};
@@ -2683,7 +2659,7 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
+ MOCK_METHOD(Region, getDirtyRegion, (), (const));
MOCK_METHOD2(composeSurfaces,
std::optional<base::unique_fd>(
const Region&, const compositionengine::CompositionRefreshArgs&));
@@ -2711,7 +2687,6 @@
TEST_F(OutputDevOptRepaintFlashTest, doesNothingIfFlashDelayNotSet) {
mRefreshArgs.devOptFlashDirtyRegionsDelay = {};
- mRefreshArgs.repaintEverything = true;
mOutput.mState.isEnabled = true;
mOutput.devOptRepaintFlash(mRefreshArgs);
@@ -2719,7 +2694,6 @@
TEST_F(OutputDevOptRepaintFlashTest, postsAndPreparesANewFrameIfNotEnabled) {
mRefreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::microseconds(1);
- mRefreshArgs.repaintEverything = true;
mOutput.mState.isEnabled = false;
InSequence seq;
@@ -2729,13 +2703,12 @@
mOutput.devOptRepaintFlash(mRefreshArgs);
}
-TEST_F(OutputDevOptRepaintFlashTest, postsAndPreparesANewFrameIfNotDirty) {
+TEST_F(OutputDevOptRepaintFlashTest, postsAndPreparesANewFrameIfEnabled) {
mRefreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::microseconds(1);
- mRefreshArgs.repaintEverything = true;
mOutput.mState.isEnabled = true;
InSequence seq;
- EXPECT_CALL(mOutput, getDirtyRegion(true)).WillOnce(Return(kEmptyRegion));
+ EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kEmptyRegion));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, prepareFrame());
@@ -2744,11 +2717,10 @@
TEST_F(OutputDevOptRepaintFlashTest, alsoComposesSurfacesAndQueuesABufferIfDirty) {
mRefreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::microseconds(1);
- mRefreshArgs.repaintEverything = false;
mOutput.mState.isEnabled = true;
InSequence seq;
- EXPECT_CALL(mOutput, getDirtyRegion(false)).WillOnce(Return(kNotEmptyRegion));
+ EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kNotEmptyRegion));
EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs)));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
EXPECT_CALL(mOutput, postFramebuffer());
@@ -3148,9 +3120,14 @@
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _, _))
- .WillRepeatedly(Return(NO_ERROR));
-
+ EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _))
+ .WillRepeatedly([&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ });
verify().execute().expectAFenceWasReturned();
}
@@ -3175,8 +3152,14 @@
}));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
- .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ .WillRepeatedly([&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ });
verify().execute().expectAFenceWasReturned();
}
@@ -3188,8 +3171,7 @@
r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
- const constexpr uint32_t kInternalLayerStack = 1234;
- mOutput.setLayerStackFilter(kInternalLayerStack, true);
+ mOutput.setLayerFilter({ui::LayerStack{1234u}, true});
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
@@ -3205,8 +3187,14 @@
}));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
- .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _))
+ .WillRepeatedly([&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ });
verify().execute().expectAFenceWasReturned();
}
@@ -3229,9 +3217,12 @@
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
.Times(2)
- .WillOnce(Return(NO_ERROR));
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
verify().execute().expectAFenceWasReturned();
EXPECT_FALSE(mOutput.mState.reusedClientComposition);
@@ -3258,8 +3249,9 @@
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
- .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
verify().execute().expectAFenceWasReturned();
@@ -3293,8 +3285,14 @@
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
.WillOnce(Return(mOutputBuffer))
.WillOnce(Return(otherOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
- .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ .WillRepeatedly([&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ });
verify().execute().expectAFenceWasReturned();
EXPECT_FALSE(mOutput.mState.reusedClientComposition);
@@ -3323,10 +3321,12 @@
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _, _))
- .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
verify().execute().expectAFenceWasReturned();
EXPECT_FALSE(mOutput.mState.reusedClientComposition);
@@ -3375,8 +3375,9 @@
struct ExpectDisplaySettingsState
: public CallOrderStateMachineHelper<TestType, ExpectDisplaySettingsState> {
auto thenExpectDisplaySettingsUsed(renderengine::DisplaySettings settings) {
- EXPECT_CALL(getInstance()->mRenderEngine, drawLayers(settings, _, _, false, _, _))
- .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(getInstance()->mRenderEngine, drawLayers(settings, _, _, false, _))
+ .WillOnce(Return(ByMove(futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()}))));
return nextState<ExecuteState>();
}
};
@@ -3474,8 +3475,15 @@
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _))
- .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
+ .WillRepeatedly(
+ [&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
+ });
}
Layer mLayer1;
@@ -3527,7 +3535,9 @@
EXPECT_CALL(*mRenderSurface, setProtected(true));
// Must happen after setting the protected content state.
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
@@ -3597,7 +3607,9 @@
InSequence seq;
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
@@ -3614,7 +3626,9 @@
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
+ .WillOnce(Return(ByMove(futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()}))));
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
.WillRepeatedly(Return(&mLayer.outputLayer));
diff --git a/services/surfaceflinger/CompositionEngine/tests/TestUtils.h b/services/surfaceflinger/CompositionEngine/tests/TestUtils.h
new file mode 100644
index 0000000..c80fde6
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/TestUtils.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <future>
+
+namespace android::compositionengine {
+namespace {
+
+template <class T>
+std::future<T> futureOf(T obj) {
+ std::promise<T> resultPromise;
+ std::future<T> resultFuture = resultPromise.get_future();
+ resultPromise.set_value(std::move(obj));
+ return resultFuture;
+}
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index ec81322..818334d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -27,6 +27,8 @@
#include <utils/Errors.h>
#include <memory>
+#include "tests/TestUtils.h"
+
namespace android::compositionengine {
using namespace std::chrono_literals;
@@ -342,10 +344,11 @@
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 {
+ 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 &&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
@@ -353,8 +356,7 @@
EXPECT_EQ(0.5f, layers[0]->alpha);
EXPECT_EQ(0.75f, layers[1]->alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
-
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
EXPECT_CALL(*layerFE1,
@@ -363,7 +365,7 @@
EXPECT_CALL(*layerFE2,
prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(false)))
.WillOnce(Return(clientCompList2));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
mOutputState.isSecure = false;
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
@@ -394,10 +396,11 @@
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 {
+ 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 &&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
@@ -406,7 +409,7 @@
EXPECT_EQ(0.75f, layers[1]->alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
EXPECT_CALL(*layerFE1,
@@ -415,7 +418,7 @@
EXPECT_CALL(*layerFE2,
prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(true)))
.WillOnce(Return(clientCompList2));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
mOutputState.isSecure = true;
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
@@ -448,10 +451,11 @@
mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(2, 3, 10, 5));
- 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 {
+ 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 &&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
@@ -460,12 +464,12 @@
EXPECT_EQ(0.75f, layers[1]->alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
@@ -650,10 +654,11 @@
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(*layerFE3, prepareClientCompositionList(_)).WillOnce(Return(clientCompList3));
- const auto drawLayers = [&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>& layers,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> size_t {
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
// 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(), 4u);
@@ -673,10 +678,10 @@
EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
}
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
@@ -710,10 +715,11 @@
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(*layerFE3, prepareClientCompositionList(_)).WillOnce(Return(clientCompList3));
- const auto drawLayers = [&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>& layers,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> size_t {
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
// 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(), 4u);
@@ -734,10 +740,10 @@
EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
}
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
@@ -859,10 +865,11 @@
BackgroundBlurOnly)))
.WillOnce(Return(clientCompList3));
- const auto drawLayers = [&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>& layers,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> int32_t {
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
// 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);
@@ -871,10 +878,10 @@
EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings->source.solidColor);
EXPECT_EQ(0.0f, blurSettings->alpha);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index f5cfd2f..0d5e362 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -26,6 +26,8 @@
#include <renderengine/mock/RenderEngine.h>
#include <chrono>
+#include "tests/TestUtils.h"
+
namespace android::compositionengine {
using namespace std::chrono_literals;
using impl::planner::CachedSet;
@@ -47,23 +49,24 @@
class TestableFlattener : public Flattener {
public:
- TestableFlattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch,
- std::optional<Flattener::CachedSetRenderSchedulingTunables>
- cachedSetRenderSchedulingTunables = std::nullopt)
- : Flattener(renderEngine, enableHolePunch, cachedSetRenderSchedulingTunables) {}
+ TestableFlattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables)
+ : Flattener(renderEngine, tunables) {}
const std::optional<CachedSet>& getNewCachedSetForTesting() const { return mNewCachedSet; }
};
class FlattenerTest : public testing::Test {
public:
- FlattenerTest() : FlattenerTest(std::nullopt) {}
+ FlattenerTest()
+ : FlattenerTest(Flattener::Tunables{
+ .mActiveLayerTimeout = 100ms,
+ .mRenderScheduling = std::nullopt,
+ .mEnableHolePunch = true,
+ }) {}
void SetUp() override;
protected:
- FlattenerTest(std::optional<Flattener::CachedSetRenderSchedulingTunables>
- cachedSetRenderSchedulingTunables)
- : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, true,
- cachedSetRenderSchedulingTunables)) {}
+ FlattenerTest(const Flattener::Tunables& tunables)
+ : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, tunables)) {}
void initializeOverrideBuffer(const std::vector<const LayerState*>& layers);
void initializeFlattener(const std::vector<const LayerState*>& layers);
void expectAllLayersFlattened(const std::vector<const LayerState*>& layers);
@@ -166,7 +169,9 @@
void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) {
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -400,7 +405,9 @@
// caleed for Layer2 and Layer3
layerState1->resetFramesSinceBufferUpdate();
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -422,7 +429,9 @@
layerState1->incrementFramesSinceBufferUpdate();
mTime += 200ms;
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -473,7 +482,9 @@
// called for Layer1 and Layer2
layerState3->resetFramesSinceBufferUpdate();
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -486,7 +497,9 @@
EXPECT_EQ(nullptr, overrideBuffer5);
// Layers 1 and 2 will be flattened a new drawFrame would be called for Layer4 and Layer5
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -514,8 +527,9 @@
layerState3->incrementFramesSinceBufferUpdate();
mTime += 200ms;
-
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -569,7 +583,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -579,7 +595,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -631,7 +647,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -641,7 +659,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -659,6 +677,75 @@
EXPECT_EQ(peekThroughLayer1, peekThroughLayer2);
}
+// A test that verifies the hole puch optimization can be done on a single layer.
+TEST_F(FlattenerTest, flattenLayers_holePunchSingleLayer) {
+ mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+
+ // An opaque static background
+ auto& layerState0 = mTestLayers[0]->layerState;
+ const auto& overrideBuffer0 = layerState0->getOutputLayer()->getState().overrideInfo.buffer;
+
+ // a rounded updating layer
+ auto& layerState1 = mTestLayers[1]->layerState;
+ const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+
+ EXPECT_CALL(*mTestLayers[1]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ std::vector<LayerFE::LayerSettings> clientCompositionList = {
+ LayerFE::LayerSettings{},
+ };
+ clientCompositionList[0].source.buffer.buffer = std::make_shared<
+ renderengine::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer,
+ mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE);
+ EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(clientCompositionList));
+
+ const std::vector<const LayerState*> layers = {
+ layerState0.get(),
+ layerState1.get(),
+ };
+
+ initializeFlattener(layers);
+
+ // layer 1 satisfies every condition in CachedSet::requiresHolePunch()
+ mTime += 200ms;
+ layerState1->resetFramesSinceBufferUpdate(); // it is updating
+
+ initializeOverrideBuffer(layers);
+ // Expect no cache invalidation the first time (there's no cache yet)
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+ // This will render a CachedSet of layer 0. Though it is just one layer, it satisfies the
+ // exception that there would be a hole punch above it.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+ // We've rendered a CachedSet, but we haven't merged it in.
+ EXPECT_EQ(nullptr, overrideBuffer0);
+
+ // This time we merge the CachedSet in and we should still have only two sets.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
+ initializeOverrideBuffer(layers);
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+ EXPECT_NE(nullptr, overrideBuffer0); // got overridden
+ EXPECT_EQ(nullptr, overrideBuffer1); // did not
+
+ // expect 0's peek though layer to be 1's output layer
+ const auto* peekThroughLayer0 =
+ layerState0->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+ const auto* peekThroughLayer1 =
+ layerState1->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+ EXPECT_EQ(&mTestLayers[1]->outputLayer, peekThroughLayer0);
+ EXPECT_EQ(nullptr, peekThroughLayer1);
+}
+
TEST_F(FlattenerTest, flattenLayers_flattensBlurBehindRunIfFirstRun) {
auto& layerState1 = mTestLayers[0]->layerState;
@@ -684,7 +771,9 @@
layerState3->resetFramesSinceBufferUpdate();
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -728,7 +817,9 @@
layerState1->resetFramesSinceBufferUpdate();
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillRepeatedly(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -780,7 +871,9 @@
layerState1->resetFramesSinceBufferUpdate();
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -827,7 +920,9 @@
layerStateWithBlurBehind->resetFramesSinceBufferUpdate();
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -868,7 +963,9 @@
// Mark the layers inactive
mTime += 200ms;
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -880,7 +977,7 @@
// Simulate attempting to render prior to merging the new cached set with the layer stack.
// Here we should not try to re-render.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We provide the override buffer now that it's rendered
@@ -899,11 +996,13 @@
public:
FlattenerRenderSchedulingTest()
: FlattenerTest(
- Flattener::CachedSetRenderSchedulingTunables{.cachedSetRenderDuration =
+ Flattener::Tunables{.mActiveLayerTimeout = 100ms,
+ .mRenderScheduling = Flattener::Tunables::
+ RenderScheduling{.cachedSetRenderDuration =
kCachedSetRenderDuration,
.maxDeferRenderAttempts =
- kMaxDeferRenderAttempts}) {
- }
+ kMaxDeferRenderAttempts},
+ .mEnableHolePunch = true}) {}
};
TEST_F(FlattenerRenderSchedulingTest, flattenLayers_renderCachedSets_defersUpToMaxAttempts) {
@@ -925,13 +1024,15 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
for (size_t i = 0; i < kMaxDeferRenderAttempts; i++) {
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
mFlattener->renderCachedSets(mOutputState,
std::chrono::steady_clock::now() -
(kCachedSetRenderDuration + 10ms));
}
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState,
std::chrono::steady_clock::now() -
(kCachedSetRenderDuration + 10ms));
@@ -965,7 +1066,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -975,7 +1078,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -1014,7 +1117,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -1024,7 +1129,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -1063,7 +1168,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -1073,7 +1180,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 4445eea..802a17d 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -232,7 +232,7 @@
}
void DisplayDevice::setLayerStack(ui::LayerStack stack) {
- mCompositionDisplay->setLayerStackFilter(stack, isInternal());
+ mCompositionDisplay->setLayerFilter({stack, isInternal()});
if (mRefreshRateOverlay) {
mRefreshRateOverlay->setLayerStack(stack);
}
@@ -349,7 +349,7 @@
}
ui::LayerStack DisplayDevice::getLayerStack() const {
- return mCompositionDisplay->getState().layerStackId;
+ return mCompositionDisplay->getState().layerFilter.layerStack;
}
ui::Transform::RotationFlags DisplayDevice::getTransformHint() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index afd12b5..43a6bd5 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -86,9 +86,7 @@
bool isVirtual() const { return !mConnectionType; }
bool isPrimary() const { return mIsPrimary; }
- bool isInternal() const {
- return !isVirtual() && mConnectionType == ui::DisplayConnectionType::Internal;
- }
+ bool isInternal() const { return mConnectionType == ui::DisplayConnectionType::Internal; }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
@@ -273,7 +271,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;
@@ -311,7 +309,7 @@
int32_t sequenceId = sNextSequenceId++;
std::optional<Physical> physical;
sp<IGraphicBufferProducer> surface;
- ui::LayerStack layerStack = ui::NO_LAYER_STACK;
+ ui::LayerStack layerStack;
uint32_t flags = 0;
Rect layerStackSpaceRect;
Rect orientedDisplaySpaceRect;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index a790b4c..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
@@ -271,7 +269,6 @@
display->setConnected(true);
auto& displayData = mDisplayData[displayId];
displayData.hwcDisplay = std::move(display);
- displayData.isVirtual = true;
return true;
}
@@ -279,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];
@@ -372,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;
@@ -428,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
@@ -597,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:
@@ -678,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);
}
@@ -693,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;
@@ -853,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 {};
@@ -868,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;
}
@@ -909,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;
@@ -922,8 +902,8 @@
}
return DisplayIdentificationInfo{.id = PhysicalDisplayId::fromPort(port),
- .name = isPrimary ? "Internal display"
- : "External display",
+ .name = isPrimary ? "Primary display"
+ : "Secondary display",
.deviceProductInfo = std::nullopt};
}();
}
@@ -936,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 {};
}
@@ -947,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 49f96d9..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>
@@ -228,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;
@@ -366,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;
@@ -382,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;
@@ -418,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;
@@ -428,5 +432,3 @@
} // namespace impl
} // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
new file mode 100644
index 0000000..f0c5b58
--- /dev/null
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 "FlagManager.h"
+
+#include <SurfaceFlingerProperties.sysprop.h>
+#include <android-base/parsebool.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <server_configurable_flags/get_flags.h>
+#include <cinttypes>
+
+namespace android {
+static constexpr const char* kExperimentNamespace = "surface_flinger_native_boot";
+static constexpr const int64_t kDemoFlag = -1;
+
+FlagManager::~FlagManager() = default;
+
+void FlagManager::dump(std::string& result) const {
+ base::StringAppendF(&result, "FlagManager values: \n");
+ base::StringAppendF(&result, "demo_flag: %" PRId64 "\n", demo_flag());
+}
+
+namespace {
+template <typename T>
+std::optional<T> doParse(const char* str);
+
+template <>
+[[maybe_unused]] std::optional<int32_t> doParse(const char* str) {
+ int32_t ret;
+ return base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt;
+}
+
+template <>
+[[maybe_unused]] std::optional<int64_t> doParse(const char* str) {
+ int64_t ret;
+ return base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt;
+}
+
+template <>
+[[maybe_unused]] std::optional<bool> doParse(const char* str) {
+ base::ParseBoolResult parseResult = base::ParseBool(str);
+ switch (parseResult) {
+ case base::ParseBoolResult::kTrue:
+ return std::make_optional(true);
+ case base::ParseBoolResult::kFalse:
+ return std::make_optional(false);
+ case base::ParseBoolResult::kError:
+ return std::nullopt;
+ }
+}
+} // namespace
+
+std::string FlagManager::getServerConfigurableFlag(const std::string& experimentFlagName) const {
+ return server_configurable_flags::GetServerConfigurableFlag(kExperimentNamespace,
+ experimentFlagName, "");
+}
+
+template int32_t FlagManager::getValue<int32_t>(const std::string&, std::optional<int32_t>,
+ int32_t) const;
+template int64_t FlagManager::getValue<int64_t>(const std::string&, std::optional<int64_t>,
+ int64_t) const;
+template bool FlagManager::getValue<bool>(const std::string&, std::optional<bool>, bool) const;
+template <typename T>
+T FlagManager::getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt,
+ T defaultValue) const {
+ // System property takes precedence over the experiment config server value.
+ if (systemPropertyOpt.has_value()) {
+ return *systemPropertyOpt;
+ }
+ std::string str = getServerConfigurableFlag(experimentFlagName);
+ return str.empty() ? defaultValue : doParse<T>(str.c_str()).value_or(defaultValue);
+}
+
+int64_t FlagManager::demo_flag() const {
+ std::optional<int64_t> sysPropVal = std::nullopt;
+ return getValue("DemoFeature__demo_flag", sysPropVal, kDemoFlag);
+}
+} // namespace android
diff --git a/services/surfaceflinger/FlagManager.h b/services/surfaceflinger/FlagManager.h
new file mode 100644
index 0000000..65e30a4
--- /dev/null
+++ b/services/surfaceflinger/FlagManager.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <cstdint>
+#include <optional>
+#include <string>
+
+namespace android {
+// Manages flags for SurfaceFlinger, including default values, system properties, and Mendel
+// experiment configuration values.
+class FlagManager {
+public:
+ FlagManager() = default;
+ virtual ~FlagManager();
+ void dump(std::string& result) const;
+
+ int64_t demo_flag() const;
+
+private:
+ friend class FlagManagerTest;
+
+ // Wrapper for mocking in test.
+ virtual std::string getServerConfigurableFlag(const std::string& experimentFlagName) const;
+
+ template <typename T>
+ T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt,
+ T defaultValue) const;
+};
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index db59007..b872c85 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -107,7 +107,7 @@
mDrawingState.requestedCrop = mDrawingState.crop;
mDrawingState.z = 0;
mDrawingState.color.a = 1.0f;
- mDrawingState.layerStack = 0;
+ mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK;
mDrawingState.sequence = 0;
mDrawingState.requested_legacy = mDrawingState.active_legacy;
mDrawingState.width = UINT32_MAX;
@@ -391,7 +391,6 @@
void Layer::prepareBasicGeometryCompositionState() {
const auto& drawingState{getDrawingState()};
- const uint32_t layerStack = getLayerStack();
const auto alpha = static_cast<float>(getAlpha());
const bool opaque = isOpaque(drawingState);
const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
@@ -403,9 +402,7 @@
}
auto* compositionState = editCompositionState();
- compositionState->layerStackId =
- (layerStack != ~0u) ? std::make_optional(layerStack) : std::nullopt;
- compositionState->internalOnly = getPrimaryDisplayOnly();
+ compositionState->outputFilter = getOutputFilter();
compositionState->isVisible = isVisible();
compositionState->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
compositionState->shadowRadius = mEffectiveShadowRadius;
@@ -728,14 +725,14 @@
mDrawingState.bufferlessSurfaceFramesTX.clear();
}
-uint32_t Layer::getTransactionFlags(uint32_t flags) {
- auto ret = mTransactionFlags & flags;
- mTransactionFlags &= ~flags;
- return ret;
+uint32_t Layer::clearTransactionFlags(uint32_t mask) {
+ const auto flags = mTransactionFlags & mask;
+ mTransactionFlags &= ~mask;
+ return flags;
}
-uint32_t Layer::setTransactionFlags(uint32_t flags) {
- return mTransactionFlags |= flags;
+void Layer::setTransactionFlags(uint32_t mask) {
+ mTransactionFlags |= mask;
}
bool Layer::setPosition(float x, float y) {
@@ -1005,7 +1002,7 @@
return true;
}
-bool Layer::setLayerStack(uint32_t layerStack) {
+bool Layer::setLayerStack(ui::LayerStack layerStack) {
if (mDrawingState.layerStack == layerStack) return false;
mDrawingState.sequence++;
mDrawingState.layerStack = layerStack;
@@ -1052,12 +1049,11 @@
return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE;
};
-uint32_t Layer::getLayerStack() const {
- auto p = mDrawingParent.promote();
- if (p == nullptr) {
- return getDrawingState().layerStack;
+ui::LayerStack Layer::getLayerStack() const {
+ if (const auto parent = mDrawingParent.promote()) {
+ return parent->getLayerStack();
}
- return p->getLayerStack();
+ return getDrawingState().layerStack;
}
bool Layer::setShadowRadius(float shadowRadius) {
@@ -1113,46 +1109,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);
}
@@ -1279,42 +1288,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 {
@@ -1377,7 +1367,7 @@
info.mVisibleRegion = getVisibleRegion(display);
info.mSurfaceDamageRegion = surfaceDamageRegion;
- info.mLayerStack = getLayerStack();
+ info.mLayerStack = getLayerStack().id;
info.mX = ds.transform.tx();
info.mY = ds.transform.ty();
info.mZ = ds.z;
@@ -2037,6 +2027,7 @@
layerInfo->set_curr_frame(mCurrentFrameNumber);
layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
+ layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius);
layerInfo->set_corner_radius(getRoundedCornerState().radius);
layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
layerInfo->set_is_trusted_overlay(isTrustedOverlay());
@@ -2093,7 +2084,7 @@
LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
[&]() { return layerInfo->mutable_transparent_region(); });
- layerInfo->set_layer_stack(getLayerStack());
+ layerInfo->set_layer_stack(getLayerStack().id);
layerInfo->set_z(state.z);
LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(),
@@ -2140,7 +2131,7 @@
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
WindowInfo info;
if (useDrawing) {
- info = fillInputInfo({nullptr});
+ info = fillInputInfo(nullptr);
} else {
info = state.inputInfo;
}
@@ -2169,7 +2160,7 @@
return getCroppedBufferSize(getDrawingState());
}
-void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& toPhysicalDisplay) {
+void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTransform) {
// Transform layer size to screen space and inset it by surface insets.
// If this is a portal window, set the touchableRegion to the layerBounds.
Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE
@@ -2189,13 +2180,13 @@
return;
}
- ui::Transform layerToDisplay = getInputTransform();
- // Transform that takes window coordinates to unrotated display coordinates
- ui::Transform t = toPhysicalDisplay * layerToDisplay;
+ const ui::Transform layerTransform = getInputTransform();
+ // Transform that takes window coordinates to non-rotated display coordinates
+ ui::Transform t = displayTransform * layerTransform;
int32_t xSurfaceInset = info.surfaceInset;
int32_t ySurfaceInset = info.surfaceInset;
- // Bring screenBounds into unrotated space
- Rect screenBounds = toPhysicalDisplay.transform(Rect{mScreenBounds});
+ // Bring screenBounds into non-unrotated space
+ Rect screenBounds = displayTransform.transform(Rect{mScreenBounds});
const float xScale = t.getScaleX();
const float yScale = t.getScaleY();
@@ -2274,36 +2265,50 @@
}
}
-WindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) {
+WindowInfo Layer::fillInputInfo(const DisplayDevice* display) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
mDrawingState.inputInfo.ownerUid = mOwnerUid;
mDrawingState.inputInfo.ownerPid = mOwnerPid;
mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL;
mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
- mDrawingState.inputInfo.displayId = getLayerStack();
+ mDrawingState.inputInfo.displayId = getLayerStack().id;
}
WindowInfo info = mDrawingState.inputInfo;
info.id = sequence;
+ info.displayId = getLayerStack().id;
- if (info.displayId == ADISPLAY_ID_NONE) {
- info.displayId = getLayerStack();
- }
-
- // Transform that goes from "logical(rotated)" display to physical/unrotated display.
- // This is for when inputflinger operates in physical display-space.
- ui::Transform toPhysicalDisplay;
+ // Transform that maps from LayerStack space to display space, e.g. rotated to non-rotated.
+ // Used when InputFlinger operates in display space.
+ ui::Transform displayTransform;
if (display) {
- toPhysicalDisplay = display->getTransform();
- // getOrientation() without masking can contain more-significant bits (eg. ROT_INVALID).
- static constexpr uint32_t ALL_ROTATIONS_MASK =
- ui::Transform::ROT_90 | ui::Transform::ROT_180 | ui::Transform::ROT_270;
- info.displayOrientation = toPhysicalDisplay.getOrientation() & ALL_ROTATIONS_MASK;
- info.displayWidth = display->getWidth();
- info.displayHeight = display->getHeight();
+ // The physical orientation is set when the orientation of the display panel is different
+ // than the default orientation of the device. Other services like InputFlinger do not know
+ // about this, so we do not need to expose the physical orientation of the panel outside of
+ // SurfaceFlinger.
+ const ui::Rotation inversePhysicalOrientation =
+ ui::ROTATION_0 - display->getPhysicalOrientation();
+ auto width = display->getWidth();
+ auto height = display->getHeight();
+ if (inversePhysicalOrientation == ui::ROTATION_90 ||
+ inversePhysicalOrientation == ui::ROTATION_270) {
+ std::swap(width, height);
+ }
+ const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags(
+ inversePhysicalOrientation),
+ width, height);
+ displayTransform = undoPhysicalOrientation * display->getTransform();
+
+ // Send the inverse of the display orientation so that input can transform points back to
+ // the rotated display space.
+ const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation();
+ info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation);
+
+ info.displayWidth = width;
+ info.displayHeight = height;
}
- fillInputFrameInfo(info, toPhysicalDisplay);
+ fillInputFrameInfo(info, displayTransform);
// For compatibility reasons we let layers which can receive input
// receive input before they have actually submitted a buffer. Because
@@ -2319,15 +2324,11 @@
auto cropLayer = mDrawingState.touchableRegionCrop.promote();
if (info.replaceTouchableRegionWithCrop) {
- if (cropLayer == nullptr) {
- info.touchableRegion = Region(toPhysicalDisplay.transform(Rect{mScreenBounds}));
- } else {
- info.touchableRegion =
- Region(toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
- }
+ const Rect bounds(cropLayer ? cropLayer->mScreenBounds : mScreenBounds);
+ info.touchableRegion = Region(displayTransform.transform(bounds));
} else if (cropLayer != nullptr) {
info.touchableRegion = info.touchableRegion.intersect(
- toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
+ displayTransform.transform(Rect{cropLayer->mScreenBounds}));
}
// Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
@@ -2338,9 +2339,8 @@
// 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()) {
- sp<Layer> clonedRoot = getClonedRoot();
- if (clonedRoot != nullptr) {
- Rect rect = toPhysicalDisplay.transform(Rect{clonedRoot->mScreenBounds});
+ if (const sp<Layer> clonedRoot = getClonedRoot()) {
+ const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds});
info.touchableRegion = info.touchableRegion.intersect(rect);
}
}
@@ -2536,14 +2536,14 @@
}
}
-bool Layer::getPrimaryDisplayOnly() const {
+bool Layer::isInternalDisplayOverlay() const {
const State& s(mDrawingState);
if (s.flags & layer_state_t::eLayerSkipScreenshot) {
return true;
}
sp<Layer> parent = mDrawingParent.promote();
- return parent == nullptr ? false : parent->getPrimaryDisplayOnly();
+ return parent && parent->isInternalDisplayOverlay();
}
void Layer::setClonedChild(const sp<Layer>& clonedChild) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3ed7ee9..4200be4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -151,12 +151,7 @@
Geometry requested_legacy;
int32_t z;
- // The identifier of the layer stack this layer belongs to. A layer can
- // only be associated to a single layer stack. A layer stack is a
- // z-ordered group of layers which can be associated to one or more
- // displays. Using the same layer stack on different displays is a way
- // to achieve mirroring.
- uint32_t layerStack;
+ ui::LayerStack layerStack;
uint32_t flags;
uint8_t reserved[2];
@@ -280,6 +275,8 @@
Rect bufferCrop;
Rect destinationFrame;
+
+ sp<IBinder> releaseBufferEndpoint;
};
/*
@@ -403,8 +400,8 @@
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;
+ virtual bool setLayerStack(ui::LayerStack);
+ virtual ui::LayerStack getLayerStack() const;
virtual bool setMetadata(const LayerMetadata& data);
virtual void setChildrenDrawingParent(const sp<Layer>&);
virtual bool reparent(const sp<IBinder>& newParentHandle);
@@ -422,7 +419,8 @@
const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */,
std::optional<nsecs_t> /* dequeueTime */,
const FrameTimelineInfo& /*info*/,
- const sp<ITransactionCompletedListener>& /* releaseBufferListener */) {
+ const sp<ITransactionCompletedListener>& /* releaseBufferListener */,
+ const sp<IBinder>& /* releaseBufferEndpoint */) {
return false;
};
virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
@@ -642,13 +640,12 @@
bool isLegacyDataSpace() const;
uint32_t getTransactionFlags() const { return mTransactionFlags; }
- uint32_t getTransactionFlags(uint32_t flags);
- uint32_t setTransactionFlags(uint32_t flags);
- // Deprecated, please use compositionengine::Output::belongsInOutput()
- // instead.
- // TODO(lpique): Move the remaining callers (screencap) to the new function.
- bool belongsToDisplay(uint32_t layerStack) const { return getLayerStack() == layerStack; }
+ // Sets the masked bits.
+ void setTransactionFlags(uint32_t mask);
+
+ // Clears and returns the masked bits.
+ uint32_t clearTransactionFlags(uint32_t mask);
FloatRect getBounds(const Region& activeTransparentRegion) const;
FloatRect getBounds() const;
@@ -681,6 +678,14 @@
*/
bool isHiddenByPolicy() const;
+ // True if the layer should be skipped in screenshots, screen recordings,
+ // and mirroring to external or virtual displays.
+ bool isInternalDisplayOverlay() const;
+
+ ui::LayerFilter getOutputFilter() const {
+ return {getLayerStack(), isInternalDisplayOverlay()};
+ }
+
bool isRemovedFromCurrentState() const;
LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*);
@@ -697,8 +702,6 @@
gui::WindowInfo::Type getWindowType() const { return mWindowType; }
- bool getPrimaryDisplayOnly() const;
-
void updateMirrorInfo();
/*
@@ -708,12 +711,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.
*/
@@ -854,7 +851,8 @@
bool getPremultipledAlpha() const;
void setInputInfo(const gui::WindowInfo& info);
- gui::WindowInfo fillInputInfo(const sp<DisplayDevice>& display);
+ gui::WindowInfo fillInputInfo(const DisplayDevice*);
+
/**
* Returns whether this layer has an explicitly set input-info.
*/
@@ -1058,6 +1056,8 @@
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;
@@ -1073,10 +1073,8 @@
// hasInputInfo() or no-op if no such parent is found.
void fillTouchOcclusionMode(gui::WindowInfo& info);
- // Fills in the frame and transform info for the gui::WindowInfo
- void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& toPhysicalDisplay);
-
- bool updateFrameRateForLayerTree(bool treeHasFrameRateVote);
+ // Fills in the frame and transform info for the gui::WindowInfo.
+ void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& displayTransform);
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index aee820a..f52e60d 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -45,8 +45,8 @@
const auto& lState = l->getDrawingState();
const auto& rState = r->getDrawingState();
- uint32_t ls = lState.layerStack;
- uint32_t rs = rState.layerStack;
+ const auto ls = lState.layerStack;
+ const auto rs = rState.layerStack;
if (ls != rs)
return (ls > rs) ? 1 : -1;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 2adfe14..0789e8d 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -281,7 +281,7 @@
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
-void RefreshRateOverlay::setLayerStack(uint32_t stack) {
+void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
mLayer->setLayerStack(stack);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
@@ -292,7 +292,7 @@
mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
std::nullopt /* dequeueTime */, FrameTimelineInfo{},
- nullptr /* releaseBufferListener */);
+ nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
@@ -306,7 +306,7 @@
mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
std::nullopt /* dequeueTime */, FrameTimelineInfo{},
- nullptr /* releaseBufferListener */);
+ nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index fd1e2df..63ae383 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -18,6 +18,7 @@
#include <math/vec4.h>
#include <renderengine/RenderEngine.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Size.h>
#include <utils/StrongPointer.h>
@@ -41,7 +42,7 @@
public:
RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner);
- void setLayerStack(uint32_t stack);
+ void setLayerStack(ui::LayerStack);
void setViewport(ui::Size);
void changeRefreshRate(const Fps&);
void onInvalidate();
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/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index c38cd68..e922d46 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -140,6 +140,8 @@
return 0;
}
+ constexpr float kScoreForFractionalPairs = .8f;
+
// Slightly prefer seamless switches.
constexpr float kSeamedSwitchPenalty = 0.95f;
const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
@@ -156,19 +158,29 @@
const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
if (layer.vote == LayerVoteType::ExplicitDefault) {
// Find the actual rate the layer will render, assuming
- // that layerPeriod is the minimal time to render a frame
+ // that layerPeriod is the minimal period to render a frame.
+ // For example if layerPeriod is 20ms and displayPeriod is 16ms,
+ // then the actualLayerPeriod will be 32ms, because it is the
+ // smallest multiple of the display period which is >= layerPeriod.
auto actualLayerPeriod = displayPeriod;
int multiplier = 1;
while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
multiplier++;
actualLayerPeriod = displayPeriod * multiplier;
}
+
+ // Because of the threshold we used above it's possible that score is slightly
+ // above 1.
return std::min(1.0f,
static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod));
}
if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
layer.vote == LayerVoteType::Heuristic) {
+ if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) {
+ return kScoreForFractionalPairs * seamlessness;
+ }
+
// Calculate how many display vsyncs we need to present a single frame for this
// layer
const auto [displayFramesQuotient, displayFramesRemainder] =
@@ -421,7 +433,7 @@
const auto layerScore =
calculateLayerScoreLocked(layer, *scores[i].refreshRate, isSeamlessSwitch);
- ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
+ ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
scores[i].refreshRate->getName().c_str(), layerScore);
scores[i].score += weight * layerScore;
}
@@ -582,7 +594,7 @@
template <typename Iter>
const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
- constexpr auto EPSILON = 0.001f;
+ constexpr auto kEpsilon = 0.0001f;
const RefreshRate* bestRefreshRate = begin->refreshRate;
float max = begin->score;
for (auto i = begin; i != end; ++i) {
@@ -591,7 +603,7 @@
ATRACE_INT(refreshRate->getName().c_str(), round<int>(score * 100));
- if (score > max * (1 + EPSILON)) {
+ if (score > max * (1 + kEpsilon)) {
max = score;
bestRefreshRate = refreshRate;
}
@@ -910,7 +922,10 @@
int RefreshRateConfigs::getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate) {
// This calculation needs to be in sync with the java code
// in DisplayManagerService.getDisplayInfoForFrameRateOverride
- constexpr float kThreshold = 0.1f;
+
+ // The threshold must be smaller than 0.001 in order to differentiate
+ // between the fractional pairs (e.g. 59.94 and 60).
+ constexpr float kThreshold = 0.0009f;
const auto numPeriods = displayFrameRate.getValue() / layerFrameRate.getValue();
const auto numPeriodsRounded = std::round(numPeriods);
if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
@@ -920,6 +935,17 @@
return static_cast<int>(numPeriodsRounded);
}
+bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) {
+ if (smaller.getValue() > bigger.getValue()) {
+ return isFractionalPairOrMultiple(bigger, smaller);
+ }
+
+ const auto multiplier = std::round(bigger.getValue() / smaller.getValue());
+ constexpr float kCoef = 1000.f / 1001.f;
+ return bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier / kCoef)) ||
+ bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier * kCoef));
+}
+
void RefreshRateConfigs::dump(std::string& result) const {
std::lock_guard lock(mLock);
base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n",
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 4a9a1fd..0d75689 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -335,6 +335,10 @@
// layer refresh rate.
static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
+ // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000
+ // for an integer t.
+ static bool isFractionalPairOrMultiple(Fps, Fps);
+
using UidToFrameRateOverride = std::map<uid_t, Fps>;
// Returns the frame rate override for each uid.
//
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index f808981..534efee 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -669,7 +669,7 @@
}
}
-void Scheduler::notifyTouchEvent() {
+void Scheduler::onTouchHint() {
if (mTouchTimer) {
mTouchTimer->reset();
@@ -878,7 +878,7 @@
void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
if (timeline.refreshRequired) {
- mSchedulerCallback.repaintEverythingForHWC();
+ mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
}
std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
@@ -891,21 +891,21 @@
}
void Scheduler::onDisplayRefreshed(nsecs_t timestamp) {
- bool callRepaint = false;
- {
+ const bool refresh = [=] {
std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
- if (mLastVsyncPeriodChangeTimeline->refreshTimeNanos < timestamp) {
- mLastVsyncPeriodChangeTimeline->refreshRequired = false;
- } else {
- // We need to send another refresh as refreshTimeNanos is still in the future
- callRepaint = true;
+ if (timestamp < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
+ // We need to schedule another refresh as refreshTimeNanos is still in the future.
+ return true;
}
- }
- }
- if (callRepaint) {
- mSchedulerCallback.repaintEverythingForHWC();
+ mLastVsyncPeriodChangeTimeline->refreshRequired = false;
+ }
+ return false;
+ }();
+
+ if (refresh) {
+ mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 4b6905b..420ba61 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -56,10 +56,13 @@
} // namespace frametimeline
struct ISchedulerCallback {
+ // Indicates frame activity, i.e. whether commit and/or composite is taking place.
+ enum class FrameHint { kNone, kActive };
+
+ virtual void scheduleRefresh(FrameHint) = 0;
virtual void setVsyncEnabled(bool) = 0;
virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
scheduler::RefreshRateConfigEvent) = 0;
- virtual void repaintEverythingForHWC() = 0;
virtual void kernelTimerChanged(bool expired) = 0;
virtual void triggerOnFrameRateOverridesChanged() = 0;
@@ -136,8 +139,8 @@
bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
void resetIdleTimer();
- // Function that resets the touch timer.
- void notifyTouchEvent();
+ // Indicates that touch interaction is taking place.
+ void onTouchHint();
void setDisplayPowerState(bool normal);
@@ -194,6 +197,8 @@
private:
friend class TestableScheduler;
+ using FrameHint = ISchedulerCallback::FrameHint;
+
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
enum class ContentDetectionState { Off, On };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 967f028..15db2ed 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>
@@ -277,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");
@@ -358,10 +342,8 @@
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
mPowerAdvisor(*this),
- mWindowInfosListenerInvoker(new WindowInfosListenerInvoker()) {
+ mWindowInfosListenerInvoker(new WindowInfosListenerInvoker(this)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
-
- mSetInputWindowsListener = new SetInputWindowsListener([&]() { setInputWindowsFinished(); });
}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
@@ -433,10 +415,7 @@
property_get("ro.build.type", value, "user");
mIsUserBuild = strcmp(value, "user") == 0;
- property_get("debug.sf.showupdates", value, "0");
- mDebugRegion = atoi(value);
-
- ALOGI_IF(mDebugRegion, "showupdates enabled");
+ mDebugFlashDelay = base::GetUintProperty("debug.sf.showupdates"s, 0u);
// DDMS debugging deprecated (b/120782499)
property_get("debug.sf.ddms", value, "0");
@@ -636,17 +615,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);
}
}
@@ -813,10 +789,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;
@@ -985,6 +961,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();
@@ -1044,18 +1025,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;
}
@@ -1082,8 +1063,8 @@
}
if (display->setDesiredActiveMode(info)) {
- // This will trigger HWC refresh without resetting the idle timer.
- repaintEverythingForHWC();
+ scheduleRefresh(FrameHint::kNone);
+
// Start receiving vsync samples now, so that we can detect a period
// switch.
mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod());
@@ -1279,15 +1260,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());
}
@@ -1311,34 +1292,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;
}
@@ -1658,7 +1646,7 @@
Boost powerBoost = static_cast<Boost>(boostId);
if (powerBoost == Boost::INTERACTION) {
- mScheduler->notifyTouchEvent();
+ mScheduler->onTouchHint();
}
return NO_ERROR;
@@ -1675,16 +1663,26 @@
return mScheduler->createDisplayEventConnection(handle, eventRegistration);
}
-void SurfaceFlinger::signalTransaction() {
- mScheduler->resetIdleTimer();
+void SurfaceFlinger::scheduleInvalidate(FrameHint hint) {
+ if (hint == FrameHint::kActive) {
+ mScheduler->resetIdleTimer();
+ }
mPowerAdvisor.notifyDisplayUpdateImminent();
mEventQueue->invalidate();
}
+void SurfaceFlinger::scheduleRefresh(FrameHint hint) {
+ mForceRefresh = true;
+ scheduleInvalidate(hint);
+}
+
+void SurfaceFlinger::scheduleRepaint() {
+ mGeometryDirty = true;
+ scheduleRefresh(FrameHint::kActive);
+}
+
void SurfaceFlinger::signalLayerUpdate() {
- mScheduler->resetIdleTimer();
- mPowerAdvisor.notifyDisplayUpdateImminent();
- mEventQueue->invalidate();
+ scheduleInvalidate(FrameHint::kActive);
}
void SurfaceFlinger::signalRefresh() {
@@ -1755,8 +1753,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
@@ -1787,7 +1785,7 @@
void SurfaceFlinger::onComposerHalRefresh(hal::HWDisplayId) {
Mutex::Autolock lock(mStateLock);
- repaintEverythingForHWC();
+ scheduleRefresh(FrameHint::kNone);
}
void SurfaceFlinger::setVsyncEnabled(bool enabled) {
@@ -1948,17 +1946,13 @@
}
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();
}
}
- bool refreshNeeded;
+ bool refreshNeeded = mForceRefresh.exchange(false);
{
mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) ||
mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) ||
@@ -1968,8 +1962,9 @@
mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod));
- refreshNeeded = handleMessageTransaction();
+ refreshNeeded |= flushAndCommitTransactions();
refreshNeeded |= handleMessageInvalidate();
+
if (tracePreComposition) {
if (mVisibleRegionsDirty) {
mTracing.notifyLocked("visibleRegionsDirty");
@@ -1991,7 +1986,6 @@
updateCursorAsync();
updateInputFlinger();
- refreshNeeded |= mRepaintEverything;
if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
@@ -2013,25 +2007,23 @@
notifyRegionSamplingThread();
}
-bool SurfaceFlinger::handleMessageTransaction() {
+bool SurfaceFlinger::flushAndCommitTransactions() {
ATRACE_CALL();
- if (getTransactionFlags(eTransactionFlushNeeded)) {
+ if (clearTransactionFlags(eTransactionFlushNeeded)) {
flushTransactionQueues();
}
- uint32_t transactionFlags = peekTransactionFlags();
- bool runHandleTransaction =
- ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal;
- if (runHandleTransaction) {
- handleTransaction(eTransactionMask);
+ const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || mForceTraversal;
+ if (shouldCommit) {
+ commitTransactions();
}
if (transactionFlushNeeded()) {
setTransactionFlags(eTransactionFlushNeeded);
}
- return runHandleTransaction;
+ return shouldCommit;
}
void SurfaceFlinger::onMessageRefresh() {
@@ -2055,7 +2047,6 @@
refreshArgs.layersWithQueuedFrames.push_back(layerFE);
}
- refreshArgs.repaintEverything = mRepaintEverything.exchange(false);
refreshArgs.outputColorSetting = useColorManagement
? mDisplayColorSetting
: compositionengine::OutputColorSetting::kUnmanaged;
@@ -2063,7 +2054,7 @@
refreshArgs.forceOutputColorMode = mForceColorMode;
refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
- refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty;
+ refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty;
refreshArgs.blursAreExpensive = mBlursAreExpensive;
refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags();
@@ -2072,11 +2063,11 @@
mDrawingState.colorMatrixChanged = false;
}
- refreshArgs.devOptForceClientComposition = mDebugDisableHWC || mDebugRegion;
+ refreshArgs.devOptForceClientComposition = mDebugDisableHWC;
- if (mDebugRegion != 0) {
- refreshArgs.devOptFlashDirtyRegionsDelay =
- std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0);
+ if (mDebugFlashDelay != 0) {
+ refreshArgs.devOptForceClientComposition = true;
+ refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
}
const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(mExpectedPresentTime);
@@ -2085,8 +2076,6 @@
refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
refreshArgs.nextInvalidateTime = mEventQueue->nextExpectedInvalidate();
- mGeometryInvalid = false;
-
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
const auto presentTime = systemTime();
@@ -2308,7 +2297,7 @@
int32_t maxArea = 0;
mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
const auto layerFe = layer->getCompositionEngineLayerFE();
- if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) {
+ if (layer->isVisible() && compositionDisplay->includesLayer(layerFe)) {
const Dataspace transfer =
static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK);
const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
@@ -2439,8 +2428,8 @@
const auto& displayDevice = pair.second;
const auto display = displayDevice->getCompositionDisplay();
for (const auto& layer : mDrawingState.layersSortedByZ) {
- // only consider the layers on the given layer stack
- if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ // Only consider the layers on this display.
+ if (!display->includesLayer(layer->getOutputFilter())) {
continue;
}
@@ -2460,29 +2449,26 @@
}
}
-void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) {
+void SurfaceFlinger::commitTransactions() {
ATRACE_CALL();
- // here we keep a copy of the drawing state (that is the state that's
- // going to be overwritten by handleTransactionLocked()) outside of
- // mStateLock so that the side-effects of the State assignment
- // don't happen with mStateLock held (which can cause deadlocks).
+ // Keep a copy of the drawing state (that is going to be overwritten
+ // by commitTransactionsLocked) outside of mStateLock so that the side
+ // effects of the State assignment don't happen with mStateLock held,
+ // which can cause deadlocks.
State drawingState(mDrawingState);
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
mDebugInTransaction = systemTime();
// Here we're guaranteed that some transaction flags are set
- // so we can call handleTransactionLocked() unconditionally.
- // We call getTransactionFlags(), which will also clear the flags,
- // with mStateLock held to guarantee that mCurrentState won't change
- // until the transaction is committed.
+ // so we can call commitTransactionsLocked unconditionally.
+ // We clear the flags with mStateLock held to guarantee that
+ // mCurrentState won't change until the transaction is committed.
modulateVsync(&VsyncModulator::onTransactionCommit);
- transactionFlags = getTransactionFlags(eTransactionMask);
- handleTransactionLocked(transactionFlags);
+ commitTransactionsLocked(clearTransactionFlags(eTransactionMask));
mDebugInTransaction = 0;
- // here the transaction has been committed
}
void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes,
@@ -2745,14 +2731,12 @@
compositionengine::DisplayCreationArgsBuilder builder;
if (const auto& physical = state.physical) {
builder.setId(physical->id);
- builder.setConnectionType(physical->type);
} else {
builder.setId(acquireVirtualDisplay(resolution, pixelFormat));
}
builder.setPixels(resolution);
builder.setIsSecure(state.isSecure);
- builder.setLayerStackId(state.layerStack);
builder.setPowerAdvisor(&mPowerAdvisor);
builder.setName(state.displayName);
auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
@@ -2858,7 +2842,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);
}
}
@@ -2938,8 +2922,8 @@
mDrawingState.displays = mCurrentState.displays;
}
-void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) {
- // Commit display transactions
+void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) {
+ // Commit display transactions.
const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
if (displayTransactionNeeded) {
processDisplayChangesLocked();
@@ -2953,18 +2937,9 @@
mSomeChildrenChanged = false;
}
- // Update transform hint
+ // Update transform hint.
if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) {
- // The transform hint might have changed for some layers
- // (either because a display has changed, or because a layer
- // as changed).
- //
- // Walk through all the layers in currentLayers,
- // and update their transform hint.
- //
- // If a layer is visible only on a single display, then that
- // display is used to calculate the hint, otherwise we use the
- // default display.
+ // Layers and/or displays have changed, so update the transform hint for each layer.
//
// NOTE: we do this here, rather than when presenting the display so that
// the hint is set before we acquire a buffer from the surface texture.
@@ -2975,30 +2950,29 @@
// (soon to become the drawing state list).
//
sp<const DisplayDevice> hintDisplay;
- uint32_t currentlayerStack = 0;
- bool first = true;
+ ui::LayerStack layerStack;
+
mCurrentState.traverse([&](Layer* layer) REQUIRES(mStateLock) {
// NOTE: we rely on the fact that layers are sorted by
// layerStack first (so we don't have to traverse the list
// of displays for every layer).
- uint32_t layerStack = layer->getLayerStack();
- if (first || currentlayerStack != layerStack) {
- currentlayerStack = layerStack;
- // figure out if this layerstack is mirrored
- // (more than one display) if so, pick the default display,
- // if not, pick the only display it's on.
+ if (const auto filter = layer->getOutputFilter(); layerStack != filter.layerStack) {
+ layerStack = filter.layerStack;
hintDisplay = nullptr;
+
+ // Find the display that includes the layer.
for (const auto& [token, display] : mDisplays) {
- if (display->getCompositionDisplay()
- ->belongsInOutput(layer->getLayerStack(),
- layer->getPrimaryDisplayOnly())) {
- if (hintDisplay) {
- hintDisplay = nullptr;
- break;
- } else {
- hintDisplay = display;
- }
+ if (!display->getCompositionDisplay()->includesLayer(filter)) {
+ continue;
}
+
+ // Pick the primary display if another display mirrors the layer.
+ if (hintDisplay) {
+ hintDisplay = nullptr;
+ break;
+ }
+
+ hintDisplay = display;
}
}
@@ -3012,20 +2986,10 @@
hintDisplay = getDefaultDisplayDeviceLocked();
}
- // could be null if there is no display available at all to get
- // the transform hint from.
- if (hintDisplay) {
- layer->updateTransformHint(hintDisplay->getTransformHint());
- }
-
- first = false;
+ layer->updateTransformHint(hintDisplay->getTransformHint());
});
}
- /*
- * Perform our own transaction if needed
- */
-
if (mLayersAdded) {
mLayersAdded = false;
// Layers have been added.
@@ -3047,7 +3011,9 @@
});
}
- commitTransaction();
+ doCommitTransactions();
+ signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
+ mAnimTransactionPending = false;
}
void SurfaceFlinger::updateInputFlinger() {
@@ -3058,11 +3024,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) {
@@ -3077,22 +3043,23 @@
return value;
}
-void SurfaceFlinger::updateInputWindowInfo() {
- std::vector<WindowInfo> inputInfos;
+void SurfaceFlinger::notifyWindowInfos() {
+ std::vector<WindowInfo> windowInfos;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
- sp<DisplayDevice> display = enablePerWindowInputRotation()
- ? ON_MAIN_THREAD(getDisplayWithInputByLayer(layer))
- : nullptr;
+
+ const DisplayDevice* display = nullptr;
+ if (enablePerWindowInputRotation()) {
+ display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get();
+ }
+
// 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() {
@@ -3195,14 +3162,9 @@
mEventQueue->setDuration(config.sfWorkDuration);
}
-void SurfaceFlinger::commitTransaction() {
+void SurfaceFlinger::doCommitTransactions() {
ATRACE_CALL();
- commitTransactionLocked();
- signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
- mAnimTransactionPending = false;
-}
-void SurfaceFlinger::commitTransactionLocked() {
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (const auto& l : mLayersPendingRemoval) {
@@ -3246,11 +3208,10 @@
void SurfaceFlinger::commitOffscreenLayers() {
for (Layer* offscreenLayer : mOffscreenLayers) {
offscreenLayer->traverse(LayerVector::StateSet::Drawing, [](Layer* layer) {
- uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
- if (!trFlags) return;
-
- layer->doTransaction(0);
- layer->commitChildList();
+ if (layer->clearTransactionFlags(eTransactionNeeded)) {
+ layer->doTransaction(0);
+ layer->commitChildList();
+ }
});
}
}
@@ -3258,7 +3219,7 @@
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) {
auto display = displayDevice->getCompositionDisplay();
- if (display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ if (display->includesLayer(layer->getOutputFilter())) {
display->editState().dirtyRegion.orSelf(dirty);
}
}
@@ -3286,14 +3247,14 @@
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display.
mDrawingState.traverse([&](Layer* layer) {
- uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
- if (trFlags || mForceTransactionDisplayChange) {
- const uint32_t flags = layer->doTransaction(0);
- if (flags & Layer::eVisibleRegion)
- mVisibleRegionsDirty = true;
- }
+ if (layer->clearTransactionFlags(eTransactionNeeded) || mForceTransactionDisplayChange) {
+ const uint32_t flags = layer->doTransaction(0);
+ if (flags & Layer::eVisibleRegion) {
+ mVisibleRegionsDirty = true;
+ }
+ }
- if (layer->hasReadyFrame()) {
+ if (layer->hasReadyFrame()) {
frameQueued = true;
if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.emplace(layer);
@@ -3301,7 +3262,7 @@
ATRACE_NAME("!layer->shouldPresentNow()");
layer->useEmptyDamage();
}
- } else {
+ } else {
layer->useEmptyDamage();
}
});
@@ -3354,10 +3315,6 @@
return !mLayersWithQueuedFrames.empty() && newDataLatched;
}
-void SurfaceFlinger::invalidateHwcGeometry() {
- mGeometryInvalid = true;
-}
-
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle,
@@ -3404,23 +3361,23 @@
}));
}
-uint32_t SurfaceFlinger::peekTransactionFlags() {
+uint32_t SurfaceFlinger::getTransactionFlags() const {
return mTransactionFlags;
}
-uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
- return mTransactionFlags.fetch_and(~flags) & flags;
+uint32_t SurfaceFlinger::clearTransactionFlags(uint32_t mask) {
+ return mTransactionFlags.fetch_and(~mask) & mask;
}
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
- return setTransactionFlags(flags, TransactionSchedule::Late);
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask) {
+ return setTransactionFlags(mask, TransactionSchedule::Late);
}
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule,
- const sp<IBinder>& token) {
- uint32_t old = mTransactionFlags.fetch_or(flags);
- modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token);
- if ((old & flags) == 0) signalTransaction();
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
+ const sp<IBinder>& applyToken) {
+ const uint32_t old = mTransactionFlags.fetch_or(mask);
+ modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken);
+ if ((old & mask) == 0) scheduleInvalidate(FrameHint::kActive);
return old;
}
@@ -4220,7 +4177,7 @@
if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp,
s.cachedBuffer, frameNumber, dequeueBufferTimestamp, frameTimelineInfo,
- s.releaseBufferListener)) {
+ s.releaseBufferListener, s.releaseBufferEndpoint)) {
flags |= eTraversalNeeded;
}
} else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
@@ -4479,7 +4436,7 @@
d.what = DisplayState::eDisplayProjectionChanged |
DisplayState::eLayerStackChanged;
d.token = token;
- d.layerStack = 0;
+ d.layerStack = ui::DEFAULT_LAYER_STACK;
d.orientation = ui::ROTATION_0;
d.orientedDisplaySpaceRect.makeInvalid();
d.layerStackSpaceRect.makeInvalid();
@@ -4510,23 +4467,22 @@
}
sp<DisplayDevice> SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const {
- sp<DisplayDevice> display;
- for (const auto& pair : mDisplays) {
- const auto& displayDevice = pair.second;
- if (!displayDevice->receivesInput() ||
- !displayDevice->getCompositionDisplay()
- ->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ const auto filter = layer->getOutputFilter();
+ sp<DisplayDevice> inputDisplay;
+
+ for (const auto& [_, display] : mDisplays) {
+ if (!display->receivesInput() || !display->getCompositionDisplay()->includesLayer(filter)) {
continue;
}
// Don't return immediately so that we can log duplicates.
- if (display) {
- ALOGE("Multiple display devices claim to accept input for the same layerstack: %d",
- layer->getLayerStack());
+ if (inputDisplay) {
+ ALOGE("Multiple displays claim to accept input for the same layer stack: %u",
+ filter.layerStack.id);
continue;
}
- display = displayDevice;
+ inputDisplay = display;
}
- return display;
+ return inputDisplay;
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
@@ -4571,7 +4527,7 @@
mVisibleRegionsDirty = true;
mHasPoweredOff = true;
- repaintEverything();
+ scheduleRefresh(FrameHint::kActive);
} else if (mode == hal::PowerMode::OFF) {
// Turn off the display
if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) {
@@ -5163,7 +5119,7 @@
colorizer.bold(result);
result.append("h/w composer state:\n");
colorizer.reset(result);
- bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
+ const bool hwcDisabled = mDebugDisableHWC || mDebugFlashDelay;
StringAppendF(&result, " h/w composer %s\n", hwcDisabled ? "disabled" : "enabled");
getHwComposer().dump(result);
@@ -5372,9 +5328,8 @@
status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
- status_t credentialCheck = CheckTransactCodeCredentials(code);
- if (credentialCheck != OK) {
- return credentialCheck;
+ if (const status_t error = CheckTransactCodeCredentials(code); error != OK) {
+ return error;
}
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
@@ -5391,47 +5346,43 @@
}
int n;
switch (code) {
- case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
- case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
+ case 1000: // Unused.
+ case 1001:
+ return NAME_NOT_FOUND;
+ case 1002: // Toggle flashing on surface damage.
+ if (const int delay = data.readInt32(); delay > 0) {
+ mDebugFlashDelay = delay;
+ } else {
+ mDebugFlashDelay = mDebugFlashDelay ? 0 : 1;
+ }
+ scheduleRepaint();
return NO_ERROR;
- case 1002: // SHOW_UPDATES
- n = data.readInt32();
- mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
- invalidateHwcGeometry();
- repaintEverything();
+ case 1004: // Force refresh ahead of next VSYNC.
+ scheduleRefresh(FrameHint::kActive);
return NO_ERROR;
- case 1004:{ // repaint everything
- repaintEverything();
+ case 1005: { // Force commit ahead of next VSYNC.
+ Mutex::Autolock lock(mStateLock);
+ setTransactionFlags(eTransactionNeeded | eDisplayTransactionNeeded |
+ eTraversalNeeded);
return NO_ERROR;
}
- case 1005:{ // force transaction
- Mutex::Autolock _l(mStateLock);
- setTransactionFlags(
- eTransactionNeeded|
- eDisplayTransactionNeeded|
- eTraversalNeeded);
- return NO_ERROR;
- }
- case 1006:{ // send empty update
+ case 1006: // Force refresh immediately.
signalRefresh();
return NO_ERROR;
- }
- case 1008: // toggle use of hw composer
- n = data.readInt32();
- mDebugDisableHWC = n != 0;
- invalidateHwcGeometry();
- repaintEverything();
+ case 1007: // Unused.
+ return NAME_NOT_FOUND;
+ case 1008: // Toggle forced GPU composition.
+ mDebugDisableHWC = data.readInt32() != 0;
+ scheduleRepaint();
return NO_ERROR;
- case 1009: // toggle use of transform hint
- n = data.readInt32();
- mDebugDisableTransformHint = n != 0;
- invalidateHwcGeometry();
- repaintEverything();
+ case 1009: // Toggle use of transform hint.
+ mDebugDisableTransformHint = data.readInt32() != 0;
+ scheduleRepaint();
return NO_ERROR;
- case 1010: // interrogate.
+ case 1010: // Interrogate.
reply->writeInt32(0);
reply->writeInt32(0);
- reply->writeInt32(mDebugRegion);
+ reply->writeInt32(mDebugFlashDelay);
reply->writeInt32(0);
reply->writeInt32(mDebugDisableHWC);
return NO_ERROR;
@@ -5486,12 +5437,15 @@
mClientColorMatrix = mat4();
}
+ // TODO(b/193487656): Restore once HWASan bug is fixed.
+#if 0
// Check that supplied matrix's last row is {0,0,0,1} so we can avoid
// the division by w in the fragment shader
float4 lastRow(transpose(mClientColorMatrix)[3]);
if (any(greaterThan(abs(lastRow - float4{0, 0, 0, 1}), float4{1e-4f}))) {
ALOGE("The color transform's last row must be (0, 0, 0, 1)");
}
+#endif
updateColorMatrixLocked();
return NO_ERROR;
@@ -5545,8 +5499,7 @@
if (data.readInt32(&colorMode) == NO_ERROR) {
mForceColorMode = static_cast<ColorMode>(colorMode);
}
- invalidateHwcGeometry();
- repaintEverything();
+ scheduleRepaint();
return NO_ERROR;
}
// Deprecate, use 1030 to check whether the device is color managed.
@@ -5711,12 +5664,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
@@ -5778,8 +5729,7 @@
if (error != OK) {
return error;
}
- invalidateHwcGeometry();
- repaintEverything();
+ scheduleRepaint();
return NO_ERROR;
}
}
@@ -5787,17 +5737,6 @@
return err;
}
-void SurfaceFlinger::repaintEverything() {
- mRepaintEverything = true;
- signalTransaction();
-}
-
-void SurfaceFlinger::repaintEverythingForHWC() {
- mRepaintEverything = true;
- mPowerAdvisor.notifyDisplayUpdateImminent();
- mEventQueue->invalidate();
-}
-
void SurfaceFlinger::kernelTimerChanged(bool expired) {
static bool updateOverlay =
property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true);
@@ -6389,12 +6328,14 @@
// Use an empty fence for the buffer fence, since we just created the buffer so
// there is no need for synchronization with the GPU.
base::unique_fd bufferFence;
- base::unique_fd drawFence;
getRenderEngine().useProtectedContext(useProtected);
const constexpr bool kUseFramebufferCache = false;
- getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
- kUseFramebufferCache, std::move(bufferFence), &drawFence);
+ auto [status, drawFence] =
+ getRenderEngine()
+ .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
+ kUseFramebufferCache, std::move(bufferFence))
+ .get();
if (drawFence >= 0) {
sp<Fence> releaseFence = new Fence(dup(drawFence));
@@ -6407,10 +6348,10 @@
// Always switch back to unprotected context.
getRenderEngine().useProtectedContext(false);
- return NO_ERROR;
+ return status;
}
-void SurfaceFlinger::setInputWindowsFinished() {
+void SurfaceFlinger::windowInfosReported() {
Mutex::Autolock _l(mStateLock);
signalSynchronousTransactions(CountDownLatch::eSyncInputWindows);
}
@@ -6434,12 +6375,12 @@
// We loop through the first level of layers without traversing,
// as we need to determine which layers belong to the requested display.
for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (!layer->belongsToDisplay(layerStack)) {
+ if (layer->getLayerStack() != layerStack) {
continue;
}
// relative layers are traversed in Layer::traverseInZOrder
layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (layer->getPrimaryDisplayOnly()) {
+ if (layer->isInternalDisplayOverlay()) {
return;
}
if (!layer->isVisible()) {
@@ -6798,33 +6739,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();
- }
+uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const {
+ 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);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 00590dd..33bc17b 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;
@@ -286,8 +285,12 @@
template <typename F, typename T = std::invoke_result_t<F>>
[[nodiscard]] std::future<T> schedule(F&&);
- // force full composition on all displays
- void repaintEverything();
+ // Schedule commit of transactions on the main thread ahead of the next VSYNC.
+ void scheduleInvalidate(FrameHint);
+ // As above, but also force refresh regardless if transactions were committed.
+ void scheduleRefresh(FrameHint) override;
+ // As above, but also force dirty geometry to repaint.
+ void scheduleRepaint();
surfaceflinger::Factory& getFactory() { return mFactory; }
@@ -333,7 +336,7 @@
// 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
@@ -349,7 +352,6 @@
uint32_t permissions,
std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
REQUIRES(mStateLock);
- virtual void commitTransactionLocked();
// Used internally by computeLayerBounds() to gets the clip rectangle to use for the
// root layers on a particular display in layer-coordinate space. The
@@ -752,8 +754,6 @@
void setVsyncEnabled(bool) override;
// Initiates a refresh rate change to be applied on invalidate.
void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override;
- // Forces full composition on all displays without resetting the scheduler idle timer.
- void repaintEverythingForHWC() override;
// Called when kernel idle timer has expired. Used to update the refresh rate overlay.
void kernelTimerChanged(bool expired) override;
// Called when the frame rate override list changed to trigger an event.
@@ -772,8 +772,6 @@
* Message handling
*/
// Can only be called from the main thread or with mStateLock held
- void signalTransaction();
- // Can only be called from the main thread or with mStateLock held
void signalLayerUpdate();
void signalRefresh();
@@ -805,8 +803,12 @@
// incoming transactions
void onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime);
- // Returns whether the transaction actually modified any state
- bool handleMessageTransaction();
+ // Returns whether transactions were committed.
+ bool flushAndCommitTransactions() EXCLUDES(mStateLock);
+
+ void commitTransactions() EXCLUDES(mStateLock);
+ void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
+ void doCommitTransactions() REQUIRES(mStateLock);
// Handle the REFRESH message queue event, sending the current frame down to RenderEngine and
// the Composer HAL for presentation
@@ -815,11 +817,8 @@
// Returns whether a new buffer has been latched (see handlePageFlip())
bool handleMessageInvalidate();
- void handleTransaction(uint32_t transactionFlags);
- void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
-
void updateInputFlinger();
- void updateInputWindowInfo();
+ void notifyWindowInfos();
void commitInputWindowCommands() REQUIRES(mStateLock);
void updateCursorAsync();
@@ -849,18 +848,23 @@
void flushTransactionQueues();
// Returns true if there is at least one transaction that needs to be flushed
bool transactionFlushNeeded();
- uint32_t getTransactionFlags(uint32_t flags);
- uint32_t peekTransactionFlags();
- // Can only be called from the main thread or with mStateLock held
- uint32_t setTransactionFlags(uint32_t flags);
+
+ uint32_t getTransactionFlags() const;
+
+ // Sets the masked bits, and returns the old flags.
+ uint32_t setTransactionFlags(uint32_t mask);
+
+ // Clears and returns the masked bits.
+ uint32_t clearTransactionFlags(uint32_t mask);
+
// Indicate SF should call doTraversal on layers, but don't trigger a wakeup! We use this cases
// where there are still pending transactions but we know they won't be ready until a frame
// arrives from a different layer. So we need to ensure we performTransaction from invalidate
// 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, const sp<IBinder>& = {});
- void commitTransaction() REQUIRES(mStateLock);
+ uint32_t setTransactionFlags(uint32_t mask, TransactionSchedule,
+ const sp<IBinder>& applyToken = {});
void commitOffscreenLayers();
bool transactionIsReadyToBeApplied(
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
@@ -943,7 +947,7 @@
return width > mMaxRenderTargetSize || height > mMaxRenderTargetSize;
}
- int getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
+ uint32_t getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
/*
* Display and layer stack management
@@ -1034,8 +1038,6 @@
/*
* Compositing
*/
- void invalidateHwcGeometry();
-
void postComposition();
void getCompositorTiming(CompositorTiming* compositorTiming);
void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
@@ -1119,15 +1121,19 @@
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.
@@ -1206,8 +1212,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,7 +1254,8 @@
bool mLayersRemoved = false;
bool mLayersAdded = false;
- std::atomic<bool> mRepaintEverything = false;
+ std::atomic_bool mForceRefresh = false;
+ std::atomic_bool mGeometryDirty = false;
// constant members (no synchronization needed for access)
const nsecs_t mBootTime = systemTime();
@@ -1276,7 +1282,6 @@
bool mSomeDataspaceChanged = false;
bool mForceTransactionDisplayChange = false;
- bool mGeometryInvalid = false;
bool mAnimCompositionPending = false;
// Tracks layers that have pending frames which are candidates for being
@@ -1311,13 +1316,13 @@
std::optional<DisplayIdGenerator<HalVirtualDisplayId>> hal;
} mVirtualDisplayIdGenerators;
- // don't use a lock for these, we don't care
- int mDebugRegion = 0;
- bool mDebugDisableHWC = false;
- bool mDebugDisableTransformHint = false;
+ std::atomic_uint mDebugFlashDelay = 0;
+ std::atomic_bool mDebugDisableHWC = false;
+ std::atomic_bool mDebugDisableTransformHint = false;
+ std::atomic<nsecs_t> mDebugInTransaction = 0;
+ std::atomic_bool mForceFullDamage = false;
+
bool mLayerCachingEnabled = false;
- volatile nsecs_t mDebugInTransaction = 0;
- bool mForceFullDamage = false;
bool mPropagateBackpressureClientComposition = false;
sp<SurfaceInterceptor> mInterceptor;
@@ -1443,8 +1448,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.
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 9be3abe..0782fef 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -323,11 +323,10 @@
}
void SurfaceInterceptor::addLayerStackLocked(Transaction* transaction, int32_t layerId,
- uint32_t layerStack)
-{
+ ui::LayerStack layerStack) {
SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
LayerStackChange* layerStackChange(change->mutable_layer_stack());
- layerStackChange->set_layer_stack(layerStack);
+ layerStackChange->set_layer_stack(layerStack.id);
}
void SurfaceInterceptor::addCropLocked(Transaction* transaction, int32_t layerId,
@@ -568,12 +567,11 @@
}
}
-void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction,
- int32_t sequenceId, uint32_t layerStack)
-{
+void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId,
+ ui::LayerStack layerStack) {
DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
LayerStackChange* layerStackChange(dispChange->mutable_layer_stack());
- layerStackChange->set_layer_stack(layerStack);
+ layerStackChange->set_layer_stack(layerStack.id);
}
void SurfaceInterceptor::addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId,
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 7b331b9..970c3e5 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -160,7 +160,7 @@
void addTransparentRegionLocked(Transaction* transaction, int32_t layerId,
const Region& transRegion);
void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags, uint8_t mask);
- void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack);
+ void addLayerStackLocked(Transaction* transaction, int32_t layerId, ui::LayerStack);
void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
@@ -183,8 +183,7 @@
DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId);
void addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId,
const sp<const IGraphicBufferProducer>& surface);
- void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId,
- uint32_t layerStack);
+ void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, ui::LayerStack);
void addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, uint32_t flags);
void addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w,
uint32_t h);
diff --git a/services/surfaceflinger/TimeStats/OWNERS b/services/surfaceflinger/TimeStats/OWNERS
index ded3ebb..d78f5e2 100644
--- a/services/surfaceflinger/TimeStats/OWNERS
+++ b/services/surfaceflinger/TimeStats/OWNERS
@@ -1 +1,2 @@
+adyabr@google.com
alecmouri@google.com
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 55136fb..dc2aa58 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -17,12 +17,32 @@
#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);
@@ -46,7 +66,8 @@
mWindowInfosListeners.erase(who);
}
-void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos) {
+void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
+ bool shouldSync) {
std::unordered_set<sp<IWindowInfosListener>, ISurfaceComposer::SpHash<IWindowInfosListener>>
windowInfosListeners;
@@ -57,8 +78,18 @@
}
}
+ mCallbacksPending = windowInfosListeners.size();
+
for (const auto& listener : windowInfosListeners) {
- listener->onWindowInfosChanged(windowInfos);
+ listener->onWindowInfosChanged(windowInfos,
+ shouldSync ? mWindowInfosReportedListener : nullptr);
+ }
+}
+
+void WindowInfosListenerInvoker::windowInfosReported() {
+ mCallbacksPending--;
+ if (mCallbacksPending == 0) {
+ mSf->windowInfosReported();
}
}
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index b979de1..5e5796f 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -16,32 +16,42 @@
#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);
+ 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/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index dddc677..9f4e7d2 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -130,6 +130,9 @@
repeated BlurRegion blur_regions = 54;
bool is_trusted_overlay = 55;
+
+ // Corner radius explicitly set on layer rather than inherited
+ float requested_corner_radius = 56;
}
message PositionProto {
@@ -228,4 +231,4 @@
int32 top = 8;
int32 right = 9;
int32 bottom = 10;
-}
\ No newline at end of file
+}
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/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index fa3f0e7..d33bc10 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -93,7 +93,7 @@
ASSERT_TRUE(mBGSurfaceControl->isValid());
Transaction t;
- t.setDisplayLayerStack(mDisplay, 0);
+ t.setDisplayLayerStack(mDisplay, ui::DEFAULT_LAYER_STACK);
ASSERT_EQ(NO_ERROR,
t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply());
}
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
index af00ec7..1361ded 100644
--- a/services/surfaceflinger/tests/EffectLayer_test.cpp
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -33,7 +33,7 @@
mParentLayer = createColorLayer("Parent layer", Color::RED);
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
});
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index 9fa3d4c..8d7e175 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -159,7 +159,7 @@
{0, 0, static_cast<int32_t>(width),
static_cast<int32_t>(height)},
Color::RED);
- transaction->setLayerStack(mSurfaceControl, 0)
+ transaction->setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
.setBuffer(mSurfaceControl, gb)
.setAcquireFence(mSurfaceControl, fence)
@@ -232,7 +232,7 @@
mDisplayHeight = mode.resolution.getHeight();
Transaction setupTransaction;
- setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0);
+ setupTransaction.setDisplayLayerStack(mPrimaryDisplay, ui::DEFAULT_LAYER_STACK);
setupTransaction.apply();
}
@@ -310,7 +310,7 @@
Color::RED);
Transaction transaction;
- transaction.setLayerStack(sc, 0)
+ transaction.setLayerStack(sc, ui::DEFAULT_LAYER_STACK)
.setLayer(sc, std::numeric_limits<int32_t>::max() - 1)
.setBuffer(sc, gb)
.setAcquireFence(sc, fence)
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 0bc8fe7..6bd7920 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -266,7 +266,7 @@
sp<IBinder> mDisplay;
uint32_t mDisplayWidth;
uint32_t mDisplayHeight;
- uint32_t mDisplayLayerStack;
+ ui::LayerStack mDisplayLayerStack = ui::DEFAULT_LAYER_STACK;
Rect mDisplayRect = Rect::INVALID_RECT;
// leave room for ~256 layers
@@ -294,8 +294,6 @@
// vsyncs.
mBufferPostDelay = static_cast<int32_t>(1e6 / mode.refreshRate) * 3;
- mDisplayLayerStack = 0;
-
mBlackBgSurface =
createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 43d957c..4076253 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -643,7 +643,8 @@
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
- Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
+ const auto layerStack = ui::LayerStack::fromValue(mDisplayLayerStack.id + 1);
+ Transaction().setLayerStack(layer, layerStack).apply();
{
SCOPED_TRACE("non-existing layer stack");
getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index ee4d367..e1a7ecc 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -63,7 +63,7 @@
TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index d027865..3ec6da9 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -36,7 +36,7 @@
mParentLayer = createColorLayer("Parent layer", Color::RED);
mChildLayer = createColorLayer("Child layer", Color::GREEN, mParentLayer.get());
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
t.setCrop(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer);
t.setPosition(mChildLayer, 50, 50);
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index 08de01c..1ed6c65 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -52,7 +52,7 @@
mColorLayer = 0;
}
- void createDisplay(const ui::Size& layerStackSize, uint32_t layerStack) {
+ void createDisplay(const ui::Size& layerStackSize, ui::LayerStack layerStack) {
mVirtualDisplay =
SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
asTransaction([&](Transaction& t) {
@@ -63,7 +63,7 @@
});
}
- void createColorLayer(uint32_t layerStack) {
+ void createColorLayer(ui::LayerStack layerStack) {
mColorLayer =
createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
@@ -90,8 +90,9 @@
};
TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
- createDisplay(mMainDisplayState.layerStackSpaceRect, 1 /* layerStack */);
- createColorLayer(1 /* layerStack */);
+ constexpr ui::LayerStack kLayerStack{1u};
+ createDisplay(mMainDisplayState.layerStackSpaceRect, kLayerStack);
+ createColorLayer(kLayerStack);
asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
@@ -113,8 +114,8 @@
// Assumption here is that the new mirrored display has the same layer stack rect as the
// primary display that it is mirroring.
- createDisplay(mMainDisplayState.layerStackSpaceRect, 0 /* layerStack */);
- createColorLayer(0 /* layerStack */);
+ createDisplay(mMainDisplayState.layerStackSpaceRect, ui::DEFAULT_LAYER_STACK);
+ createColorLayer(ui::DEFAULT_LAYER_STACK);
asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
index fde6e6e..50a4092 100644
--- a/services/surfaceflinger/tests/RelativeZ_test.cpp
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -43,7 +43,7 @@
mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN);
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer);
t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer);
});
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 579a26e..c4d42fa 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -99,10 +99,10 @@
}
static void waitForReleaseBufferCallback(ReleaseBufferCallbackHelper& releaseCallback,
- const ReleaseCallbackId& expectedCallbackId) {
+ const ReleaseCallbackId& expectedReleaseBufferId) {
ReleaseCallbackId actualReleaseBufferId;
releaseCallback.getCallbackData(&actualReleaseBufferId);
- EXPECT_EQ(expectedCallbackId, actualReleaseBufferId);
+ EXPECT_EQ(expectedReleaseBufferId, actualReleaseBufferId);
releaseCallback.verifyNoCallbacks();
}
static ReleaseBufferCallbackHelper* getReleaseBufferCallbackHelper() {
@@ -333,4 +333,60 @@
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
+TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) {
+ sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
+ sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+
+ CallbackHelper callback1, callback2;
+
+ TransactionCompletedListener::setInstance(firstCompletedListener);
+
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Send initial buffer for the layer
+ submitBuffer(layer, firstBuffer, Fence::NO_FENCE, callback1, firstBufferCallbackId,
+ *releaseCallback);
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+
+ // Sent a second buffer to allow the first buffer to get released.
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+ Transaction transaction1;
+ transaction1.setFrameNumber(layer, secondBufferCallbackId.framenumber);
+ transaction1.setBuffer(layer, secondBuffer, secondBufferCallbackId,
+ releaseCallback->getCallback());
+ transaction1.setAcquireFence(layer, Fence::NO_FENCE);
+ transaction1.addTransactionCompletedCallback(callback1.function, callback1.getContext());
+
+ // Set a different TransactionCompletedListener to mimic a second process
+ TransactionCompletedListener::setInstance(secondCompletedListener);
+
+ // Make sure the second "process" has a callback set up.
+ Transaction transaction2;
+ transaction2.addTransactionCompletedCallback(callback2.function, callback2.getContext());
+
+ // This merging order, merge transaction1 first then transaction2, seems to ensure the listener
+ // for transaction2 is ordered first. This makes sure the wrong process is added first to the
+ // layer's vector of listeners. With the bug, only the secondCompletedListener will get the
+ // release callback id, since it's ordered first. Then firstCompletedListener would fail to get
+ // the release callback id and not invoke the release callback.
+ Transaction().merge(std::move(transaction1)).merge(std::move(transaction2)).apply();
+
+ expected = ExpectedResult();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index ab2064e..95301b3 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -53,7 +53,7 @@
TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
@@ -563,7 +563,7 @@
Transaction()
.show(redLayer)
.show(secureLayer)
- .setLayerStack(redLayer, 0)
+ .setLayerStack(redLayer, ui::DEFAULT_LAYER_STACK)
.setLayer(redLayer, INT32_MAX)
.apply();
@@ -655,7 +655,7 @@
Transaction()
.show(layer)
.hide(mFGSurfaceControl)
- .setLayerStack(layer, 0)
+ .setLayerStack(layer, ui::DEFAULT_LAYER_STACK)
.setLayer(layer, INT32_MAX)
.setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255})
.setCrop(layer, bounds)
@@ -702,7 +702,7 @@
.show(layer)
.show(childLayer)
.hide(mFGSurfaceControl)
- .setLayerStack(layer, 0)
+ .setLayerStack(layer, ui::DEFAULT_LAYER_STACK)
.setLayer(layer, INT32_MAX)
.setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255})
.setColor(childLayer, {childColor.r / 255, childColor.g / 255, childColor.b / 255})
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index a424059..ee16f40 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -283,7 +283,7 @@
ASSERT_TRUE(mFGSurfaceControl->isValid());
Transaction t;
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ASSERT_EQ(NO_ERROR,
t.setLayer(mBGSurfaceControl, INT_MAX - 3)
.show(mBGSurfaceControl)
@@ -380,7 +380,7 @@
}
void SurfaceInterceptorTest::layerStackUpdate(Transaction& t) {
- t.setLayerStack(mBGSurfaceControl, STACK_UPDATE);
+ t.setLayerStack(mBGSurfaceControl, ui::LayerStack::fromValue(STACK_UPDATE));
}
void SurfaceInterceptorTest::hiddenFlagUpdate(Transaction& t) {
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 89f6086..60cffb1 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -65,7 +65,7 @@
SurfaceComposerClient::Transaction t;
t.setDisplaySurface(vDisplay, producer);
- t.setDisplayLayerStack(vDisplay, 0);
+ t.setDisplayLayerStack(vDisplay, ui::DEFAULT_LAYER_STACK);
t.setDisplayProjection(vDisplay, displayState.orientation,
Rect(displayState.layerStackSpaceRect), Rect(resolution));
t.apply();
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
new file mode 100644
index 0000000..de116f2
--- /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, ui::DEFAULT_LAYER_STACK)
+ .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, ui::DEFAULT_LAYER_STACK)
+ .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/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index a9e935d..b3b4ec1 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -363,7 +363,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -426,7 +426,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -479,7 +479,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -534,7 +534,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -586,7 +586,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -651,7 +651,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -703,7 +703,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -750,7 +750,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -797,7 +797,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -1195,7 +1195,7 @@
fillSurfaceRGBA8(mFGSurfaceControl, RED);
Transaction t;
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
t.show(mBGSurfaceControl);
@@ -1342,7 +1342,7 @@
ALOGD("TransactionTest::SetLayerStack");
{
TransactionScope ts(*sFakeComposer);
- ts.setLayerStack(mFGSurfaceControl, 1);
+ ts.setLayerStack(mFGSurfaceControl, ui::LayerStack{1});
}
// Foreground layer should have disappeared.
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 8bd6e62..078b0d4 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -57,6 +57,7 @@
"DisplayDevice_InitiateModeChange.cpp",
"DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
+ "FlagManagerTest.cpp",
"FpsReporterTest.cpp",
"FpsTest.cpp",
"FramebufferSurfaceTest.cpp",
@@ -70,10 +71,10 @@
"MessageQueueTest.cpp",
"SurfaceFlinger_CreateDisplayTest.cpp",
"SurfaceFlinger_DestroyDisplayTest.cpp",
+ "SurfaceFlinger_DisplayTransactionCommitTest.cpp",
"SurfaceFlinger_GetDisplayNativePrimariesTest.cpp",
- "SurfaceFlinger_HandleTransactionLockedTest.cpp",
- "SurfaceFlinger_NotifyPowerBoostTest.cpp",
"SurfaceFlinger_HotplugTest.cpp",
+ "SurfaceFlinger_NotifyPowerBoostTest.cpp",
"SurfaceFlinger_OnInitializeDisplaysTest.cpp",
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
@@ -164,6 +165,7 @@
"libsync",
"libui",
"libutils",
+ "server_configurable_flags",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
index 6a7ec9b..6f85498 100644
--- a/services/surfaceflinger/tests/unittests/CachingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -14,11 +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"
-#pragma clang diagnostic ignored "-Wextra"
-
#undef LOG_TAG
#define LOG_TAG "CachingTest"
@@ -42,7 +37,7 @@
sp<IBinder> binder = new BBinder();
// test getting invalid client_cache_id
client_cache_t id;
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(id);
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
EXPECT_EQ(BufferQueue::INVALID_BUFFER_SLOT, slot);
}
@@ -51,7 +46,7 @@
client_cache_t id;
id.token = binder;
id.id = 0;
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(id);
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 1, slot);
client_cache_t idB;
@@ -72,31 +67,28 @@
std::vector<client_cache_t> ids;
uint32_t cacheId = 0;
// fill up cache
- for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
client_cache_t id;
id.token = binder;
id.id = cacheId;
ids.push_back(id);
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(id);
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot);
cacheId++;
}
- for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(ids[i]);
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(ids[static_cast<uint32_t>(i)]);
EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot);
}
- for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
client_cache_t id;
id.token = binder;
id.id = cacheId;
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(id);
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot);
cacheId++;
}
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 98c1889..5135ff9 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -82,7 +82,7 @@
constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
constexpr int DEFAULT_TEXTURE_ID = 6000;
-constexpr int DEFAULT_LAYER_STACK = 7000;
+constexpr ui::LayerStack LAYER_STACK{7000u};
constexpr int DEFAULT_DISPLAY_MAX_LUMINANCE = 500;
@@ -157,7 +157,7 @@
// pain)
// mFlinger.mutableVisibleRegionsDirty() = true;
- mFlinger.mutableGeometryInvalid() = true;
+ mFlinger.mutableGeometryDirty() = true;
}
template <typename Case>
@@ -255,6 +255,14 @@
LayerCase::cleanup(this);
}
+template <class T>
+std::future<T> futureOf(T obj) {
+ std::promise<T> resultPromise;
+ std::future<T> resultFuture = resultPromise.get_future();
+ resultPromise.set_value(std::move(obj));
+ return resultFuture;
+}
+
/* ------------------------------------------------------------------------
* Variants for each display configuration which can be tested
*/
@@ -287,10 +295,8 @@
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::Internal)
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setIsSecure(Derived::IS_SECURE)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
test_info->test_case_name() + "." + test_info->name())
@@ -309,7 +315,7 @@
.setPowerMode(Derived::INIT_POWER_MODE)
.inject();
Mock::VerifyAndClear(test->mNativeWindow);
- test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
+ test->mDisplay->setLayerStack(LAYER_STACK);
}
template <typename Case>
@@ -339,16 +345,18 @@
template <typename Case>
static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>&,
- const std::shared_ptr<renderengine::ExternalTexture>&,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&,
+ const bool, base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.clip);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
});
}
@@ -388,17 +396,19 @@
.WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1),
Return(0)));
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>&,
- const std::shared_ptr<renderengine::ExternalTexture>&,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&,
+ const bool, base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.clip);
EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
});
}
@@ -622,10 +632,10 @@
static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layerSettings,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -633,11 +643,14 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so gtet the back layer.
+ std::future<renderengine::RenderEngineResult> resultFuture =
+ futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
if (layerSettings.empty()) {
ADD_FAILURE() << "layerSettings was not expected to be empty in "
"setupREBufferCompositionCommonCallExpectations "
"verification lambda";
- return NO_ERROR;
+ return resultFuture;
}
const renderengine::LayerSettings* layer = layerSettings.back();
EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull()));
@@ -649,7 +662,7 @@
EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
- return NO_ERROR;
+ return resultFuture;
});
}
@@ -671,10 +684,10 @@
static void setupREColorCompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layerSettings,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -682,11 +695,14 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
+ std::future<renderengine::RenderEngineResult> resultFuture =
+ futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
if (layerSettings.empty()) {
ADD_FAILURE()
<< "layerSettings was not expected to be empty in "
"setupREColorCompositionCallExpectations verification lambda";
- return NO_ERROR;
+ return resultFuture;
}
const renderengine::LayerSettings* layer = layerSettings.back();
EXPECT_THAT(layer->source.buffer.buffer, IsNull());
@@ -696,7 +712,7 @@
EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
- return NO_ERROR;
+ return resultFuture;
});
}
@@ -748,10 +764,10 @@
static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layerSettings,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -759,11 +775,14 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
+ std::future<renderengine::RenderEngineResult> resultFuture =
+ futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
if (layerSettings.empty()) {
ADD_FAILURE() << "layerSettings was not expected to be empty in "
"setupInsecureREBufferCompositionCommonCallExpectations "
"verification lambda";
- return NO_ERROR;
+ return resultFuture;
}
const renderengine::LayerSettings* layer = layerSettings.back();
EXPECT_THAT(layer->source.buffer.buffer, IsNull());
@@ -771,7 +790,7 @@
EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
EXPECT_EQ(1.0f, layer->alpha);
- return NO_ERROR;
+ return resultFuture;
});
}
@@ -834,7 +853,7 @@
template <typename L>
static void initLayerDrawingStateAndComputeBounds(CompositionTest* test, sp<L> layer) {
auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
- layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
+ layerDrawingState.layerStack = LAYER_STACK;
layerDrawingState.width = 100;
layerDrawingState.height = 100;
layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 60b0f53..5a21e7b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -139,20 +139,18 @@
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber());
- constexpr auto kConnectionType = ui::DisplayConnectionType::Internal;
- constexpr bool kIsPrimary = true;
-
auto compositionDisplay =
compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
compositionengine::DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(kConnectionType)
.setPixels({DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT})
.setPowerAdvisor(&mPowerAdvisor)
.build());
- auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, kConnectionType,
+ constexpr bool kIsPrimary = true;
+ auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+ ui::DisplayConnectionType::Internal,
DEFAULT_DISPLAY_HWC_DISPLAY_ID, kIsPrimary);
injector.setNativeWindow(mNativeWindow);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index de058a4..0f1cc67 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -267,11 +267,6 @@
.setPixels({WIDTH, HEIGHT})
.setPowerAdvisor(&test->mPowerAdvisor);
- const auto connectionType = CONNECTION_TYPE::value;
- if (connectionType) {
- ceDisplayArgs.setConnectionType(*connectionType);
- }
-
auto compositionDisplay =
compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
ceDisplayArgs.build());
@@ -279,7 +274,7 @@
auto injector =
TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger,
compositionDisplay,
- connectionType,
+ CONNECTION_TYPE::value,
HWC_DISPLAY_ID_OPT::value,
static_cast<bool>(PRIMARY));
@@ -388,7 +383,6 @@
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(DisplayVariant::DISPLAY_ID::get())
- .setConnectionType(PhysicalDisplay::CONNECTION_TYPE)
.setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT})
.setIsSecure(static_cast<bool>(DisplayVariant::SECURE))
.setPowerAdvisor(&test->mPowerAdvisor)
diff --git a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp
new file mode 100644
index 0000000..0905cd1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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 <cstdint>
+#undef LOG_TAG
+#define LOG_TAG "FlagManagerTest"
+
+#include "FlagManager.h"
+
+#include <android-base/properties.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <server_configurable_flags/get_flags.h>
+#include <optional>
+
+namespace android {
+
+using testing::Return;
+
+class MockFlagManager : public FlagManager {
+public:
+ MockFlagManager() = default;
+ ~MockFlagManager() = default;
+
+ MOCK_METHOD(std::string, getServerConfigurableFlag, (const std::string& experimentFlagName),
+ (const, override));
+};
+
+class FlagManagerTest : public testing::Test {
+public:
+ FlagManagerTest();
+ ~FlagManagerTest() override;
+ std::unique_ptr<MockFlagManager> mFlagManager;
+
+ template <typename T>
+ T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt,
+ T defaultValue);
+};
+
+FlagManagerTest::FlagManagerTest() {
+ 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());
+ mFlagManager = std::make_unique<MockFlagManager>();
+}
+
+FlagManagerTest::~FlagManagerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+template <typename T>
+T FlagManagerTest::getValue(const std::string& experimentFlagName,
+ std::optional<T> systemPropertyOpt, T defaultValue) {
+ return mFlagManager->getValue(experimentFlagName, systemPropertyOpt, defaultValue);
+}
+
+namespace {
+TEST_F(FlagManagerTest, getValue_bool_default) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return(""));
+ const bool defaultValue = false;
+ std::optional<bool> systemPropertyValue = std::nullopt;
+ const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, defaultValue);
+}
+
+TEST_F(FlagManagerTest, getValue_bool_sysprop) {
+ const bool defaultValue = false;
+ std::optional<bool> systemPropertyValue = std::make_optional(true);
+ const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, true);
+}
+
+TEST_F(FlagManagerTest, getValue_bool_experiment) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("1"));
+ const bool defaultValue = false;
+ std::optional<bool> systemPropertyValue = std::nullopt;
+ const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, true);
+}
+
+TEST_F(FlagManagerTest, getValue_int32_default) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return(""));
+ int32_t defaultValue = 30;
+ std::optional<int32_t> systemPropertyValue = std::nullopt;
+ int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, defaultValue);
+}
+
+TEST_F(FlagManagerTest, getValue_int32_sysprop) {
+ int32_t defaultValue = 30;
+ std::optional<int32_t> systemPropertyValue = std::make_optional(10);
+ int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, 10);
+}
+
+TEST_F(FlagManagerTest, getValue_int32_experiment) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("50"));
+ std::int32_t defaultValue = 30;
+ std::optional<std::int32_t> systemPropertyValue = std::nullopt;
+ std::int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, 50);
+}
+
+TEST_F(FlagManagerTest, getValue_int64_default) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return(""));
+ int64_t defaultValue = 30;
+ std::optional<int64_t> systemPropertyValue = std::nullopt;
+ int64_t result = getValue("flag_name", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, defaultValue);
+}
+
+TEST_F(FlagManagerTest, getValue_int64_sysprop) {
+ int64_t defaultValue = 30;
+ std::optional<int64_t> systemPropertyValue = std::make_optional(10);
+ int64_t result = getValue("flag_name", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, 10);
+}
+
+TEST_F(FlagManagerTest, getValue_int64_experiment) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("50"));
+ int64_t defaultValue = 30;
+ std::optional<int64_t> systemPropertyValue = std::nullopt;
+ int64_t result = getValue("flag_name", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, 50);
+}
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index c04919f..a6bfde7 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -98,9 +98,15 @@
static inline const DisplayModeId HWC_CONFIG_ID_30 = DisplayModeId(4);
static inline const DisplayModeId HWC_CONFIG_ID_25 = DisplayModeId(5);
static inline const DisplayModeId HWC_CONFIG_ID_50 = DisplayModeId(6);
+ static inline const DisplayModeId HWC_CONFIG_ID_24 = DisplayModeId(7);
+ static inline const DisplayModeId HWC_CONFIG_ID_24_FRAC = DisplayModeId(8);
+ static inline const DisplayModeId HWC_CONFIG_ID_30_FRAC = DisplayModeId(9);
+ static inline const DisplayModeId HWC_CONFIG_ID_60_FRAC = DisplayModeId(10);
// Test configs
DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
+ DisplayModePtr mConfig60Frac =
+ createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, Fps(59.94f).getPeriodNsecs());
DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
DisplayModePtr mConfig90DifferentGroup =
createDisplayMode(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
@@ -116,9 +122,15 @@
DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
DisplayModePtr mConfig30DifferentGroup =
createDisplayMode(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
+ DisplayModePtr mConfig30Frac =
+ createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, Fps(29.97f).getPeriodNsecs());
+ DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, Fps(25.0f).getPeriodNsecs());
DisplayModePtr mConfig25DifferentGroup =
createDisplayMode(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
+ DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, Fps(24.0f).getPeriodNsecs());
+ DisplayModePtr mConfig24Frac =
+ createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, Fps(23.976f).getPeriodNsecs());
// Test device configurations
// The positions of the configs in the arrays below MUST match their IDs. For example,
@@ -145,6 +157,11 @@
mConfig50};
DisplayModes m60_120Device = {mConfig60, mConfig120};
+ // This is a typical TV configuration.
+ DisplayModes m24_25_30_50_60WithFracDevice = {mConfig24, mConfig24Frac, mConfig25,
+ mConfig30, mConfig30Frac, mConfig50,
+ mConfig60, mConfig60Frac};
+
// Expected RefreshRate objects
RefreshRate mExpected60Config = {mConfig60, RefreshRate::ConstructorTag(0)};
RefreshRate mExpectedAlmost60Config = {createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665),
@@ -1230,7 +1247,109 @@
const auto& refreshRate =
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
EXPECT_TRUE(refreshRate.getFps().equalsWithMargin(Fps(test.second)))
- << "Expecting " << test.first << "fps => " << test.second << "Hz";
+ << "Expecting " << test.first << "fps => " << test.second << "Hz"
+ << " but it was " << refreshRate.getFps();
+ }
+}
+
+TEST_F(RefreshRateConfigsTest,
+ getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) {
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ // Test that 23.976 will choose 24 if 23.976 is not supported
+ {
+ android::DisplayModes modes = {mConfig24, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr.desiredRefreshRate = Fps(23.976f);
+ lr.name = "ExplicitExactOrMultiple 23.976 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+
+ // Test that 24 will choose 23.976 if 24 is not supported
+ {
+ android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.desiredRefreshRate = Fps(24.f);
+ lr.name = "ExplicitExactOrMultiple 24 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+
+ // Test that 29.97 will prefer 59.94 over 60 and 30
+ {
+ android::DisplayModes modes = {mConfig24, mConfig24Frac, mConfig25,
+ mConfig30, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.desiredRefreshRate = Fps(29.97f);
+ lr.name = "ExplicitExactOrMultiple 29.97f fps";
+ EXPECT_EQ(HWC_CONFIG_ID_60_FRAC,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) {
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ // Test that voting for supported refresh rate will select this refresh rate
+ {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ for (auto desiredRefreshRate : {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f}) {
+ lr.vote = LayerVoteType::ExplicitExact;
+ lr.desiredRefreshRate = Fps(desiredRefreshRate);
+ std::stringstream ss;
+ ss << "ExplicitExact " << desiredRefreshRate << " fps";
+ lr.name = ss.str();
+
+ auto selecteRefreshRate =
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+
+ EXPECT_TRUE(selecteRefreshRate.getFps().equalsWithMargin(lr.desiredRefreshRate))
+ << "Expecting " << lr.desiredRefreshRate << " but it was "
+ << selecteRefreshRate.getFps();
+ }
+ }
+
+ // Test that 23.976 will choose 24 if 23.976 is not supported
+ {
+ android::DisplayModes modes = {mConfig24, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.vote = LayerVoteType::ExplicitExact;
+ lr.desiredRefreshRate = Fps(23.976f);
+ lr.name = "ExplicitExact 23.976 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+
+ // Test that 24 will choose 23.976 if 24 is not supported
+ {
+ android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.desiredRefreshRate = Fps(24.f);
+ lr.name = "ExplicitExact 24 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
}
}
@@ -2028,6 +2147,29 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
}
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) {
+ RefreshRateConfigs::Config config = {.enableFrameRateOverride = true};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
+ /*currentConfigId=*/HWC_CONFIG_ID_60, config);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 0.5f},
+ LayerRequirement{.weight = 0.5f}};
+ auto& explicitDefaultLayer = layers[0];
+ auto& explicitExactOrMultipleLayer = layers[1];
+
+ explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
+ explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
+ explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+
+ explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault;
+ explicitDefaultLayer.name = "ExplicitDefault";
+ explicitDefaultLayer.desiredRefreshRate = Fps(59.94f);
+
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
EXPECT_TRUE(mExpected60Config < mExpected90Config);
EXPECT_FALSE(mExpected60Config < mExpected60Config);
@@ -2116,7 +2258,38 @@
refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, Fps(22.5f)));
- EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, Fps(22.6f)));
+
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(25.f)));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(23.976f)));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(30.f), Fps(29.97f)));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(60.f), Fps(59.94f)));
+}
+
+TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) {
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.976f), Fps(24.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(23.976f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(30.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(29.97f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(60.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(59.94f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(60.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(29.97f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(30.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(59.94f)));
+
+ const std::vector<float> refreshRates = {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f};
+ for (auto refreshRate : refreshRates) {
+ EXPECT_FALSE(
+ RefreshRateConfigs::isFractionalPairOrMultiple(Fps(refreshRate), Fps(refreshRate)));
+ }
+
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(25.f)));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.978f), Fps(25.f)));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(59.94f)));
}
TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) {
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_DisplayTransactionCommitTest.cpp
similarity index 74%
rename from services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
rename to services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
index b713334..6959ee3 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
@@ -22,8 +22,7 @@
namespace android {
namespace {
-class HandleTransactionLockedTest : public DisplayTransactionTest {
-public:
+struct DisplayTransactionCommitTest : DisplayTransactionTest {
template <typename Case>
void setupCommonPreconditions();
@@ -55,7 +54,7 @@
};
template <typename Case>
-void HandleTransactionLockedTest::setupCommonPreconditions() {
+void DisplayTransactionCommitTest::setupCommonPreconditions() {
// Wide color displays support is configured appropriately
Case::WideColorSupport::injectConfigChange(this);
@@ -68,7 +67,7 @@
}
template <typename Case, bool connected>
-void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
+void DisplayTransactionCommitTest::expectHotplugReceived(mock::EventThread* eventThread) {
const auto convert = [](auto physicalDisplayId) {
return std::make_optional(DisplayId{physicalDisplayId});
};
@@ -79,7 +78,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
+void DisplayTransactionCommitTest::setupCommonCallExpectationsForConnectProcessing() {
Case::Display::setupHwcHotplugCallExpectations(this);
Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
@@ -97,7 +96,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
+void DisplayTransactionCommitTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
expectHotplugReceived<Case, false>(mEventThread);
@@ -105,7 +104,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
+void DisplayTransactionCommitTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
// The display device should have been set up in the list of displays.
ASSERT_TRUE(hasDisplayDevice(displayToken));
const auto& device = getDisplayDevice(displayToken);
@@ -137,7 +136,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
+void DisplayTransactionCommitTest::verifyPhysicalDisplayIsConnected() {
// HWComposer should have an entry for the display
EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
@@ -150,14 +149,14 @@
verifyDisplayIsConnected<Case>(displayToken);
}
-void HandleTransactionLockedTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
+void DisplayTransactionCommitTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
EXPECT_FALSE(hasDisplayDevice(displayToken));
EXPECT_FALSE(hasCurrentDisplayState(displayToken));
EXPECT_FALSE(hasDrawingDisplayState(displayToken));
}
template <typename Case>
-void HandleTransactionLockedTest::processesHotplugConnectCommon() {
+void DisplayTransactionCommitTest::processesHotplugConnectCommon() {
// --------------------------------------------------------------------
// Preconditions
@@ -174,7 +173,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -191,7 +190,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::ignoresHotplugConnectCommon() {
+void DisplayTransactionCommitTest::ignoresHotplugConnectCommon() {
// --------------------------------------------------------------------
// Preconditions
@@ -203,7 +202,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -213,7 +212,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::processesHotplugDisconnectCommon() {
+void DisplayTransactionCommitTest::processesHotplugDisconnectCommon() {
// --------------------------------------------------------------------
// Preconditions
@@ -238,7 +237,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -255,18 +254,18 @@
verifyDisplayIsNotConnected(existing.token());
}
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectPrimaryDisplay) {
+TEST_F(DisplayTransactionCommitTest, processesHotplugConnectPrimaryDisplay) {
processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
+TEST_F(DisplayTransactionCommitTest, processesHotplugConnectExternalDisplay) {
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
processesHotplugConnectCommon<SimpleExternalDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
+TEST_F(DisplayTransactionCommitTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
// Inject both a primary and external display.
PrimaryDisplayVariant::injectHwcDisplay(this);
ExternalDisplayVariant::injectHwcDisplay(this);
@@ -281,108 +280,119 @@
ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
- processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
+TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectPrimaryDisplay) {
+ EXPECT_EXIT(processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>(),
+ testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
+TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectExternalDisplay) {
processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) {
- using Case = SimplePrimaryDisplayCase;
+TEST_F(DisplayTransactionCommitTest, processesHotplugConnectThenDisconnectPrimary) {
+ 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.commitTransactionsLocked(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;
+TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectThenConnectPrimary) {
+ 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.commitTransactionsLocked(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) {
+TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayAdded) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
@@ -433,7 +443,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -453,7 +463,7 @@
mFlinger.mutableDrawingState().displays.removeItem(displayToken);
}
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
+TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayAddedWithNoSurface) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
@@ -479,7 +489,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -493,7 +503,7 @@
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
}
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
+TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayRemoval) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
@@ -511,7 +521,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -520,11 +530,11 @@
verifyDisplayIsNotConnected(existing.token());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayLayerStackChanges) {
using Case = NonHwcVirtualDisplayCase;
- constexpr uint32_t oldLayerStack = 0u;
- constexpr uint32_t newLayerStack = 123u;
+ constexpr ui::LayerStack oldLayerStack = ui::DEFAULT_LAYER_STACK;
+ constexpr ui::LayerStack newLayerStack{123u};
// --------------------------------------------------------------------
// Preconditions
@@ -540,7 +550,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -548,7 +558,7 @@
EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayTransformChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr ui::Rotation oldTransform = ui::ROTATION_0;
@@ -568,7 +578,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -576,7 +586,7 @@
EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayLayerStackRectChanges) {
using Case = NonHwcVirtualDisplayCase;
const Rect oldLayerStackRect(0, 0, 0, 0);
@@ -596,7 +606,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -604,7 +614,7 @@
EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayRectChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayRectChanges) {
using Case = NonHwcVirtualDisplayCase;
const Rect oldDisplayRect(0, 0);
@@ -624,7 +634,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -632,7 +642,7 @@
EXPECT_EQ(newDisplayRect, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayWidthChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr int oldWidth = 0;
@@ -674,10 +684,10 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
}
-TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayHeightChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr int oldWidth = 0;
@@ -719,10 +729,10 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
}
-TEST_F(HandleTransactionLockedTest, processesDisplaySizeDisplayRectAndLayerStackRectChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplaySizeDisplayRectAndLayerStackRectChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr uint32_t kOldWidth = 567;
@@ -769,7 +779,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
EXPECT_EQ(display.mutableDisplayDevice()->getBounds(), kNewSize);
EXPECT_EQ(display.mutableDisplayDevice()->getWidth(), kNewWidth);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index ef8b149..bafa910 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -63,15 +63,11 @@
// The primary display should have a current state
ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token()));
const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token());
- // The layer stack state should be set to zero
- EXPECT_EQ(0u, primaryDisplayState.layerStack);
- // The orientation state should be set to zero
+
+ // The primary display state should be reset
+ EXPECT_EQ(ui::DEFAULT_LAYER_STACK, primaryDisplayState.layerStack);
EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
-
- // The orientedDisplaySpaceRect state should be set to INVALID
EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.orientedDisplaySpaceRect);
-
- // The layerStackSpaceRect state should be set to INVALID
EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.layerStackSpaceRect);
// The width and height should both be zero
@@ -99,4 +95,4 @@
}
} // namespace
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
index fc40818..7d9e22b 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
@@ -25,6 +25,8 @@
namespace android {
namespace {
+constexpr ui::LayerStack LAYER_STACK{456u};
+
class SetDisplayStateLockedTest : public DisplayTransactionTest {};
TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) {
@@ -38,7 +40,7 @@
DisplayState state;
state.what = DisplayState::eLayerStackChanged;
state.token = displayToken;
- state.layerStack = 456;
+ state.layerStack = LAYER_STACK;
// --------------------------------------------------------------------
// Invocation
@@ -167,13 +169,13 @@
display.inject();
// The display has a layer stack set
- display.mutableCurrentDisplayState().layerStack = 456u;
+ display.mutableCurrentDisplayState().layerStack = LAYER_STACK;
// The incoming request sets the same layer stack
DisplayState state;
state.what = DisplayState::eLayerStackChanged;
state.token = display.token();
- state.layerStack = 456u;
+ state.layerStack = LAYER_STACK;
// --------------------------------------------------------------------
// Invocation
@@ -187,7 +189,7 @@
EXPECT_EQ(0u, flags);
// The current display state is unchanged
- EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+ EXPECT_EQ(LAYER_STACK, display.getCurrentDisplayState().layerStack);
}
TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) {
@@ -201,13 +203,13 @@
display.inject();
// The display has a layer stack set
- display.mutableCurrentDisplayState().layerStack = 654u;
+ display.mutableCurrentDisplayState().layerStack = ui::LayerStack{LAYER_STACK.id + 1};
// The incoming request sets a different layer stack
DisplayState state;
state.what = DisplayState::eLayerStackChanged;
state.token = display.token();
- state.layerStack = 456u;
+ state.layerStack = LAYER_STACK;
// --------------------------------------------------------------------
// Invocation
@@ -221,7 +223,7 @@
EXPECT_EQ(eDisplayTransactionNeeded, flags);
// The desired display state has been set to the new value.
- EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+ EXPECT_EQ(LAYER_STACK, display.getCurrentDisplayState().layerStack);
}
TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfFlagsNotChanged) {
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 56ae414..d8352ed 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -316,9 +316,9 @@
dispSurface, producer);
}
- auto handleTransactionLocked(uint32_t transactionFlags) {
- Mutex::Autolock _l(mFlinger->mStateLock);
- return mFlinger->handleTransactionLocked(transactionFlags);
+ auto commitTransactionsLocked(uint32_t transactionFlags) {
+ Mutex::Autolock lock(mFlinger->mStateLock);
+ return mFlinger->commitTransactionsLocked(transactionFlags);
}
void onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) {
@@ -326,7 +326,7 @@
}
auto setDisplayStateLocked(const DisplayState& s) {
- Mutex::Autolock _l(mFlinger->mStateLock);
+ Mutex::Autolock lock(mFlinger->mStateLock);
return mFlinger->setDisplayStateLocked(s);
}
@@ -426,7 +426,7 @@
auto& mutableDisplays() { return mFlinger->mDisplays; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableEventQueue() { return mFlinger->mEventQueue; }
- auto& mutableGeometryInvalid() { return mFlinger->mGeometryInvalid; }
+ auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; }
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
@@ -439,8 +439,7 @@
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) {
@@ -600,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;
}
}
}
@@ -764,9 +762,9 @@
};
private:
+ void scheduleRefresh(FrameHint) override {}
void setVsyncEnabled(bool) override {}
void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {}
- void repaintEverythingForHWC() override {}
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() {}
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 2845d0a..a749ece 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -119,7 +119,7 @@
FrameTracer::FrameEvent::QUEUE, /*duration*/ 0));
layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache,
frameNumber, dequeueTime, FrameTimelineInfo{},
- nullptr /* releaseBufferCallback */);
+ nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint*/);
commitTransaction(layer.get());
bool computeVisisbleRegions;
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 7bf224d..2a7921f 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -119,7 +119,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
acquireFence->signalForTest(12);
commitTransaction(layer.get());
@@ -147,7 +148,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -160,7 +162,8 @@
mRenderEngine, false);
nsecs_t start = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
nsecs_t end = systemTime();
acquireFence2->signalForTest(12);
@@ -200,7 +203,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
acquireFence->signalForTest(12);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
@@ -228,7 +232,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -260,7 +265,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto bufferSurfaceFrameTX = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -298,7 +304,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -309,7 +316,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
acquireFence2->signalForTest(12);
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -339,7 +347,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -353,7 +362,7 @@
auto dropStartTime1 = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0},
- nullptr /* releaseBufferCallback */);
+ nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint */);
auto dropEndTime1 = systemTime();
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -367,7 +376,8 @@
mRenderEngine, false);
auto dropStartTime2 = systemTime();
layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
auto dropEndTime2 = systemTime();
acquireFence3->signalForTest(12);
@@ -411,7 +421,8 @@
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0},
- nullptr /* releaseBufferCallback */);
+ nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2,
/*inputEventId*/ 0},
10);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index ab19886..291559f 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -23,20 +23,20 @@
namespace android::mock {
struct SchedulerCallback final : ISchedulerCallback {
+ MOCK_METHOD(void, scheduleRefresh, (FrameHint), (override));
MOCK_METHOD1(setVsyncEnabled, void(bool));
MOCK_METHOD2(changeRefreshRate,
void(const scheduler::RefreshRateConfigs::RefreshRate&,
scheduler::RefreshRateConfigEvent));
- MOCK_METHOD0(repaintEverythingForHWC, void());
MOCK_METHOD1(kernelTimerChanged, void(bool));
MOCK_METHOD0(triggerOnFrameRateOverridesChanged, void());
};
struct NoOpSchedulerCallback final : ISchedulerCallback {
+ void scheduleRefresh(FrameHint) override {}
void setVsyncEnabled(bool) override {}
void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
scheduler::RefreshRateConfigEvent) override {}
- void repaintEverythingForHWC() override {}
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() {}
};