diff options
author | Scott Lobdell <slobdell@google.com> | 2021-04-25 19:53:06 +0000 |
---|---|---|
committer | Rob Seymour <rseymour@google.com> | 2021-05-06 22:32:25 +0000 |
commit | afbe732519a96ff0a42a1c98bd59fd04080b4a96 (patch) | |
tree | 9ca836d438ca47756e4761ee4b844b85bd7e8857 | |
parent | 7a303d6e8135bbd0a32075986c9f7083e0fbef23 (diff) | |
parent | 7132116dfd8bdb9c5b505db8d8a27526a4e889d8 (diff) |
Merge SP1A.210425.001
Change-Id: I219cc0af128876534b77a72c36979fa1fe08ba13
253 files changed, 5374 insertions, 4326 deletions
diff --git a/.clang-format b/.clang-format index 03af56d640..6725a1fde8 100644 --- a/.clang-format +++ b/.clang-format @@ -11,3 +11,4 @@ ContinuationIndentWidth: 8 IndentWidth: 4 PenaltyBreakBeforeFirstCallParameter: 100000 SpacesBeforeTrailingComments: 1 +IncludeBlocks: Preserve diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index cedff0ba8a..79419d3ae6 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -323,9 +323,6 @@ static const char* k_funcgraphCpuPath = static const char* k_funcgraphProcPath = "options/funcgraph-proc"; -static const char* k_funcgraphFlatPath = - "options/funcgraph-flat"; - static const char* k_ftraceFilterPath = "set_ftrace_filter"; @@ -703,7 +700,6 @@ static bool setKernelTraceFuncs(const char* funcs) ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true); ok &= setKernelOptionEnable(k_funcgraphCpuPath, true); ok &= setKernelOptionEnable(k_funcgraphProcPath, true); - ok &= setKernelOptionEnable(k_funcgraphFlatPath, true); // Set the requested filter functions. ok &= truncateFile(k_ftraceFilterPath); diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index f48f1fb6f8..aff32c38c2 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -99,6 +99,7 @@ cc_defaults { "libhidlbase", "liblog", "libutils", + "libbinderdebug", ], srcs: [ "DumpstateService.cpp", diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index c0010c0ced..336c5a2b3d 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -793,6 +793,9 @@ void Dumpstate::PrintHeader() const { if (module_metadata_version != 0) { printf("Module Metadata version: %" PRId64 "\n", module_metadata_version); } + printf("SDK extension versions [r=%s s=%s]\n", + android::base::GetProperty("build.version.extensions.r", "-").c_str(), + android::base::GetProperty("build.version.extensions.s", "-").c_str()); printf("Kernel: "); DumpFileToFd(STDOUT_FILENO, "", "/proc/version"); diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 2c573e4f4a..db508b52bd 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -1032,12 +1032,12 @@ class ZippedBugReportStreamTest : public DumpstateBaseTest { ZipArchiveHandle handle_; }; -// Generate a quick wifi report redirected to a file, open it and verify entry exist. -TEST_F(ZippedBugReportStreamTest, StreamWifiReport) { - std::string out_path = kTestDataPath + "out.zip"; +// Generate a quick LimitedOnly report redirected to a file, open it and verify entry exist. +TEST_F(ZippedBugReportStreamTest, StreamLimitedOnlyReport) { + std::string out_path = kTestDataPath + "StreamLimitedOnlyReportOut.zip"; android::base::unique_fd out_fd; CreateFd(out_path, &out_fd); - ds_.options_->wifi_only = true; + ds_.options_->limited_only = true; ds_.options_->stream_to_socket = true; RedirectOutputToFd(out_fd); @@ -1051,7 +1051,7 @@ TEST_F(ZippedBugReportStreamTest, StreamWifiReport) { ExtractToMemory(handle_, &entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()), entry.uncompressed_length); EXPECT_THAT(bugreport_txt_name, - testing::ContainsRegex("(bugreport-.+-wifi(-[[:digit:]]+){6}\\.txt)")); + testing::ContainsRegex("(bugreport-.+(-[[:digit:]]+){6}\\.txt)")); VerifyEntry(handle_, bugreport_txt_name, &entry); } diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp index 91aa018451..6ab6b7f951 100644 --- a/cmds/dumpsys/Android.bp +++ b/cmds/dumpsys/Android.bp @@ -32,6 +32,7 @@ cc_defaults { "libutils", "liblog", "libbinder", + "libbinderdebug", ], static_libs: [ diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS index 2a9b681318..4f6a89ebe5 100644 --- a/cmds/dumpsys/OWNERS +++ b/cmds/dumpsys/OWNERS @@ -2,3 +2,6 @@ set noparent nandana@google.com jsharkey@android.com + +# for ServiceManager mock +per-file dumpsys_test.cpp=smoreland@google.com diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index a017246184..ba1c449dbf 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -25,6 +25,7 @@ #include <binder/Parcel.h> #include <binder/ProcessState.h> #include <binder/TextOutput.h> +#include <binderdebug/BinderDebug.h> #include <serviceutils/PriorityDumper.h> #include <utils/Log.h> #include <utils/Vector.h> @@ -60,13 +61,15 @@ static void usage() { "usage: dumpsys\n" " To dump all services.\n" "or:\n" - " dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--help | -l | --skip SERVICES " + " dumpsys [-t TIMEOUT] [--priority LEVEL] [--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" " --pid: dump PID instead of usual dump\n" + " --thread: dump thread usage 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" @@ -125,7 +128,8 @@ int Dumpsys::main(int argc, char* const argv[]) { Type type = Type::DUMP; int timeoutArgMs = 10000; int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL; - static struct option longOptions[] = {{"pid", no_argument, 0, 0}, + static struct option longOptions[] = {{"thread", no_argument, 0, 0}, + {"pid", no_argument, 0, 0}, {"priority", required_argument, 0, 0}, {"proto", no_argument, 0, 0}, {"skip", no_argument, 0, 0}, @@ -163,6 +167,8 @@ int Dumpsys::main(int argc, char* const argv[]) { } } else if (!strcmp(longOptions[optionIndex].name, "pid")) { type = Type::PID; + } else if (!strcmp(longOptions[optionIndex].name, "thread")) { + type = Type::THREAD; } break; @@ -329,6 +335,23 @@ static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd) { return OK; } +static status_t dumpThreadsToFd(const sp<IBinder>& service, const unique_fd& fd) { + pid_t pid; + status_t status = service->getDebugPid(&pid); + if (status != OK) { + return status; + } + BinderPidInfo pidInfo; + status = getBinderPidInfo(BinderDebugContext::BINDER, pid, &pidInfo); + if (status != OK) { + return status; + } + WriteStringToFd("Threads in use: " + std::to_string(pidInfo.threadUsage) + "/" + + std::to_string(pidInfo.threadCount) + "\n", + fd.get()); + return OK; +} + status_t Dumpsys::startDumpThread(Type type, const String16& serviceName, const Vector<String16>& args) { sp<IBinder> service = sm_->checkService(serviceName); @@ -359,6 +382,9 @@ status_t Dumpsys::startDumpThread(Type type, const String16& serviceName, case Type::PID: err = dumpPidToFd(service, remote_end); break; + case Type::THREAD: + err = dumpThreadsToFd(service, remote_end); + break; default: std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl; return; diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h index 929c55c364..349947ce12 100644 --- a/cmds/dumpsys/dumpsys.h +++ b/cmds/dumpsys/dumpsys.h @@ -52,13 +52,14 @@ class Dumpsys { static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags); enum class Type { - DUMP, // dump using `dump` function - PID, // dump pid of server only + DUMP, // dump using `dump` function + PID, // dump pid of server only + THREAD, // dump thread usage of server only }; /** * Starts a thread to connect to a service and get its dump output. The thread redirects - * the output to a pipe. Thread must be stopped by a subsequent callto {@code + * the output to a pipe. Thread must be stopped by a subsequent call to {@code * stopDumpThread}. * @param serviceName * @param args list of arguments to pass to service dump method. diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp index 6854c7550e..58fec30c9b 100644 --- a/cmds/dumpsys/tests/Android.bp +++ b/cmds/dumpsys/tests/Android.bp @@ -19,6 +19,7 @@ cc_test { "libbase", "libbinder", "libutils", + "libbinderdebug", ], static_libs: [ @@ -26,6 +27,4 @@ cc_test { "libgmock", "libserviceutils", ], - - clang: true, } diff --git a/cmds/dumpsys/tests/AndroidTest.xml b/cmds/dumpsys/tests/AndroidTest.xml index 1a8c67f7aa..c2351d9aff 100644 --- a/cmds/dumpsys/tests/AndroidTest.xml +++ b/cmds/dumpsys/tests/AndroidTest.xml @@ -23,4 +23,4 @@ <option name="native-test-device-path" value="/data/local/tmp" /> <option name="module-name" value="dumpsys_test" /> </test> -</configuration>
\ No newline at end of file +</configuration> diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index 67a77f6015..c9d2dbb883 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -16,12 +16,15 @@ #include "../dumpsys.h" +#include <regex> #include <vector> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <android-base/file.h> +#include <binder/Binder.h> +#include <binder/ProcessState.h> #include <serviceutils/PriorityDumper.h> #include <utils/String16.h> #include <utils/String8.h> @@ -56,6 +59,7 @@ class ServiceManagerMock : public IServiceManager { MOCK_METHOD1(waitForService, sp<IBinder>(const String16&)); MOCK_METHOD1(isDeclared, bool(const String16&)); MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&)); + MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); }; @@ -222,6 +226,10 @@ class DumpsysTest : public Test { EXPECT_THAT(stdout_, HasSubstr(expected)); } + void AssertOutputFormat(const std::string format) { + EXPECT_THAT(stdout_, testing::MatchesRegex(format)); + } + void AssertDumped(const std::string& service, const std::string& dump) { EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump)); EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: ")); @@ -574,6 +582,30 @@ TEST_F(DumpsysTest, ListServiceWithPid) { AssertOutput(std::to_string(getpid()) + "\n"); } +// Tests 'dumpsys --thread' +TEST_F(DumpsysTest, ListAllServicesWithThread) { + ExpectListServices({"Locksmith", "Valet"}); + ExpectCheckService("Locksmith"); + ExpectCheckService("Valet"); + + CallMain({"--thread"}); + + AssertRunningServices({"Locksmith", "Valet"}); + + const std::string format("(.|\n)*((Threads in use: [0-9]+/[0-9]+)?\n-(.|\n)*){2}"); + AssertOutputFormat(format); +} + +// Tests 'dumpsys --thread service_name' +TEST_F(DumpsysTest, ListServiceWithThread) { + ExpectCheckService("Locksmith"); + + CallMain({"--thread", "Locksmith"}); + // returns an empty string without root enabled + const std::string format("(^$|Threads in use: [0-9]/[0-9]+\n)"); + AssertOutputFormat(format); +} + TEST_F(DumpsysTest, GetBytesWritten) { const char* serviceName = "service2"; const char* dumpContents = "dump1"; @@ -599,3 +631,13 @@ TEST_F(DumpsysTest, WriteDumpWithoutThreadStart) { /* as_proto = */ false, elapsedDuration, bytesWritten); EXPECT_THAT(status, Eq(INVALID_OPERATION)); } + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + // start a binder thread pool for testing --thread option + android::ProcessState::self()->setThreadPoolMaxThreadCount(8); + ProcessState::self()->startThreadPool(); + + return RUN_ALL_TESTS(); +} diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index 3a87776162..83f01de01e 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -179,6 +179,11 @@ static int otapreopt_chroot(const int argc, char **arg) { // want it for product APKs. Same notes as vendor above. TryExtraMount("product", arg[2], "/postinstall/product"); + // Try to mount the system_ext partition. update_engine doesn't do this for + // us, but we want it for system_ext APKs. Same notes as vendor and product + // above. + TryExtraMount("system_ext", arg[2], "/postinstall/system_ext"); + constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig"; // Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot if (mount("tmpfs", kPostInstallLinkerconfig, "tmpfs", 0, nullptr) != 0) { diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index d5110f6203..2722e214e8 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -417,7 +417,7 @@ void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const { } } out << "-->" << std::endl; - out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlags::HALS_ONLY); + out << vintf::toXml(manifest, vintf::SerializeFlags::HALS_ONLY); } std::string ListCommand::INIT_VINTF_NOTES{ diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp index 7c1ca91528..6f08f74690 100644 --- a/cmds/lshal/test.cpp +++ b/cmds/lshal/test.cpp @@ -47,8 +47,6 @@ using ::android::hardware::hidl_vec; using ::android::hardware::Void; using android::vintf::Arch; using android::vintf::CompatibilityMatrix; -using android::vintf::gCompatibilityMatrixConverter; -using android::vintf::gHalManifestConverter; using android::vintf::HalManifest; using android::vintf::Transport; using android::vintf::VintfObject; @@ -510,7 +508,7 @@ TEST_F(ListTest, DumpVintf) { std::string error; vintf::HalManifest m; - EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str(), &error)) + EXPECT_EQ(true, vintf::fromXml(&m, out.str(), &error)) << "--init-vintf does not emit valid HAL manifest: " << error; } @@ -775,10 +773,10 @@ TEST_F(ListTest, Vintf) { auto deviceMatrix = std::make_shared<CompatibilityMatrix>(); auto frameworkMatrix = std::make_shared<CompatibilityMatrix>(); - ASSERT_TRUE(gHalManifestConverter(deviceManifest.get(), deviceManifestXml)); - ASSERT_TRUE(gHalManifestConverter(frameworkManifest.get(), frameworkManifestXml)); - ASSERT_TRUE(gCompatibilityMatrixConverter(deviceMatrix.get(), deviceMatrixXml)); - ASSERT_TRUE(gCompatibilityMatrixConverter(frameworkMatrix.get(), frameworkMatrixXml)); + ASSERT_TRUE(fromXml(deviceManifest.get(), deviceManifestXml)); + ASSERT_TRUE(fromXml(frameworkManifest.get(), frameworkManifestXml)); + ASSERT_TRUE(fromXml(deviceMatrix.get(), deviceMatrixXml)); + ASSERT_TRUE(fromXml(frameworkMatrix.get(), frameworkMatrixXml)); ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest)); ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix)); @@ -964,7 +962,7 @@ public: " </hal>\n" "</manifest>"; auto manifest = std::make_shared<HalManifest>(); - EXPECT_TRUE(gHalManifestConverter(manifest.get(), mockManifestXml)); + EXPECT_TRUE(fromXml(manifest.get(), mockManifestXml)); EXPECT_CALL(*mockList, getDeviceManifest()) .Times(AnyNumber()) .WillRepeatedly(Return(manifest)); diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 2f5524940e..b429fb3440 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -58,22 +58,34 @@ static bool forEachManifest(const std::function<bool(const ManifestWithDescripti return false; } -static bool isVintfDeclared(const std::string& name) { - size_t firstSlash = name.find('/'); - size_t lastDot = name.rfind('.', firstSlash); - if (firstSlash == std::string::npos || lastDot == std::string::npos) { - LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. " - << "some.package.foo.IFoo/default) but got: " << name; - return false; +struct AidlName { + std::string package; + std::string iface; + std::string instance; + + static bool fill(const std::string& name, AidlName* aname) { + size_t firstSlash = name.find('/'); + size_t lastDot = name.rfind('.', firstSlash); + if (firstSlash == std::string::npos || lastDot == std::string::npos) { + LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. " + << "some.package.foo.IFoo/default) but got: " << name; + return false; + } + aname->package = name.substr(0, lastDot); + aname->iface = name.substr(lastDot + 1, firstSlash - lastDot - 1); + aname->instance = name.substr(firstSlash + 1); + return true; } - const std::string package = name.substr(0, lastDot); - const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1); - const std::string instance = name.substr(firstSlash+1); +}; + +static bool isVintfDeclared(const std::string& name) { + AidlName aname; + if (!AidlName::fill(name, &aname)) return false; - bool found = forEachManifest([&] (const ManifestWithDescription& mwd) { - if (mwd.manifest->hasAidlInstance(package, iface, instance)) { + bool found = forEachManifest([&](const ManifestWithDescription& mwd) { + if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) { LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest."; - return true; + return true; // break } return false; // continue }); @@ -81,13 +93,34 @@ static bool isVintfDeclared(const std::string& name) { if (!found) { // Although it is tested, explicitly rebuilding qualified name, in case it // becomes something unexpected. - LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance - << " in the VINTF manifest."; + LOG(ERROR) << "Could not find " << aname.package << "." << aname.iface << "/" + << aname.instance << " in the VINTF manifest."; } return found; } +static std::optional<std::string> getVintfUpdatableApex(const std::string& name) { + AidlName aname; + if (!AidlName::fill(name, &aname)) return std::nullopt; + + std::optional<std::string> updatableViaApex; + + forEachManifest([&](const ManifestWithDescription& mwd) { + mwd.manifest->forEachInstance([&](const auto& manifestInstance) { + if (manifestInstance.format() != vintf::HalFormat::AIDL) return true; + if (manifestInstance.package() != aname.package) return true; + if (manifestInstance.interface() != aname.iface) return true; + if (manifestInstance.instance() != aname.instance) return true; + updatableViaApex = manifestInstance.updatableViaApex(); + return false; // break (libvintf uses opposite convention) + }); + return false; // continue + }); + + return updatableViaApex; +} + static std::vector<std::string> getVintfInstances(const std::string& interface) { size_t lastDot = interface.rfind('.'); if (lastDot == std::string::npos) { @@ -388,6 +421,22 @@ binder::Status ServiceManager::getDeclaredInstances(const std::string& interface return Status::ok(); } +Status ServiceManager::updatableViaApex(const std::string& name, + std::optional<std::string>* outReturn) { + auto ctx = mAccess->getCallingContext(); + + if (!mAccess->canFind(ctx, name)) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + *outReturn = std::nullopt; + +#ifndef VENDORSERVICEMANAGER + *outReturn = getVintfUpdatableApex(name); +#endif + return Status::ok(); +} + void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who, ServiceCallbackMap::iterator* it, bool* found) { diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index c0891152e6..4f23c21078 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -46,6 +46,8 @@ public: binder::Status isDeclared(const std::string& name, bool* outReturn) override; binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override; + binder::Status updatableViaApex(const std::string& name, + std::optional<std::string>* outReturn) override; binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service, const sp<IClientCallback>& cb) override; binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override; diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index 06afefd3c8..3798ba73a4 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -46,7 +46,6 @@ message SurfaceChange { HiddenFlagChange hidden_flag = 12; OpaqueFlagChange opaque_flag = 13; SecureFlagChange secure_flag = 14; - DeferredTransactionChange deferred_transaction = 15; CornerRadiusChange corner_radius = 16; ReparentChange reparent = 17; RelativeParentChange relative_parent = 18; @@ -113,11 +112,6 @@ message SecureFlagChange { required bool secure_flag = 1; } -message DeferredTransactionChange { - required int32 layer_id = 1; - required uint64 frame_number = 2; -} - message DisplayChange { required int32 id = 1; diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index a6d9a3feb6..cfd42fec30 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -402,11 +402,6 @@ status_t Replayer::doSurfaceTransaction( case SurfaceChange::SurfaceChangeCase::kSecureFlag: setSecureFlag(transaction, change.id(), change.secure_flag()); break; - case SurfaceChange::SurfaceChangeCase::kDeferredTransaction: - waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock); - setDeferredTransaction(transaction, change.id(), - change.deferred_transaction()); - break; case SurfaceChange::SurfaceChangeCase::kReparent: setReparentChange(transaction, change.id(), change.reparent()); break; @@ -560,19 +555,6 @@ void Replayer::setSecureFlag(SurfaceComposerClient::Transaction& t, t.setFlags(mLayers[id], flag, layer_state_t::eLayerSecure); } -void Replayer::setDeferredTransaction(SurfaceComposerClient::Transaction& t, - layer_id id, const DeferredTransactionChange& dtc) { - ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, " - "frame_number=%llu", - id, dtc.layer_id(), dtc.frame_number()); - if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) { - ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id()); - return; - } - - t.deferTransactionUntil_legacy(mLayers[id], mLayers[dtc.layer_id()], dtc.frame_number()); -} - void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t, display_id id, const DispSurfaceChange& /*dsc*/) { sp<IGraphicBufferProducer> outProducer; @@ -676,13 +658,6 @@ void Replayer::waitUntilTimestamp(int64_t timestamp) { std::this_thread::sleep_for(std::chrono::nanoseconds(timestamp - mCurrentTime)); } -void Replayer::waitUntilDeferredTransactionLayerExists( - const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock) { - if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) { - mLayerCond.wait(lock, [&] { return (mLayers[dtc.layer_id()] != nullptr); }); - } -} - status_t Replayer::loadSurfaceComposerClient() { mComposerClient = new SurfaceComposerClient; return mComposerClient->initCheck(); diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h index 252db2bfbb..d62522a497 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -110,8 +110,6 @@ class Replayer { layer_id id, const OpaqueFlagChange& ofc); void setSecureFlag(SurfaceComposerClient::Transaction& t, layer_id id, const SecureFlagChange& sfc); - void setDeferredTransaction(SurfaceComposerClient::Transaction& t, - layer_id id, const DeferredTransactionChange& dtc); void setReparentChange(SurfaceComposerClient::Transaction& t, layer_id id, const ReparentChange& c); void setRelativeParentChange(SurfaceComposerClient::Transaction& t, @@ -131,8 +129,6 @@ class Replayer { display_id id, const ProjectionChange& pc); void waitUntilTimestamp(int64_t timestamp); - void waitUntilDeferredTransactionLayerExists( - const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock); status_t loadSurfaceComposerClient(); Trace mTrace; diff --git a/data/etc/android.software.translation.xml b/data/etc/android.software.translation.xml deleted file mode 100644 index 3b361e5cb8..0000000000 --- a/data/etc/android.software.translation.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2020 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<permissions> - <feature name="android.software.translation" /> -</permissions> diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml index c3c3a7f247..41f15144d4 100644 --- a/data/etc/handheld_core_hardware.xml +++ b/data/etc/handheld_core_hardware.xml @@ -54,7 +54,6 @@ <feature name="android.software.autofill" /> <feature name="android.software.cant_save_state" /> <feature name="android.software.secure_lock_screen" /> - <feature name="android.software.translation" /> <!-- Feature to specify if the device supports adding device admins. --> <feature name="android.software.device_admin" /> diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml index 4b565fda97..8c369dea99 100644 --- a/data/etc/tablet_core_hardware.xml +++ b/data/etc/tablet_core_hardware.xml @@ -54,7 +54,6 @@ <feature name="android.software.autofill" /> <feature name="android.software.cant_save_state" /> <feature name="android.software.secure_lock_screen" /> - <feature name="android.software.translation" /> <!-- Feature to specify if the device supports adding device admins. --> <feature name="android.software.device_admin" /> diff --git a/include/android/bitmap.h b/include/android/bitmap.h index a70dffd756..6704a1ddf2 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -241,6 +241,7 @@ typedef struct AHardwareBuffer AHardwareBuffer; * * Available since API level 30. * + * @param env Handle to the JNI environment pointer. * @param bitmap Handle to an android.graphics.Bitmap. * @param outBuffer On success, is set to a pointer to the * {@link AHardwareBuffer} associated with bitmap. This acquires diff --git a/include/android/choreographer.h b/include/android/choreographer.h index cc5420e239..b743f491e4 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -32,6 +32,11 @@ __BEGIN_DECLS struct AChoreographer; +/** + * Opaque type that provides access to an AChoreographer object. + * + * A pointer can be obtained using {@link AChoreographer_getInstance()}. + */ typedef struct AChoreographer AChoreographer; /** diff --git a/include/android/font.h b/include/android/font.h index a172618829..8a3a474f25 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -189,7 +189,7 @@ const char* _Nonnull AFont_getFontFilePath(const AFont* _Nonnull font) __INTRODU * Available since API level 29. * * \param font a font object. Passing NULL is not allowed. - * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned. + * \return a positive integer less than or equal to {@link AFONT_WEIGHT_MAX} is returned. */ uint16_t AFont_getWeight(const AFont* _Nonnull font) __INTRODUCED_IN(29); @@ -241,7 +241,7 @@ size_t AFont_getCollectionIndex(const AFont* _Nonnull font) __INTRODUCED_IN(29); * In this case, AFont_getAxisCount returns 2 and AFont_getAxisTag * and AFont_getAxisValue will return following values. * \code{.cpp} - * AFont* font = AFontIterator_next(ite); + * AFont* font = ASystemFontIterator_next(ite); * * // Returns the number of axes * AFont_getAxisCount(font); // Returns 2 @@ -289,7 +289,7 @@ uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex) * * \param font a font object. Passing NULL is not allowed. * \param axisIndex an index to the font variation settings. Passing value larger than or - * equal to {@link ASYstemFont_getAxisCount} is not allwed. + * equal to {@link AFont_getAxisCount} is not allowed. * \return a float value for the given font variation setting. */ float AFont_getAxisValue(const AFont* _Nonnull font, uint32_t axisIndex) diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index 49e478c2f3..4417422687 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -36,7 +36,7 @@ * // Simple font query for the ASCII character. * std::vector<uint16_t> text = { 'A' }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a valid font file. * AFontMatcher_destroy(matcher); * @@ -44,17 +44,17 @@ * std::vector<uint16_t> text = { 0x9AA8 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); * AFontMatcher_setLocales(matcher, "zh-CN,ja-JP"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Simplified Chinese font. * AFontMatcher_setLocales(matcher, "ja-JP,zh-CN"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Japanese font. * AFontMatcher_destroy(matcher); * * // Querying font for text/color emoji * std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 8 and the font will points a color emoji font. * AFontMatcher_destroy(matcher); * @@ -62,7 +62,7 @@ * // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character. * std::vector<uint16_t> text = { 0x05D0, 0x0E01 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Hebrew font. * AFontMatcher_destroy(matcher); * \endcode @@ -146,7 +146,7 @@ void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29); /** * Set font style to matcher. * - * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL} + * If this function is not called, the matcher performs with {@link AFONT_WEIGHT_NORMAL} * with non-italic style. * * Available since API level 29. @@ -206,7 +206,7 @@ void AFontMatcher_setFamilyVariant( * \param textLength a length of the given text buffer. This must not be zero. * \param runLengthOut if not null, the font run length will be filled. * \return a font to be used for given text and params. You need to release the returned font by - * ASystemFont_close when it is no longer needed. + * AFont_close when it is no longer needed. */ AFont* _Nonnull AFontMatcher_match( const AFontMatcher* _Nonnull matcher, diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h index ee1eee2be6..8d1bf99fe7 100644 --- a/include/android/imagedecoder.h +++ b/include/android/imagedecoder.h @@ -15,7 +15,7 @@ */ /** - * @defgroup ImageDecoder + * @defgroup ImageDecoder Android Image Decoder * * Functions for converting encoded images into RGBA pixels. * @@ -261,7 +261,8 @@ int AImageDecoder_createFromBuffer(const void* _Nonnull buffer, size_t length, /** * Delete the AImageDecoder. - * + * @param decoder {@link AImageDecoder} object created with one of AImageDecoder_createFrom... + * functions. * Available since API level 30. */ void AImageDecoder_delete(AImageDecoder* _Nullable decoder) __INTRODUCED_IN(30); @@ -276,6 +277,7 @@ void AImageDecoder_delete(AImageDecoder* _Nullable decoder) __INTRODUCED_IN(30); * Available since API level 30. * * @param format {@link AndroidBitmapFormat} to use for the output. + * @param decoder an {@link AImageDecoder} object. * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value * indicating the reason for the failure. On failure, the * {@link AImageDecoder} uses the format it was already planning @@ -307,6 +309,7 @@ int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* _Nonnull decoder, * * Available since API level 30. * + * @param decoder an {@link AImageDecoder} object. * @param unpremultipliedRequired Pass true to leave the pixels unpremultiplied. * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value * indicating the reason for the failure. @@ -335,6 +338,7 @@ int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* _Nonnull decoder, * * Available since API level 30. * + * @param decoder an {@link AImageDecoder} object. * @param dataspace The {@link ADataSpace} to decode into. An ADataSpace * specifies how to interpret the colors. By default, * AImageDecoder will decode into the ADataSpace specified by @@ -373,6 +377,7 @@ int AImageDecoder_setDataSpace(AImageDecoder* _Nonnull decoder, int32_t dataspac * * Available since API level 30. * + * @param decoder an {@link AImageDecoder} object. * @param width Width of the output (prior to cropping). * This will affect future calls to * {@link AImageDecoder_getMinimumStride}, which will now return @@ -404,6 +409,7 @@ int AImageDecoder_setTargetSize(AImageDecoder* _Nonnull decoder, int32_t width, * * Available since API level 30. * + * @param decoder an {@link AImageDecoder} object. * @param sampleSize A subsampling rate of the original image. Must be greater * than or equal to 1. A sampleSize of 2 means to skip every * other pixel/line, resulting in a width and height that are @@ -437,6 +443,7 @@ int AImageDecoder_computeSampledSize(const AImageDecoder* _Nonnull decoder, int * * Available since API level 30. * + * @param decoder an {@link AImageDecoder} object. * @param crop Rectangle describing a crop of the decode. It must be contained inside of * the (possibly scaled, by {@link AImageDecoder_setTargetSize}) * image dimensions. This will affect future calls to @@ -475,6 +482,8 @@ typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo; * This is owned by the {@link AImageDecoder} and will be destroyed when the * AImageDecoder is destroyed via {@link AImageDecoder_delete}. * + * @param decoder an {@link AImageDecoder} object. + * * Available since API level 30. */ const AImageDecoderHeaderInfo* _Nonnull AImageDecoder_getHeaderInfo( @@ -562,7 +571,7 @@ int32_t AImageDecoderHeaderInfo_getDataSpace( /** * Return the minimum stride that can be used in - * {@link AImageDecoder_decodeImage). + * {@link AImageDecoder_decodeImage}. * * This stride provides no padding, meaning it will be exactly equal to the * width times the number of bytes per pixel for the {@link AndroidBitmapFormat} @@ -571,6 +580,8 @@ int32_t AImageDecoderHeaderInfo_getDataSpace( * If the output is scaled (via {@link AImageDecoder_setTargetSize}) and/or * cropped (via {@link AImageDecoder_setCrop}), this takes those into account. * + * @param decoder an {@link AImageDecoder} object. + * * Available since API level 30. */ size_t AImageDecoder_getMinimumStride(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30); @@ -664,6 +675,8 @@ int AImageDecoder_decodeImage(AImageDecoder* _Nonnull decoder, * A single frame GIF is considered to *not* be animated. This may require * seeking past the first frame to verify whether there is a following frame. * + * @param decoder an {@link AImageDecoder} object. + * * Errors: * - returns false if |decoder| is null. */ @@ -671,7 +684,7 @@ bool AImageDecoder_isAnimated(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(31); enum { - /* + /** * Reported by {@link AImageDecoder_getRepeatCount} if the * animation should repeat forever. * @@ -696,6 +709,7 @@ enum { * an image with only one frame (i.e. {@link AImageDecoder_isAnimated} returns * false) if the encoded image contains a repeat count. * + * @param decoder an {@link AImageDecoder} object. * @return Number of times to repeat on success or a value * indicating the reason for the failure. * @@ -725,6 +739,7 @@ int32_t AImageDecoder_getRepeatCount(AImageDecoder* _Nonnull decoder) * skipping frames in an image with such frames may not produce the correct * results. * + * @param decoder an {@link AImageDecoder} object. * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value * indicating the reason for the failure. * @@ -755,6 +770,7 @@ int AImageDecoder_advanceFrame(AImageDecoder* _Nonnull decoder) * the end of the animation or an error or in the middle of the * animation. * + * @param decoder an {@link AImageDecoder} object. * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value * indicating the reason for the failure. * @@ -847,7 +863,7 @@ int64_t AImageDecoderFrameInfo_getDuration( /** * The rectangle of the image (within 0, 0, - * {@link AImageDecoder_getWidth}, {@link AImageDecoder_getHeight}) + * {@link AImageDecoderHeaderInfo_getWidth}, {@link AImageDecoderHeaderInfo_getHeight}) * updated by this frame. * * Introduced in API 31. @@ -905,15 +921,15 @@ bool AImageDecoderFrameInfo_hasAlphaWithinBounds( * sequential client does not need this. */ enum { - // No disposal. The following frame will be drawn directly - // on top of this one. + /// No disposal. The following frame will be drawn directly + /// on top of this one. ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE = 1, - // The frame’s rectangle is cleared to transparent (by AImageDecoder) - // before decoding the next frame. + /// The frame’s rectangle is cleared to transparent (by AImageDecoder) + /// before decoding the next frame. ANDROID_IMAGE_DECODER_DISPOSE_OP_BACKGROUND = 2, - // The frame’s rectangle is reverted to the prior frame before decoding - // the next frame. This is handled by AImageDecoder, unless - // {@link AImageDecoder_setInternallyHandleDisposePrevious} is set to false. + /// The frame’s rectangle is reverted to the prior frame before decoding + /// the next frame. This is handled by AImageDecoder, unless + /// {@link AImageDecoder_setInternallyHandleDisposePrevious} is set to false. ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS = 3, }; @@ -948,10 +964,10 @@ int32_t AImageDecoderFrameInfo_getDisposeOp( * sequential client does not need this. */ enum { - // This frame replaces existing content. This corresponds - // to webp’s “do not blend”. + /// This frame replaces existing content. This corresponds + /// to webp’s “do not blend”. ANDROID_IMAGE_DECODER_BLEND_OP_SRC = 1, - // This frame blends with the previous frame. + /// This frame blends with the previous frame. ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER = 2, }; @@ -1002,6 +1018,7 @@ int32_t AImageDecoderFrameInfo_getBlendOp( * When asked to decode frame i+1, AImageDecoder will now assume that * the client provided i-1 in |pixels|. * + * @param decoder an {@link AImageDecoder} object. * @param handleInternally Whether AImageDecoder will internally * handle ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS * frames. diff --git a/include/android/sensor.h b/include/android/sensor.h index 92b79c75ff..9dc6983e50 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -228,8 +228,8 @@ enum { * * If a device supports the sensor additional information feature, it will * report additional information events via {@link ASensorEvent} and will - * have {@link ASensorEvent#type} set to - * {@link ASENSOR_TYPE_ADDITIONAL_INFO} and {@link ASensorEvent#sensor} set + * have the type of {@link ASensorEvent} set to + * {@link ASENSOR_TYPE_ADDITIONAL_INFO} and the sensor of {@link ASensorEvent} set * to the handle of the reporting sensor. * * Additional information reports consist of multiple frames ordered by @@ -428,6 +428,10 @@ typedef struct ADynamicSensorEvent { } ADynamicSensorEvent; typedef struct AAdditionalInfoEvent { + /** + * Event type, such as ASENSOR_ADDITIONAL_INFO_BEGIN, ASENSOR_ADDITIONAL_INFO_END and others. + * Refer to {@link ASENSOR_TYPE_ADDITIONAL_INFO} for the expected reporting behavior. + */ int32_t type; int32_t serial; union { @@ -436,12 +440,22 @@ typedef struct AAdditionalInfoEvent { }; } AAdditionalInfoEvent; +/** + * Information that describes a sensor event, refer to + * <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional + * documentation. + */ /* NOTE: changes to this struct has to be backward compatible */ typedef struct ASensorEvent { int32_t version; /* sizeof(struct ASensorEvent) */ - int32_t sensor; - int32_t type; - int32_t reserved0; + int32_t sensor; /** The sensor that generates this event */ + int32_t type; /** Sensor type for the event, such as {@link ASENSOR_TYPE_ACCELEROMETER} */ + int32_t reserved0; /** do not use */ + /** + * The time in nanoseconds at which the event happened, and its behavior + * is identical to <a href="/reference/android/hardware/SensorEvent#timestamp"> + * SensorEvent::timestamp</a> in Java API. + */ int64_t timestamp; union { union { @@ -653,9 +667,10 @@ int ASensorManager_createHardwareBufferDirectChannel( /** * Destroy a direct channel * - * Destroy a direct channel previously created using {@link ASensorManager_createDirectChannel}. - * The buffer used for creating direct channel does not get destroyed with - * {@link ASensorManager_destroy} and has to be close or released separately. + * Destroy a direct channel previously created by using one of + * ASensorManager_create*DirectChannel() derivative functions. + * Note that the buffer used for creating the direct channel does not get destroyed with + * ASensorManager_destroyDirectChannel and has to be closed or released separately. * * Available since API level 26. * @@ -701,7 +716,7 @@ void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) * \param channelId channel id (a positive integer) returned from * {@link ASensorManager_createSharedMemoryDirectChannel} or * {@link ASensorManager_createHardwareBufferDirectChannel}. - * + * \param rate one of predefined ASENSOR_DIRECT_RATE_... that is supported by the sensor. * \return positive token for success or negative error code. */ int ASensorManager_configureDirectReport(ASensorManager* manager, @@ -718,7 +733,7 @@ int ASensorManager_configureDirectReport(ASensorManager* manager, * \param queue {@link ASensorEventQueue} for sensor event to be report to. * \param sensor {@link ASensor} to be enabled. * \param samplingPeriodUs sampling period of sensor in microseconds. - * \param maxBatchReportLatencyus maximum time interval between two batch of sensor events are + * \param maxBatchReportLatencyUs maximum time interval between two batches of sensor events are * delievered in microseconds. For sensor streaming, set to 0. * \return 0 on success or a negative error code on failure. */ @@ -778,7 +793,7 @@ int ASensorEventQueue_hasEvents(ASensorEventQueue* queue); * Retrieve next available events from the queue to a specified event array. * * \param queue {@link ASensorEventQueue} to get events from - * \param events pointer to an array of {@link ASensorEvents}. + * \param events pointer to an array of {@link ASensorEvent}. * \param count max number of event that can be filled into array event. * \return number of events returned on success; negative error code when * no events are pending or an error has occurred. @@ -798,7 +813,7 @@ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* even * Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on * the given {@link ASensorEventQueue}. * - * Sensor data events are always delivered to the {@ASensorEventQueue}. + * Sensor data events are always delivered to the {@link ASensorEventQueue}. * * The {@link ASENSOR_TYPE_ADDITIONAL_INFO} events will be returned through * {@link ASensorEventQueue_getEvents}. The client is responsible for checking @@ -890,7 +905,7 @@ bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21); * * \param sensor a {@link ASensor} to denote the sensor to be checked. * \param channelType Channel type constant, either - * {@ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY} + * {@link ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY} * or {@link ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER}. * \returns true if sensor supports the specified direct channel type. */ @@ -913,15 +928,15 @@ int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_ * Returns the sensor's handle. * * The handle identifies the sensor within the system and is included in the - * {@link ASensorEvent#sensor} field of sensor events, including those sent with type + * sensor field of {@link ASensorEvent}, including those sent with type * {@link ASENSOR_TYPE_ADDITIONAL_INFO}. * * A sensor's handle is able to be used to map {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to the * sensor that generated the event. * * It is important to note that the value returned by {@link ASensor_getHandle} is not the same as - * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists - * between the values. + * the value returned by the Java API <a href="/reference/android/hardware/Sensor#getId()"> + * android.hardware.Sensor's getId()</a> and no mapping exists between the values. * * Available since API level 29. */ diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h index 7994aa9914..e0a8045d41 100644 --- a/include/android/sharedmem.h +++ b/include/android/sharedmem.h @@ -59,9 +59,10 @@ extern "C" { * * Use close() to release the shared memory region. * - * Use {@link android.os.ParcelFileDescriptor} to pass the file descriptor to - * another process. File descriptors may also be sent to other processes over a Unix domain - * socket with sendmsg and SCM_RIGHTS. See sendmsg(3) and cmsg(3) man pages for more information. + * Use <a href="/reference/android/os/ParcelFileDescriptor">android.os.ParcelFileDescriptor</a> + * to pass the file descriptor to another process. File descriptors may also be sent to other + * processes over a Unix domain socket with sendmsg and SCM_RIGHTS. See sendmsg(3) and + * cmsg(3) man pages for more information. * * If you intend to share this file descriptor with a child process after * calling exec(3), note that you will need to use fcntl(2) with FD_SETFD @@ -71,7 +72,8 @@ extern "C" { * * \param name an optional name. * \param size size of the shared memory region - * \return file descriptor that denotes the shared memory; -1 and sets errno on failure, or -EINVAL if the error is that size was 0. + * \return file descriptor that denotes the shared memory; + * -1 and sets errno on failure, or -EINVAL if the error is that size was 0. */ int ASharedMemory_create(const char *name, size_t size) __INTRODUCED_IN(26); diff --git a/include/android/surface_control.h b/include/android/surface_control.h index c5e3587517..b7eafcd6cd 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -147,6 +147,28 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats) __INTRODUCED_IN(29); + +/** + * The ASurfaceTransaction_OnCommit callback is invoked when transaction is applied and the updates + * are ready to be presented. This callback will be invoked before the + * ASurfaceTransaction_OnComplete callback. + * + * \param context Optional context provided by the client that is passed into the callback. + * + * \param stats Opaque handle that can be passed to ASurfaceTransactionStats functions to query + * information about the transaction. The handle is only valid during the callback. + * Present and release fences are not available for this callback. Querying them using + * ASurfaceTransactionStats_getPresentFenceFd and ASurfaceTransactionStats_getPreviousReleaseFenceFd + * will result in failure. + * + * THREADING + * The transaction committed callback can be invoked on any thread. + * + * Available since API level 31. + */ +typedef void (*ASurfaceTransaction_OnCommit)(void* context, ASurfaceTransactionStats* stats) + __INTRODUCED_IN(31); + /** * Returns the timestamp of when the frame was latched by the framework. Once a frame is * latched by the framework, it is presented at the following hardware vsync. @@ -161,6 +183,8 @@ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_ * The recipient of the callback takes ownership of the fence and is responsible for closing * it. If a device does not support present fences, a -1 will be returned. * + * This query is not valid for ASurfaceTransaction_OnCommit callback. + * * Available since API level 29. */ int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats) @@ -218,6 +242,8 @@ int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surfac * The client must ensure that all pending refs on a buffer are released before attempting to reuse * this buffer, otherwise synchronization errors may occur. * + * This query is not valid for ASurfaceTransaction_OnCommit callback. + * * Available since API level 29. */ int ASurfaceTransactionStats_getPreviousReleaseFenceFd( @@ -236,6 +262,16 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* c ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29); /** + * Sets the callback that will be invoked when the updates from this transaction are applied and are + * ready to be presented. This callback will be invoked before the ASurfaceTransaction_OnComplete + * callback. + * + * Available since API level 31. + */ +void ASurfaceTransaction_setOnCommit(ASurfaceTransaction* transaction, void* context, + ASurfaceTransaction_OnCommit func) __INTRODUCED_IN(31); + +/** * Reparents the \a surface_control from its old parent to the \a new_parent surface control. * Any children of the reparented \a surface_control will remain children of the \a surface_control. * @@ -329,39 +365,53 @@ void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction, __INTRODUCED_IN(29); /** - * \param source The sub-rect within the buffer's content to be rendered inside the surface's area - * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width - * and height must be > 0. + * Bounds the surface and its children to the bounds specified. The crop and buffer size will be + * used to determine the bounds of the surface. If no crop is specified and the surface has no + * buffer, the surface bounds is only constrained by the size of its parent bounds. + * + * \param crop The bounds of the crop to apply. * * Available since API level 31. */ -void ASurfaceTransaction_setSourceRect(ASurfaceTransaction* transaction, - ASurfaceControl* surface_control, const ARect& source) +void ASurfaceTransaction_setCrop(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control, const ARect& crop) __INTRODUCED_IN(31); /** - * \param destination Specifies the rect in the parent's space where this surface will be drawn. The - * post source rect bounds are scaled to fit the destination rect. The surface's destination rect is - * clipped by the bounds of its parent. The destination rect's width and height must be > 0. + * Specifies the position in the parent's space where the surface will be drawn. + * + * \param x The x position to render the surface. + * \param y The y position to render the surface. * * Available since API level 31. */ void ASurfaceTransaction_setPosition(ASurfaceTransaction* transaction, - ASurfaceControl* surface_control, const ARect& destination) + ASurfaceControl* surface_control, int32_t x, int32_t y) __INTRODUCED_IN(31); /** * \param transform The transform applied after the source rect is applied to the buffer. This - * parameter should be set to 0 for no transform. To specify a transfrom use the + * parameter should be set to 0 for no transform. To specify a transform use the * NATIVE_WINDOW_TRANSFORM_* enum. * * Available since API level 31. */ -void ASurfaceTransaction_setTransform(ASurfaceTransaction* transaction, +void ASurfaceTransaction_setBufferTransform(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, int32_t transform) __INTRODUCED_IN(31); /** + * Sets an x and y scale of a surface with (0, 0) as the centerpoint of the scale. + * + * \param xScale The scale in the x direction. Must be greater than 0. + * \param yScale The scale in the y direction. Must be greater than 0. + * + * Available since API level 31. + */ +void ASurfaceTransaction_setScale(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control, float xScale, float yScale) + __INTRODUCED_IN(31); +/** * Parameter for ASurfaceTransaction_setBufferTransparency(). */ enum { diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h index 4757254cc0..9ae211ea14 100644 --- a/include/android/surface_texture.h +++ b/include/android/surface_texture.h @@ -86,8 +86,8 @@ ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) __INTRO /** * Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread. A * new OpenGL ES texture object is created and populated with the SurfaceTexture image frame - * that was current at the time of the last call to {@link #detachFromGLContext}. This new - * texture is bound to the GL_TEXTURE_EXTERNAL_OES texture target. + * that was current at the time of the last call to {@link ASurfaceTexture_detachFromGLContext}. + * This new texture is bound to the GL_TEXTURE_EXTERNAL_OES texture target. * * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES * contexts. Note, however, that the image contents are only accessible from one OpenGL ES @@ -106,8 +106,8 @@ int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName) __I * Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object. * This call must be made with the OpenGL ES context current on the calling thread. The OpenGL * ES texture object will be deleted as a result of this call. After calling this method all - * calls to {@link #updateTexImage} will fail until a successful call to {@link #attachToGLContext} - * is made. + * calls to {@link ASurfaceTexture_updateTexImage} will fail until a successful call to + * {@link ASurfaceTexture_attachToGLContext} is made. * * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES * contexts. Note, however, that the image contents are only accessible from one OpenGL ES diff --git a/include/android/thermal.h b/include/android/thermal.h index 0ea13d3a8d..32580badc0 100644 --- a/include/android/thermal.h +++ b/include/android/thermal.h @@ -60,6 +60,10 @@ extern "C" { #endif +/** + * Thermal status used in function {@link AThermal_getCurrentThermalStatus} and + * {@link AThermal_StatusCallback}. + */ enum AThermalStatus { /** Error in thermal status. */ ATHERMAL_STATUS_ERROR = -1, @@ -194,10 +198,10 @@ int AThermal_unregisterThermalStatusListener(AThermalManager *manager, * * The value returned is a non-negative float that represents how much of the thermal envelope * is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is - * (or will be) throttled at {@link #THERMAL_STATUS_SEVERE}. Such throttling can affect the + * (or will be) throttled at {@link #ATHERMAL_STATUS_SEVERE}. Such throttling can affect the * CPU, GPU, and other subsystems. Values may exceed 1.0, but there is no implied mapping * to specific thermal levels beyond that point. This means that values greater than 1.0 - * may correspond to {@link #THERMAL_STATUS_SEVERE}, but may also represent heavier throttling. + * may correspond to {@link #ATHERMAL_STATUS_SEVERE}, but may also represent heavier throttling. * * A value of 0.0 corresponds to a fixed distance from 1.0, but does not correspond to any * particular thermal status or temperature. Values on (0.0, 1.0] may be expected to scale diff --git a/include/android/trace.h b/include/android/trace.h index dcefffb20d..d11158bb74 100644 --- a/include/android/trace.h +++ b/include/android/trace.h @@ -91,7 +91,7 @@ void ATrace_beginAsyncSection(const char* sectionName, int32_t cookie) __INTRODU * * Available since API level 29. * - * \param methodName The method name to appear in the trace. + * \param sectionName The method name to appear in the trace. * \param cookie Unique identifier for distinguishing simultaneous events */ void ATrace_endAsyncSection(const char* sectionName, int32_t cookie) __INTRODUCED_IN(29); diff --git a/include/android/window.h b/include/android/window.h index 436bf3a830..c1448646b6 100644 --- a/include/android/window.h +++ b/include/android/window.h @@ -103,8 +103,9 @@ enum { * bar) while this window is displayed. This allows the window to * use the entire display space for itself -- the status bar will * be hidden when an app window with this flag set is on the top - * layer. A fullscreen window will ignore a value of {@link - * AWINDOW_SOFT_INPUT_ADJUST_RESIZE}; the window will stay + * layer. A fullscreen window will ignore a value of + * <a href="/reference/android/view/WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE"> + * SOFT_INPUT_ADJUST_RESIZE</a>; the window will stay * fullscreen and will not resize. */ AWINDOW_FLAG_FULLSCREEN = 0x00000400, diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index e980dd04ec..a97cf87de3 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -60,10 +60,6 @@ cc_library_headers { // Currently, these are only on system android (not vendor, not host) // TODO(b/183654927) - move these into separate libraries libbinder_device_interface_sources = [ - "AppOpsManager.cpp", - "IAppOpsCallback.cpp", - "IAppOpsService.cpp", - "IPermissionController.cpp", "PermissionCache.cpp", "PermissionController.cpp", @@ -160,6 +156,7 @@ cc_library { "-Werror", "-Wzero-as-null-pointer-constant", "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION", + "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", ], product_variables: { binder32bit: { @@ -192,6 +189,9 @@ cc_library { // Only check our headers "--header-filter=^.*frameworks/native/libs/binder/.*.h$", ], + tidy_checks: [ + "-performance-no-int-to-ptr", + ], tidy_checks_as_errors: [ // Explicitly list the checks that should not occur in this module. "abseil-*", @@ -199,20 +199,9 @@ cc_library { "bugprone-*", "cert-*", "clang-analyzer-*", - "-clang-analyzer-core.CallAndMessage", - "-clang-analyzer-core.uninitialized.Assign", - "-clang-analyzer-unix.Malloc", - "-clang-analyzer-deadcode.DeadStores", - "-clang-analyzer-optin.cplusplus.UninitializedObject", "google-*", - "-google-readability-*", - "-google-runtime-references", "misc-*", - "-misc-no-recursion", - "-misc-redundant-expression", - "-misc-unused-using-decls", "performance*", - "-performance-no-int-to-ptr", "portability*", ], diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 53b36fffdc..fdcf94acfa 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -107,8 +107,7 @@ void BpBinder::ObjectManager::kill() // --------------------------------------------------------------------------- - -BpBinder* BpBinder::create(int32_t handle) { +sp<BpBinder> BpBinder::create(int32_t handle) { int32_t trackedUid = -1; if (sCountByUidEnabled) { trackedUid = IPCThreadState::self()->getCallingUid(); @@ -134,10 +133,10 @@ BpBinder* BpBinder::create(int32_t handle) { } sTrackingMap[trackedUid]++; } - return new BpBinder(BinderHandle{handle}, trackedUid); + return sp<BpBinder>::make(BinderHandle{handle}, trackedUid); } -BpBinder* BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress& address) { +sp<BpBinder> BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress& address) { LOG_ALWAYS_FATAL_IF(connection == nullptr, "BpBinder::create null connection"); // These are not currently tracked, since there is no UID or other @@ -145,7 +144,7 @@ BpBinder* BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress // needed, connection objects keep track of all BpBinder objects on a // per-connection basis. - return new BpBinder(SocketHandle{connection, address}); + return sp<BpBinder>::make(SocketHandle{connection, address}); } BpBinder::BpBinder(Handle&& handle) @@ -194,7 +193,7 @@ bool BpBinder::isDescriptorCached() const { const String16& BpBinder::getInterfaceDescriptor() const { if (isDescriptorCached() == false) { - sp<BpBinder> thiz = const_cast<BpBinder*>(this); + sp<BpBinder> thiz = sp<BpBinder>::fromExisting(const_cast<BpBinder*>(this)); Parcel data; data.markForBinder(thiz); @@ -226,7 +225,7 @@ bool BpBinder::isBinderAlive() const status_t BpBinder::pingBinder() { Parcel data; - data.markForBinder(this); + data.markForBinder(sp<BpBinder>::fromExisting(this)); Parcel reply; return transact(PING_TRANSACTION, data, &reply); } @@ -403,7 +402,7 @@ void BpBinder::reportOneDeath(const Obituary& obit) ALOGV("Reporting death to recipient: %p\n", recipient.get()); if (recipient == nullptr) return; - recipient->binderDied(this); + recipient->binderDied(wp<BpBinder>::fromExisting(this)); } diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp index 349658ecfa..a90bfd29ba 100644 --- a/libs/binder/BufferedTextOutput.cpp +++ b/libs/binder/BufferedTextOutput.cpp @@ -254,7 +254,7 @@ BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const BufferState* bs = ts.states[mIndex].get(); if (bs != nullptr && bs->seq == mSeq) return bs; - ts.states.editItemAt(mIndex) = new BufferState(mIndex); + ts.states.editItemAt(mIndex) = sp<BufferState>::make(mIndex); bs = ts.states[mIndex].get(); if (bs != nullptr) return bs; } diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp index b19004d454..2780bd4cd9 100644 --- a/libs/binder/IInterface.cpp +++ b/libs/binder/IInterface.cpp @@ -33,14 +33,14 @@ IInterface::~IInterface() { sp<IBinder> IInterface::asBinder(const IInterface* iface) { if (iface == nullptr) return nullptr; - return const_cast<IInterface*>(iface)->onAsBinder(); + return sp<IBinder>::fromExisting(const_cast<IInterface*>(iface)->onAsBinder()); } // static sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface) { if (iface == nullptr) return nullptr; - return iface->onAsBinder(); + return sp<IBinder>::fromExisting(iface->onAsBinder()); } diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index cca8f81e45..bd974b02b1 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -68,7 +68,7 @@ private: // TODO: Reimplemement based on standard C++ container? }; -static sp<HeapCache> gHeapCache = new HeapCache(); +static sp<HeapCache> gHeapCache = sp<HeapCache>::make(); /******************************************************************************/ @@ -288,7 +288,7 @@ void BpMemoryHeap::assertMapped() const int32_t heapId = mHeapId.load(memory_order_acquire); if (heapId == -1) { sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this))); - sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get())); + sp<BpMemoryHeap> heap = sp<BpMemoryHeap>::cast(find_heap(binder)); heap->assertReallyMapped(); if (heap->mBase != MAP_FAILED) { Mutex::Autolock _l(mLock); diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 406bd54e6f..6fb1227f63 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -90,6 +90,8 @@ static const char *kReturnStrings[] = { "BR_DEAD_BINDER", "BR_CLEAR_DEATH_NOTIFICATION_DONE", "BR_FAILED_REPLY", + "BR_FROZEN_REPLY", + "BR_ONEWAY_SPAM_SUSPECT", "BR_TRANSACTION_SEC_CTX", }; @@ -894,6 +896,11 @@ status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) } switch (cmd) { + case BR_ONEWAY_SPAM_SUSPECT: + ALOGE("Process seems to be sending too many oneway calls."); + CallStack::logStack("oneway spamming", CallStack::getCurrent().get(), + ANDROID_LOG_ERROR); + [[fallthrough]]; case BR_TRANSACTION_COMPLETE: if (!reply && !acquireResult) goto finish; break; diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index ca067e2d7f..f684cf672f 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -75,6 +75,7 @@ public: sp<IBinder> waitForService(const String16& name16) override; bool isDeclared(const String16& name) override; Vector<String16> getDeclaredInstances(const String16& interface) override; + std::optional<String16> updatableViaApex(const String16& name) override; // for legacy ABI const String16& getInterfaceDescriptor() const override { @@ -102,7 +103,7 @@ sp<IServiceManager> defaultServiceManager() } } - gDefaultServiceManager = new ServiceManagerShim(sm); + gDefaultServiceManager = sp<ServiceManagerShim>::make(sm); }); return gDefaultServiceManager; @@ -324,7 +325,7 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) } if (out != nullptr) return out; - sp<Waiter> waiter = new Waiter; + sp<Waiter> waiter = sp<Waiter>::make(); if (!mTheRealServiceManager->registerForNotifications( name, waiter).isOk()) { return nullptr; @@ -388,4 +389,12 @@ Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interf return res; } +std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& name) { + std::optional<std::string> declared; + if (!mTheRealServiceManager->updatableViaApex(String8(name).c_str(), &declared).isOk()) { + return std::nullopt; + } + return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt; +} + } // namespace android diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp index f96b6bb4eb..b503bebc5e 100644 --- a/libs/binder/LazyServiceRegistrar.cpp +++ b/libs/binder/LazyServiceRegistrar.cpp @@ -129,7 +129,9 @@ bool ClientCounterCallbackImpl::registerService(const sp<IBinder>& service, cons } if (!reRegister) { - if(!manager->registerClientCallback(name, service, this).isOk()) { + if (!manager->registerClientCallback(name, service, + sp<android::os::IClientCallback>::fromExisting(this)) + .isOk()) { ALOGE("Failed to add client callback for service %s", name.c_str()); return false; } diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp index b46b3e88fc..c4475c7780 100644 --- a/libs/binder/MemoryDealer.cpp +++ b/libs/binder/MemoryDealer.cpp @@ -228,10 +228,8 @@ Allocation::~Allocation() // ---------------------------------------------------------------------------- MemoryDealer::MemoryDealer(size_t size, const char* name, uint32_t flags) - : mHeap(new MemoryHeapBase(size, flags, name)), - mAllocator(new SimpleBestFitAllocator(size)) -{ -} + : mHeap(sp<MemoryHeapBase>::make(size, flags, name)), + mAllocator(new SimpleBestFitAllocator(size)) {} MemoryDealer::~MemoryDealer() { @@ -243,7 +241,7 @@ sp<IMemory> MemoryDealer::allocate(size_t size) sp<IMemory> memory; const ssize_t offset = allocator()->allocate(size); if (offset >= 0) { - memory = new Allocation(this, heap(), offset, size); + memory = sp<Allocation>::make(sp<MemoryDealer>::fromExisting(this), heap(), offset, size); } return memory; } diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 0425159f63..a73530938c 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -293,7 +293,8 @@ status_t Parcel::unflattenBinder(sp<IBinder>* out) const if (flat) { switch (flat->hdr.type) { case BINDER_TYPE_BINDER: { - sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie); + sp<IBinder> binder = + sp<IBinder>::fromExisting(reinterpret_cast<IBinder*>(flat->cookie)); return finishUnflattenBinder(binder, out); } case BINDER_TYPE_HANDLE: { diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index abb792eda0..1d3beb4736 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -43,6 +43,7 @@ #define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2) #define DEFAULT_MAX_BINDER_THREADS 15 +#define DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION 1 #ifdef __ANDROID_VNDK__ const char* kDefaultDriver = "/dev/vndbinder"; @@ -105,7 +106,7 @@ sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault) } std::lock_guard<std::mutex> l(gProcessMutex); - gProcess = new ProcessState(driver); + gProcess = sp<ProcessState>::make(driver); }); if (requireDefault) { @@ -299,8 +300,8 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) return nullptr; } - b = BpBinder::create(handle); - e->binder = b; + sp<BpBinder> b = BpBinder::create(handle); + e->binder = b.get(); if (b) e->refs = b->getWeakRefs(); result = b; } else { @@ -340,7 +341,7 @@ void ProcessState::spawnPooledThread(bool isMain) if (mThreadPoolStarted) { String8 name = makeBinderThreadName(); ALOGV("Spawning new pooled thread, name=%s\n", name.string()); - sp<Thread> t = new PoolThread(isMain); + sp<Thread> t = sp<PoolThread>::make(isMain); t->run(name.string()); } } @@ -358,6 +359,15 @@ status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { return result; } +status_t ProcessState::enableOnewaySpamDetection(bool enable) { + uint32_t enableDetection = enable ? 1 : 0; + if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) { + ALOGI("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno)); + return -errno; + } + return NO_ERROR; +} + void ProcessState::giveThreadPoolName() { androidSetThreadName( makeBinderThreadName().string() ); } @@ -388,6 +398,11 @@ static int open_driver(const char *driver) if (result == -1) { ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); } + uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION; + result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable); + if (result == -1) { + ALOGI("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/RpcConnection.cpp b/libs/binder/RpcConnection.cpp index dab3246fc5..1388a801e4 100644 --- a/libs/binder/RpcConnection.cpp +++ b/libs/binder/RpcConnection.cpp @@ -18,6 +18,16 @@ #include <binder/RpcConnection.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#include <unistd.h> + +#include <string_view> + #include <binder/Parcel.h> #include <binder/Stability.h> #include <utils/String8.h> @@ -25,11 +35,6 @@ #include "RpcState.h" #include "RpcWireFormat.h" -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/un.h> -#include <unistd.h> - #ifdef __GLIBC__ extern "C" pid_t gettid(); #endif @@ -41,6 +46,7 @@ extern "C" pid_t gettid(); namespace android { using base::unique_fd; +using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>; RpcConnection::SocketAddress::~SocketAddress() {} @@ -51,17 +57,22 @@ RpcConnection::RpcConnection() { } RpcConnection::~RpcConnection() { LOG_RPC_DETAIL("RpcConnection destroyed %p", this); + + std::lock_guard<std::mutex> _l(mSocketMutex); + LOG_ALWAYS_FATAL_IF(mServers.size() != 0, + "Should not be able to destroy a connection with servers in use."); } sp<RpcConnection> RpcConnection::make() { - return new RpcConnection; + return sp<RpcConnection>::make(); } class UnixSocketAddress : public RpcConnection::SocketAddress { public: explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) { unsigned int pathLen = strlen(path) + 1; - LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "%u %s", pathLen, path); + LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s", + pathLen, path); memcpy(mAddr.sun_path, path, pathLen); } virtual ~UnixSocketAddress() {} @@ -78,11 +89,11 @@ private: }; bool RpcConnection::setupUnixDomainServer(const char* path) { - return addServer(UnixSocketAddress(path)); + return setupSocketServer(UnixSocketAddress(path)); } bool RpcConnection::addUnixDomainClient(const char* path) { - return addClient(UnixSocketAddress(path)); + return addSocketClient(UnixSocketAddress(path)); } #ifdef __BIONIC__ @@ -97,7 +108,7 @@ public: }) {} virtual ~VsockSocketAddress() {} std::string toString() const override { - return String8::format("cid %du port %du", mAddr.svm_cid, mAddr.svm_port).c_str(); + return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str(); } const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); } size_t addrSize() const override { return sizeof(mAddr); } @@ -110,63 +121,140 @@ bool RpcConnection::setupVsockServer(unsigned int port) { // realizing value w/ this type at compile time to avoid ubsan abort constexpr unsigned int kAnyCid = VMADDR_CID_ANY; - return addServer(VsockSocketAddress(kAnyCid, port)); + return setupSocketServer(VsockSocketAddress(kAnyCid, port)); } bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) { - return addClient(VsockSocketAddress(cid, port)); + return addSocketClient(VsockSocketAddress(cid, port)); } #endif // __BIONIC__ +class SocketAddressImpl : public RpcConnection::SocketAddress { +public: + SocketAddressImpl(const sockaddr* addr, size_t size, const String8& desc) + : mAddr(addr), mSize(size), mDesc(desc) {} + [[nodiscard]] std::string toString() const override { + return std::string(mDesc.c_str(), mDesc.size()); + } + [[nodiscard]] const sockaddr* addr() const override { return mAddr; } + [[nodiscard]] size_t addrSize() const override { return mSize; } + void set(const sockaddr* addr, size_t size) { + mAddr = addr; + mSize = size; + } + +private: + const sockaddr* mAddr = nullptr; + size_t mSize = 0; + String8 mDesc; +}; + +AddrInfo GetAddrInfo(const char* addr, unsigned int port) { + addrinfo hint{ + .ai_flags = 0, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = 0, + }; + addrinfo* aiStart = nullptr; + if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) { + ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc)); + return AddrInfo(nullptr, nullptr); + } + if (aiStart == nullptr) { + ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port); + return AddrInfo(nullptr, nullptr); + } + return AddrInfo(aiStart, &freeaddrinfo); +} + +bool RpcConnection::setupInetServer(unsigned int port) { + auto aiStart = GetAddrInfo("127.0.0.1", port); + if (aiStart == nullptr) return false; + SocketAddressImpl socketAddress(nullptr, 0, String8::format("127.0.0.1:%u", port)); + for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) { + socketAddress.set(ai->ai_addr, ai->ai_addrlen); + if (setupSocketServer(socketAddress)) return true; + } + ALOGE("None of the socket address resolved for 127.0.0.1:%u can be set up as inet server.", + port); + return false; +} + +bool RpcConnection::addInetClient(const char* addr, unsigned int port) { + auto aiStart = GetAddrInfo(addr, port); + if (aiStart == nullptr) return false; + SocketAddressImpl socketAddress(nullptr, 0, String8::format("%s:%u", addr, port)); + for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) { + socketAddress.set(ai->ai_addr, ai->ai_addrlen); + if (addSocketClient(socketAddress)) return true; + } + ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port); + return false; +} + +bool RpcConnection::addNullDebuggingClient() { + 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; + } + + addClient(std::move(serverFd)); + return true; +} + sp<IBinder> RpcConnection::getRootObject() { - ExclusiveSocket socket(this, SocketUse::CLIENT); - return state()->getRootObject(socket.fd(), this); + ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT); + return state()->getRootObject(socket.fd(), sp<RpcConnection>::fromExisting(this)); } status_t RpcConnection::transact(const RpcAddress& address, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - ExclusiveSocket socket(this, + ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), (flags & IBinder::FLAG_ONEWAY) ? SocketUse::CLIENT_ASYNC : SocketUse::CLIENT); - return state()->transact(socket.fd(), address, code, data, this, reply, flags); + return state()->transact(socket.fd(), address, code, data, + sp<RpcConnection>::fromExisting(this), reply, flags); } status_t RpcConnection::sendDecStrong(const RpcAddress& address) { - ExclusiveSocket socket(this, SocketUse::CLIENT_REFCOUNT); + ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT_REFCOUNT); return state()->sendDecStrong(socket.fd(), address); } void RpcConnection::join() { - // establish a connection - { - unique_fd clientFd( - TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC))); - if (clientFd < 0) { - // If this log becomes confusing, should save more state from setupUnixDomainServer - // in order to output here. - ALOGE("Could not accept4 socket: %s", strerror(errno)); - return; - } - - LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get()); - - assignServerToThisThread(std::move(clientFd)); + // TODO(b/185167543): do this dynamically, instead of from a static number + // of threads + unique_fd clientFd( + TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC))); + if (clientFd < 0) { + // If this log becomes confusing, should save more state from setupUnixDomainServer + // in order to output here. + ALOGE("Could not accept4 socket: %s", strerror(errno)); + return; } - // We may not use the connection we just established (two threads might - // establish connections for each other), but for now, just use one - // server/socket connection. - ExclusiveSocket socket(this, SocketUse::SERVER); + LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get()); + + // 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<ConnectionSocket> socket = assignServerToThisThread(std::move(clientFd)); while (true) { - status_t error = state()->getAndExecuteCommand(socket.fd(), this); + status_t error = + state()->getAndExecuteCommand(socket->fd, sp<RpcConnection>::fromExisting(this)); if (error != OK) { ALOGI("Binder socket thread closing w/ status %s", statusToString(error).c_str()); - return; + break; } } + + LOG_ALWAYS_FATAL_IF(!removeServerSocket(socket), + "bad state: socket object guaranteed to be in list"); } void RpcConnection::setForServer(const wp<RpcServer>& server) { @@ -177,7 +265,7 @@ wp<RpcServer> RpcConnection::server() { return mForServer; } -bool RpcConnection::addServer(const SocketAddress& addr) { +bool RpcConnection::setupSocketServer(const SocketAddress& addr) { LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server."); unique_fd serverFd( @@ -203,7 +291,7 @@ bool RpcConnection::addServer(const SocketAddress& addr) { return true; } -bool RpcConnection::addClient(const SocketAddress& addr) { +bool RpcConnection::addSocketClient(const SocketAddress& addr) { unique_fd serverFd( TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0))); if (serverFd == -1) { @@ -220,18 +308,34 @@ bool RpcConnection::addClient(const SocketAddress& addr) { LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get()); + addClient(std::move(serverFd)); + return true; +} + +void RpcConnection::addClient(unique_fd&& fd) { std::lock_guard<std::mutex> _l(mSocketMutex); - sp<ConnectionSocket> connection = new ConnectionSocket(); - connection->fd = std::move(serverFd); + sp<ConnectionSocket> connection = sp<ConnectionSocket>::make(); + connection->fd = std::move(fd); mClients.push_back(connection); - return true; } -void RpcConnection::assignServerToThisThread(base::unique_fd&& fd) { +sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd&& fd) { std::lock_guard<std::mutex> _l(mSocketMutex); - sp<ConnectionSocket> connection = new ConnectionSocket(); + sp<ConnectionSocket> connection = sp<ConnectionSocket>::make(); connection->fd = std::move(fd); + connection->exclusiveTid = gettid(); mServers.push_back(connection); + + return connection; +} + +bool RpcConnection::removeServerSocket(const sp<ConnectionSocket>& socket) { + std::lock_guard<std::mutex> _l(mSocketMutex); + if (auto it = std::find(mServers.begin(), mServers.end(), socket); it != mServers.end()) { + mServers.erase(it); + return true; + } + return false; } RpcConnection::ExclusiveSocket::ExclusiveSocket(const sp<RpcConnection>& connection, SocketUse use) @@ -246,37 +350,31 @@ RpcConnection::ExclusiveSocket::ExclusiveSocket(const sp<RpcConnection>& connect // CHECK FOR DEDICATED CLIENT SOCKET // - // A server/looper should always use a dedicated connection. - if (use != SocketUse::SERVER) { - findSocket(tid, &exclusive, &available, mConnection->mClients, - mConnection->mClientsOffset); - - // WARNING: this assumes a server cannot request its client to send - // a transaction, as mServers is excluded below. - // - // Imagine we have more than one thread in play, and a single thread - // sends a synchronous, then an asynchronous command. Imagine the - // asynchronous command is sent on the first client socket. Then, if - // we naively send a synchronous command to that same socket, the - // thread on the far side might be busy processing the asynchronous - // command. So, we move to considering the second available thread - // for subsequent calls. - if (use == SocketUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) { - mConnection->mClientsOffset = - (mConnection->mClientsOffset + 1) % mConnection->mClients.size(); - } + // A server/looper should always use a dedicated connection if available + findSocket(tid, &exclusive, &available, mConnection->mClients, mConnection->mClientsOffset); + + // WARNING: this assumes a server cannot request its client to send + // a transaction, as mServers is excluded below. + // + // Imagine we have more than one thread in play, and a single thread + // sends a synchronous, then an asynchronous command. Imagine the + // asynchronous command is sent on the first client socket. Then, if + // we naively send a synchronous command to that same socket, the + // thread on the far side might be busy processing the asynchronous + // command. So, we move to considering the second available thread + // for subsequent calls. + if (use == SocketUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) { + mConnection->mClientsOffset = + (mConnection->mClientsOffset + 1) % mConnection->mClients.size(); } - // USE SERVING SOCKET (to start serving or for nested transaction) + // USE SERVING SOCKET (for nested transaction) // // asynchronous calls cannot be nested if (use != SocketUse::CLIENT_ASYNC) { - // servers should start serving on an available thread only - // otherwise, this should only be a nested call - bool useAvailable = use == SocketUse::SERVER; - - findSocket(tid, &exclusive, (useAvailable ? &available : nullptr), - mConnection->mServers, 0 /* index hint */); + // server sockets are always assigned to a thread + findSocket(tid, &exclusive, nullptr /*available*/, mConnection->mServers, + 0 /* index hint */); } // if our thread is already using a connection, prioritize using that @@ -290,8 +388,6 @@ RpcConnection::ExclusiveSocket::ExclusiveSocket(const sp<RpcConnection>& connect break; } - LOG_ALWAYS_FATAL_IF(use == SocketUse::SERVER, "Must create connection to join one."); - // in regular binder, this would usually be a deadlock :) LOG_ALWAYS_FATAL_IF(mConnection->mClients.size() == 0, "Not a client of any connection. You must create a connection to an " diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index df07916f7a..1fa37bacb3 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -36,7 +36,7 @@ RpcServer::RpcServer() {} RpcServer::~RpcServer() {} sp<RpcServer> RpcServer::make() { - return new RpcServer; + return sp<RpcServer>::make(); } void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() { @@ -47,7 +47,7 @@ sp<RpcConnection> RpcServer::addClientConnection() { LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!"); auto connection = RpcConnection::make(); - connection->setForServer(this); + connection->setForServer(sp<RpcServer>::fromExisting(this)); mConnections.push_back(connection); return connection; } diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 755ff35781..d9341369fa 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -40,7 +40,7 @@ status_t RpcState::onBinderLeaving(const sp<RpcConnection>& connection, const sp // We need to be able to send instructions over the socket for how to // connect to a different server, and we also need to let the host // process know that this is happening. - ALOGE("Canot send binder from unrelated binder RPC connection."); + ALOGE("Cannot send binder from unrelated binder RPC connection."); return INVALID_OPERATION; } @@ -498,19 +498,20 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, } } - Parcel data; - // transaction->data is owned by this function. Parcel borrows this data and - // only holds onto it for the duration of this function call. Parcel will be - // deleted before the 'transactionData' object. - data.ipcSetDataReference(transaction->data, - transactionData.size() - offsetof(RpcWireTransaction, data), - nullptr /*object*/, 0 /*objectCount*/, do_nothing_to_transact_data); - data.markForRpc(connection); - Parcel reply; reply.markForRpc(connection); if (replyStatus == OK) { + Parcel data; + // transaction->data is owned by this function. Parcel borrows this data and + // only holds onto it for the duration of this function call. Parcel will be + // deleted before the 'transactionData' object. + data.ipcSetDataReference(transaction->data, + transactionData.size() - offsetof(RpcWireTransaction, data), + nullptr /*object*/, 0 /*objectCount*/, + do_nothing_to_transact_data); + data.markForRpc(connection); + if (target) { replyStatus = target->transact(transaction->code, data, &reply, transaction->flags); } else { diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl index 2fabf947cd..75c4092559 100644 --- a/libs/binder/aidl/android/os/IServiceManager.aidl +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -108,6 +108,11 @@ interface IServiceManager { @utf8InCpp String[] getDeclaredInstances(@utf8InCpp String iface); /** + * If updatable-via-apex, returns the APEX via which this is updated. + */ + @nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name); + + /** * Request a callback when the number of clients of the service changes. * Used by LazyServiceRegistrar to dynamically stop services that have no clients. */ diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 7079544080..7e9be417e1 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -131,8 +131,8 @@ protected: virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); - inline IBinder* remote() { return mRemote; } - inline IBinder* remote() const { return mRemote; } + inline IBinder* remote() const { return mRemote; } + inline sp<IBinder> remoteStrong() const { return sp<IBinder>::fromExisting(mRemote); } private: BpRefBase(const BpRefBase& o); diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 8ab789318d..ad618f9de4 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -40,8 +40,8 @@ using binder_proxy_limit_callback = void(*)(int); class BpBinder : public IBinder { public: - static BpBinder* create(int32_t handle); - static BpBinder* create(const sp<RpcConnection>& connection, const RpcAddress& address); + static sp<BpBinder> create(int32_t handle); + static sp<BpBinder> create(const sp<RpcConnection>& connection, const RpcAddress& address); /** * Return value: @@ -143,6 +143,7 @@ public: private: friend PrivateAccessorForId; + friend class sp<BpBinder>; struct BinderHandle { int32_t handle; diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index b86fc0b629..ff90b30380 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -143,11 +143,10 @@ public: \ { \ ::android::sp<I##INTERFACE> intr; \ if (obj != nullptr) { \ - intr = static_cast<I##INTERFACE*>( \ - obj->queryLocalInterface( \ - I##INTERFACE::descriptor).get()); \ + intr = ::android::sp<I##INTERFACE>::cast( \ + obj->queryLocalInterface(I##INTERFACE::descriptor)); \ if (intr == nullptr) { \ - intr = new Bp##INTERFACE(obj); \ + intr = ::android::sp<Bp##INTERFACE>::make(obj); \ } \ } \ return intr; \ diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 5f0d056c5d..3dbe2c49f4 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -20,6 +20,8 @@ #include <utils/Vector.h> #include <utils/String16.h> +#include <optional> + namespace android { // ---------------------------------------------------------------------- @@ -99,6 +101,12 @@ public: * Get all instances of a service as declared in the VINTF manifest */ virtual Vector<String16> getDeclaredInstances(const String16& interface) = 0; + + /** + * If this instance is updatable via an APEX, returns the APEX with which + * this can be updated. + */ + virtual std::optional<String16> updatableViaApex(const String16& name) = 0; }; sp<IServiceManager> defaultServiceManager(); diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 211790d14c..957837233b 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -101,6 +101,10 @@ public: // is for an RPC transaction). void markForBinder(const sp<IBinder>& binder); + // Whenever possible, markForBinder should be preferred. This method is + // called automatically on reply Parcels for RPC transactions. + void markForRpc(const sp<RpcConnection>& connection); + // Whether this Parcel is written for RPC transactions (after calls to // markForBinder or markForRpc). bool isForRpc() const; @@ -536,10 +540,6 @@ private: const binder_size_t* objects, size_t objectsCount, release_func relFunc); - // Whenever possible, markForBinder should be preferred. This method is - // called automatically on reply Parcels for RPC transactions. - void markForRpc(const sp<RpcConnection>& connection); - status_t finishWrite(size_t len); void releaseObjects(); void acquireObjects(); diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index ca29440e7c..b9db5d726c 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -58,6 +58,7 @@ public: void spawnPooledThread(bool isMain); status_t setThreadPoolMaxThreadCount(size_t maxThreads); + status_t enableOnewaySpamDetection(bool enable); void giveThreadPoolName(); String8 getDriverName(); @@ -88,7 +89,8 @@ private: static sp<ProcessState> init(const char *defaultDriver, bool requireDefault); friend class IPCThreadState; - + friend class sp<ProcessState>; + explicit ProcessState(const char* driver); ~ProcessState(); diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h index efa922dbda..2395e78de2 100644 --- a/libs/binder/include/binder/RpcConnection.h +++ b/libs/binder/include/binder/RpcConnection.h @@ -74,6 +74,25 @@ public: #endif // __BIONIC__ /** + * Creates an RPC server at the current port. + */ + [[nodiscard]] bool setupInetServer(unsigned int port); + + /** + * Connects to an RPC server at the given address and port. + */ + [[nodiscard]] bool addInetClient(const char* addr, unsigned int port); + + /** + * For debugging! + * + * Sets up an empty socket. All queries to this socket which require a + * response will never be satisfied. All data sent here will be + * unceremoniously cast down the bottomless pit, /dev/null. + */ + [[nodiscard]] bool addNullDebuggingClient(); + + /** * Query the other side of the connection for the root object hosted by that * process's RpcServer (if one exists) */ @@ -109,10 +128,6 @@ private: friend sp<RpcConnection>; RpcConnection(); - bool addServer(const SocketAddress& address); - bool addClient(const SocketAddress& address); - void assignServerToThisThread(base::unique_fd&& fd); - struct ConnectionSocket : public RefBase { base::unique_fd fd; @@ -121,11 +136,16 @@ private: std::optional<pid_t> exclusiveTid; }; + bool setupSocketServer(const SocketAddress& address); + bool addSocketClient(const SocketAddress& address); + void addClient(base::unique_fd&& fd); + sp<ConnectionSocket> assignServerToThisThread(base::unique_fd&& fd); + bool removeServerSocket(const sp<ConnectionSocket>& socket); + enum class SocketUse { CLIENT, CLIENT_ASYNC, CLIENT_REFCOUNT, - SERVER, }; // RAII object for connection socket diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index a2c2aee7b8..d29b651f0b 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -72,6 +72,7 @@ public: ~RpcServer(); private: + friend sp<RpcServer>; RpcServer(); bool mAgreedExperimental = false; diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h index c30ae01d60..aaafa36d40 100644 --- a/libs/binder/include/binder/Status.h +++ b/libs/binder/include/binder/Status.h @@ -91,6 +91,9 @@ public: static Status fromExceptionCode(int32_t exceptionCode, const char* message); + // warning: this is still considered an error if it is constructed with a + // zero value error code. Please use Status::ok() instead and avoid zero + // error codes static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode); static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode, const String8& message); diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h index 157919903f..151235c16b 100644 --- a/libs/binder/include/private/binder/binder_module.h +++ b/libs/binder/include/private/binder/binder_module.h @@ -32,10 +32,6 @@ #include <sys/ioctl.h> #include <linux/android/binder.h> -#ifdef __cplusplus -namespace android { -#endif - #ifndef BR_FROZEN_REPLY // Temporary definition of BR_FROZEN_REPLY. For production // this will come from UAPI binder.h @@ -88,8 +84,18 @@ struct binder_frozen_status_info { }; #endif //BINDER_GET_FROZEN_INFO -#ifdef __cplusplus -} // namespace android -#endif +#ifndef BR_ONEWAY_SPAM_SUSPECT +// Temporary definition of BR_ONEWAY_SPAM_SUSPECT. For production +// this will come from UAPI binder.h +#define BR_ONEWAY_SPAM_SUSPECT _IO('r', 19) +#endif //BR_ONEWAY_SPAM_SUSPECT + +#ifndef BINDER_ENABLE_ONEWAY_SPAM_DETECTION +/* + * Temporary definitions for oneway spam detection support. For the final version + * these will be defined in the UAPI binder.h file from upstream kernel. + */ +#define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32) +#endif //BINDER_ENABLE_ONEWAY_SPAM_DETECTION #endif // _BINDER_MODULE_H_ diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index b9adc9a025..9e2050b411 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -173,7 +173,7 @@ typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transacti * Available since API level 29. * * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for - * sanity checks on transactions. + * validity checks on transactions. This should be utf-8. * \param onCreate see AIBinder_Class_onCreate. * \param onDestroy see AIBinder_Class_onDestroy. * \param onTransact see AIBinder_Class_onTransact. @@ -645,7 +645,9 @@ binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) __INTRODU * * \return the class descriptor string. This pointer will never be null; a * descriptor is required to define a class. The pointer is owned by the class - * and will remain valid as long as the class does. + * and will remain valid as long as the class does. For a local class, this will + * be the same value (not necessarily pointer equal) as is passed into + * AIBinder_Class_define. Format is utf-8. */ const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) __INTRODUCED_IN(31); @@ -669,7 +671,7 @@ const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) __INTRODUC * * \return whether "lhs < rhs" is true */ -bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs); +bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs) __INTRODUCED_IN(31); /** * Clone an AIBinder_Weak. Useful because even if a weak binder promotes to a @@ -683,7 +685,7 @@ bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs); * \return clone of the input parameter. This must be deleted with * AIBinder_Weak_delete. Null if weak input parameter is also null. */ -AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak); +AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak) __INTRODUCED_IN(31); /** * Whether AIBinder_Weak is less than another. @@ -718,7 +720,7 @@ AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak); * * \return whether "lhs < rhs" is true */ -bool AIBinder_Weak_lt(const AIBinder_Weak* lhs, const AIBinder_Weak* rhs); +bool AIBinder_Weak_lt(const AIBinder_Weak* lhs, const AIBinder_Weak* rhs) __INTRODUCED_IN(31); __END_DECLS diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 55169140df..a90b4aabca 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -124,6 +124,15 @@ void AServiceManager_forEachDeclaredInstance(const char* interface, void* contex __INTRODUCED_IN(31); /** + * Check if a service is updatable via an APEX module. + * + * \param instance identifier of the service + * + * \return whether the interface is updatable via APEX + */ +bool AServiceManager_isUpdatableViaApex(const char* instance) __INTRODUCED_IN(31); + +/** * Prevent lazy services without client from shutting down their process * * \param persist 'true' if the process should not exit. diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 67c85b66d4..7d4b82e4b6 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -118,14 +118,15 @@ LIBBINDER_NDK31 { # introduced=31 AIBinder_getCallingSid; # apex AIBinder_setRequestingSid; # apex AParcel_markSensitive; # llndk - AServiceManager_isDeclared; # apex llndk AServiceManager_forEachDeclaredInstance; # apex llndk - AServiceManager_registerLazyService; # llndk - AServiceManager_waitForService; # apex llndk AServiceManager_forceLazyServicesPersist; # llndk + AServiceManager_isDeclared; # apex llndk + AServiceManager_isUpdatableViaApex; # apex + AServiceManager_reRegister; # llndk + AServiceManager_registerLazyService; # llndk AServiceManager_setActiveServicesCallback; # llndk AServiceManager_tryUnregister; # llndk - AServiceManager_reRegister; # llndk + AServiceManager_waitForService; # apex llndk AIBinder_forceDowngradeToSystemStability; # apex AIBinder_forceDowngradeToVendorStability; # llndk diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp index 1ccd0d2a2b..7649a26ff6 100644 --- a/libs/binder/ndk/service_manager.cpp +++ b/libs/binder/ndk/service_manager.cpp @@ -105,6 +105,14 @@ void AServiceManager_forEachDeclaredInstance(const char* interface, void* contex callback(String8(instance).c_str(), context); } } +bool AServiceManager_isUpdatableViaApex(const char* instance) { + if (instance == nullptr) { + return false; + } + + sp<IServiceManager> sm = defaultServiceManager(); + return sm->updatableViaApex(String16(instance)) != std::nullopt; +} void AServiceManager_forceLazyServicesPersist(bool persist) { auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance(); serviceRegistrar.forcePersist(persist); diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 6a88401962..62db3cfbd2 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -300,6 +300,11 @@ TEST(NdkBinder, GetLazyService) { EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())); } +TEST(NdkBinder, IsUpdatable) { + bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default"); + EXPECT_EQ(isUpdatable, false); +} + // This is too slow TEST(NdkBinder, CheckLazyServiceShutDown) { ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService)); diff --git a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h index b92a6a9f8e..749bf212e6 100644 --- a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h +++ b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h @@ -20,5 +20,12 @@ #include <fuzzer/FuzzedDataProvider.h> namespace android { +/** + * Fill parcel data, including some random binder objects and FDs + */ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider); +/** + * Fill parcel data, but don't fill any objects. + */ +void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider); } // namespace android diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/parcel_fuzzer/main.cpp index 78606ccd91..332e2ada52 100644 --- a/libs/binder/parcel_fuzzer/main.cpp +++ b/libs/binder/parcel_fuzzer/main.cpp @@ -23,6 +23,7 @@ #include <iostream> #include <android-base/logging.h> +#include <binder/RpcConnection.h> #include <fuzzbinder/random_parcel.h> #include <fuzzer/FuzzedDataProvider.h> @@ -32,6 +33,8 @@ #include <sys/time.h> using android::fillRandomParcel; +using android::RpcConnection; +using android::sp; void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) { // TODO: functionality to create random parcels for libhwbinder parcels @@ -56,7 +59,18 @@ void doFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads, provider.ConsumeIntegralInRange<size_t>(0, maxInstructions)); P p; - fillRandomParcel(&p, std::move(provider)); + if constexpr (std::is_same_v<P, android::Parcel>) { + if (provider.ConsumeBool()) { + auto connection = sp<RpcConnection>::make(); + CHECK(connection->addNullDebuggingClient()); + p.markForRpc(connection); + fillRandomParcelData(&p, std::move(provider)); + } else { + fillRandomParcel(&p, std::move(provider)); + } + } else { + fillRandomParcel(&p, std::move(provider)); + } // since we are only using a byte to index CHECK(reads.size() <= 255) << reads.size(); diff --git a/libs/binder/parcel_fuzzer/random_parcel.cpp b/libs/binder/parcel_fuzzer/random_parcel.cpp index 9ca4c8aca4..b045a22eff 100644 --- a/libs/binder/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/parcel_fuzzer/random_parcel.cpp @@ -75,4 +75,9 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) { } } +void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) { + std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes()); + CHECK(OK == p->write(data.data(), data.size())); +} + } // namespace android diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index e12a429cf9..57c9013f60 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -65,15 +65,15 @@ rust_bindgen { // rustified "--constified-enum", "android::c_interface::consts::.*", - "--whitelist-type", "android::c_interface::.*", - "--whitelist-type", "AStatus", - "--whitelist-type", "AIBinder_Class", - "--whitelist-type", "AIBinder", - "--whitelist-type", "AIBinder_Weak", - "--whitelist-type", "AIBinder_DeathRecipient", - "--whitelist-type", "AParcel", - "--whitelist-type", "binder_status_t", - "--whitelist-function", ".*", + "--allowlist-type", "android::c_interface::.*", + "--allowlist-type", "AStatus", + "--allowlist-type", "AIBinder_Class", + "--allowlist-type", "AIBinder", + "--allowlist-type", "AIBinder_Weak", + "--allowlist-type", "AIBinder_DeathRecipient", + "--allowlist-type", "AParcel", + "--allowlist-type", "binder_status_t", + "--allowlist-function", ".*", ], shared_libs: [ "libbinder_ndk", diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 321b422185..695a83e414 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -548,6 +548,28 @@ unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> { } } +/// The features to enable when creating a native Binder. +/// +/// This should always be initialised with a default value, e.g.: +/// ``` +/// # use binder::BinderFeatures; +/// BinderFeatures { +/// set_requesting_sid: true, +/// ..BinderFeatures::default(), +/// } +/// ``` +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct BinderFeatures { + /// Indicates that the service intends to receive caller security contexts. This must be true + /// for `ThreadState::with_calling_sid` to work. + pub set_requesting_sid: bool, + // Ensure that clients include a ..BinderFeatures::default() to preserve backwards compatibility + // when new fields are added. #[non_exhaustive] doesn't work because it prevents struct + // expressions entirely. + #[doc(hidden)] + pub _non_exhaustive: (), +} + /// Declare typed interfaces for a binder object. /// /// Given an interface trait and descriptor string, create a native and remote @@ -730,8 +752,9 @@ macro_rules! declare_binder_interface { impl $native { /// Create a new binder service. - pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> { - let binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability); + pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> { + let mut binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability); + $crate::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid); $crate::Strong::new(Box::new(binder)) } } diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index 30928a5cff..2694cba870 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -107,10 +107,9 @@ use binder_ndk_sys as sys; pub mod parcel; pub use crate::binder::{ - FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable, - Stability, Strong, TransactionCode, TransactionFlags, Weak, - FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, - LAST_CALL_TRANSACTION, + BinderFeatures, FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable, + Stability, Strong, TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION, + FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION, }; pub use error::{status_t, ExceptionCode, Result, Status, StatusCode}; pub use native::add_service; @@ -125,8 +124,8 @@ pub mod public_api { pub use super::parcel::ParcelFileDescriptor; pub use super::{add_service, get_interface}; pub use super::{ - DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder, Status, - StatusCode, Strong, ThreadState, Weak, WpIBinder, + BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder, + Status, StatusCode, Strong, ThreadState, Weak, WpIBinder, }; /// Binder result containing a [`Status`] on error. diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp index 0bf76c696a..607860f462 100644 --- a/libs/binder/rust/tests/Android.bp +++ b/libs/binder/rust/tests/Android.bp @@ -114,8 +114,8 @@ rust_bindgen { source_stem: "bindings", cpp_std: "gnu++17", bindgen_flags: [ - "--whitelist-type", "Transaction", - "--whitelist-var", "TESTDATA_.*", + "--allowlist-type", "Transaction", + "--allowlist-var", "TESTDATA_.*", ], shared_libs: [ diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs index 60e3502759..03320076cb 100644 --- a/libs/binder/rust/tests/integration.rs +++ b/libs/binder/rust/tests/integration.rs @@ -19,7 +19,7 @@ use binder::declare_binder_interface; use binder::parcel::Parcel; use binder::{ - Binder, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode, + Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode, FIRST_CALL_TRANSACTION, }; use std::convert::{TryFrom, TryInto}; @@ -55,7 +55,8 @@ fn main() -> Result<(), &'static str> { }))); service.set_requesting_sid(true); if let Some(extension_name) = extension_name { - let extension = BnTest::new_binder(TestService { s: extension_name }); + let extension = + BnTest::new_binder(TestService { s: extension_name }, BinderFeatures::default()); service .set_extension(&mut extension.as_binder()) .expect("Could not add extension"); @@ -212,8 +213,8 @@ mod tests { use std::time::Duration; use binder::{ - Binder, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface, SpIBinder, - StatusCode, Strong, + Binder, BinderFeatures, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface, + SpIBinder, StatusCode, Strong, }; use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY}; @@ -495,9 +496,12 @@ mod tests { #[test] fn reassociate_rust_binder() { let service_name = "testing_service"; - let service_ibinder = BnTest::new_binder(TestService { - s: service_name.to_string(), - }) + let service_ibinder = BnTest::new_binder( + TestService { + s: service_name.to_string(), + }, + BinderFeatures::default(), + ) .as_binder(); let service: Strong<dyn ITest> = service_ibinder @@ -510,9 +514,12 @@ mod tests { #[test] fn weak_binder_upgrade() { let service_name = "testing_service"; - let service = BnTest::new_binder(TestService { - s: service_name.to_string(), - }); + let service = BnTest::new_binder( + TestService { + s: service_name.to_string(), + }, + BinderFeatures::default(), + ); let weak = Strong::downgrade(&service); @@ -525,9 +532,12 @@ mod tests { fn weak_binder_upgrade_dead() { let service_name = "testing_service"; let weak = { - let service = BnTest::new_binder(TestService { - s: service_name.to_string(), - }); + let service = BnTest::new_binder( + TestService { + s: service_name.to_string(), + }, + BinderFeatures::default(), + ); Strong::downgrade(&service) }; @@ -538,9 +548,12 @@ mod tests { #[test] fn weak_binder_clone() { let service_name = "testing_service"; - let service = BnTest::new_binder(TestService { - s: service_name.to_string(), - }); + let service = BnTest::new_binder( + TestService { + s: service_name.to_string(), + }, + BinderFeatures::default(), + ); let weak = Strong::downgrade(&service); let cloned = weak.clone(); @@ -556,12 +569,18 @@ mod tests { #[test] #[allow(clippy::eq_op)] fn binder_ord() { - let service1 = BnTest::new_binder(TestService { - s: "testing_service1".to_string(), - }); - let service2 = BnTest::new_binder(TestService { - s: "testing_service2".to_string(), - }); + let service1 = BnTest::new_binder( + TestService { + s: "testing_service1".to_string(), + }, + BinderFeatures::default(), + ); + let service2 = BnTest::new_binder( + TestService { + s: "testing_service2".to_string(), + }, + BinderFeatures::default(), + ); assert!(!(service1 < service1)); assert!(!(service1 > service1)); diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs index ce75ab7125..4702e45f1f 100644 --- a/libs/binder/rust/tests/ndk_rust_interop.rs +++ b/libs/binder/rust/tests/ndk_rust_interop.rs @@ -16,15 +16,13 @@ //! Rust Binder NDK interop tests -use std::ffi::CStr; -use std::os::raw::{c_char, c_int}; -use ::IBinderRustNdkInteropTest::binder::{self, Interface, StatusCode}; use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTest::{ BnBinderRustNdkInteropTest, IBinderRustNdkInteropTest, }; -use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::{ - IBinderRustNdkInteropTestOther, -}; +use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::IBinderRustNdkInteropTestOther; +use ::IBinderRustNdkInteropTest::binder::{self, BinderFeatures, Interface, StatusCode}; +use std::ffi::CStr; +use std::os::raw::{c_char, c_int}; /// Look up the provided AIDL service and call its echo method. /// @@ -37,18 +35,21 @@ pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int { // The Rust class descriptor pointer will not match the NDK one, but the // descriptor strings match so this needs to still associate. - let service: binder::Strong<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) { - Err(e) => { - eprintln!("Could not find Ndk service {}: {:?}", service_name, e); - return StatusCode::NAME_NOT_FOUND as c_int; - } - Ok(service) => service, - }; + let service: binder::Strong<dyn IBinderRustNdkInteropTest> = + match binder::get_interface(service_name) { + Err(e) => { + eprintln!("Could not find Ndk service {}: {:?}", service_name, e); + return StatusCode::NAME_NOT_FOUND as c_int; + } + Ok(service) => service, + }; match service.echo("testing") { - Ok(s) => if s != "testing" { - return StatusCode::BAD_VALUE as c_int; - }, + Ok(s) => { + if s != "testing" { + return StatusCode::BAD_VALUE as c_int; + } + } Err(e) => return e.into(), } @@ -88,7 +89,7 @@ impl IBinderRustNdkInteropTest for Service { #[no_mangle] 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); + let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default()); 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/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs index f1b068ee43..66ba846c2d 100644 --- a/libs/binder/rust/tests/serialization.rs +++ b/libs/binder/rust/tests/serialization.rs @@ -18,11 +18,11 @@ //! access. use binder::declare_binder_interface; +use binder::parcel::ParcelFileDescriptor; use binder::{ - Binder, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status, + Binder, BinderFeatures, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status, StatusCode, TransactionCode, }; -use binder::parcel::ParcelFileDescriptor; use std::ffi::{c_void, CStr, CString}; use std::sync::Once; @@ -85,7 +85,7 @@ static mut SERVICE: Option<SpIBinder> = None; pub extern "C" fn rust_service() -> *mut c_void { unsafe { SERVICE_ONCE.call_once(|| { - SERVICE = Some(BnReadParcelTest::new_binder(()).as_binder()); + SERVICE = Some(BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder()); }); SERVICE.as_ref().unwrap().as_raw().cast() } @@ -108,8 +108,12 @@ impl ReadParcelTest for BpReadParcelTest {} impl ReadParcelTest for () {} #[allow(clippy::float_cmp)] -fn on_transact(_service: &dyn ReadParcelTest, code: TransactionCode, - parcel: &Parcel, reply: &mut Parcel) -> Result<()> { +fn on_transact( + _service: &dyn ReadParcelTest, + code: TransactionCode, + parcel: &Parcel, + reply: &mut Parcel, +) -> Result<()> { match code { bindings::Transaction_TEST_BOOL => { assert_eq!(parcel.read::<bool>()?, true); diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index afc4b1b72c..f303b7c1e3 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -151,6 +151,27 @@ cc_test { require_root: true, } +cc_benchmark { + name: "binderRpcBenchmark", + defaults: ["binder_test_defaults"], + host_supported: true, + target: { + darwin: { + enabled: false, + }, + }, + srcs: [ + "binderRpcBenchmark.cpp", + "IBinderRpcBenchmark.aidl", + ], + shared_libs: [ + "libbase", + "libbinder", + "liblog", + "libutils", + ], +} + cc_test { name: "binderThroughputTest", defaults: ["binder_test_defaults"], diff --git a/libs/binder/tests/IBinderRpcBenchmark.aidl b/libs/binder/tests/IBinderRpcBenchmark.aidl new file mode 100644 index 0000000000..1457422d30 --- /dev/null +++ b/libs/binder/tests/IBinderRpcBenchmark.aidl @@ -0,0 +1,20 @@ +/* + * 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. + */ + +interface IBinderRpcBenchmark { + @utf8InCpp String repeatString(@utf8InCpp String str); + IBinder repeatBinder(IBinder binder); +} diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index e2193fadab..dc8c0f157e 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -88,6 +88,7 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_GETPID, BINDER_LIB_TEST_ECHO_VECTOR, BINDER_LIB_TEST_REJECT_BUF, + BINDER_LIB_TEST_CAN_GET_SID, }; pid_t start_server_process(int arg2, bool usePoll = false) @@ -1192,6 +1193,14 @@ TEST_F(BinderLibTest, BufRejected) { EXPECT_NE(NO_ERROR, ret); } +TEST_F(BinderLibTest, GotSid) { + sp<IBinder> server = addServer(); + + Parcel data; + status_t ret = server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr); + EXPECT_EQ(OK, ret); +} + class BinderLibTestService : public BBinder { public: @@ -1494,6 +1503,9 @@ class BinderLibTestService : public BBinder case BINDER_LIB_TEST_REJECT_BUF: { return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR; } + case BINDER_LIB_TEST_CAN_GET_SID: { + return IPCThreadState::self()->getCallingSid() == nullptr ? BAD_VALUE : NO_ERROR; + } default: return UNKNOWN_TRANSACTION; }; diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp new file mode 100644 index 0000000000..7c82226aef --- /dev/null +++ b/libs/binder/tests/binderRpcBenchmark.cpp @@ -0,0 +1,141 @@ +/* + * 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 <BnBinderRpcBenchmark.h> +#include <android-base/logging.h> +#include <benchmark/benchmark.h> +#include <binder/Binder.h> +#include <binder/RpcConnection.h> +#include <binder/RpcServer.h> + +#include <thread> + +#include <sys/types.h> +#include <unistd.h> + +using android::BBinder; +using android::IBinder; +using android::interface_cast; +using android::OK; +using android::RpcConnection; +using android::RpcServer; +using android::sp; +using android::binder::Status; + +class MyBinderRpcBenchmark : public BnBinderRpcBenchmark { + Status repeatString(const std::string& str, std::string* out) override { + *out = str; + return Status::ok(); + } + Status repeatBinder(const sp<IBinder>& str, sp<IBinder>* out) override { + *out = str; + return Status::ok(); + } +}; + +static sp<RpcConnection> gConnection = RpcConnection::make(); + +void BM_getRootObject(benchmark::State& state) { + while (state.KeepRunning()) { + CHECK(gConnection->getRootObject() != nullptr); + } +} +BENCHMARK(BM_getRootObject); + +void BM_pingTransaction(benchmark::State& state) { + sp<IBinder> binder = gConnection->getRootObject(); + CHECK(binder != nullptr); + + while (state.KeepRunning()) { + CHECK_EQ(OK, binder->pingBinder()); + } +} +BENCHMARK(BM_pingTransaction); + +void BM_repeatString(benchmark::State& state) { + sp<IBinder> binder = gConnection->getRootObject(); + CHECK(binder != nullptr); + sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder); + CHECK(iface != nullptr); + + // Googlers might see go/another-look-at-aidl-hidl-perf + // + // When I checked in July 2019, 99.5% of AIDL transactions and 99.99% of HIDL + // transactions were less than one page in size (system wide during a test + // involving media and camera). This is why this diverges from + // binderThroughputTest and hwbinderThroughputTest. Future consideration - get + // this data on continuous integration. Here we are testing sending a + // transaction of twice this size. In other cases, we should focus on + // benchmarks of particular usecases. If individual binder transactions like + // the ones tested here are fast, then Android performance will be dominated + // by how many binder calls work together (and by factors like the scheduler, + // thermal throttling, core choice, etc..). + std::string str = std::string(getpagesize() * 2, 'a'); + CHECK_EQ(str.size(), getpagesize() * 2); + + while (state.KeepRunning()) { + std::string out; + Status ret = iface->repeatString(str, &out); + CHECK(ret.isOk()) << ret; + } +} +BENCHMARK(BM_repeatString); + +void BM_repeatBinder(benchmark::State& state) { + sp<IBinder> binder = gConnection->getRootObject(); + CHECK(binder != nullptr); + sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder); + CHECK(iface != nullptr); + + while (state.KeepRunning()) { + // force creation of a new address + sp<IBinder> binder = sp<BBinder>::make(); + + sp<IBinder> out; + Status ret = iface->repeatBinder(binder, &out); + CHECK(ret.isOk()) << ret; + } +} +BENCHMARK(BM_repeatBinder); + +int main(int argc, char** argv) { + ::benchmark::Initialize(&argc, argv); + if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; + + std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark"; + (void)unlink(addr.c_str()); + + std::thread([addr]() { + sp<RpcServer> server = RpcServer::make(); + server->setRootObject(sp<MyBinderRpcBenchmark>::make()); + + server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction(); + + sp<RpcConnection> connection = server->addClientConnection(); + CHECK(connection->setupUnixDomainServer(addr.c_str())); + + connection->join(); + }).detach(); + + for (size_t tries = 0; tries < 5; tries++) { + usleep(10000); + if (gConnection->addUnixDomainClient(addr.c_str())) goto success; + } + LOG(FATAL) << "Could not connect."; +success: + + ::benchmark::RunSpecifiedBenchmarks(); +} diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index a51c98774e..dd68fdbc6d 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -80,11 +80,10 @@ public: sp<RpcConnection> connection; Status sendString(const std::string& str) override { - std::cout << "Child received string: " << str << std::endl; + (void)str; return Status::ok(); } Status doubleString(const std::string& str, std::string* strstr) override { - std::cout << "Child received string to double: " << str << std::endl; *strstr = str + str; return Status::ok(); } @@ -199,13 +198,8 @@ private: static std::string allocateSocketAddress() { static size_t id = 0; - static bool gUseTmp = access("/tmp/", F_OK) != -1; - - if (gUseTmp) { - return "/tmp/binderRpcTest_" + std::to_string(id++); - } else { - return "/dev/binderRpcTest_" + std::to_string(id++); - } + std::string temp = getenv("TMPDIR") ?: "/tmp"; + return temp + "/binderRpcTest_" + std::to_string(id++); }; struct ProcessConnection { @@ -262,6 +256,7 @@ enum class SocketType { #ifdef __BIONIC__ VSOCK, #endif // __BIONIC__ + INET, }; static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) { switch (info.param) { @@ -271,6 +266,8 @@ static inline std::string PrintSocketType(const testing::TestParamInfo<SocketTyp case SocketType::VSOCK: return "vm_socket"; #endif // __BIONIC__ + case SocketType::INET: + return "inet_socket"; default: LOG_ALWAYS_FATAL("Unknown socket type"); return ""; @@ -310,6 +307,9 @@ public: CHECK(connection->setupVsockServer(port)); break; #endif // __BIONIC__ + case SocketType::INET: + CHECK(connection->setupInetServer(port)); + break; default: LOG_ALWAYS_FATAL("Unknown socket type"); } @@ -340,6 +340,9 @@ public: if (ret.connection->addVsockClient(VMADDR_CID_LOCAL, port)) goto success; break; #endif // __BIONIC__ + case SocketType::INET: + if (ret.connection->addInetClient("127.0.0.1", port)) goto success; + break; default: LOG_ALWAYS_FATAL("Unknown socket type"); } @@ -745,7 +748,7 @@ TEST_P(BinderRpc, ThreadingStressTest) { threads.push_back(std::thread([&] { for (size_t j = 0; j < kNumCalls; j++) { sp<IBinder> out; - proc.rootIface->repeatBinder(proc.rootBinder, &out); + EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &out)); EXPECT_EQ(proc.rootBinder, out); } })); @@ -754,6 +757,28 @@ TEST_P(BinderRpc, ThreadingStressTest) { for (auto& t : threads) t.join(); } +TEST_P(BinderRpc, OnewayStressTest) { + constexpr size_t kNumClientThreads = 10; + constexpr size_t kNumServerThreads = 10; + constexpr size_t kNumCalls = 100; + + auto proc = createRpcTestSocketServerProcess(kNumServerThreads); + + std::vector<std::thread> threads; + for (size_t i = 0; i < kNumClientThreads; i++) { + threads.push_back(std::thread([&] { + for (size_t j = 0; j < kNumCalls; j++) { + EXPECT_OK(proc.rootIface->sendString("a")); + } + + // check threads are not stuck + EXPECT_OK(proc.rootIface->sleepMs(250)); + })); + } + + for (auto& t : threads) t.join(); +} + TEST_P(BinderRpc, OnewayCallDoesNotWait) { constexpr size_t kReallyLongTimeMs = 100; constexpr size_t kSleepMs = kReallyLongTimeMs * 5; @@ -857,12 +882,13 @@ TEST_P(BinderRpc, Fds) { } INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, - ::testing::Values(SocketType::UNIX + ::testing::ValuesIn({ + SocketType::UNIX, #ifdef __BIONIC__ - , - SocketType::VSOCK + SocketType::VSOCK, #endif // __BIONIC__ - ), + SocketType::INET, + }), PrintSocketType); } // namespace android diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index ffb3ef2c70..c857d62cb2 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -226,7 +226,7 @@ public: IncrementNativeHandle, IncrementNoCopyNoMove, IncrementParcelableVector, - ToUpper, + DoubleString, CallMeBack, IncrementInt32, IncrementUint32, @@ -256,7 +256,7 @@ public: virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0; virtual status_t increment(const std::vector<TestParcelable>& a, std::vector<TestParcelable>* aPlusOne) const = 0; - virtual status_t toUpper(const String8& str, String8* upperStr) const = 0; + virtual status_t doubleString(const String8& str, String8* doubleStr) const = 0; // As mentioned above, sp<IBinder> is already tested by setDeathToken virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0; virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0; @@ -329,9 +329,10 @@ public: std::vector<TestParcelable>*); return callRemote<Signature>(Tag::IncrementParcelableVector, a, aPlusOne); } - status_t toUpper(const String8& str, String8* upperStr) const override { + status_t doubleString(const String8& str, String8* doubleStr) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); - return callRemote<decltype(&ISafeInterfaceTest::toUpper)>(Tag::ToUpper, str, upperStr); + return callRemote<decltype(&ISafeInterfaceTest::doubleString)>(Tag::DoubleString, str, + doubleStr); } void callMeBack(const sp<ICallback>& callback, int32_t a) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); @@ -454,10 +455,9 @@ public: } return NO_ERROR; } - status_t toUpper(const String8& str, String8* upperStr) const override { + status_t doubleString(const String8& str, String8* doubleStr) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); - *upperStr = str; - upperStr->toUpper(); + *doubleStr = str + str; return NO_ERROR; } void callMeBack(const sp<ICallback>& callback, int32_t a) const override { @@ -548,8 +548,8 @@ public: std::vector<TestParcelable>*) const; return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment); } - case ISafeInterfaceTest::Tag::ToUpper: { - return callLocal(data, reply, &ISafeInterfaceTest::toUpper); + case ISafeInterfaceTest::Tag::DoubleString: { + return callLocal(data, reply, &ISafeInterfaceTest::doubleString); } case ISafeInterfaceTest::Tag::CallMeBack: { return callLocalAsync(data, reply, &ISafeInterfaceTest::callMeBack); @@ -726,12 +726,12 @@ TEST_F(SafeInterfaceTest, TestIncremementParcelableVector) { } } -TEST_F(SafeInterfaceTest, TestToUpper) { - const String8 str{"Hello, world!"}; - String8 upperStr; - status_t result = mSafeInterfaceTest->toUpper(str, &upperStr); +TEST_F(SafeInterfaceTest, TestDoubleString) { + const String8 str{"asdf"}; + String8 doubleStr; + status_t result = mSafeInterfaceTest->doubleString(str, &doubleStr); ASSERT_EQ(NO_ERROR, result); - ASSERT_TRUE(upperStr == String8{"HELLO, WORLD!"}); + ASSERT_TRUE(doubleStr == String8{"asdfasdf"}); } TEST_F(SafeInterfaceTest, TestCallMeBack) { diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp index cb309bdd81..2ce13df4b3 100644 --- a/libs/binder/tests/binderStabilityTest.cpp +++ b/libs/binder/tests/binderStabilityTest.cpp @@ -192,6 +192,8 @@ TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) { EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8; EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8; + EXPECT_EQ(std::nullopt, android::defaultServiceManager()->updatableViaApex(instance)) + << instance8; } } diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp index 4ecbe531c2..761e45c967 100644 --- a/libs/fakeservicemanager/ServiceManager.cpp +++ b/libs/fakeservicemanager/ServiceManager.cpp @@ -73,4 +73,9 @@ Vector<String16> ServiceManager::getDeclaredInstances(const String16& name) { return out; } +std::optional<String16> ServiceManager::updatableViaApex(const String16& name) { + (void)name; + return std::nullopt; +} + } // namespace android diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h index 4ef47fb043..e26c21b9e9 100644 --- a/libs/fakeservicemanager/ServiceManager.h +++ b/libs/fakeservicemanager/ServiceManager.h @@ -19,6 +19,7 @@ #include <binder/IServiceManager.h> #include <map> +#include <optional> namespace android { @@ -48,6 +49,8 @@ public: Vector<String16> getDeclaredInstances(const String16& iface) override; + std::optional<String16> updatableViaApex(const String16& name) override; + private: std::map<String16, sp<IBinder>> mNameToService; }; diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 7c11b03034..f734582377 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -39,22 +39,66 @@ cc_library_headers { min_sdk_version: "29", } +cc_library_headers { + name: "libgui_aidl_headers", + vendor_available: true, + static_libs: [ + "libgui_aidl_static", + ], + + export_static_lib_headers: [ + "libgui_aidl_static", + ], +} + filegroup { name: "libgui_aidl", srcs: ["aidl/**/*.aidl"], path: "aidl/", } +cc_library_static { + name: "libgui_aidl_static", + vendor_available: true, + srcs: [ + ":libgui_aidl", + ], + + shared_libs: [ + "libbinder", + "libui", + ], + + local_include_dirs: [ + "include", + ], + + export_shared_lib_headers: [ + "libbinder", + ], + + aidl: { + export_aidl_headers: true + } +} + + cc_defaults { name: "libgui_defaults", double_loadable: true, defaults: ["libgui_bufferqueue-defaults"], + static_libs: [ + "libgui_aidl_static", + ], + export_static_lib_headers: [ + "libgui_aidl_static", + ], + srcs: [ ":framework_native_aidl", ":inputconstants_aidl", - ":libgui_aidl", ":libgui_bufferqueue_sources", "BitTube.cpp", @@ -110,6 +154,10 @@ cc_defaults { "libinput", ], + export_header_lib_headers: [ + "libgui_aidl_headers", + ], + // bufferhub is not used when building libgui for vendors target: { vendor: { @@ -131,15 +179,16 @@ cc_defaults { }, }, + aidl: { + export_aidl_headers: true, + }, + header_libs: [ "libdvr_headers", + "libgui_aidl_headers", "libpdx_headers", ], - aidl: { - export_aidl_headers: true, - }, - pgo: { sampling: true, profile_file: "libgui/libgui.profdata", @@ -170,8 +219,8 @@ cc_library_static { srcs: [ ":inputconstants_aidl", - ":libgui_aidl", ":libgui_bufferqueue_sources", + ":libgui_aidl", ], } diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index bcdd06b6c8..3d854c2b92 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -161,9 +161,9 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont 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) + .apply(); mNumAcquired = 0; mNumFrameAvailable = 0; @@ -186,6 +186,7 @@ BLASTBufferQueue::~BLASTBufferQueue() { void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format) { std::unique_lock _lock{mMutex}; + BQA_LOGV("update width=%d height=%d format=%d", width, height, format); if (mFormat != format) { mFormat = format; mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); @@ -204,13 +205,16 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, if (mRequestedSize != newSize) { mRequestedSize.set(newSize); mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height); - if (mLastBufferScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { + if (mLastBufferInfo.scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { // If the buffer supports scaling, update the frame immediately since the client may // want to scale the existing buffer to the new size. mSize = mRequestedSize; - t.setFrame(mSurfaceControl, - {0, 0, static_cast<int32_t>(mSize.width), - static_cast<int32_t>(mSize.height)}); + // 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. + if (mLastBufferInfo.hasBuffer) { + setMatrix(&t, mLastBufferInfo); + } applyTransaction = true; } } @@ -239,29 +243,49 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence ATRACE_CALL(); BQA_LOGV("transactionCallback"); - if (!stats.empty()) { - mTransformHint = stats[0].transformHint; - mBufferItemConsumer->setTransformHint(mTransformHint); - mBufferItemConsumer - ->updateFrameTimestamps(stats[0].frameEventStats.frameNumber, - stats[0].frameEventStats.refreshStartTime, - stats[0].frameEventStats.gpuCompositionDoneFence, - stats[0].presentFence, stats[0].previousReleaseFence, - stats[0].frameEventStats.compositorTiming, - stats[0].latchTime, - stats[0].frameEventStats.dequeueReadyTime); - currFrameNumber = stats[0].frameEventStats.frameNumber; - - if (mTransactionCompleteCallback && - currFrameNumber >= mTransactionCompleteFrameNumber) { - if (currFrameNumber > mTransactionCompleteFrameNumber) { - BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64 - " than expected=%" PRIu64, - currFrameNumber, mTransactionCompleteFrameNumber); + if (!mSurfaceControlsWithPendingCallback.empty()) { + sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front(); + mSurfaceControlsWithPendingCallback.pop(); + bool found = false; + for (auto stat : stats) { + if (!SurfaceControl::isSameSurface(pendingSC, stat.surfaceControl)) { + continue; + } + + mTransformHint = stat.transformHint; + mBufferItemConsumer->setTransformHint(mTransformHint); + mBufferItemConsumer + ->updateFrameTimestamps(stat.frameEventStats.frameNumber, + stat.frameEventStats.refreshStartTime, + stat.frameEventStats.gpuCompositionDoneFence, + stat.presentFence, stat.previousReleaseFence, + stat.frameEventStats.compositorTiming, + stat.latchTime, + stat.frameEventStats.dequeueReadyTime); + + currFrameNumber = stat.frameEventStats.frameNumber; + + if (mTransactionCompleteCallback && + currFrameNumber >= mTransactionCompleteFrameNumber) { + if (currFrameNumber > mTransactionCompleteFrameNumber) { + BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64 + " than expected=%" PRIu64, + currFrameNumber, mTransactionCompleteFrameNumber); + } + transactionCompleteCallback = std::move(mTransactionCompleteCallback); + mTransactionCompleteFrameNumber = 0; } - transactionCompleteCallback = std::move(mTransactionCompleteCallback); - mTransactionCompleteFrameNumber = 0; + + found = true; + break; + } + + if (!found) { + BQA_LOGE("Failed to find matching SurfaceControl in transaction callback"); } + } else { + BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was " + "empty."); } decStrong((void*)transactionCallbackThunk); @@ -374,8 +398,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); - mLastBufferScalingMode = bufferItem.mScalingMode; + Rect crop = computeCrop(bufferItem); mLastAcquiredFrameNumber = bufferItem.mFrameNumber; + mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), + bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, + bufferItem.mScalingMode, crop); auto releaseBufferCallback = std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */, @@ -387,10 +414,10 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setAcquireFence(mSurfaceControl, bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this)); + mSurfaceControlsWithPendingCallback.push(mSurfaceControl); - t->setFrame(mSurfaceControl, - {0, 0, static_cast<int32_t>(mSize.width), static_cast<int32_t>(mSize.height)}); - t->setCrop(mSurfaceControl, computeCrop(bufferItem)); + setMatrix(t, mLastBufferInfo); + t->setCrop(mSurfaceControl, crop); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); if (!bufferItem.mIsAutoTimestamp) { @@ -494,6 +521,7 @@ void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) { + mSize = mRequestedSize; // Only reject buffers if scaling mode is freeze. return false; } @@ -515,6 +543,19 @@ bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) { return mSize != bufferSize; } +void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t, + const BufferInfo& bufferInfo) { + uint32_t bufWidth = bufferInfo.crop.getWidth(); + uint32_t bufHeight = bufferInfo.crop.getHeight(); + + float sx = mSize.width / static_cast<float>(bufWidth); + float sy = mSize.height / static_cast<float>(bufHeight); + + t->setMatrix(mSurfaceControl, sx, 0, 0, sy); + // Update position based on crop. + t->setPosition(mSurfaceControl, bufferInfo.crop.left * sx * -1, bufferInfo.crop.top * sy * -1); +} + void BLASTBufferQueue::setTransactionCompleteCallback( uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback) { std::lock_guard _lock{mMutex}; diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 9cd3f631c8..e1b1efc0ed 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -152,6 +152,7 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, *outCount = ev.vsync.count; outVsyncEventData->id = ev.vsync.vsyncId; outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; + outVsyncEventData->frameInterval = ev.vsync.frameInterval; break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 454aa9eb7b..53721cf6f7 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -99,7 +99,7 @@ public: SAFE_PARCEL(data.writeVectorSize, listenerCallbacks); for (const auto& [listener, callbackIds] : listenerCallbacks) { SAFE_PARCEL(data.writeStrongBinder, listener); - SAFE_PARCEL(data.writeInt64Vector, callbackIds); + SAFE_PARCEL(data.writeParcelableVector, callbackIds); } SAFE_PARCEL(data.writeUint64, transactionId); @@ -497,6 +497,28 @@ public: return result; } + status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeInt32, atomId); + + status_t err = remote()->transact(BnSurfaceComposer::ON_PULL_ATOM, data, &reply); + if (err != NO_ERROR) { + ALOGE("onPullAtom failed to transact: %d", err); + return err; + } + + int32_t size = 0; + SAFE_PARCEL(reply.readInt32, &size); + const void* dataPtr = reply.readInplace(size); + if (dataPtr == nullptr) { + return UNEXPECTED_NULL; + } + pulledData->assign((const char*)dataPtr, size); + SAFE_PARCEL(reply.readBool, success); + return NO_ERROR; + } + status_t enableVSyncInjections(bool enable) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -1246,7 +1268,7 @@ status_t BnSurfaceComposer::onTransact( for (int32_t i = 0; i < listenersSize; i++) { SAFE_PARCEL(data.readStrongBinder, &tmpBinder); std::vector<CallbackId> callbackIds; - SAFE_PARCEL(data.readInt64Vector, &callbackIds); + SAFE_PARCEL(data.readParcelableVector, &callbackIds); listenerCallbacks.emplace_back(tmpBinder, callbackIds); } @@ -2021,6 +2043,19 @@ status_t BnSurfaceComposer::onTransact( } return overrideHdrTypes(display, hdrTypesVector); } + case ON_PULL_ATOM: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + int32_t atomId = 0; + SAFE_PARCEL(data.readInt32, &atomId); + + std::string pulledData; + bool success; + status_t err = onPullAtom(atomId, &pulledData, &success); + SAFE_PARCEL(reply->writeByteArray, pulledData.size(), + reinterpret_cast<const uint8_t*>(pulledData.data())); + SAFE_PARCEL(reply->writeBool, success); + return err; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index b42793b8ac..f74f91e034 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -152,7 +152,7 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) { } status_t TransactionStats::writeToParcel(Parcel* output) const { - status_t err = output->writeInt64Vector(callbackIds); + status_t err = output->writeParcelableVector(callbackIds); if (err != NO_ERROR) { return err; } @@ -176,7 +176,7 @@ status_t TransactionStats::writeToParcel(Parcel* output) const { } status_t TransactionStats::readFromParcel(const Parcel* input) { - status_t err = input->readInt64Vector(&callbackIds); + status_t err = input->readParcelableVector(&callbackIds); if (err != NO_ERROR) { return err; } @@ -227,8 +227,9 @@ status_t ListenerStats::readFromParcel(const Parcel* input) { return NO_ERROR; } -ListenerStats ListenerStats::createEmpty(const sp<IBinder>& listener, - const std::unordered_set<CallbackId>& callbackIds) { +ListenerStats ListenerStats::createEmpty( + const sp<IBinder>& listener, + const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds) { ListenerStats listenerStats; listenerStats.listener = listener; listenerStats.transactionStats.emplace_back(callbackIds); @@ -278,4 +279,28 @@ status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& } } +ListenerCallbacks ListenerCallbacks::filter(CallbackId::Type type) const { + std::vector<CallbackId> filteredCallbackIds; + for (const auto& callbackId : callbackIds) { + if (callbackId.type == type) { + filteredCallbackIds.push_back(callbackId); + } + } + return ListenerCallbacks(transactionCompletedListener, filteredCallbackIds); +} + +status_t CallbackId::writeToParcel(Parcel* output) const { + SAFE_PARCEL(output->writeInt64, id); + SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(type)); + return NO_ERROR; +} + +status_t CallbackId::readFromParcel(const Parcel* input) { + SAFE_PARCEL(input->readInt64, &id); + int32_t typeAsInt; + SAFE_PARCEL(input->readInt32, &typeAsInt); + type = static_cast<CallbackId::Type>(typeAsInt); + return NO_ERROR; +} + }; // namespace android diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 5b213ad5c3..517b49e6b5 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -45,7 +45,6 @@ layer_state_t::layer_state_t() reserved(0), cornerRadius(0.0f), backgroundBlurRadius(0), - barrierFrameNumber(0), transform(0), transformToDisplayInverse(false), crop(Rect::INVALID_RECT), @@ -87,9 +86,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeUint32, mask); SAFE_PARCEL(matrix.write, output); SAFE_PARCEL(output.write, crop); - SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, barrierSurfaceControl_legacy); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl); - SAFE_PARCEL(output.writeUint64, barrierFrameNumber); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild); SAFE_PARCEL(output.writeFloat, color.r); @@ -143,7 +140,7 @@ status_t layer_state_t::write(Parcel& output) const for (auto listener : listeners) { SAFE_PARCEL(output.writeStrongBinder, listener.transactionCompletedListener); - SAFE_PARCEL(output.writeInt64Vector, listener.callbackIds); + SAFE_PARCEL(output.writeParcelableVector, listener.callbackIds); } SAFE_PARCEL(output.writeFloat, shadowRadius); SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority); @@ -193,9 +190,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(matrix.read, input); SAFE_PARCEL(input.read, crop); - SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &barrierSurfaceControl_legacy); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl); - SAFE_PARCEL(input.readUint64, &barrierFrameNumber); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild); @@ -263,7 +258,7 @@ status_t layer_state_t::read(const Parcel& input) sp<IBinder> listener; std::vector<CallbackId> callbackIds; SAFE_PARCEL(input.readNullableStrongBinder, &listener); - SAFE_PARCEL(input.readInt64Vector, &callbackIds); + SAFE_PARCEL(input.readParcelableVector, &callbackIds); listeners.emplace_back(listener, callbackIds); } SAFE_PARCEL(input.readFloat, &shadowRadius); @@ -425,11 +420,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eBlurRegionsChanged; blurRegions = other.blurRegions; } - if (other.what & eDeferTransaction_legacy) { - what |= eDeferTransaction_legacy; - barrierSurfaceControl_legacy = other.barrierSurfaceControl_legacy; - barrierFrameNumber = other.barrierFrameNumber; - } if (other.what & eRelativeLayerChanged) { what |= eRelativeLayerChanged; what &= ~eLayerChanged; @@ -455,10 +445,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eCropChanged; crop = other.crop; } - if (other.what & eFrameChanged) { - what |= eFrameChanged; - orientedDisplaySpaceRect = other.orientedDisplaySpaceRect; - } if (other.what & eBufferChanged) { what |= eBufferChanged; buffer = other.buffer; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e01a5aee32..5db0eae416 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -139,7 +139,7 @@ JankDataListener::~JankDataListener() { // 0 is an invalid callback id TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {} -CallbackId TransactionCompletedListener::getNextIdLocked() { +int64_t TransactionCompletedListener::getNextIdLocked() { return mCallbackIdCounter++; } @@ -163,13 +163,13 @@ void TransactionCompletedListener::startListeningLocked() { CallbackId TransactionCompletedListener::addCallbackFunction( const TransactionCompletedCallback& callbackFunction, const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>& - surfaceControls) { + surfaceControls, + CallbackId::Type callbackType) { std::lock_guard<std::mutex> lock(mMutex); startListeningLocked(); - CallbackId callbackId = getNextIdLocked(); + CallbackId callbackId(getNextIdLocked(), callbackType); mCallbacks[callbackId].callbackFunction = callbackFunction; - auto& callbackSurfaceControls = mCallbacks[callbackId].surfaceControls; for (const auto& surfaceControl : surfaceControls) { @@ -228,7 +228,7 @@ void TransactionCompletedListener::removeSurfaceStatsListener(void* context, voi void TransactionCompletedListener::addSurfaceControlToCallbacks( const sp<SurfaceControl>& surfaceControl, - const std::unordered_set<CallbackId>& callbackIds) { + const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds) { std::lock_guard<std::mutex> lock(mMutex); for (auto callbackId : callbackIds) { @@ -240,7 +240,7 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks( } void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) { - std::unordered_map<CallbackId, CallbackTranslation> callbacksMap; + std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> callbacksMap; std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap; std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> surfaceListeners; { @@ -267,7 +267,36 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } for (const auto& transactionStats : listenerStats.transactionStats) { + // handle on commit callbacks + for (auto callbackId : transactionStats.callbackIds) { + if (callbackId.type != CallbackId::Type::ON_COMMIT) { + continue; + } + auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId]; + if (!callbackFunction) { + ALOGE("cannot call null callback function, skipping"); + continue; + } + std::vector<SurfaceControlStats> surfaceControlStats; + for (const auto& surfaceStats : transactionStats.surfaceStats) { + surfaceControlStats + .emplace_back(callbacksMap[callbackId] + .surfaceControls[surfaceStats.surfaceControl], + transactionStats.latchTime, surfaceStats.acquireTime, + transactionStats.presentFence, + surfaceStats.previousReleaseFence, surfaceStats.transformHint, + surfaceStats.eventStats); + } + + callbackFunction(transactionStats.latchTime, transactionStats.presentFence, + surfaceControlStats); + } + + // handle on complete callbacks for (auto callbackId : transactionStats.callbackIds) { + if (callbackId.type != CallbackId::Type::ON_COMPLETE) { + continue; + } auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId]; if (!callbackFunction) { ALOGE("cannot call null callback function, skipping"); @@ -542,7 +571,9 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel return BAD_VALUE; } for (size_t j = 0; j < numCallbackIds; j++) { - listenerCallbacks[listener].callbackIds.insert(parcel->readInt64()); + CallbackId id; + parcel->readParcelable(&id); + listenerCallbacks[listener].callbackIds.insert(id); } size_t numSurfaces = parcel->readUint32(); if (numSurfaces > parcel->dataSize()) { @@ -628,7 +659,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeStrongBinder(ITransactionCompletedListener::asBinder(listener)); parcel->writeUint32(static_cast<uint32_t>(callbackInfo.callbackIds.size())); for (auto callbackId : callbackInfo.callbackIds) { - parcel->writeInt64(callbackId); + parcel->writeParcelable(callbackId); } parcel->writeUint32(static_cast<uint32_t>(callbackInfo.surfaceControls.size())); for (auto surfaceControl : callbackInfo.surfaceControls) { @@ -896,7 +927,7 @@ void SurfaceComposerClient::Transaction::setEarlyWakeupEnd() { } layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) { - auto handle = sc->getHandle(); + auto handle = sc->getLayerStateHandle(); if (mComposerStates.count(handle) == 0) { // we don't have it, add an initialized layer_state to our list @@ -1140,23 +1171,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBlurR return *this; } -SurfaceComposerClient::Transaction& -SurfaceComposerClient::Transaction::deferTransactionUntil_legacy( - const sp<SurfaceControl>& sc, const sp<SurfaceControl>& barrierSurfaceControl, - uint64_t frameNumber) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eDeferTransaction_legacy; - s->barrierSurfaceControl_legacy = barrierSurfaceControl; - s->barrierFrameNumber = frameNumber; - - registerSurfaceControlForCallback(sc); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent( const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent) { layer_state_t* s = getLayerState(sc); @@ -1164,8 +1178,11 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent mStatus = BAD_INDEX; return *this; } + if (SurfaceControl::isSameSurface(sc, newParent)) { + return *this; + } s->what |= layer_state_t::eReparent; - s->parentSurfaceControlForChild = newParent; + s->parentSurfaceControlForChild = newParent ? newParent->getParentingLayer() : nullptr; registerSurfaceControlForCallback(sc); return *this; @@ -1232,20 +1249,6 @@ SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp<Surfac return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame( - const sp<SurfaceControl>& sc, const Rect& frame) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eFrameChanged; - s->orientedDisplaySpaceRect = frame; - - registerSurfaceControlForCallback(sc); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer, ReleaseBufferCallback callback) { @@ -1417,9 +1420,9 @@ SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp<Surfa return *this; } -SurfaceComposerClient::Transaction& -SurfaceComposerClient::Transaction::addTransactionCompletedCallback( - TransactionCompletedCallbackTakesContext callback, void* callbackContext) { +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCallback( + TransactionCompletedCallbackTakesContext callback, void* callbackContext, + CallbackId::Type callbackType) { auto listener = TransactionCompletedListener::getInstance(); auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1, @@ -1427,13 +1430,26 @@ SurfaceComposerClient::Transaction::addTransactionCompletedCallback( const auto& surfaceControls = mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls; - CallbackId callbackId = listener->addCallbackFunction(callbackWithContext, surfaceControls); + CallbackId callbackId = + listener->addCallbackFunction(callbackWithContext, surfaceControls, callbackType); mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace( callbackId); return *this; } +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::addTransactionCompletedCallback( + TransactionCompletedCallbackTakesContext callback, void* callbackContext) { + return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMPLETE); +} + +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::addTransactionCommittedCallback( + TransactionCompletedCallbackTakesContext callback, void* callbackContext) { + return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMMIT); +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect( const sp<SurfaceControl>& sc) { layer_state_t* s = getLayerState(sc); @@ -1824,7 +1840,8 @@ status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32 } ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - *outSurface = new SurfaceControl(this, handle, gbp, id, transformHint); + *outSurface = + new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint, flags); } } return err; @@ -1977,6 +1994,11 @@ status_t SurfaceComposerClient::overrideHdrTypes(const sp<IBinder>& display, return ComposerService::getComposerService()->overrideHdrTypes(display, hdrTypes); } +status_t SurfaceComposerClient::onPullAtom(const int32_t atomId, std::string* outData, + bool* success) { + return ComposerService::getComposerService()->onPullAtom(atomId, outData, success); +} + status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 4be6d2b539..9871447552 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -35,6 +35,7 @@ #include <ui/StaticDisplayInfo.h> #include <gui/BufferQueueCore.h> +#include <gui/BLASTBufferQueue.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> @@ -51,12 +52,17 @@ namespace android { SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbp, int32_t layerId, - uint32_t transform) + uint32_t w, uint32_t h, PixelFormat format, uint32_t transform, + uint32_t flags) : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), mLayerId(layerId), mTransformHint(transform), + mWidth(w), + mHeight(h), + mFormat(format), + mCreateFlags(flags), mExtension(mHandle, &mGraphicBufferProducer) {} SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) { @@ -65,6 +71,9 @@ SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) { mGraphicBufferProducer = other->mGraphicBufferProducer; mTransformHint = other->mTransformHint; mLayerId = other->mLayerId; + mWidth = other->mWidth; + mHeight = other->mHeight; + mCreateFlags = other->mCreateFlags; } SurfaceControl::~SurfaceControl() @@ -73,13 +82,13 @@ SurfaceControl::~SurfaceControl() // happen without delay, since these resources are quite heavy. mClient.clear(); mHandle.clear(); - mGraphicBufferProducer.clear(); + mBbq.clear(); IPCThreadState::self()->flushCommands(); } void SurfaceControl::disconnect() { - if (mGraphicBufferProducer != nullptr) { - mGraphicBufferProducer->disconnect( + if (getIGraphicBufferProducer() != nullptr) { + getIGraphicBufferProducer()->disconnect( BufferQueueCore::CURRENTLY_CONNECTED_API); } } @@ -121,22 +130,29 @@ status_t SurfaceControl::writeSurfaceToParcel( { sp<IGraphicBufferProducer> bp; if (control != nullptr) { - bp = control->mGraphicBufferProducer; + bp = control->getIGraphicBufferProducer(); } return parcel->writeStrongBinder(IInterface::asBinder(bp)); } -sp<Surface> SurfaceControl::generateSurfaceLocked() const +sp<Surface> SurfaceControl::generateSurfaceLocked() { + uint32_t ignore; + auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow | + ISurfaceComposerClient::eOpaque); + mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat, + flags, mHandle, {}, &ignore); + mBbq = new BLASTBufferQueue("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat); + // This surface is always consumed by SurfaceFlinger, so the // producerControlledByApp value doesn't matter; using false. mExtension.init(); - mSurfaceData = new Surface(mGraphicBufferProducer, false); + mSurfaceData = mBbq->getSurface(true); return mSurfaceData; } -sp<Surface> SurfaceControl::getSurface() const +sp<Surface> SurfaceControl::getSurface() { Mutex::Autolock _l(mLock); if (mSurfaceData == nullptr) { @@ -145,25 +161,42 @@ sp<Surface> SurfaceControl::getSurface() const return mSurfaceData; } -sp<Surface> SurfaceControl::createSurface() const +sp<Surface> SurfaceControl::createSurface() { + return getSurface(); +} + +void SurfaceControl::updateDefaultBufferSize(uint32_t width, uint32_t height) { Mutex::Autolock _l(mLock); - return generateSurfaceLocked(); + mWidth = width; mHeight = height; + if (mBbq) { + mBbq->update(this, width, height, mFormat); + } + } -sp<IBinder> SurfaceControl::getHandle() const +sp<IBinder> SurfaceControl::getLayerStateHandle() const { return mHandle; } +sp<IBinder> SurfaceControl::getHandle() const { + if (mBbqChild != nullptr) { + return mBbqChild->getHandle(); + } + return getLayerStateHandle(); +} + int32_t SurfaceControl::getLayerId() const { return mLayerId; } -sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer() const +sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer() { + getSurface(); Mutex::Autolock _l(mLock); - return mGraphicBufferProducer; + + return mBbq->getIGraphicBufferProducer(); } sp<SurfaceComposerClient> SurfaceControl::getClient() const @@ -184,9 +217,11 @@ void SurfaceControl::setTransformHint(uint32_t hint) { status_t SurfaceControl::writeToParcel(Parcel& parcel) { SAFE_PARCEL(parcel.writeStrongBinder, ISurfaceComposerClient::asBinder(mClient->getClient())); SAFE_PARCEL(parcel.writeStrongBinder, mHandle); - SAFE_PARCEL(parcel.writeStrongBinder, IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); SAFE_PARCEL(parcel.writeInt32, mLayerId); SAFE_PARCEL(parcel.writeUint32, mTransformHint); + SAFE_PARCEL(parcel.writeUint32, mWidth); + SAFE_PARCEL(parcel.writeUint32, mHeight); + SAFE_PARCEL(parcel.writeUint32, mFormat); return NO_ERROR; } @@ -195,21 +230,26 @@ status_t SurfaceControl::readFromParcel(const Parcel& parcel, sp<SurfaceControl>* outSurfaceControl) { sp<IBinder> client; sp<IBinder> handle; - sp<IBinder> gbp; int32_t layerId; uint32_t transformHint; + uint32_t width; + uint32_t height; + uint32_t format; SAFE_PARCEL(parcel.readStrongBinder, &client); SAFE_PARCEL(parcel.readStrongBinder, &handle); - SAFE_PARCEL(parcel.readNullableStrongBinder, &gbp); SAFE_PARCEL(parcel.readInt32, &layerId); SAFE_PARCEL(parcel.readUint32, &transformHint); + SAFE_PARCEL(parcel.readUint32, &width); + SAFE_PARCEL(parcel.readUint32, &height); + SAFE_PARCEL(parcel.readUint32, &format); // We aren't the original owner of the surface. *outSurfaceControl = new SurfaceControl(new SurfaceComposerClient( interface_cast<ISurfaceComposerClient>(client)), - handle.get(), interface_cast<IGraphicBufferProducer>(gbp), layerId, + handle.get(), nullptr, layerId, + width, height, format, transformHint); return NO_ERROR; @@ -237,6 +277,13 @@ status_t SurfaceControl::writeNullableToParcel(Parcel& parcel, return NO_ERROR; } +sp<SurfaceControl> SurfaceControl::getParentingLayer() { + if (mBbqChild != nullptr) { + return mBbqChild; + } + return this; +} + typedef bool (*InitFunc_t)(sp<IGraphicBufferProducer>*, const sp<IBinder>&); typedef void (*DeinitFunc_t)(const sp<IBinder>&); SurfaceControl::VpsExtension::VpsExtension() diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index fbd16f4ea2..139dbb7f6b 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -142,6 +142,39 @@ private: ui::Size mRequestedSize GUARDED_BY(mMutex); int32_t mFormat GUARDED_BY(mMutex); + struct BufferInfo { + bool hasBuffer = false; + uint32_t width; + uint32_t height; + uint32_t transform; + // This is used to check if we should update the blast layer size immediately or wait until + // we get the next buffer. This will support scenarios where the layer can change sizes + // and the buffer will scale to fit the new size. + uint32_t scalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + Rect crop; + + void update(bool hasBuffer, uint32_t width, uint32_t height, uint32_t transform, + uint32_t scalingMode, const Rect& crop) { + this->hasBuffer = hasBuffer; + this->width = width; + this->height = height; + this->transform = transform; + this->scalingMode = scalingMode; + if (!crop.isEmpty()) { + this->crop = crop; + } else { + this->crop = Rect(width, height); + } + } + }; + + // Last acquired buffer's info. This is used to calculate the correct scale when size change is + // requested. We need to use the old buffer's info to determine what scale we need to apply to + // ensure the correct size. + BufferInfo mLastBufferInfo GUARDED_BY(mMutex); + void setMatrix(SurfaceComposerClient::Transaction* t, const BufferInfo& bufferInfo) + REQUIRES(mMutex); + uint32_t mTransformHint GUARDED_BY(mMutex); sp<IGraphicBufferConsumer> mConsumer; @@ -159,11 +192,6 @@ private: std::queue<FrameTimelineInfo> mNextFrameTimelineInfoQueue GUARDED_BY(mMutex); - // Last acquired buffer's scaling mode. This is used to check if we should update the blast - // layer size immediately or wait until we get the next buffer. This will support scenarios - // where the layer can change sizes and the buffer will scale to fit the new size. - uint32_t mLastBufferScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; - // Tracks the last acquired frame number uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0; @@ -181,6 +209,10 @@ private: // it for debugging purposes. std::unordered_map<uint64_t /* bufferId */, nsecs_t> mDequeueTimestamps GUARDED_BY(mTimestampMutex); + + // Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a + // callback for them. + std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex); }; } // namespace android diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index d74c2ba72b..4ade240dcf 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -30,6 +30,9 @@ struct VsyncEventData { // The deadline in CLOCK_MONOTONIC that the app needs to complete its // frame by (both on the CPU and the GPU) int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max(); + + // The current frame interval in ns when this frame was scheduled. + int64_t frameInterval = 0; }; class DisplayEventDispatcher : public LooperCallback { diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 7179a20d22..0dffbde88a 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -75,6 +75,7 @@ public: uint32_t count; nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); nsecs_t deadlineTimestamp __attribute__((aligned(8))); + nsecs_t frameInterval __attribute__((aligned(8))); int64_t vsyncId; }; diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h index 3b4c009609..a23c20248c 100644 --- a/libs/gui/include/gui/FrameTimelineInfo.h +++ b/libs/gui/include/gui/FrameTimelineInfo.h @@ -18,7 +18,6 @@ #include <stdint.h> -#include <android/os/IInputConstants.h> #include <binder/Parcel.h> namespace android { @@ -31,7 +30,11 @@ struct FrameTimelineInfo { int64_t vsyncId = INVALID_VSYNC_ID; // The id of the input event that caused this buffer - int32_t inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; + // Default is android::os::IInputConstants::INVALID_INPUT_EVENT_ID = 0 + // We copy the value of the input event ID instead of including the header, because libgui + // header libraries containing FrameTimelineInfo must be available to vendors, but libinput is + // not directly vendor available. + int32_t inputEventId = 0; status_t write(Parcel& output) const; status_t read(const Parcel& input); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index ccd6d4e754..cb0468901a 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -275,6 +275,12 @@ public: virtual status_t overrideHdrTypes(const sp<IBinder>& display, const std::vector<ui::Hdr>& hdrTypes) = 0; + /* Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd. + * + * Requires the calling uid be from system server. + */ + virtual status_t onPullAtom(const int32_t atomId, std::string* outData, bool* success) = 0; + virtual status_t enableVSyncInjections(bool enable) = 0; virtual status_t injectVSync(nsecs_t when) = 0; @@ -600,6 +606,7 @@ public: OVERRIDE_HDR_TYPES, ADD_HDR_LAYER_INFO_LISTENER, REMOVE_HDR_LAYER_INFO_LISTENER, + ON_PULL_ATOM, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index 098760e89d..2d71194f70 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -36,7 +36,22 @@ namespace android { class ITransactionCompletedListener; class ListenerCallbacks; -using CallbackId = int64_t; +class CallbackId : public Parcelable { +public: + int64_t id; + enum class Type : int32_t { ON_COMPLETE, ON_COMMIT } type; + + CallbackId() {} + CallbackId(int64_t id, Type type) : id(id), type(type) {} + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + bool operator==(const CallbackId& rhs) const { return id == rhs.id && type == rhs.type; } +}; + +struct CallbackIdHash { + std::size_t operator()(const CallbackId& key) const { return std::hash<int64_t>()(key.id); } +}; class FrameEventHistoryStats : public Parcelable { public: @@ -112,7 +127,7 @@ public: TransactionStats() = default; TransactionStats(const std::vector<CallbackId>& ids) : callbackIds(ids) {} - TransactionStats(const std::unordered_set<CallbackId>& ids) + TransactionStats(const std::unordered_set<CallbackId, CallbackIdHash>& ids) : callbackIds(ids.begin(), ids.end()) {} TransactionStats(const std::vector<CallbackId>& ids, nsecs_t latch, const sp<Fence>& present, const std::vector<SurfaceStats>& surfaces) @@ -129,8 +144,9 @@ public: status_t writeToParcel(Parcel* output) const override; status_t readFromParcel(const Parcel* input) override; - static ListenerStats createEmpty(const sp<IBinder>& listener, - const std::unordered_set<CallbackId>& callbackIds); + static ListenerStats createEmpty( + const sp<IBinder>& listener, + const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds); sp<IBinder> listener; std::vector<TransactionStats> transactionStats; @@ -156,7 +172,8 @@ public: class ListenerCallbacks { public: - ListenerCallbacks(const sp<IBinder>& listener, const std::unordered_set<CallbackId>& callbacks) + ListenerCallbacks(const sp<IBinder>& listener, + const std::unordered_set<CallbackId, CallbackIdHash>& callbacks) : transactionCompletedListener(listener), callbackIds(callbacks.begin(), callbacks.end()) {} @@ -170,9 +187,12 @@ public: if (callbackIds.empty()) { return rhs.callbackIds.empty(); } - return callbackIds.front() == rhs.callbackIds.front(); + return callbackIds.front().id == rhs.callbackIds.front().id; } + // Returns a new ListenerCallbacks filtered by type + ListenerCallbacks filter(CallbackId::Type type) const; + sp<IBinder> transactionCompletedListener; std::vector<CallbackId> callbackIds; }; @@ -191,7 +211,7 @@ struct CallbackIdsHash { // same members. It is sufficient to just check the first CallbackId in the vectors. If // they match, they are the same. If they do not match, they are not the same. std::size_t operator()(const std::vector<CallbackId>& callbackIds) const { - return std::hash<CallbackId>{}((callbackIds.empty()) ? 0 : callbackIds.front()); + return std::hash<int64_t>{}((callbackIds.empty()) ? 0 : callbackIds.front().id); } }; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 65d771053b..b4f62f2206 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -82,10 +82,9 @@ struct layer_state_t { eTransparentRegionChanged = 0x00000020, eFlagsChanged = 0x00000040, eLayerStackChanged = 0x00000080, - /* was eCropChanged_legacy, now available 0x00000100, */ - eDeferTransaction_legacy = 0x00000200, eReleaseBufferListenerChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, + eLayerCreated = 0x00001000, /* was eDetachChildren, now available 0x00002000, */ eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, @@ -105,7 +104,7 @@ struct layer_state_t { eHasListenerCallbacksChanged = 0x20000000, eInputInfoChanged = 0x40000000, eCornerRadiusChanged = 0x80000000, - eFrameChanged = 0x1'00000000, + /* was eFrameChanged, now available 0x1'00000000, */ eCachedBufferChanged = 0x2'00000000, eBackgroundColorChanged = 0x4'00000000, eMetadataChanged = 0x8'00000000, @@ -152,9 +151,7 @@ struct layer_state_t { matrix22_t matrix; float cornerRadius; uint32_t backgroundBlurRadius; - sp<SurfaceControl> barrierSurfaceControl_legacy; sp<SurfaceControl> reparentSurfaceControl; - uint64_t barrierFrameNumber; sp<SurfaceControl> relativeLayerSurfaceControl; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 2487961426..5bbd8e3d85 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -336,7 +336,7 @@ public: struct CallbackInfo { // All the callbacks that have been requested for a TransactionCompletedListener in the // Transaction - std::unordered_set<CallbackId> callbackIds; + std::unordered_set<CallbackId, CallbackIdHash> callbackIds; // All the SurfaceControls that have been modified in this TransactionCompletedListener's // process that require a callback if there is one or more callbackIds set. std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls; @@ -454,13 +454,7 @@ public: const std::vector<BlurRegion>& regions); Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack); Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p); - // Defers applying any changes made in this transaction until the Layer - // identified by handle reaches the given frameNumber. If the Layer identified - // by handle is removed, then we will apply this transaction regardless of - // what frame number has been reached. - Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc, - const sp<SurfaceControl>& barrierSurfaceControl, - uint64_t frameNumber); + /// Reparents the current layer to the new parent handle. The new parent must not be null. Transaction& reparent(const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent); @@ -473,7 +467,6 @@ public: Transaction& setTransform(const sp<SurfaceControl>& sc, uint32_t transform); Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc, bool transformToDisplayInverse); - Transaction& setFrame(const sp<SurfaceControl>& sc, const Rect& frame); Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer, ReleaseBufferCallback callback = nullptr); Transaction& setCachedBuffer(const sp<SurfaceControl>& sc, int32_t bufferId); @@ -491,9 +484,15 @@ public: // Sets information about the priority of the frame. Transaction& setFrameRateSelectionPriority(const sp<SurfaceControl>& sc, int32_t priority); + Transaction& addTransactionCallback(TransactionCompletedCallbackTakesContext callback, + void* callbackContext, CallbackId::Type callbackType); + Transaction& addTransactionCompletedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext); + Transaction& addTransactionCommittedCallback( + TransactionCompletedCallbackTakesContext callback, void* callbackContext); + // ONLY FOR BLAST ADAPTER Transaction& notifyProducerDisconnect(const sp<SurfaceControl>& sc); // Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour. @@ -574,6 +573,8 @@ public: static status_t overrideHdrTypes(const sp<IBinder>& display, const std::vector<ui::Hdr>& hdrTypes); + static status_t onPullAtom(const int32_t atomId, std::string* outData, bool* success); + static void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation, const Rect& layerStackRect, const Rect& displayRect); @@ -626,14 +627,13 @@ public: class TransactionCompletedListener : public BnTransactionCompletedListener { TransactionCompletedListener(); - CallbackId getNextIdLocked() REQUIRES(mMutex); + int64_t getNextIdLocked() REQUIRES(mMutex); std::mutex mMutex; bool mListening GUARDED_BY(mMutex) = false; - CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1; - + int64_t mCallbackIdCounter GUARDED_BY(mMutex) = 1; struct CallbackTranslation { TransactionCompletedCallback callbackFunction; std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash> @@ -651,7 +651,8 @@ class TransactionCompletedListener : public BnTransactionCompletedListener { SurfaceStatsCallback callback; }; - std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex); + std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> mCallbacks + GUARDED_BY(mMutex); std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex); std::unordered_map<uint64_t /* graphicsBufferId */, ReleaseBufferCallback> mReleaseBufferCallbacks GUARDED_BY(mMutex); @@ -667,10 +668,12 @@ public: CallbackId addCallbackFunction( const TransactionCompletedCallback& callbackFunction, const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>& - surfaceControls); + surfaceControls, + CallbackId::Type callbackType); - void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl, - const std::unordered_set<CallbackId>& callbackIds); + void addSurfaceControlToCallbacks( + const sp<SurfaceControl>& surfaceControl, + const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds); /* * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 87dbbcc52f..12d1a344da 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -37,6 +37,7 @@ namespace android { class IGraphicBufferProducer; class Surface; class SurfaceComposerClient; +class BLASTBufferQueue; // --------------------------------------------------------------------------- @@ -70,12 +71,13 @@ public: static status_t writeSurfaceToParcel( const sp<SurfaceControl>& control, Parcel* parcel); - sp<Surface> getSurface() const; - sp<Surface> createSurface() const; + sp<Surface> getSurface(); + sp<Surface> createSurface(); sp<IBinder> getHandle() const; + sp<IBinder> getLayerStateHandle() const; int32_t getLayerId() const; - sp<IGraphicBufferProducer> getIGraphicBufferProducer() const; + sp<IGraphicBufferProducer> getIGraphicBufferProducer(); status_t clearLayerFrameStats() const; status_t getLayerFrameStats(FrameStats* outStats) const; @@ -85,12 +87,16 @@ public: uint32_t getTransformHint() const; void setTransformHint(uint32_t hint); + void updateDefaultBufferSize(uint32_t width, uint32_t height); explicit SurfaceControl(const sp<SurfaceControl>& other); SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbp, int32_t layerId, - uint32_t transformHint = 0); + uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0, + uint32_t transformHint = 0, uint32_t flags = 0); + + sp<SurfaceControl> getParentingLayer(); private: // can't be copied @@ -102,7 +108,7 @@ private: ~SurfaceControl(); - sp<Surface> generateSurfaceLocked() const; + sp<Surface> generateSurfaceLocked(); status_t validate() const; sp<SurfaceComposerClient> mClient; @@ -110,8 +116,14 @@ private: sp<IGraphicBufferProducer> mGraphicBufferProducer; mutable Mutex mLock; mutable sp<Surface> mSurfaceData; + mutable sp<BLASTBufferQueue> mBbq; + mutable sp<SurfaceControl> mBbqChild; int32_t mLayerId; uint32_t mTransformHint; + uint32_t mWidth; + uint32_t mHeight; + PixelFormat mFormat; + uint32_t mCreateFlags; // VpsExtension class VpsExtension { diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index fe48d88376..5a5da97599 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -140,7 +140,6 @@ protected: /*parent*/ nullptr); t.setLayerStack(mSurfaceControl, 0) .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) - .setFrame(mSurfaceControl, Rect(resolution)) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) .apply(); @@ -218,13 +217,13 @@ protected: col >= region.left - border && col < region.right + border; } if (!outsideRegion && inRegion) { - EXPECT_GE(epsilon, abs(r - *(pixel))); - EXPECT_GE(epsilon, abs(g - *(pixel + 1))); - EXPECT_GE(epsilon, abs(b - *(pixel + 2))); + ASSERT_GE(epsilon, abs(r - *(pixel))); + ASSERT_GE(epsilon, abs(g - *(pixel + 1))); + ASSERT_GE(epsilon, abs(b - *(pixel + 2))); } else if (outsideRegion && !inRegion) { - EXPECT_GE(epsilon, abs(r - *(pixel))); - EXPECT_GE(epsilon, abs(g - *(pixel + 1))); - EXPECT_GE(epsilon, abs(b - *(pixel + 2))); + ASSERT_GE(epsilon, abs(r - *(pixel))); + ASSERT_GE(epsilon, abs(g - *(pixel + 1))); + ASSERT_GE(epsilon, abs(b - *(pixel + 2))); } ASSERT_EQ(false, ::testing::Test::HasFailure()); } @@ -466,7 +465,8 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + checkScreenCapture(r, g, b, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); } TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { @@ -522,16 +522,148 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { adapter.waitForCallbacks(); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); - - ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, - {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, + {10, 10, (int32_t)bufferSideLength - 10, + (int32_t)bufferSideLength - 10})); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(0, 0, 0, {0, 0, (int32_t)bufferSideLength, (int32_t)bufferSideLength}, /*border*/ 0, /*outsideRegion*/ true)); } +TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { + // add black background + auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect); + ASSERT_NE(nullptr, bg.get()); + Transaction t; + t.setLayerStack(bg, 0) + .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) + .setColor(bg, half3{0, 0, 0}) + .setLayer(bg, 0) + .apply(); + + Rect windowSize(1000, 1000); + Rect bufferSize(windowSize); + Rect bufferCrop(200, 200, 700, 700); + + BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight()); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufferSize.getWidth(), + bufferSize.getHeight(), PIXEL_FORMAT_RGBA_8888, + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast<void**>(&bufData)); + // fill buffer with grey + fillBuffer(bufData, bufferSize, buf->getStride(), 127, 127, 127); + + // fill crop area with different colors so we can verify the cropped region has been scaled + // correctly. + fillBuffer(bufData, Rect(200, 200, 450, 450), buf->getStride(), /* rgb */ 255, 0, 0); + fillBuffer(bufData, Rect(200, 451, 450, 700), buf->getStride(), /* rgb */ 0, 255, 0); + fillBuffer(bufData, Rect(451, 200, 700, 450), buf->getStride(), /* rgb */ 0, 0, 255); + fillBuffer(bufData, Rect(451, 451, 700, 700), buf->getStride(), /* rgb */ 255, 0, 0); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, + bufferCrop /* Rect::INVALID_RECT */, + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + + adapter.waitForCallbacks(); + + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + + // Verify cropped region is scaled correctly. + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, {510, 10, 990, 490})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {510, 510, 990, 990})); + // Verify outside region is black. + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 0, + {0, 0, (int32_t)windowSize.getWidth(), + (int32_t)windowSize.getHeight()}, + /*border*/ 0, /*outsideRegion*/ true)); +} + +TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { + // add black background + auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect); + ASSERT_NE(nullptr, bg.get()); + Transaction t; + t.setLayerStack(bg, 0) + .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) + .setColor(bg, half3{0, 0, 0}) + .setLayer(bg, 0) + .apply(); + + Rect windowSize(1000, 1000); + Rect bufferSize(500, 500); + Rect bufferCrop(100, 100, 350, 350); + + BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight()); + sp<IGraphicBufferProducer> igbProducer; + setUpProducer(adapter, igbProducer); + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buf; + auto ret = igbProducer->dequeueBuffer(&slot, &fence, bufferSize.getWidth(), + bufferSize.getHeight(), PIXEL_FORMAT_RGBA_8888, + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + + uint32_t* bufData; + buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN), + reinterpret_cast<void**>(&bufData)); + // fill buffer with grey + fillBuffer(bufData, bufferSize, buf->getStride(), 127, 127, 127); + + // fill crop area with different colors so we can verify the cropped region has been scaled + // correctly. + fillBuffer(bufData, Rect(100, 100, 225, 225), buf->getStride(), /* rgb */ 255, 0, 0); + fillBuffer(bufData, Rect(100, 226, 225, 350), buf->getStride(), /* rgb */ 0, 255, 0); + fillBuffer(bufData, Rect(226, 100, 350, 225), buf->getStride(), /* rgb */ 0, 0, 255); + fillBuffer(bufData, Rect(226, 226, 350, 350), buf->getStride(), /* rgb */ 255, 0, 0); + buf->unlock(); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */, + HAL_DATASPACE_UNKNOWN, + bufferCrop /* Rect::INVALID_RECT */, + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0, + Fence::NO_FENCE); + igbProducer->queueBuffer(slot, input, &qbOutput); + ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); + + adapter.waitForCallbacks(); + + ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + // Verify cropped region is scaled correctly. + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 255, {510, 10, 990, 490})); + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {510, 510, 990, 990})); + // Verify outside region is black. + ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 0, 0, + {0, 0, (int32_t)windowSize.getWidth(), + (int32_t)windowSize.getHeight()}, + /*border*/ 0, /*outsideRegion*/ true)); +} + class TestProducerListener : public BnProducerListener { public: sp<IGraphicBufferProducer> mIgbp; @@ -596,7 +728,6 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { t.setLayerStack(bgSurface, 0) .show(bgSurface) .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) - .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1) .apply(); @@ -619,7 +750,8 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + checkScreenCapture(r, g, b, + {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); } class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { @@ -834,26 +966,6 @@ public: if (postedTime) *postedTime = systemTime(); igbProducer->queueBuffer(slot, input, qbOutput); } - - void createBufferQueueProducer(sp<IGraphicBufferProducer>* bqIgbp) { - mBufferQueueSurfaceControl = - mClient->createSurface(String8("BqSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceBufferQueue); - ASSERT_NE(nullptr, mBufferQueueSurfaceControl.get()); - Transaction() - .setLayerStack(mBufferQueueSurfaceControl, 0) - .show(mBufferQueueSurfaceControl) - .setDataspace(mBufferQueueSurfaceControl, ui::Dataspace::V0_SRGB) - .setSize(mBufferQueueSurfaceControl, mDisplayWidth, mDisplayHeight) - .setLayer(mBufferQueueSurfaceControl, std::numeric_limits<int32_t>::max()) - .apply(); - - sp<Surface> bqSurface = mBufferQueueSurfaceControl->getSurface(); - ASSERT_NE(nullptr, bqSurface.get()); - - *bqIgbp = bqSurface->getIGraphicBufferProducer(); - setUpProducer(*bqIgbp); - } sp<SurfaceControl> mBufferQueueSurfaceControl; }; @@ -909,55 +1021,6 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) { adapter.waitForCallbacks(); } -// Runs the same Frame Event History test -TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic_BufferQueue) { - sp<IGraphicBufferProducer> bqIgbp; - createBufferQueueProducer(&bqIgbp); - - ProducerFrameEventHistory history; - IGraphicBufferProducer::QueueBufferOutput qbOutput; - nsecs_t requestedPresentTimeA = 0; - nsecs_t postedTimeA = 0; - setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true); - history.applyDelta(qbOutput.frameTimestamps); - - FrameEvents* events = nullptr; - events = history.getFrame(1); - ASSERT_NE(nullptr, events); - ASSERT_EQ(1, events->frameNumber); - ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeA); - - // wait for buffer to be presented - std::this_thread::sleep_for(200ms); - - nsecs_t requestedPresentTimeB = 0; - nsecs_t postedTimeB = 0; - setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true); - history.applyDelta(qbOutput.frameTimestamps); - events = history.getFrame(1); - ASSERT_NE(nullptr, events); - - // frame number, requestedPresentTime, and postTime should not have changed - ASSERT_EQ(1, events->frameNumber); - ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeA); - - ASSERT_GE(events->latchTime, postedTimeA); - ASSERT_FALSE(events->hasDequeueReadyInfo()); - - ASSERT_NE(nullptr, events->gpuCompositionDoneFence); - ASSERT_NE(nullptr, events->displayPresentFence); - ASSERT_NE(nullptr, events->releaseFence); - - // we should also have gotten the initial values for the next frame - events = history.getFrame(2); - ASSERT_NE(nullptr, events); - ASSERT_EQ(2, events->frameNumber); - ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeB); -} - TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp<IGraphicBufferProducer> igbProducer; @@ -1008,53 +1071,4 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { ASSERT_GE(events->postedTime, postedTimeB); } -TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame_BufferQueue) { - sp<IGraphicBufferProducer> bqIgbp; - createBufferQueueProducer(&bqIgbp); - - ProducerFrameEventHistory history; - IGraphicBufferProducer::QueueBufferOutput qbOutput; - nsecs_t requestedPresentTimeA = 0; - nsecs_t postedTimeA = 0; - nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); - setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true, - presentTimeDelay); - history.applyDelta(qbOutput.frameTimestamps); - - FrameEvents* events = nullptr; - events = history.getFrame(1); - ASSERT_NE(nullptr, events); - ASSERT_EQ(1, events->frameNumber); - ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeA); - - // queue another buffer so the first can be dropped - nsecs_t requestedPresentTimeB = 0; - nsecs_t postedTimeB = 0; - setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true); - history.applyDelta(qbOutput.frameTimestamps); - events = history.getFrame(1); - ASSERT_NE(nullptr, events); - - // frame number, requestedPresentTime, and postTime should not have changed - ASSERT_EQ(1, events->frameNumber); - ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeA); - - // a valid latchtime should not be set - ASSERT_FALSE(events->hasLatchInfo()); - ASSERT_FALSE(events->hasDequeueReadyInfo()); - - ASSERT_NE(nullptr, events->gpuCompositionDoneFence); - ASSERT_NE(nullptr, events->displayPresentFence); - ASSERT_NE(nullptr, events->releaseFence); - - // we should also have gotten the initial values for the next frame - events = history.getFrame(2); - ASSERT_NE(nullptr, events); - ASSERT_EQ(2, events->frameNumber); - ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime); - ASSERT_GE(events->postedTime, postedTimeB); -} - } // namespace android diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp index 7dbba31ba8..bcd39dbbf4 100644 --- a/libs/gui/tests/DisplayEventStructLayout_test.cpp +++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp @@ -34,7 +34,8 @@ TEST(DisplayEventStructLayoutTest, TestEventAlignment) { CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0); CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8); CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16); - CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 24); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, frameInterval, 24); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 32); CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 751b95af66..ea8c2957a1 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -102,14 +102,13 @@ protected: // test flakiness. mSurfaceControl = mComposerClient->createSurface( String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, 0); + SurfaceComposerClient::Transaction().apply(true); ASSERT_TRUE(mSurfaceControl != nullptr); ASSERT_TRUE(mSurfaceControl->isValid()); Transaction t; - ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff) - .show(mSurfaceControl) - .apply()); + ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff).show(mSurfaceControl).apply()); mSurface = mSurfaceControl->getSurface(); ASSERT_TRUE(mSurface != nullptr); @@ -776,6 +775,10 @@ public: const std::vector<ui::Hdr>& /*hdrTypes*/) override { return NO_ERROR; } + status_t onPullAtom(const int32_t /*atomId*/, std::string* /*outData*/, + bool* /*success*/) override { + return NO_ERROR; + } status_t enableVSyncInjections(bool /*enable*/) override { return NO_ERROR; } diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index bf8ec34627..3657fcfdfe 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -309,7 +309,8 @@ status_t InputChannel::openInputChannelPair(const std::string& name, int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { status_t result = -errno; - ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", name.c_str(), errno); + ALOGE("channel '%s' ~ Could not create socket pair. errno=%s(%d)", name.c_str(), + strerror(errno), errno); outServerChannel.reset(); outClientChannel.reset(); return result; diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index dc2dd297c5..0edb213089 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -130,7 +130,7 @@ public: virtual ~Choreographer() override EXCLUDES(gChoreographers.lock); int64_t getVsyncId() const; int64_t getFrameDeadline() const; - + int64_t getFrameInterval() const; private: Choreographer(const Choreographer&) = delete; @@ -418,6 +418,10 @@ int64_t Choreographer::getFrameDeadline() const { return mLastVsyncEventData.deadlineTimestamp; } +int64_t Choreographer::getFrameInterval() const { + return mLastVsyncEventData.frameInterval; +} + } // namespace android using namespace android; @@ -501,6 +505,10 @@ int64_t AChoreographer_getFrameDeadline(const AChoreographer* choreographer) { return AChoreographer_to_Choreographer(choreographer)->getFrameDeadline(); } +int64_t AChoreographer_getFrameInterval(const AChoreographer* choreographer) { + return AChoreographer_to_Choreographer(choreographer)->getFrameInterval(); +} + } // namespace android /* Glue for the NDK interface */ diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h index 0f4fd4521f..7d25ce8253 100644 --- a/libs/nativedisplay/include-private/private/android/choreographer.h +++ b/libs/nativedisplay/include-private/private/android/choreographer.h @@ -42,6 +42,11 @@ int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer); // value. int64_t AChoreographer_getFrameDeadline(const AChoreographer* choreographer); +// Returns the current interval in ns between frames. +// Client are expected to call this function from their frame callback function. +// Calling this function from anywhere else will return an undefined value. +int64_t AChoreographer_getFrameInterval(const AChoreographer* choreographer); + // Trampoline functions allowing libandroid.so to define the NDK symbols without including // the entirety of libnativedisplay as a whole static lib. As libnativedisplay // maintains global state, libnativedisplay can never be directly statically diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt index fda6a20a0b..9ed4915481 100644 --- a/libs/nativedisplay/libnativedisplay.map.txt +++ b/libs/nativedisplay/libnativedisplay.map.txt @@ -31,6 +31,7 @@ LIBNATIVEDISPLAY_PLATFORM { android::AChoreographer_signalRefreshRateCallbacks*; android::AChoreographer_getVsyncId*; android::AChoreographer_getFrameDeadline*; + android::AChoreographer_getFrameInterval*; android::ADisplay_acquirePhysicalDisplays*; android::ADisplay_release*; android::ADisplay_getMaxSupportedFps*; diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index 20a1f74792..d93a84cd25 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -164,45 +164,56 @@ enum AHardwareBuffer_Format { * Buffer usage flags, specifying how the buffer will be accessed. */ enum AHardwareBuffer_UsageFlags { - /// The buffer will never be locked for direct CPU reads using the - /// AHardwareBuffer_lock() function. Note that reading the buffer - /// using OpenGL or Vulkan functions or memory mappings is still - /// allowed. + /** + * The buffer will never be locked for direct CPU reads using the + * AHardwareBuffer_lock() function. Note that reading the buffer + * using OpenGL or Vulkan functions or memory mappings is still + * allowed. + */ AHARDWAREBUFFER_USAGE_CPU_READ_NEVER = 0UL, - /// The buffer will sometimes be locked for direct CPU reads using - /// the AHardwareBuffer_lock() function. Note that reading the - /// buffer using OpenGL or Vulkan functions or memory mappings - /// does not require the presence of this flag. + /** + * The buffer will sometimes be locked for direct CPU reads using + * the AHardwareBuffer_lock() function. Note that reading the + * buffer using OpenGL or Vulkan functions or memory mappings + * does not require the presence of this flag. + */ AHARDWAREBUFFER_USAGE_CPU_READ_RARELY = 2UL, - /// The buffer will often be locked for direct CPU reads using - /// the AHardwareBuffer_lock() function. Note that reading the - /// buffer using OpenGL or Vulkan functions or memory mappings - /// does not require the presence of this flag. + /** + * The buffer will often be locked for direct CPU reads using + * the AHardwareBuffer_lock() function. Note that reading the + * buffer using OpenGL or Vulkan functions or memory mappings + * does not require the presence of this flag. + */ AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN = 3UL, - /// CPU read value mask. - AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL, - /// The buffer will never be locked for direct CPU writes using the - /// AHardwareBuffer_lock() function. Note that writing the buffer - /// using OpenGL or Vulkan functions or memory mappings is still - /// allowed. + /** CPU read value mask. */ + AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL, + /** + * The buffer will never be locked for direct CPU writes using the + * AHardwareBuffer_lock() function. Note that writing the buffer + * using OpenGL or Vulkan functions or memory mappings is still + * allowed. + */ AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER = 0UL << 4, - /// The buffer will sometimes be locked for direct CPU writes using - /// the AHardwareBuffer_lock() function. Note that writing the - /// buffer using OpenGL or Vulkan functions or memory mappings - /// does not require the presence of this flag. + /** + * The buffer will sometimes be locked for direct CPU writes using + * the AHardwareBuffer_lock() function. Note that writing the + * buffer using OpenGL or Vulkan functions or memory mappings + * does not require the presence of this flag. + */ AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY = 2UL << 4, - /// The buffer will often be locked for direct CPU writes using - /// the AHardwareBuffer_lock() function. Note that writing the - /// buffer using OpenGL or Vulkan functions or memory mappings - /// does not require the presence of this flag. + /** + * The buffer will often be locked for direct CPU writes using + * the AHardwareBuffer_lock() function. Note that writing the + * buffer using OpenGL or Vulkan functions or memory mappings + * does not require the presence of this flag. + */ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN = 3UL << 4, - /// CPU write value mask. + /** CPU write value mask. */ AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4, - - /// The buffer will be read from by the GPU as a texture. + /** The buffer will be read from by the GPU as a texture. */ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8, - /// The buffer will be written to by the GPU as a framebuffer attachment. + /** The buffer will be written to by the GPU as a framebuffer attachment.*/ AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9, /** * The buffer will be written to by the GPU as a framebuffer @@ -237,7 +248,7 @@ enum AHardwareBuffer_UsageFlags { * buffers are expected to behave. */ AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14, - /// The buffer will be read by a hardware video encoder. + /** The buffer will be read by a hardware video encoder. */ AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16, /** * The buffer will be used for direct writes from sensors. diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 50e9d53604..61b3f94aab 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -157,6 +157,7 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window); * For all of these parameters, if 0 is supplied then the window's base * value will come back in force. * + * \param window pointer to an ANativeWindow object. * \param width width of the buffers in pixels. * \param height height of the buffers in pixels. * \param format one of the AHardwareBuffer_Format constants. @@ -191,6 +192,7 @@ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); * * Available since API level 26. * + * \param window pointer to an ANativeWindow object. * \param transform combination of {@link ANativeWindowTransform} flags * \return 0 for success, or -EINVAL if \p transform is invalid */ @@ -208,6 +210,7 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo * * Available since API level 28. * + * \param window pointer to an ANativeWindow object. * \param dataSpace data space of all buffers queued after this call. * \return 0 for success, -EINVAL if window is invalid or the dataspace is not * supported. @@ -306,6 +309,8 @@ enum ANativeWindow_ChangeFrameRateStrategy { * valid refresh rate for this device's display - e.g., it's fine to pass 30fps * to a device that can only run the display at 60fps. * + * \param window pointer to an ANativeWindow object. + * * \param compatibility The frame rate compatibility of this window. The * compatibility value may influence the system's choice of display refresh * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp new file mode 100644 index 0000000000..a5712b319f --- /dev/null +++ b/libs/permission/Android.bp @@ -0,0 +1,23 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_library_shared { + name: "libpermission", + srcs: [ + "AppOpsManager.cpp", + "IAppOpsCallback.cpp", + "IAppOpsService.cpp", + ], + export_include_dirs: ["include"], + shared_libs: [ + "libbinder", + "liblog", + "libutils", + ], +} diff --git a/libs/binder/AppOpsManager.cpp b/libs/permission/AppOpsManager.cpp index de42f36d74..baa9d75116 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/permission/AppOpsManager.cpp @@ -37,7 +37,7 @@ static const sp<IBinder>& getClientId() { pthread_mutex_lock(&gClientIdMutex); if (gClientId == nullptr) { - gClientId = new BBinder(); + gClientId = sp<BBinder>::make(); } pthread_mutex_unlock(&gClientIdMutex); return gClientId; diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/permission/IAppOpsCallback.cpp index 2b3f462ab8..2b3f462ab8 100644 --- a/libs/binder/IAppOpsCallback.cpp +++ b/libs/permission/IAppOpsCallback.cpp diff --git a/libs/binder/IAppOpsService.cpp b/libs/permission/IAppOpsService.cpp index d59f44562e..d59f44562e 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/permission/IAppOpsService.cpp diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h index c048cbed37..c048cbed37 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/permission/include/binder/AppOpsManager.h diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/permission/include/binder/IAppOpsCallback.h index eb76f57bf8..eb76f57bf8 100644 --- a/libs/binder/include/binder/IAppOpsCallback.h +++ b/libs/permission/include/binder/IAppOpsCallback.h diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/permission/include/binder/IAppOpsService.h index 22f056b235..22f056b235 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/permission/include/binder/IAppOpsService.h diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 026b19a75a..f395ab43d8 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -48,6 +48,7 @@ filegroup { name: "librenderengine_sources", srcs: [ "Description.cpp", + "ExternalTexture.cpp", "Mesh.cpp", "RenderEngine.cpp", "Texture.cpp", @@ -91,6 +92,7 @@ filegroup { "skia/debug/CaptureTimer.cpp", "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", + "skia/debug/SkiaMemoryReporter.cpp", "skia/filters/BlurFilter.cpp", "skia/filters/LinearEffect.cpp", ], diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp new file mode 100644 index 0000000000..eabff58eba --- /dev/null +++ b/libs/renderengine/ExternalTexture.cpp @@ -0,0 +1,43 @@ +/* + * 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 <renderengine/ExternalTexture.h> +#include <renderengine/RenderEngine.h> +#include <ui/GraphicBuffer.h> + +#include "log/log_main.h" + +namespace android::renderengine { + +ExternalTexture::ExternalTexture(const sp<GraphicBuffer>& buffer, RenderEngine& renderEngine, + uint32_t usage) + : mBuffer(buffer), mRenderEngine(renderEngine) { + LOG_ALWAYS_FATAL_IF(buffer == nullptr, + "Attempted to bind a null buffer to an external texture!"); + // GLESRenderEngine has a separate texture cache for output buffers, + if (usage == Usage::WRITEABLE && + (mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::GLES || + mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::THREADED)) { + return; + } + mRenderEngine.mapExternalTextureBuffer(mBuffer, usage & Usage::WRITEABLE); +} + +ExternalTexture::~ExternalTexture() { + mRenderEngine.unmapExternalTextureBuffer(mBuffer); +} + +} // namespace android::renderengine diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index a2963a7c33..d87315fdc2 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -746,7 +746,8 @@ void GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp<Grap return; } -void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { +void GLESRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, + bool /*isRenderable*/) { ATRACE_CALL(); mImageManager->cacheAsync(buffer, nullptr); } @@ -797,8 +798,8 @@ status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBu return NO_ERROR; } -void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { - mImageManager->releaseAsync(bufferId, nullptr); +void GLESRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { + mImageManager->releaseAsync(buffer->getId(), nullptr); } std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting( @@ -1102,7 +1103,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, - const sp<GraphicBuffer>& buffer, + const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { ATRACE_CALL(); @@ -1125,7 +1126,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } - validateOutputBufferUsage(buffer); + validateOutputBufferUsage(buffer->getBuffer()); std::unique_ptr<BindNativeBufferAsFramebuffer> fbo; // Gathering layers that requested blur, we'll need them to decide when to render to an @@ -1142,11 +1143,13 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, if (blurLayersSize == 0) { fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, - buffer.get()->getNativeBuffer(), + buffer->getBuffer() + .get() + ->getNativeBuffer(), useFramebufferCache); if (fbo->getStatus() != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors(); return fbo->getStatus(); } @@ -1157,7 +1160,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius); if (status != NO_ERROR) { ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors(); return status; } @@ -1194,7 +1197,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, auto status = mBlurFilter->prepare(); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't render first blur pass"); return status; } @@ -1203,6 +1206,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, // Done blurring, time to bind the native FBO and render our blur onto it. fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer.get() + ->getBuffer() ->getNativeBuffer(), useFramebufferCache); status = fbo->getStatus(); @@ -1215,7 +1219,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, } if (status != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't bind native framebuffer"); return status; } @@ -1223,7 +1227,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, status = mBlurFilter->render(blurLayersSize > 1); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't render blur filter"); return status; } @@ -1250,7 +1254,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, disableTexture = false; isOpaque = layer->source.buffer.isOpaque; - sp<GraphicBuffer> gBuf = layer->source.buffer.buffer; + sp<GraphicBuffer> gBuf = layer->source.buffer.buffer->getBuffer(); validateInputBufferUsage(gBuf); bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf, layer->source.buffer.fence); @@ -1274,7 +1278,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, // Do not cache protected EGLImage, protected memory is limited. if (gBuf->getUsage() & GRALLOC_USAGE_PROTECTED) { - unbindExternalTextureBuffer(gBuf->getId()); + unmapExternalTextureBuffer(gBuf); } } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index cd7a86bb0e..e7ed9c01fa 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -60,16 +60,14 @@ public: void primeCache() override; void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; - void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex); - void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex); - bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; bool useProtectedContext(bool useProtectedContext) override; status_t drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, - const sp<GraphicBuffer>& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + const std::shared_ptr<ExternalTexture>& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) override; bool cleanupPostRender(CleanupMode mode) override; int getContextPriority() override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } @@ -105,6 +103,9 @@ protected: EXCLUDES(mFramebufferImageCacheMutex); size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; + void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) + EXCLUDES(mRenderingMutex); + void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex); private: friend class BindNativeBufferAsFramebuffer; diff --git a/libs/renderengine/include/renderengine/ExternalTexture.h b/libs/renderengine/include/renderengine/ExternalTexture.h new file mode 100644 index 0000000000..07f0833d4a --- /dev/null +++ b/libs/renderengine/include/renderengine/ExternalTexture.h @@ -0,0 +1,61 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android-base/macros.h> +#include <ui/GraphicBuffer.h> + +namespace android::renderengine { + +class RenderEngine; + +/** + * Manages GPU image resources on behalf of clients using RenderEngine. + * + * Clients of RenderEngine are required to wrap their GraphicBuffer objects as an ExternalTexture, + * which is then mapped into GPU resources required by RenderEngine. When a client no longer needs + * to use the GraphicBuffer as input into RenderEngine::drawLayers, then the client should delete + * their ExternalTexture so that resources may be freed. + */ +class ExternalTexture { +public: + // Usage specifies the rendering intent for the buffer. + enum Usage : uint32_t { + // When a buffer is not READABLE but is WRITEABLE, then GLESRenderEngine will use that as a + // hint to load the buffer into a separate cache + READABLE = 1 << 0, + + // The buffer needs to be mapped as a 2D texture if set, otherwise must be mapped as an + // external texture + WRITEABLE = 1 << 1, + }; + // Creates an ExternalTexture for the provided buffer and RenderEngine instance, with the given + // usage hint of type Usage. + ExternalTexture(const sp<GraphicBuffer>& buffer, RenderEngine& renderEngine, uint32_t usage); + + ~ExternalTexture(); + + // Retrieves the buffer that is bound to this texture. + const sp<GraphicBuffer>& getBuffer() const { return mBuffer; } + +private: + sp<GraphicBuffer> mBuffer; + RenderEngine& mRenderEngine; + DISALLOW_COPY_AND_ASSIGN(ExternalTexture); +}; + +} // namespace android::renderengine diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 7661233967..c54c5ba047 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -16,11 +16,9 @@ #pragma once -#include <iosfwd> - #include <math/mat4.h> #include <math/vec3.h> -#include <renderengine/Texture.h> +#include <renderengine/ExternalTexture.h> #include <ui/BlurRegion.h> #include <ui/Fence.h> #include <ui/FloatRect.h> @@ -31,6 +29,8 @@ #include <ui/StretchEffect.h> #include <ui/Transform.h> +#include <iosfwd> + namespace android { namespace renderengine { @@ -39,7 +39,7 @@ struct Buffer { // Buffer containing the image that we will render. // If buffer == nullptr, then the rest of the fields in this struct will be // ignored. - sp<GraphicBuffer> buffer = nullptr; + std::shared_ptr<ExternalTexture> buffer = nullptr; // Fence that will fire when the buffer is ready to be bound. sp<Fence> fence = nullptr; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 4639a684a5..a9223ef28c 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -17,19 +17,20 @@ #ifndef SF_RENDERENGINE_H_ #define SF_RENDERENGINE_H_ -#include <stdint.h> -#include <sys/types.h> -#include <memory> - #include <android-base/unique_fd.h> #include <math/mat4.h> #include <renderengine/DisplaySettings.h> +#include <renderengine/ExternalTexture.h> #include <renderengine/Framebuffer.h> #include <renderengine/Image.h> #include <renderengine/LayerSettings.h> +#include <stdint.h> +#include <sys/types.h> #include <ui/GraphicTypes.h> #include <ui/Transform.h> +#include <memory> + /** * Allows to set RenderEngine backend to GLES (default) or SkiaGL (NOT yet supported). */ @@ -51,6 +52,7 @@ class Region; namespace renderengine { +class ExternalTexture; class Image; class Mesh; class Texture; @@ -104,23 +106,6 @@ public: virtual void genTextures(size_t count, uint32_t* names) = 0; virtual void deleteTextures(size_t count, uint32_t const* names) = 0; - // Caches Image resources for this buffer, but does not bind the buffer to - // a particular texture. - // Note that work is deferred to an additional thread, i.e. this call - // is made asynchronously, but the caller can expect that cache/unbind calls - // are performed in a manner that's conflict serializable, i.e. unbinding - // a buffer should never occur before binding the buffer if the caller - // called {bind, cache}ExternalTextureBuffer before calling unbind. - virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0; - // Removes internal resources referenced by the bufferId. This method should be - // invoked when the caller will no longer hold a reference to a GraphicBuffer - // and needs to clean up its resources. - // Note that work is deferred to an additional thread, i.e. this call - // is made asynchronously, but the caller can expect that cache/unbind calls - // are performed in a manner that's conflict serializable, i.e. unbinding - // a buffer should never occur before binding the buffer if the caller - // called {bind, cache}ExternalTextureBuffer before calling unbind. - virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0; enum class CleanupMode { CLEAN_OUTPUT_RESOURCES, @@ -141,7 +126,7 @@ public: // do any work. virtual bool cleanupPostRender(CleanupMode mode = CleanupMode::CLEAN_OUTPUT_RESOURCES) = 0; - // queries + // queries that are required to be thread safe virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; @@ -149,8 +134,11 @@ public: // ----- BEGIN NEW INTERFACE ----- + // queries that are required to be thread safe virtual bool isProtected() const = 0; virtual bool supportsProtectedContent() const = 0; + + // Attempt to switch RenderEngine into and out of protectedContext mode virtual bool useProtectedContext(bool useProtectedContext) = 0; // Notify RenderEngine of changes to the dimensions of the primary display @@ -190,8 +178,9 @@ public: // now, this always returns NO_ERROR. virtual status_t drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, - const sp<GraphicBuffer>& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0; + const std::shared_ptr<ExternalTexture>& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) = 0; virtual void cleanFramebufferCache() = 0; // Returns the priority this context was actually created with. Note: this may not be // the same as specified at context creation time, due to implementation limits on the @@ -199,7 +188,8 @@ public: virtual int getContextPriority() = 0; // Returns true if blur was requested in the RenderEngineCreationArgs and the implementation - // also supports background blur. If false, no blur will be applied when drawing layers. + // also supports background blur. If false, no blur will be applied when drawing layers. This + // query is required to be thread safe. virtual bool supportsBackgroundBlur() = 0; // Returns the current type of RenderEngine instance that was created. @@ -211,6 +201,31 @@ public: static void validateOutputBufferUsage(const sp<GraphicBuffer>&); protected: + // Maps GPU resources for this buffer. + // Note that work may be deferred to an additional thread, i.e. this call + // is made asynchronously, but the caller can expect that map/unmap calls + // are performed in a manner that's conflict serializable, i.e. unmapping + // a buffer should never occur before binding the buffer if the caller + // called mapExternalTextureBuffer before calling unmap. + // Note also that if the buffer contains protected content, then mapping those GPU resources may + // be deferred until the buffer is really used for drawing. This is because typical SoCs that + // support protected memory only support a limited amount, so optimisitically mapping protected + // memory may be too burdensome. If a buffer contains protected content and the RenderEngine + // implementation supports protected context, then GPU resources may be mapped into both the + // protected and unprotected contexts. + // If the buffer may ever be written to by RenderEngine, then isRenderable must be true. + virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) = 0; + // Unmaps GPU resources used by this buffer. This method should be + // invoked when the caller will no longer hold a reference to a GraphicBuffer + // and needs to clean up its resources. + // Note that if there are multiple callers holding onto the same buffer, then the buffer's + // resources may be internally ref-counted to guard against use-after-free errors. Note that + // work may be deferred to an additional thread, i.e. this call is expected to be made + // asynchronously, but the caller can expect that map/unmap calls are performed in a manner + // that's conflict serializable, i.e. unmap a buffer should never occur before binding the + // buffer if the caller called mapExternalTextureBuffer before calling unmap. + virtual void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0; + friend class ExternalTexture; friend class threaded::RenderEngineThreaded; const RenderEngineType mRenderEngineType; }; @@ -295,7 +310,8 @@ private: bool precacheToneMapperShaderOnly = false; bool supportsBackgroundBlur = false; RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM; - RenderEngine::RenderEngineType renderEngineType = RenderEngine::RenderEngineType::GLES; + RenderEngine::RenderEngineType renderEngineType = + RenderEngine::RenderEngineType::SKIA_GL_THREADED; }; } // namespace renderengine diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index a27d28e371..f7d64544b4 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -39,8 +39,6 @@ public: MOCK_METHOD1(dump, void(std::string&)); MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); - MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp<GraphicBuffer>&)); - MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t)); MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&)); MOCK_CONST_METHOD0(getMaxTextureSize, size_t()); MOCK_CONST_METHOD0(getMaxViewportDims, size_t()); @@ -52,12 +50,17 @@ public: void(Rect, Rect)); MOCK_METHOD6(drawLayers, status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&, - const sp<GraphicBuffer>&, const bool, base::unique_fd&&, + const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&, base::unique_fd*)); MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size)); + +protected: + // mock renderengine still needs to implement these, but callers should never need to call them. + void mapExternalTextureBuffer(const sp<GraphicBuffer>&, bool) {} + void unmapExternalTextureBuffer(const sp<GraphicBuffer>&) {} }; } // namespace mock diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp index c535597aea..8ae69de7f3 100644 --- a/libs/renderengine/skia/AutoBackendTexture.cpp +++ b/libs/renderengine/skia/AutoBackendTexture.cpp @@ -29,7 +29,8 @@ namespace renderengine { namespace skia { AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, - bool isRender) { + bool isOutputBuffer) + : mIsOutputBuffer(isOutputBuffer) { ATRACE_CALL(); AHardwareBuffer_Desc desc; AHardwareBuffer_describe(buffer, &desc); @@ -40,8 +41,12 @@ AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer GrAHardwareBufferUtils::MakeBackendTexture(context, buffer, desc.width, desc.height, &mDeleteProc, &mUpdateProc, &mImageCtx, createProtectedImage, backendFormat, - isRender); + isOutputBuffer); mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format); + ALOGE_IF(!mBackendTexture.isValid(), + "Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d isWriteable:%d " + "format:%d", + this, desc.width, desc.height, createProtectedImage, isOutputBuffer, desc.format); } void AutoBackendTexture::unref(bool releaseLocalResources) { @@ -92,13 +97,16 @@ sk_sp<SkImage> AutoBackendTexture::makeImage(ui::Dataspace dataspace, SkAlphaTyp mImage = image; mDataspace = dataspace; - LOG_ALWAYS_FATAL_IF(mImage == nullptr, "Unable to generate SkImage from buffer"); + LOG_ALWAYS_FATAL_IF(mImage == nullptr, + "Unable to generate SkImage. isTextureValid:%d dataspace:%d", + mBackendTexture.isValid(), dataspace); return mImage; } sk_sp<SkSurface> AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace, GrDirectContext* context) { ATRACE_CALL(); + LOG_ALWAYS_FATAL_IF(!mIsOutputBuffer, "You can't generate a SkSurface for a read-only texture"); if (!mSurface.get() || mDataspace != dataspace) { sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(context, mBackendTexture, @@ -113,10 +121,12 @@ sk_sp<SkSurface> AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace, } mDataspace = dataspace; - LOG_ALWAYS_FATAL_IF(mSurface == nullptr, "Unable to generate SkSurface"); + LOG_ALWAYS_FATAL_IF(mSurface == nullptr, + "Unable to generate SkSurface. isTextureValid:%d dataspace:%d", + mBackendTexture.isValid(), dataspace); return mSurface; } } // namespace skia } // namespace renderengine -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h index bb758780e1..3133de60b5 100644 --- a/libs/renderengine/skia/AutoBackendTexture.h +++ b/libs/renderengine/skia/AutoBackendTexture.h @@ -21,9 +21,9 @@ #include <SkImage.h> #include <SkSurface.h> #include <sys/types.h> +#include <ui/GraphicTypes.h> #include "android-base/macros.h" -#include "ui/GraphicTypes.h" namespace android { namespace renderengine { @@ -41,26 +41,29 @@ public: // of shared ownership with Skia objects, so we wrap it here instead. class LocalRef { public: - LocalRef() {} - - ~LocalRef() { - // Destroying the texture is the same as setting it to null - setTexture(nullptr); + LocalRef(GrDirectContext* context, AHardwareBuffer* buffer, bool isOutputBuffer) { + mTexture = new AutoBackendTexture(context, buffer, isOutputBuffer); + mTexture->ref(); } - // Sets the texture to locally ref-track. - void setTexture(AutoBackendTexture* texture) { + ~LocalRef() { if (mTexture != nullptr) { mTexture->unref(true); } + } - mTexture = texture; - if (mTexture != nullptr) { - mTexture->ref(); - } + // Makes a new SkImage from the texture content. + // As SkImages are immutable but buffer content is not, we create + // a new SkImage every time. + sk_sp<SkImage> makeImage(ui::Dataspace dataspace, SkAlphaType alphaType, + GrDirectContext* context) { + return mTexture->makeImage(dataspace, alphaType, context); } - AutoBackendTexture* getTexture() const { return mTexture; } + // Makes a new SkSurface from the texture content, if needed. + sk_sp<SkSurface> getOrCreateSurface(ui::Dataspace dataspace, GrDirectContext* context) { + return mTexture->getOrCreateSurface(dataspace, context); + } DISALLOW_COPY_AND_ASSIGN(LocalRef); @@ -68,8 +71,12 @@ public: AutoBackendTexture* mTexture = nullptr; }; +private: // Creates a GrBackendTexture whose contents come from the provided buffer. - AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, bool isRender); + AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, bool isOutputBuffer); + + // The only way to invoke dtor is with unref, when mUsageCount is 0. + ~AutoBackendTexture() {} void ref() { mUsageCount++; } @@ -86,10 +93,6 @@ public: // Makes a new SkSurface from the texture content, if needed. sk_sp<SkSurface> getOrCreateSurface(ui::Dataspace dataspace, GrDirectContext* context); -private: - // The only way to invoke dtor is with unref, when mUsageCount is 0. - ~AutoBackendTexture() {} - GrBackendTexture mBackendTexture; GrAHardwareBufferUtils::DeleteImageProc mDeleteProc; GrAHardwareBufferUtils::UpdateImageProc mUpdateProc; @@ -100,6 +103,7 @@ private: int mUsageCount = 0; + const bool mIsOutputBuffer; sk_sp<SkImage> mImage = nullptr; sk_sp<SkSurface> mSurface = nullptr; ui::Dataspace mDataspace = ui::Dataspace::UNKNOWN; diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 0cd3b622fa..1c2b2fc3ca 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -25,8 +25,6 @@ #include "ui/Rect.h" #include "utils/Timers.h" -#include <android/hardware_buffer.h> - namespace android::renderengine::skia { namespace { @@ -48,7 +46,7 @@ constexpr auto kDestDataSpace = ui::Dataspace::SRGB; } // namespace static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp<GraphicBuffer> dstBuffer) { + const std::shared_ptr<ExternalTexture>& dstTexture) { // Somewhat arbitrary dimensions, but on screen and slightly shorter, based // on actual use. FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30); @@ -75,7 +73,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin auto layers = std::vector<const LayerSettings*>{&layer}; // The identity matrix will generate the fast shader - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); // This matrix, which has different scales for x and y, will // generate the slower (more general case) version, which has variants for translucent @@ -88,13 +86,14 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin // clang-format on for (auto translucent : {false, true}) { layer.shadow.casterIsTranslucent = translucent; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp<GraphicBuffer> dstBuffer, sp<GraphicBuffer> srcBuffer) { + const std::shared_ptr<ExternalTexture>& dstTexture, + const std::shared_ptr<ExternalTexture>& srcTexture) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -105,7 +104,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting }, .source = PixelSource{.buffer = Buffer{ - .buffer = srcBuffer, + .buffer = srcTexture, .maxMasteringLuminance = 1000.f, .maxContentLuminance = 1000.f, }}, @@ -128,7 +127,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting layer.source.buffer.isOpaque = isOpaque; for (auto alpha : {half(.23999f), half(1.0f)}) { layer.alpha = alpha; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } @@ -137,7 +136,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting } static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp<GraphicBuffer> dstBuffer) { + const std::shared_ptr<ExternalTexture>& dstTexture) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -145,11 +144,11 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting Geometry{ .boundaries = rect, }, - .alpha = 1, .source = PixelSource{ .solidColor = half3(0.1f, 0.2f, 0.3f), }, + .alpha = 1, }; auto layers = std::vector<const LayerSettings*>{&layer}; @@ -157,14 +156,14 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 0.05f, 50.f}) { layer.geometry.roundedCornersRadius = roundedCornersRadius; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } } static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp<GraphicBuffer> dstBuffer) { + const std::shared_ptr<ExternalTexture>& dstTexture) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -178,46 +177,11 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings auto layers = std::vector<const LayerSettings*>{&layer}; for (int radius : {9, 60}) { layer.backgroundBlurRadius = radius; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } -namespace { - -struct AHardwareBuffer_deleter { - void operator()(AHardwareBuffer* ahb) const { AHardwareBuffer_release(ahb); } -}; - -std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter> makeAHardwareBuffer() { - AHardwareBuffer* buffer = nullptr; - - int w = 32; - int h = 32; - - AHardwareBuffer_Desc hwbDesc; - hwbDesc.width = w; - hwbDesc.height = h; - hwbDesc.layers = 1; - hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER | - AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; - hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; - // The following three are not used in the allocate - hwbDesc.stride = 0; - hwbDesc.rfu0 = 0; - hwbDesc.rfu1 = 0; - - if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) { - ALOGE("Failed to allocated hardware buffer, error: %d", error); - if (buffer) { - AHardwareBuffer_release(buffer); - } - return nullptr; - } - return std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter>(buffer); -} -} // namespace - // // The collection of shaders cached here were found by using perfetto to record shader compiles // during actions that involve RenderEngine, logging the layer settings, and the shader code @@ -251,6 +215,9 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { sp<GraphicBuffer> dstBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "primeShaderCache_dst"); + + const auto dstTexture = std::make_shared<ExternalTexture>(dstBuffer, *renderengine, + ExternalTexture::Usage::WRITEABLE); // This buffer will be the source for the call to drawImageLayers. Draw // something to it as a placeholder for what an app draws. We should draw // something, but the details are not important. Make use of the shadow layer drawing step @@ -259,22 +226,29 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src"); - drawSolidLayers(renderengine, display, dstBuffer); - drawShadowLayers(renderengine, display, srcBuffer); - drawBlurLayers(renderengine, display, dstBuffer); + const auto srcTexture = + std::make_shared<ExternalTexture>(srcBuffer, *renderengine, + ExternalTexture::Usage::READABLE | + ExternalTexture::Usage::WRITEABLE); + + drawSolidLayers(renderengine, display, dstTexture); + drawShadowLayers(renderengine, display, srcTexture); + drawBlurLayers(renderengine, display, dstTexture); // The majority of shaders are related to sampling images. - drawImageLayers(renderengine, display, dstBuffer, srcBuffer); + drawImageLayers(renderengine, display, dstTexture, srcTexture); - // Draw image layers again sampling from an AHardwareBuffer if it is possible to create one. - if (auto ahb = makeAHardwareBuffer()) { - sp<GraphicBuffer> externalBuffer = GraphicBuffer::fromAHardwareBuffer(ahb.get()); - // TODO(b/184665179) doubles number of image shader compilations, but only somewhere - // between 6 and 8 will occur in real uses. - drawImageLayers(renderengine, display, dstBuffer, externalBuffer); - renderengine->unbindExternalTextureBuffer(externalBuffer->getId()); - } + // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; + const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; - renderengine->unbindExternalTextureBuffer(srcBuffer->getId()); + sp<GraphicBuffer> externalBuffer = + new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, + usageExternal, "primeShaderCache_external"); + const auto externalTexture = + std::make_shared<ExternalTexture>(externalBuffer, *renderengine, + ExternalTexture::Usage::READABLE); + // TODO(b/184665179) doubles number of image shader compilations, but only somewhere + // between 6 and 8 will occur in real uses. + drawImageLayers(renderengine, display, dstTexture, externalTexture); 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 fb7e2856e4..377b6f89ad 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -28,6 +28,7 @@ #include <SkColorFilter.h> #include <SkColorMatrix.h> #include <SkColorSpace.h> +#include <SkGraphics.h> #include <SkImage.h> #include <SkImageFilters.h> #include <SkRegion.h> @@ -40,13 +41,13 @@ #include <ui/DebugUtils.h> #include <ui/GraphicBuffer.h> #include <utils/Trace.h> -#include "Cache.h" #include <cmath> #include <cstdint> #include <memory> #include "../gl/GLExtensions.h" +#include "Cache.h" #include "ColorSpaces.h" #include "SkBlendMode.h" #include "SkImageInfo.h" @@ -54,6 +55,7 @@ #include "filters/LinearEffect.h" #include "log/log_main.h" #include "skia/debug/SkiaCapture.h" +#include "skia/debug/SkiaMemoryReporter.h" #include "system/graphics-base-v1.0.h" namespace { @@ -327,8 +329,6 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL } SkiaGLRenderEngine::~SkiaGLRenderEngine() { - cleanFramebufferCache(); - std::lock_guard<std::mutex> lock(mRenderingMutex); if (mBlurFilter) { delete mBlurFilter; @@ -482,7 +482,8 @@ static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destin sourceTransfer != destTransfer; } -void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { +void SkiaGLRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, + bool isRenderable) { // Only run this if RE is running on its own thread. This way the access to GL // operations is guaranteed to be happening on the same thread. if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) { @@ -503,25 +504,41 @@ void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buf auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; std::lock_guard<std::mutex> lock(mRenderingMutex); - auto iter = cache.find(buffer->getId()); - if (iter != cache.end()) { - ALOGV("Texture already exists in cache."); - } else { + mGraphicBufferExternalRefs[buffer->getId()]++; + + if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) { std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = - std::make_shared<AutoBackendTexture::LocalRef>(); - imageTextureRef->setTexture( - new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), false)); + std::make_shared<AutoBackendTexture::LocalRef>(grContext.get(), + buffer->toAHardwareBuffer(), + isRenderable); cache.insert({buffer->getId(), imageTextureRef}); } // restore the original state of the protected context if necessary useProtectedContext(protectedContextState); } -void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { +void SkiaGLRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mRenderingMutex); - mTextureCache.erase(bufferId); - mProtectedTextureCache.erase(bufferId); + if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId()); + iter != mGraphicBufferExternalRefs.end()) { + if (iter->second == 0) { + ALOGW("Attempted to unmap GraphicBuffer <id: %" PRId64 + "> from RenderEngine texture, but the " + "ref count was already zero!", + buffer->getId()); + mGraphicBufferExternalRefs.erase(buffer->getId()); + return; + } + + iter->second--; + + if (iter->second == 0) { + mTextureCache.erase(buffer->getId()); + mProtectedTextureCache.erase(buffer->getId()); + mGraphicBufferExternalRefs.erase(buffer->getId()); + } + } } sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> shader, @@ -619,8 +636,8 @@ private: status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, - const sp<GraphicBuffer>& buffer, - const bool useFramebufferCache, + const std::shared_ptr<ExternalTexture>& buffer, + const bool /*useFramebufferCache*/, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { ATRACE_NAME("SkiaGL::drawLayers"); @@ -643,38 +660,26 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } - validateOutputBufferUsage(buffer); + validateOutputBufferUsage(buffer->getBuffer()); auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; - AHardwareBuffer_Desc bufferDesc; - AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); - - std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef = nullptr; - if (useFramebufferCache) { - auto iter = cache.find(buffer->getId()); - if (iter != cache.end()) { - ALOGV("Cache hit!"); - ATRACE_NAME("Cache hit"); - surfaceTextureRef = iter->second; - } - } - if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) { - ATRACE_NAME("Cache miss"); - surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); - surfaceTextureRef->setTexture( - new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true)); - if (useFramebufferCache) { - ALOGD("Adding to cache"); - cache.insert({buffer->getId(), surfaceTextureRef}); - } + std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef; + if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) { + surfaceTextureRef = it->second; + } else { + surfaceTextureRef = + std::make_shared<AutoBackendTexture::LocalRef>(grContext.get(), + buffer->getBuffer() + ->toAHardwareBuffer(), + true); } const ui::Dataspace dstDataspace = mUseColorManagement ? display.outputDataspace : ui::Dataspace::UNKNOWN; sk_sp<SkSurface> dstSurface = - surfaceTextureRef->getTexture()->getOrCreateSurface(dstDataspace, grContext.get()); + surfaceTextureRef->getOrCreateSurface(dstDataspace, grContext.get()); SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get()); if (dstCanvas == nullptr) { @@ -816,27 +821,30 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, // rect to be blurred in the coordinate space of blurInput const auto blurRect = canvas->getTotalMatrix().mapRect(bounds); - if (layer->backgroundBlurRadius > 0) { - ATRACE_NAME("BackgroundBlur"); - auto blurredImage = - mBlurFilter->generate(grContext.get(), layer->backgroundBlurRadius, - blurInput, blurRect); + // TODO(b/182216890): Filter out empty layers earlier + if (blurRect.width() > 0 && blurRect.height() > 0) { + if (layer->backgroundBlurRadius > 0) { + ATRACE_NAME("BackgroundBlur"); + auto blurredImage = + mBlurFilter->generate(grContext.get(), layer->backgroundBlurRadius, + blurInput, blurRect); - cachedBlurs[layer->backgroundBlurRadius] = blurredImage; + cachedBlurs[layer->backgroundBlurRadius] = blurredImage; - mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect, blurredImage, - blurInput); - } - for (auto region : layer->blurRegions) { - if (cachedBlurs[region.blurRadius] == nullptr) { - ATRACE_NAME("BlurRegion"); - cachedBlurs[region.blurRadius] = - mBlurFilter->generate(grContext.get(), region.blurRadius, blurInput, - blurRect); + mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect, + blurredImage, blurInput); + } + for (auto region : layer->blurRegions) { + if (cachedBlurs[region.blurRadius] == nullptr) { + ATRACE_NAME("BlurRegion"); + cachedBlurs[region.blurRadius] = + mBlurFilter->generate(grContext.get(), region.blurRadius, blurInput, + blurRect); + } + + mBlurFilter->drawBlurRegion(canvas, region, blurRect, + cachedBlurs[region.blurRadius], blurInput); } - - mBlurFilter->drawBlurRegion(canvas, region, blurRect, - cachedBlurs[region.blurRadius], blurInput); } } @@ -874,26 +882,29 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, SkPaint paint; if (layer->source.buffer.buffer) { ATRACE_NAME("DrawImage"); - validateInputBufferUsage(layer->source.buffer.buffer); + validateInputBufferUsage(layer->source.buffer.buffer->getBuffer()); const auto& item = layer->source.buffer; std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr; - auto iter = cache.find(item.buffer->getId()); - if (iter != cache.end()) { + + if (const auto& iter = cache.find(item.buffer->getBuffer()->getId()); + iter != cache.end()) { imageTextureRef = iter->second; } else { - imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); - imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(), - item.buffer->toAHardwareBuffer(), - false)); - cache.insert({item.buffer->getId(), imageTextureRef}); + // If we didn't find the image in the cache, then create a local ref but don't cache + // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if + // we didn't find anything in the cache then we intentionally did not cache this + // buffer's resources. + imageTextureRef = std::make_shared< + AutoBackendTexture::LocalRef>(grContext.get(), + item.buffer->getBuffer()->toAHardwareBuffer(), + false); } sk_sp<SkImage> image = - imageTextureRef->getTexture()->makeImage(layerDataspace, - item.usePremultipliedAlpha - ? kPremul_SkAlphaType - : kUnpremul_SkAlphaType, - grContext.get()); + imageTextureRef->makeImage(layerDataspace, + item.usePremultipliedAlpha ? kPremul_SkAlphaType + : kUnpremul_SkAlphaType, + grContext.get()); auto texMatrix = getSkM44(item.textureTransform).asM33(); // textureTansform was intended to be passed directly into a shader, so when @@ -1198,15 +1209,6 @@ EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay dis return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); } -void SkiaGLRenderEngine::cleanFramebufferCache() { - // TODO(b/180767535) Remove this method and use b/180767535 instead, which would allow - // SF to control texture lifecycle more tightly rather than through custom hooks into RE. - std::lock_guard<std::mutex> lock(mRenderingMutex); - mRuntimeEffects.clear(); - mProtectedTextureCache.clear(); - mTextureCache.clear(); -} - int SkiaGLRenderEngine::getContextPriority() { int value; eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value); @@ -1249,9 +1251,44 @@ void SkiaGLRenderEngine::dump(std::string& result) { StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n", mSkSLCacheMonitor.shadersCachedSinceLastCall()); + std::vector<ResourcePair> cpuResourceMap = { + {"skia/sk_resource_cache/bitmap_", "Bitmaps"}, + {"skia/sk_resource_cache/rrect-blur_", "Masks"}, + {"skia/sk_resource_cache/rects-blur_", "Masks"}, + {"skia/sk_resource_cache/tessellated", "Shadows"}, + {"skia", "Other"}, + }; + SkiaMemoryReporter cpuReporter(cpuResourceMap, false); + SkGraphics::DumpMemoryStatistics(&cpuReporter); + StringAppendF(&result, "Skia CPU Caches: "); + cpuReporter.logTotals(result); + cpuReporter.logOutput(result); + { std::lock_guard<std::mutex> lock(mRenderingMutex); - StringAppendF(&result, "RenderEngine texture cache size: %zu\n", mTextureCache.size()); + + std::vector<ResourcePair> gpuResourceMap = { + {"texture_renderbuffer", "Texture/RenderBuffer"}, + {"texture", "Texture"}, + {"gr_text_blob_cache", "Text"}, + {"skia", "Other"}, + }; + SkiaMemoryReporter gpuReporter(gpuResourceMap, true); + mGrContext->dumpMemoryStatistics(&gpuReporter); + StringAppendF(&result, "Skia's GPU Caches: "); + gpuReporter.logTotals(result); + gpuReporter.logOutput(result); + StringAppendF(&result, "Skia's Wrapped Objects:\n"); + gpuReporter.logOutput(result, true); + + StringAppendF(&result, "RenderEngine tracked buffers: %zu\n", + mGraphicBufferExternalRefs.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) { + StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts); + } + StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n", + mTextureCache.size()); StringAppendF(&result, "Dumping buffer ids...\n"); // TODO(178539829): It would be nice to know which layer these are coming from and what // the texture sizes are. @@ -1259,7 +1296,18 @@ void SkiaGLRenderEngine::dump(std::string& result) { StringAppendF(&result, "- 0x%" PRIx64 "\n", id); } StringAppendF(&result, "\n"); - StringAppendF(&result, "RenderEngine protected texture cache size: %zu\n", + + SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true); + if (mProtectedGrContext) { + mProtectedGrContext->dumpMemoryStatistics(&gpuProtectedReporter); + } + StringAppendF(&result, "Skia's GPU Protected Caches: "); + gpuProtectedReporter.logTotals(result); + gpuProtectedReporter.logOutput(result); + StringAppendF(&result, "Skia's Protected Wrapped Objects:\n"); + gpuProtectedReporter.logOutput(result, true); + + StringAppendF(&result, "RenderEngine protected AHB/BackendTexture cache size: %zu\n", mProtectedTextureCache.size()); StringAppendF(&result, "Dumping buffer ids...\n"); for (const auto& [id, unused] : mProtectedTextureCache) { diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 8e77c16b40..e71c560a1f 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -23,6 +23,7 @@ #include <GrDirectContext.h> #include <SkSurface.h> #include <android-base/thread_annotations.h> +#include <renderengine/ExternalTexture.h> #include <renderengine/RenderEngine.h> #include <sys/types.h> @@ -52,13 +53,12 @@ public: ~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex); void primeCache() override; - void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override; - void unbindExternalTextureBuffer(uint64_t bufferId) override; status_t drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, - const sp<GraphicBuffer>& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; - void cleanFramebufferCache() override; + const std::shared_ptr<ExternalTexture>& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) override; + void cleanFramebufferCache() override {} int getContextPriority() override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; @@ -72,6 +72,8 @@ protected: void dump(std::string& result) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; + void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override; + void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override; private: static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); @@ -114,7 +116,9 @@ private: const PixelFormat mDefaultPixelFormat; const bool mUseColorManagement; - // Cache of GL textures that we'll store per GraphicBuffer ID + // Number of external holders of ExternalTexture references, per GraphicBuffer ID. + std::unordered_map<uint64_t, int32_t> mGraphicBufferExternalRefs GUARDED_BY(mRenderingMutex); + // Cache of GL textures that we'll store per GraphicBuffer ID, sliced by GPU context. std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache GUARDED_BY(mRenderingMutex); std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>> diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index d9821b62e0..9f6461a56e 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -42,15 +42,12 @@ public: virtual void primeCache() override{}; virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{}; virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{}; - virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/){}; - virtual void unbindExternalTextureBuffer(uint64_t /*bufferId*/){}; - virtual bool isProtected() const override { return false; } // mInProtectedContext; } virtual bool supportsProtectedContent() const override { return false; }; virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; }; virtual status_t drawLayers(const DisplaySettings& /*display*/, const std::vector<const LayerSettings*>& /*layers*/, - const sp<GraphicBuffer>& /*buffer*/, + const std::shared_ptr<ExternalTexture>& /*buffer*/, const bool /*useFramebufferCache*/, base::unique_fd&& /*bufferFence*/, base::unique_fd* /*drawFence*/) override { @@ -61,6 +58,11 @@ public: virtual void assertShadersCompiled(int numShaders) {} virtual int reportShadersCompiled() { return 0; } void setViewportAndProjection(Rect /*viewPort*/, Rect /*sourceCrop*/) override { } + +protected: + virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/, + bool /*isRenderable*/) override; + virtual void unmapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/) override; }; } // namespace skia diff --git a/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp b/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp new file mode 100644 index 0000000000..f24a4f1c05 --- /dev/null +++ b/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp @@ -0,0 +1,205 @@ +/* + * 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. + */ +#undef LOG_TAG +#define LOG_TAG "RenderEngine" + +#include "SkiaMemoryReporter.h" + +#include <SkString.h> +#include <android-base/stringprintf.h> +#include <log/log_main.h> + +namespace android { +namespace renderengine { +namespace skia { + +using base::StringAppendF; + +SkiaMemoryReporter::SkiaMemoryReporter(const std::vector<ResourcePair>& resourceMap, bool itemize) + : mResourceMap(resourceMap), + mItemize(itemize), + mTotalSize("bytes", 0), + mPurgeableSize("bytes", 0) {} + +const char* SkiaMemoryReporter::mapName(const char* resourceName) { + for (auto& resource : mResourceMap) { + if (SkStrContains(resourceName, resource.first)) { + return resource.second; + } + } + return nullptr; +} + +void SkiaMemoryReporter::resetCurrentElement() { + mCurrentElement.clear(); + mCurrentValues.clear(); + mIsCurrentValueWrapped = false; +} + +void SkiaMemoryReporter::processCurrentElement() { + // compute the top level element name using the map + const char* resourceName = mCurrentElement.empty() ? nullptr : mapName(mCurrentElement.c_str()); + + // if we don't have a resource name then we don't know how to label the + // data and should abort. + if (resourceName == nullptr) { + resetCurrentElement(); + return; + } + + // Only count elements that contain "size"; other values just provide metadata. + auto sizeResult = mCurrentValues.find("size"); + if (sizeResult != mCurrentValues.end() && sizeResult->second.value > 0) { + if (!mIsCurrentValueWrapped) { + mTotalSize.value += sizeResult->second.value; + mTotalSize.count++; + } + } else { + resetCurrentElement(); + return; + } + + // find the purgeable size if one exists + auto purgeableResult = mCurrentValues.find("purgeable_size"); + if (!mIsCurrentValueWrapped && purgeableResult != mCurrentValues.end()) { + mPurgeableSize.value += purgeableResult->second.value; + mPurgeableSize.count++; + } + + // do we store this element in the wrapped list or the skia managed list + auto& results = mIsCurrentValueWrapped ? mWrappedResults : mResults; + + // insert a copy of the element and all of its keys. We must make a copy here instead of + // std::move() as we will continue to use these values later in the function and again + // when we move on to process the next element. + results.insert({mCurrentElement, mCurrentValues}); + + // insert the item into its mapped category + auto result = results.find(resourceName); + if (result != results.end()) { + auto& resourceValues = result->second; + auto totalResult = resourceValues.find(sizeResult->first); + if (totalResult != resourceValues.end()) { + ALOGE_IF(sizeResult->second.units != totalResult->second.units, + "resource units do not match so the sum of resource type (%s) will be invalid", + resourceName); + totalResult->second.value += sizeResult->second.value; + totalResult->second.count++; + } else { + ALOGE("an entry (%s) should not exist in the results without a size", resourceName); + } + } else { + // only store the size for the top level resource + results.insert({resourceName, {{sizeResult->first, sizeResult->second}}}); + } + + resetCurrentElement(); +} + +void SkiaMemoryReporter::dumpNumericValue(const char* dumpName, const char* valueName, + const char* units, uint64_t value) { + if (mCurrentElement != dumpName) { + processCurrentElement(); + mCurrentElement = dumpName; + } + mCurrentValues.insert({valueName, {units, value}}); +} + +void SkiaMemoryReporter::dumpWrappedState(const char* dumpName, bool isWrappedObject) { + if (mCurrentElement != dumpName) { + processCurrentElement(); + mCurrentElement = dumpName; + } + mIsCurrentValueWrapped = isWrappedObject; +} + +void SkiaMemoryReporter::logOutput(std::string& log, bool wrappedResources) { + // process the current element before logging + processCurrentElement(); + + const auto& resultsMap = wrappedResources ? mWrappedResults : mResults; + + // log each individual element based on the resource map + for (const auto& resourceCategory : mResourceMap) { + // find the named item and print the totals + const auto categoryItem = resultsMap.find(resourceCategory.second); + if (categoryItem != resultsMap.end()) { + auto result = categoryItem->second.find("size"); + if (result != categoryItem->second.end()) { + TraceValue traceValue = convertUnits(result->second); + const char* entry = (traceValue.count > 1) ? "entries" : "entry"; + StringAppendF(&log, " %s: %.2f %s (%d %s)\n", categoryItem->first.c_str(), + traceValue.value, traceValue.units, traceValue.count, entry); + } + if (mItemize) { + for (const auto& individualItem : resultsMap) { + // if the individual item matches the category then print all its details or + // in the case of wrapped resources just print the wrapped size + const char* categoryMatch = mapName(individualItem.first.c_str()); + if (categoryMatch && strcmp(categoryMatch, resourceCategory.second) == 0) { + auto result = individualItem.second.find("size"); + TraceValue size = convertUnits(result->second); + StringAppendF(&log, " %s: size[%.2f %s]", individualItem.first.c_str(), + size.value, size.units); + if (!wrappedResources) { + for (const auto& itemValues : individualItem.second) { + if (strcmp("size", itemValues.first) == 0) { + continue; + } + TraceValue traceValue = convertUnits(itemValues.second); + if (traceValue.value == 0.0f) { + StringAppendF(&log, " %s[%s]", itemValues.first, + traceValue.units); + } else { + StringAppendF(&log, " %s[%.2f %s]", itemValues.first, + traceValue.value, traceValue.units); + } + } + } + StringAppendF(&log, "\n"); + } + } + } + } + } +} + +void SkiaMemoryReporter::logTotals(std::string& log) { + // process the current element before logging + processCurrentElement(); + + TraceValue total = convertUnits(mTotalSize); + TraceValue purgeable = convertUnits(mPurgeableSize); + StringAppendF(&log, " %.0f bytes, %.2f %s (%.2f %s is purgeable)\n", mTotalSize.value, + total.value, total.units, purgeable.value, purgeable.units); +} + +SkiaMemoryReporter::TraceValue SkiaMemoryReporter::convertUnits(const TraceValue& value) { + TraceValue output(value); + if (SkString("bytes") == SkString(output.units) && output.value >= 1024) { + output.value = output.value / 1024.0f; + output.units = "KB"; + } + if (SkString("KB") == SkString(output.units) && output.value >= 1024) { + output.value = output.value / 1024.0f; + output.units = "MB"; + } + return output; +} + +} /* namespace skia */ +} /* namespace renderengine */ +} /* namespace android */ diff --git a/libs/renderengine/skia/debug/SkiaMemoryReporter.h b/libs/renderengine/skia/debug/SkiaMemoryReporter.h new file mode 100644 index 0000000000..dbbd65b3da --- /dev/null +++ b/libs/renderengine/skia/debug/SkiaMemoryReporter.h @@ -0,0 +1,107 @@ +/* + * 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 <SkTraceMemoryDump.h> + +#include <string> +#include <unordered_map> +#include <vector> + +namespace android { +namespace renderengine { +namespace skia { + +// Mapping of resource substrings (1st element) that if found within a trace "dumpName" +// should be mapped to the category name (2nd element). All char* used in a resourcePair +// are expected to have a lifetime longer than the SkiaMemoryReporter in which they are used. +typedef std::pair<const char*, const char*> ResourcePair; + +/* + * Utility class for logging the CPU/GPU usage of Skia caches in a format that is specific + * to RenderEngine. HWUI has a similar logging class, but the data collected and the way + * it is formatted and reported on are intended to be unique to each use case. + */ +class SkiaMemoryReporter : public SkTraceMemoryDump { +public: + /** + * Creates the reporter class that can be populated by various Skia entry points, like + * SkGraphics and GrContext, as well as format and log the results. + * @param resourceMap An array of values that maps a Skia dumpName into a user defined category. + * The first vector entry that matches the dumpName is used for the mapping. + * @param itemize if true when logging the categories the individual elements will be printed + * directly after the category details are printed. Otherwise, only the category + * totals will be printed. + */ + SkiaMemoryReporter(const std::vector<ResourcePair>& resourceMap, bool itemize); + ~SkiaMemoryReporter() override {} + + void logOutput(std::string& log, bool wrappedResources = false); + void logTotals(std::string& log); + + void dumpNumericValue(const char* dumpName, const char* valueName, const char* units, + uint64_t value) override; + + void dumpStringValue(const char* dumpName, const char* valueName, const char* value) override { + // for convenience we just store this in the same format as numerical values + dumpNumericValue(dumpName, valueName, value, 0); + } + void dumpWrappedState(const char* dumpName, bool isWrappedObject) override; + + LevelOfDetail getRequestedDetails() const override { + return SkTraceMemoryDump::kLight_LevelOfDetail; + } + + bool shouldDumpWrappedObjects() const override { return true; } + void setMemoryBacking(const char*, const char*, const char*) override {} + void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {} + +private: + struct TraceValue { + TraceValue(const char* units, uint64_t value) : units(units), value(value), count(1) {} + TraceValue(const TraceValue& v) : units(v.units), value(v.value), count(v.count) {} + + const char* units; + float value; + int count; + }; + + const char* mapName(const char* resourceName); + void processCurrentElement(); + void resetCurrentElement(); + TraceValue convertUnits(const TraceValue& value); + + const std::vector<ResourcePair>& mResourceMap; + const bool mItemize; + + // variables storing the size of all non-wrapped elements being dumped + TraceValue mTotalSize; + TraceValue mPurgeableSize; + + // variables storing information on the current node being dumped + std::string mCurrentElement; + std::unordered_map<const char*, TraceValue> mCurrentValues; + bool mIsCurrentValueWrapped = false; + + // variable that stores the final format of the data after the individual elements are processed + std::unordered_map<std::string, std::unordered_map<const char*, TraceValue>> mResults; + std::unordered_map<std::string, std::unordered_map<const char*, TraceValue>> mWrappedResults; +}; + +} /* namespace skia */ +} /* namespace renderengine */ +} /* namespace android */
\ No newline at end of file diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 7846156383..34ef0a4f08 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -24,6 +24,7 @@ #include <cutils/properties.h> #include <gtest/gtest.h> +#include <renderengine/ExternalTexture.h> #include <renderengine/RenderEngine.h> #include <sync/sync.h> #include <ui/PixelFormat.h> @@ -160,27 +161,42 @@ public: class RenderEngineTest : public ::testing::TestWithParam<std::shared_ptr<RenderEngineFactory>> { public: - static sp<GraphicBuffer> allocateDefaultBuffer() { - return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, - "output"); + std::shared_ptr<renderengine::ExternalTexture> allocateDefaultBuffer() { + return std::make_shared< + renderengine:: + ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, + DEFAULT_DISPLAY_HEIGHT, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "output"), + *mRE, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); } // Allocates a 1x1 buffer to fill with a solid color - static sp<GraphicBuffer> allocateSourceBuffer(uint32_t width, uint32_t height) { - return new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_TEXTURE, - "input"); + std::shared_ptr<renderengine::ExternalTexture> allocateSourceBuffer(uint32_t width, + uint32_t height) { + return std::make_shared< + renderengine:: + ExternalTexture>(new GraphicBuffer(width, height, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_TEXTURE, + "input"), + *mRE, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); } RenderEngineTest() { 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()); - mBuffer = allocateDefaultBuffer(); } ~RenderEngineTest() { @@ -211,20 +227,21 @@ public: } uint8_t* pixels; - mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast<void**>(&pixels)); + mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast<void**>(&pixels)); file << "P6\n"; - file << mBuffer->getWidth() << "\n"; - file << mBuffer->getHeight() << "\n"; + file << mBuffer->getBuffer()->getWidth() << "\n"; + file << mBuffer->getBuffer()->getHeight() << "\n"; file << 255 << "\n"; - std::vector<uint8_t> outBuffer(mBuffer->getWidth() * mBuffer->getHeight() * 3); + std::vector<uint8_t> outBuffer(mBuffer->getBuffer()->getWidth() * + mBuffer->getBuffer()->getHeight() * 3); auto outPtr = reinterpret_cast<uint8_t*>(outBuffer.data()); - for (int32_t j = 0; j < mBuffer->getHeight(); j++) { - const uint8_t* src = pixels + (mBuffer->getStride() * j) * 4; - for (int32_t i = 0; i < mBuffer->getWidth(); i++) { + for (int32_t j = 0; j < mBuffer->getBuffer()->getHeight(); j++) { + const uint8_t* src = pixels + (mBuffer->getBuffer()->getStride() * j) * 4; + for (int32_t i = 0; i < mBuffer->getBuffer()->getWidth(); i++) { // Only copy R, G and B components outPtr[0] = src[0]; outPtr[1] = src[1]; @@ -235,7 +252,7 @@ public: } } file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size()); - mBuffer->unlock(); + mBuffer->getBuffer()->unlock(); } void expectBufferColor(const Region& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { @@ -262,13 +279,13 @@ public: void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a, std::function<bool(const uint8_t* a, const uint8_t* b)> colorCompare) { uint8_t* pixels; - mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast<void**>(&pixels)); + mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast<void**>(&pixels)); int32_t maxFails = 10; int32_t fails = 0; for (int32_t j = 0; j < region.getHeight(); j++) { - const uint8_t* src = - pixels + (mBuffer->getStride() * (region.top + j) + region.left) * 4; + const uint8_t* src = pixels + + (mBuffer->getBuffer()->getStride() * (region.top + j) + region.left) * 4; for (int32_t i = 0; i < region.getWidth(); i++) { const uint8_t expected[4] = {r, g, b, a}; bool equal = colorCompare(src, expected); @@ -289,7 +306,7 @@ public: break; } } - mBuffer->unlock(); + mBuffer->getBuffer()->unlock(); } void expectAlpha(const Rect& rect, uint8_t a) { @@ -387,7 +404,6 @@ public: base::unique_fd fence; status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence); - mCurrentBuffer = mBuffer; int fd = fence.release(); if (fd >= 0) { @@ -397,7 +413,7 @@ public: ASSERT_EQ(NO_ERROR, status); if (layers.size() > 0 && mGLESRE != nullptr) { - ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId())); + ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); } } @@ -503,17 +519,11 @@ public: void initializeRenderEngine(); std::unique_ptr<renderengine::RenderEngine> mRE; + std::shared_ptr<renderengine::ExternalTexture> mBuffer; // GLESRenderEngine for testing GLES-specific behavior. // Owened by mRE, but this is downcasted. renderengine::gl::GLESRenderEngine* mGLESRE = nullptr; - // Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to - // be freed *after* RenderEngine is destroyed, so that the EGL image is - // destroyed first. - sp<GraphicBuffer> mCurrentBuffer; - - sp<GraphicBuffer> mBuffer; - std::vector<uint32_t> mTexNames; }; @@ -530,6 +540,7 @@ void RenderEngineTest::initializeRenderEngine() { } else { mRE = renderEngineFactory->createRenderEngine(); } + mBuffer = allocateDefaultBuffer(); } struct ColorSourceVariant { @@ -566,18 +577,18 @@ template <typename OpaquenessVariant> struct BufferSourceVariant { static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b, RenderEngineTest* fixture) { - sp<GraphicBuffer> buf = RenderEngineTest::allocateSourceBuffer(1, 1); + const auto buf = fixture->allocateSourceBuffer(1, 1); uint32_t texName; fixture->mRE->genTextures(1, &texName); fixture->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast<void**>(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast<void**>(&pixels)); - for (int32_t j = 0; j < buf->getHeight(); j++) { - uint8_t* iter = pixels + (buf->getStride() * j) * 4; - for (int32_t i = 0; i < buf->getWidth(); i++) { + for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) { + uint8_t* iter = pixels + (buf->getBuffer()->getStride() * j) * 4; + for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) { iter[0] = uint8_t(r * 255); iter[1] = uint8_t(g * 255); iter[2] = uint8_t(b * 255); @@ -586,7 +597,7 @@ struct BufferSourceVariant { } } - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1012,14 +1023,14 @@ void RenderEngineTest::fillRedBufferTextureTransform() { layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; // Here will allocate a checker board texture, but transform texture // coordinates so that only the upper left is applied. - sp<GraphicBuffer> buf = allocateSourceBuffer(2, 2); + const auto buf = allocateSourceBuffer(2, 2); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast<void**>(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast<void**>(&pixels)); // Red top left, Green top right, Blue bottom left, Black bottom right pixels[0] = 255; pixels[1] = 0; @@ -1033,7 +1044,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { pixels[9] = 0; pixels[10] = 255; pixels[11] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1061,19 +1072,19 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { std::vector<const renderengine::LayerSettings*> layers; renderengine::LayerSettings layer; - sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1); + const auto buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast<void**>(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast<void**>(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1100,19 +1111,19 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { std::vector<const renderengine::LayerSettings*> layers; renderengine::LayerSettings layer; - sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1); + const auto buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast<void**>(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast<void**>(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1233,8 +1244,7 @@ TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) { } TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { - const auto& renderEngineFactory = GetParam(); - mRE = renderEngineFactory->createRenderEngine(); + initializeRenderEngine(); renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1295,7 +1305,6 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputFence) { layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr); - mCurrentBuffer = mBuffer; ASSERT_EQ(NO_ERROR, status); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } @@ -1323,9 +1332,8 @@ TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr); - mCurrentBuffer = mBuffer; ASSERT_EQ(NO_ERROR, status); - ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId())); + ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } @@ -1394,7 +1402,8 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_color fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>(); } -TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) { +// TODO(b/186010146): reenable once swiftshader is happy with this test +TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_colorSource) { initializeRenderEngine(); fillBufferAndBlurBackground<ColorSourceVariant>(); } @@ -1469,7 +1478,8 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqu fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>(); } -TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) { +// TODO(b/186010146): reenable once swiftshader is happy with this test +TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) { initializeRenderEngine(); fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>(); } @@ -1544,7 +1554,8 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_buffe fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>(); } -TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) { +// TODO(b/186010146): reenable once swiftshader is happy with this test +TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_bufferSource) { initializeRenderEngine(); fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>(); } @@ -1574,98 +1585,6 @@ TEST_P(RenderEngineTest, drawLayers_clearRegion) { clearRegion(); } -TEST_P(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - renderengine::DisplaySettings settings; - settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - settings.physicalDisplay = fullscreenRect(); - settings.clip = fullscreenRect(); - - std::vector<const renderengine::LayerSettings*> layers; - - renderengine::LayerSettings layer; - layer.geometry.boundaries = fullscreenRect().toFloatRect(); - BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this); - - layers.push_back(&layer); - invokeDraw(settings, layers); - uint64_t bufferId = layer.source.buffer.buffer->getId(); - EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); - std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier = - mGLESRE->unbindExternalTextureBufferForTesting(bufferId); - std::lock_guard<std::mutex> lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId)); - EXPECT_EQ(NO_ERROR, barrier->result); -} - -TEST_P(RenderEngineTest, cacheExternalBuffer_withNullBuffer) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier = - mGLESRE->cacheExternalTextureBufferForTesting(nullptr); - std::lock_guard<std::mutex> lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_TRUE(barrier->isOpen); - EXPECT_EQ(BAD_VALUE, barrier->result); -} - -TEST_P(RenderEngineTest, cacheExternalBuffer_cachesImages) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1); - uint64_t bufferId = buf->getId(); - std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier = - mGLESRE->cacheExternalTextureBufferForTesting(buf); - { - std::lock_guard<std::mutex> lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_EQ(NO_ERROR, barrier->result); - } - EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); - barrier = mGLESRE->unbindExternalTextureBufferForTesting(bufferId); - { - std::lock_guard<std::mutex> lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_EQ(NO_ERROR, barrier->result); - } - EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId)); -} - TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) { initializeRenderEngine(); @@ -1858,7 +1777,7 @@ TEST_P(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory sync_wait(fd, -1); } - uint64_t bufferId = layer.source.buffer.buffer->getId(); + uint64_t bufferId = layer.source.buffer.buffer->getBuffer()->getId(); uint32_t texName = layer.source.buffer.textureName; EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); EXPECT_EQ(bufferId, mGLESRE->getBufferIdForTextureNameForTesting(texName)); @@ -1966,16 +1885,16 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { // The next layer will overwrite redLayer with a GraphicBuffer that is green // applied with a translucent alpha. - auto buf = allocateSourceBuffer(1, 1); + const auto buf = allocateSourceBuffer(1, 1); { uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast<void**>(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast<void**>(&pixels)); pixels[0] = 0; pixels[1] = 255; pixels[2] = 0; pixels[3] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); } const renderengine::LayerSettings greenLayer{ diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index 63aa4c891c..e3917cce09 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -49,6 +49,9 @@ TEST_F(RenderEngineThreadedTest, dump) { TEST_F(RenderEngineThreadedTest, primeCache) { EXPECT_CALL(*mRenderEngine, primeCache()); mThreadedRE->primeCache(); + // need to call ANY synchronous function after primeCache to ensure that primeCache has + // completed asynchronously before the test completes execution. + mThreadedRE->getContextPriority(); } TEST_F(RenderEngineThreadedTest, genTextures) { @@ -159,15 +162,18 @@ TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) { TEST_F(RenderEngineThreadedTest, drawLayers) { renderengine::DisplaySettings settings; std::vector<const renderengine::LayerSettings*> layers; - sp<GraphicBuffer> buffer = new GraphicBuffer(); + std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine, + 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 sp<GraphicBuffer>&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { return NO_ERROR; }); + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { return NO_ERROR; }); status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence), &drawFence); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 9c0b3e508b..d02a58fd9e 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -74,6 +74,12 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S std::unique_lock<std::mutex> lock(mThreadMutex); pthread_setname_np(pthread_self(), mThreadName); + { + std::unique_lock<std::mutex> lock(mInitializedMutex); + mIsInitialized = true; + } + mInitializedCondition.notify_all(); + while (mRunning) { if (!mFunctionCalls.empty()) { auto task = mFunctionCalls.front(); @@ -84,21 +90,27 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S return !mRunning || !mFunctionCalls.empty(); }); } + + // we must release the RenderEngine on the thread that created it + mRenderEngine.reset(); +} + +void RenderEngineThreaded::waitUntilInitialized() const { + std::unique_lock<std::mutex> lock(mInitializedMutex); + mInitializedCondition.wait(lock, [=] { return mIsInitialized; }); } void RenderEngineThreaded::primeCache() { - std::promise<void> resultPromise; - std::future<void> resultFuture = resultPromise.get_future(); + // This function is designed so it can run asynchronously, so we do not need to wait + // for the futures. { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { + mFunctionCalls.push([](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::primeCache"); instance.primeCache(); - resultPromise.set_value(); }); } mCondition.notify_one(); - resultFuture.wait(); } void RenderEngineThreaded::dump(std::string& result) { @@ -148,90 +160,54 @@ void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) { resultFuture.wait(); } -void RenderEngineThreaded::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { +void RenderEngineThreaded::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, + bool isRenderable) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([=](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::cacheExternalTextureBuffer"); - instance.cacheExternalTextureBuffer(buffer); + ATRACE_NAME("REThreaded::mapExternalTextureBuffer"); + instance.mapExternalTextureBuffer(buffer, isRenderable); }); } mCondition.notify_one(); } -void RenderEngineThreaded::unbindExternalTextureBuffer(uint64_t bufferId) { +void RenderEngineThreaded::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([=](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::unbindExternalTextureBuffer"); - instance.unbindExternalTextureBuffer(bufferId); + ATRACE_NAME("REThreaded::unmapExternalTextureBuffer"); + instance.unmapExternalTextureBuffer(buffer); }); } mCondition.notify_one(); } size_t RenderEngineThreaded::getMaxTextureSize() const { - std::promise<size_t> resultPromise; - std::future<size_t> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::getMaxTextureSize"); - size_t size = instance.getMaxTextureSize(); - resultPromise.set_value(size); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + return mRenderEngine->getMaxTextureSize(); } size_t RenderEngineThreaded::getMaxViewportDims() const { - std::promise<size_t> resultPromise; - std::future<size_t> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::getMaxViewportDims"); - size_t size = instance.getMaxViewportDims(); - resultPromise.set_value(size); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + return mRenderEngine->getMaxViewportDims(); } bool RenderEngineThreaded::isProtected() const { - std::promise<bool> resultPromise; - std::future<bool> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::isProtected"); - bool returnValue = instance.isProtected(); - resultPromise.set_value(returnValue); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + // ensure that useProtectedContext is not currently being changed by some + // other thread. + std::lock_guard lock(mThreadMutex); + return mRenderEngine->isProtected(); } bool RenderEngineThreaded::supportsProtectedContent() const { - std::promise<bool> resultPromise; - std::future<bool> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::supportsProtectedContent"); - bool returnValue = instance.supportsProtectedContent(); - resultPromise.set_value(returnValue); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + return mRenderEngine->supportsProtectedContent(); } bool RenderEngineThreaded::useProtectedContext(bool useProtectedContext) { @@ -282,7 +258,7 @@ void RenderEngineThreaded::setViewportAndProjection(Rect viewPort, Rect sourceCr status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, - const sp<GraphicBuffer>& buffer, + const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { @@ -303,18 +279,16 @@ status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display, } void RenderEngineThreaded::cleanFramebufferCache() { - std::promise<void> resultPromise; - std::future<void> resultFuture = resultPromise.get_future(); + // This function is designed so it can run asynchronously, so we do not need to wait + // for the futures. { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { + mFunctionCalls.push([](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::cleanFramebufferCache"); instance.cleanFramebufferCache(); - resultPromise.set_value(); }); } mCondition.notify_one(); - resultFuture.wait(); } int RenderEngineThreaded::getContextPriority() { @@ -333,33 +307,21 @@ int RenderEngineThreaded::getContextPriority() { } bool RenderEngineThreaded::supportsBackgroundBlur() { - std::promise<bool> resultPromise; - std::future<bool> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::supportsBackgroundBlur"); - bool returnValue = instance.supportsBackgroundBlur(); - resultPromise.set_value(returnValue); - }); - } - mCondition.notify_one(); - return resultFuture.get(); + waitUntilInitialized(); + return mRenderEngine->supportsBackgroundBlur(); } void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) { - std::promise<void> resultPromise; - std::future<void> resultFuture = resultPromise.get_future(); + // This function is designed so it can run asynchronously, so we do not need to wait + // for the futures. { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise, size](renderengine::RenderEngine& instance) { + mFunctionCalls.push([size](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged"); instance.onPrimaryDisplaySizeChanged(size); - resultPromise.set_value(); }); } mCondition.notify_one(); - resultFuture.wait(); } } // namespace threaded diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 352c1e0694..285627e8be 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -48,8 +48,6 @@ public: void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; - void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override; - void unbindExternalTextureBuffer(uint64_t bufferId) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -61,16 +59,22 @@ public: status_t drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, - const sp<GraphicBuffer>& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + const std::shared_ptr<ExternalTexture>& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) override; void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; void onPrimaryDisplaySizeChanged(ui::Size size) override; +protected: + void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override; + void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override; + private: void threadMain(CreateInstanceFactory factory); + void waitUntilInitialized() const; /* ------------------------------------------------------------------------ * Threading @@ -84,6 +88,12 @@ private: GUARDED_BY(mThreadMutex); mutable std::condition_variable mCondition; + // Used to allow select thread safe methods to be accessed without requiring the + // method to be invoked on the RenderEngine thread + bool mIsInitialized = false; + mutable std::mutex mInitializedMutex; + mutable std::condition_variable mInitializedCondition; + /* ------------------------------------------------------------------------ * Render Engine */ diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp index 497c33c386..edd453a936 100644 --- a/libs/sensor/Android.bp +++ b/libs/sensor/Android.bp @@ -48,11 +48,10 @@ cc_library_shared { "libutils", "liblog", "libhardware", + "libpermission", ], export_include_dirs: ["include"], - export_shared_lib_headers: ["libbinder", "libhardware"], + export_shared_lib_headers: ["libbinder", "libpermission", "libhardware"], } - -subdirs = ["tests"] diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp index 47144696f2..b3537ce444 100644 --- a/libs/sensorprivacy/SensorPrivacyManager.cpp +++ b/libs/sensorprivacy/SensorPrivacyManager.cpp @@ -55,6 +55,22 @@ sp<hardware::ISensorPrivacyManager> SensorPrivacyManager::getService() return service; } +bool SensorPrivacyManager::supportsSensorToggle(int sensor) { + if (mSupportedCache.find(sensor) == mSupportedCache.end()) { + sp<hardware::ISensorPrivacyManager> service = getService(); + if (service != nullptr) { + bool result; + service->supportsSensorToggle(sensor, &result); + mSupportedCache[sensor] = result; + return result; + } + // if the SensorPrivacyManager is not available then assume sensor privacy feature isn't + // supported + return false; + } + return mSupportedCache[sensor]; +} + void SensorPrivacyManager::addSensorPrivacyListener( const sp<hardware::ISensorPrivacyListener>& listener) { diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl index 629b8c2093..c8ceeb89af 100644 --- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl +++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl @@ -20,6 +20,8 @@ import android.hardware.ISensorPrivacyListener; /** @hide */ interface ISensorPrivacyManager { + boolean supportsSensorToggle(int sensor); + void addSensorPrivacyListener(in ISensorPrivacyListener listener); void addIndividualSensorPrivacyListener(int userId, int sensor, in ISensorPrivacyListener listener); diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h index 12778e16b6..fb4cbe9d55 100644 --- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h +++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h @@ -22,6 +22,8 @@ #include <utils/threads.h> +#include <unordered_map> + // --------------------------------------------------------------------------- namespace android { @@ -35,6 +37,7 @@ public: SensorPrivacyManager(); + bool supportsSensorToggle(int sensor); void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener); status_t addIndividualSensorPrivacyListener(int userId, int sensor, const sp<hardware::ISensorPrivacyListener>& listener); @@ -50,6 +53,8 @@ private: Mutex mLock; sp<hardware::ISensorPrivacyManager> mService; sp<hardware::ISensorPrivacyManager> getService(); + + std::unordered_map<int, bool> mSupportedCache; }; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 073455a7ff..edbf21aef4 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2326,6 +2326,8 @@ void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) { if (dropWindow) { vec2 local = dropWindow->getInfo()->transform.transform(x, y); notifyDropWindowLocked(dropWindow->getToken(), local.x, local.y); + } else { + notifyDropWindowLocked(nullptr, 0, 0); } mDragState.reset(); } @@ -2372,6 +2374,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { } else if (maskedAction == AMOTION_EVENT_ACTION_UP) { finishDragAndDrop(entry.displayId, x, y); } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) { + notifyDropWindowLocked(nullptr, 0, 0); mDragState.reset(); } } @@ -3154,8 +3157,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " "This is unexpected because the wait queue is empty, so the pipe " "should be empty and we shouldn't have any problems writing an " - "event to it, status=%d", - connection->getInputChannelName().c_str(), status); + "event to it, status=%s(%d)", + connection->getInputChannelName().c_str(), statusToString(status).c_str(), + status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } else { // Pipe is full and we are waiting for the app to finish process some events @@ -3168,8 +3172,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } } else { ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " - "status=%d", - connection->getInputChannelName().c_str(), status); + "status=%s(%d)", + connection->getInputChannelName().c_str(), statusToString(status).c_str(), + status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } return; @@ -3338,8 +3343,9 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { notify = status != DEAD_OBJECT || !connection->monitor; if (notify) { - ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d", - connection->getInputChannelName().c_str(), status); + ALOGE("channel '%s' ~ Failed to receive finished signal. status=%s(%d)", + connection->getInputChannelName().c_str(), statusToString(status).c_str(), + status); } } else { // Monitor channels are never explicitly unregistered. @@ -5094,6 +5100,8 @@ Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(int32_ monitorsByDisplay[displayId].emplace_back(serverChannel, pid); mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); + ALOGI("Created monitor %s for display %" PRId32 ", gesture=%s, pid=%" PRId32, name.c_str(), + displayId, toString(isGestureMonitor), pid); } // Wake the looper because some connections have changed. @@ -5154,6 +5162,8 @@ void InputDispatcher::removeMonitorChannelLocked( const size_t numMonitors = monitors.size(); for (size_t i = 0; i < numMonitors; i++) { if (monitors[i].inputChannel->getConnectionToken() == connectionToken) { + ALOGI("Erasing monitor %s on display %" PRId32 ", pid=%" PRId32, + monitors[i].inputChannel->getName().c_str(), it->first, monitors[i].pid); monitors.erase(monitors.begin() + i); break; } diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 3bf212a51b..19abfd9adf 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -198,6 +198,10 @@ struct InputReaderConfiguration { // Used to determine which DisplayViewport should be tied to which InputDevice. std::unordered_map<std::string, uint8_t> portAssociations; + // The associations between input device names and display unique ids. + // Used to determine which DisplayViewport should be tied to which InputDevice. + std::unordered_map<std::string, std::string> uniqueIdAssociations; + // The suggested display ID to show the cursor. int32_t defaultPointerDisplayId; diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 8f75d22d87..ad503fde99 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -103,6 +103,12 @@ void InputDevice::dump(std::string& dump, const std::string& eventHubDevStr) { } else { dump += "<none>\n"; } + dump += StringPrintf(INDENT2 "AssociatedDisplayUniqueId: "); + if (mAssociatedDisplayUniqueId) { + dump += StringPrintf("%s\n", mAssociatedDisplayUniqueId->c_str()); + } else { + dump += "<none>\n"; + } dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic)); dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); @@ -293,8 +299,9 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - // In most situations, no port will be specified. + // In most situations, no port or name will be specified. mAssociatedDisplayPort = std::nullopt; + mAssociatedDisplayUniqueId = std::nullopt; mAssociatedViewport = std::nullopt; // Find the display port that corresponds to the current input port. const std::string& inputPort = mIdentifier.location; @@ -305,6 +312,13 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config mAssociatedDisplayPort = std::make_optional(displayPort->second); } } + const std::string& inputDeviceName = mIdentifier.name; + const std::unordered_map<std::string, std::string>& names = + config->uniqueIdAssociations; + const auto& displayUniqueId = names.find(inputDeviceName); + if (displayUniqueId != names.end()) { + mAssociatedDisplayUniqueId = displayUniqueId->second; + } // If the device was explicitly disabled by the user, it would be present in the // "disabledDevices" list. If it is associated with a specific display, and it was not @@ -319,6 +333,15 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config getName().c_str(), *mAssociatedDisplayPort); enabled = false; } + } else if (mAssociatedDisplayUniqueId != std::nullopt) { + mAssociatedViewport = + config->getDisplayViewportByUniqueId(*mAssociatedDisplayUniqueId); + if (!mAssociatedViewport) { + ALOGW("Input device %s should be associated with display %s but the " + "corresponding viewport cannot be found", + inputDeviceName.c_str(), mAssociatedDisplayUniqueId->c_str()); + enabled = false; + } } if (changes) { diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index b2b23e5977..291f1059c5 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -169,6 +169,7 @@ private: uint32_t mSources; bool mIsExternal; std::optional<uint8_t> mAssociatedDisplayPort; + std::optional<std::string> mAssociatedDisplayUniqueId; std::optional<DisplayViewport> mAssociatedViewport; bool mHasMic; bool mDropUntilNextSync; diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index 2c5a576160..104d087387 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -132,9 +132,7 @@ void KeyboardInputMapper::dump(std::string& dump) { std::optional<DisplayViewport> KeyboardInputMapper::findViewport( nsecs_t when, const InputReaderConfiguration* config) { - const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort(); - if (displayPort) { - // Find the viewport that contains the same port + if (getDeviceContext().getAssociatedViewport()) { return getDeviceContext().getAssociatedViewport(); } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index f5198077f3..ea7a162a1a 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -268,7 +268,9 @@ public: void assertDropTargetEquals(const sp<IBinder>& targetToken) { std::scoped_lock lock(mLock); + ASSERT_TRUE(mNotifyDropWindowWasCalled); ASSERT_EQ(targetToken, mDropTargetWindowToken); + mNotifyDropWindowWasCalled = false; } private: @@ -290,6 +292,7 @@ private: std::condition_variable mNotifyAnr; sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock); + bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false; void notifyConfigurationChanged(nsecs_t when) override { std::scoped_lock lock(mLock); @@ -403,6 +406,7 @@ private: void notifyDropWindow(const sp<IBinder>& token, float x, float y) override { std::scoped_lock lock(mLock); + mNotifyDropWindowWasCalled = true; mDropTargetWindowToken = token; } @@ -4954,4 +4958,40 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { mSecondWindow->assertNoEvents(); } +TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) { + performDrag(); + + // Set second window invisible. + mSecondWindow->setVisible(false); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}}); + + // Move on window. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); + mWindow->consumeDragEvent(false, 50, 50); + mSecondWindow->assertNoEvents(); + + // Move to another window. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); + mWindow->consumeDragEvent(true, 150, 50); + mSecondWindow->assertNoEvents(); + + // drop to another window. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); + mFakePolicy->assertDropTargetEquals(nullptr); + mWindow->assertNoEvents(); + mSecondWindow->assertNoEvents(); +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 0e721e909d..5eaca71c6a 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -269,6 +269,11 @@ public: mConfig.portAssociations.insert({inputPort, displayPort}); } + void addInputUniqueIdAssociation(const std::string& inputUniqueId, + const std::string& displayUniqueId) { + mConfig.uniqueIdAssociations.insert({inputUniqueId, displayUniqueId}); + } + void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); } void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); } @@ -2621,6 +2626,41 @@ TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) { ASSERT_FALSE(mDevice->isEnabled()); } +TEST_F(InputDeviceTest, Configure_AssignsDisplayUniqueId) { + // Device should be enabled by default. + mFakePolicy->clearViewports(); + mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD); + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0); + ASSERT_TRUE(mDevice->isEnabled()); + + // Device should be disabled because it is associated with a specific display, but the + // corresponding display is not found. + const std::string DISPLAY_UNIQUE_ID = "displayUniqueId"; + mFakePolicy->addInputUniqueIdAssociation(DEVICE_NAME, DISPLAY_UNIQUE_ID); + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DISPLAY_INFO); + ASSERT_FALSE(mDevice->isEnabled()); + + // Device should be enabled when a display is found. + mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, + DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID, + NO_PORT, ViewportType::INTERNAL); + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DISPLAY_INFO); + ASSERT_TRUE(mDevice->isEnabled()); + + // Device should be disabled after set disable. + mFakePolicy->addDisabledDevice(mDevice->getId()); + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_ENABLED_STATE); + ASSERT_FALSE(mDevice->isEnabled()); + + // Device should still be disabled even found the associated display. + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DISPLAY_INFO); + ASSERT_FALSE(mDevice->isEnabled()); +} + // --- InputMapperTest --- class InputMapperTest : public testing::Test { @@ -7853,8 +7893,6 @@ TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) { ASSERT_EQ(SECONDARY_DISPLAY_ID, args.displayId); } - - TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index 9aecaff409..4151b4512f 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -54,6 +54,7 @@ cc_library_shared { "libbinder", "libsensor", "libsensorprivacy", + "libpermission", "libprotoutil", "libcrypto", "libbase", @@ -74,6 +75,7 @@ cc_library_shared { "libactivitymanager_aidl", "libsensor", "libsensorprivacy", + "libpermission", ], } diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index a6d606f8ff..b8a8f15ff8 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -192,9 +192,9 @@ std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareCli } } const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || - (isSecure() && !targetSettings.isSecure); + ((isSecure() || isProtected()) && !targetSettings.isSecure); const bool bufferCanBeUsedAsHwTexture = - mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; + mBufferInfo.mBuffer->getBuffer()->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; compositionengine::LayerFE::LayerSettings& layer = *result; if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", @@ -219,7 +219,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareCli ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel : defaultMaxContentLuminance; layer.frameNumber = mCurrentFrameNumber; - layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; + layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0; const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering(); @@ -320,7 +320,7 @@ void BufferLayer::preparePerFrameCompositionState() { : Hwc2::IComposerClient::Composition::DEVICE; } - compositionState->buffer = mBufferInfo.mBuffer; + compositionState->buffer = mBufferInfo.mBuffer->getBuffer(); compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mBufferInfo.mBufferSlot; @@ -448,7 +448,7 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, void BufferLayer::gatherBufferInfo() { mBufferInfo.mPixelFormat = - !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->format; + !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getBuffer()->format; mBufferInfo.mFrameLatencyNeeded = true; } @@ -513,11 +513,6 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, BufferInfo oldBufferInfo = mBufferInfo; - if (!allTransactionsSignaled(expectedPresentTime)) { - mFlinger->setTransactionFlags(eTraversalNeeded); - return false; - } - status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime); if (err != NO_ERROR) { return false; @@ -550,10 +545,10 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, } if (oldBufferInfo.mBuffer != nullptr) { - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - if (bufWidth != uint32_t(oldBufferInfo.mBuffer->width) || - bufHeight != uint32_t(oldBufferInfo.mBuffer->height)) { + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); + if (bufWidth != uint32_t(oldBufferInfo.mBuffer->getBuffer()->width) || + bufHeight != uint32_t(oldBufferInfo.mBuffer->getBuffer()->height)) { recomputeVisibleRegions = true; } } @@ -562,53 +557,9 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, recomputeVisibleRegions = true; } - // Remove any sync points corresponding to the buffer which was just - // latched - { - Mutex::Autolock lock(mLocalSyncPointMutex); - auto point = mLocalSyncPoints.begin(); - while (point != mLocalSyncPoints.end()) { - if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) { - // This sync point must have been added since we started - // latching. Don't drop it yet. - ++point; - continue; - } - - if ((*point)->getFrameNumber() <= mCurrentFrameNumber) { - std::stringstream ss; - ss << "Dropping sync point " << (*point)->getFrameNumber(); - ATRACE_NAME(ss.str().c_str()); - point = mLocalSyncPoints.erase(point); - } else { - ++point; - } - } - } - return true; } -// transaction -void BufferLayer::notifyAvailableFrames(nsecs_t expectedPresentTime) { - const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime); - const bool headFenceSignaled = fenceHasSignaled(); - const bool presentTimeIsCurrent = framePresentTimeIsCurrent(expectedPresentTime); - Mutex::Autolock lock(mLocalSyncPointMutex); - for (auto& point : mLocalSyncPoints) { - if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled && - presentTimeIsCurrent) { - point->setFrameAvailable(); - sp<Layer> requestedSyncLayer = point->getRequestedSyncLayer(); - if (requestedSyncLayer) { - // Need to update the transaction flag to ensure the layer's pending transaction - // gets applied. - requestedSyncLayer->setTransactionFlags(eTransactionNeeded); - } - } - } -} - bool BufferLayer::hasReadyFrame() const { return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh(); } @@ -618,8 +569,8 @@ uint32_t BufferLayer::getEffectiveScalingMode() const { } bool BufferLayer::isProtected() const { - const sp<GraphicBuffer>& buffer(mBufferInfo.mBuffer); - return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); + return (mBufferInfo.mBuffer != nullptr) && + (mBufferInfo.mBuffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED); } bool BufferLayer::latchUnsignaledBuffers() { @@ -636,32 +587,6 @@ bool BufferLayer::latchUnsignaledBuffers() { return latch; } -// h/w composer set-up -bool BufferLayer::allTransactionsSignaled(nsecs_t expectedPresentTime) { - const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime); - bool matchingFramesFound = false; - bool allTransactionsApplied = true; - Mutex::Autolock lock(mLocalSyncPointMutex); - - for (auto& point : mLocalSyncPoints) { - if (point->getFrameNumber() > headFrameNumber) { - break; - } - matchingFramesFound = true; - - if (!point->frameIsAvailable()) { - // We haven't notified the remote layer that the frame for - // this point is available yet. Notify it now, and then - // abort this attempt to latch. - point->setFrameAvailable(); - allTransactionsApplied = false; - break; - } - - allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied(); - } - return !matchingFramesFound || allTransactionsApplied; -} // As documented in libhardware header, formats in the range // 0x100 - 0x1FF are specific to the HAL implementation, and @@ -747,8 +672,8 @@ Rect BufferLayer::getBufferSize(const State& s) const { return Rect::INVALID_RECT; } - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -779,8 +704,8 @@ FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const return parentBounds; } - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -822,7 +747,7 @@ Rect BufferLayer::getBufferCrop() const { return mBufferInfo.mCrop; } else if (mBufferInfo.mBuffer != nullptr) { // otherwise we use the whole buffer - return mBufferInfo.mBuffer->getBounds(); + return mBufferInfo.mBuffer->getBuffer()->getBounds(); } else { // if we don't have a buffer yet, we use an empty/invalid crop return Rect(); @@ -867,12 +792,14 @@ ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) { } sp<GraphicBuffer> BufferLayer::getBuffer() const { - return mBufferInfo.mBuffer; + return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; } void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) { - GLConsumer::computeTransformMatrix(outMatrix, mBufferInfo.mBuffer, mBufferInfo.mCrop, - mBufferInfo.mTransform, filteringEnabled); + GLConsumer::computeTransformMatrix(outMatrix, + mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() + : nullptr, + mBufferInfo.mCrop, mBufferInfo.mTransform, filteringEnabled); } void BufferLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) { diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 284132cad6..1d6b63ced1 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -90,8 +90,6 @@ public: bool isBufferLatched() const override { return mRefreshPending; } - void notifyAvailableFrames(nsecs_t expectedPresentTime) override; - bool hasReadyFrame() const override; // Returns the current scaling mode @@ -134,7 +132,7 @@ protected: PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; bool mTransformToDisplayInverse{false}; - sp<GraphicBuffer> mBuffer; + std::shared_ptr<renderengine::ExternalTexture> mBuffer; int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; bool mFrameLatencyNeeded{false}; @@ -156,11 +154,6 @@ protected: // Loads the corresponding system property once per process static bool latchUnsignaledBuffers(); - // Check all of the local sync points to ensure that all transactions - // which need to have been applied prior to the frame which is about to - // be latched have signaled - bool allTransactionsSignaled(nsecs_t expectedPresentTime); - static bool getOpacityForFormat(uint32_t format); // from graphics API diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 69d2d11a4d..96b22478ab 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -40,7 +40,6 @@ #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> -#include <renderengine/Image.h> #include <renderengine/RenderEngine.h> #include <utils/Log.h> #include <utils/String8.h> @@ -167,7 +166,7 @@ void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) { } auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer - : mCurrentTextureBuffer->graphicBuffer(); + : mCurrentTextureBuffer->getBuffer(); auto err = addReleaseFence(slot, buffer, fence); if (err != OK) { BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); @@ -206,9 +205,11 @@ status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t pres // before, so we need to clean up old references. if (item->mGraphicBuffer != nullptr) { std::lock_guard<std::mutex> lock(mImagesMutex); - if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->graphicBuffer() == nullptr || - mImages[item->mSlot]->graphicBuffer()->getId() != item->mGraphicBuffer->getId()) { - mImages[item->mSlot] = std::make_shared<Image>(item->mGraphicBuffer, mRE); + if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr || + mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) { + mImages[item->mSlot] = std::make_shared< + renderengine::ExternalTexture>(item->mGraphicBuffer, mRE, + renderengine::ExternalTexture::Usage::READABLE); } } @@ -222,8 +223,8 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, int slot = item.mSlot; BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, - (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr) - ? mCurrentTextureBuffer->graphicBuffer()->handle + (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->getBuffer() != nullptr) + ? mCurrentTextureBuffer->getBuffer()->handle : 0, slot, mSlots[slot].mGraphicBuffer->handle); @@ -231,7 +232,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, // releaseBufferLocked() if we're in shared buffer mode and both buffers are // the same. - std::shared_ptr<Image> nextTextureBuffer; + std::shared_ptr<renderengine::ExternalTexture> nextTextureBuffer; { std::lock_guard<std::mutex> lock(mImagesMutex); nextTextureBuffer = mImages[slot]; @@ -241,7 +242,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (pendingRelease == nullptr) { status_t status = - releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->graphicBuffer()); + releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->getBuffer()); if (status < NO_ERROR) { BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); @@ -250,7 +251,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, } } else { pendingRelease->currentTexture = mCurrentTexture; - pendingRelease->graphicBuffer = mCurrentTextureBuffer->graphicBuffer(); + pendingRelease->graphicBuffer = mCurrentTextureBuffer->getBuffer(); pendingRelease->isPending = true; } } @@ -301,14 +302,14 @@ void BufferLayerConsumer::setFilteringEnabled(bool enabled) { void BufferLayerConsumer::computeCurrentTransformMatrixLocked() { BLC_LOGV("computeCurrentTransformMatrixLocked"); - if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->graphicBuffer() == nullptr) { + if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->getBuffer() == nullptr) { BLC_LOGD("computeCurrentTransformMatrixLocked: " "mCurrentTextureBuffer is nullptr"); } GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, mCurrentTextureBuffer == nullptr ? nullptr - : mCurrentTextureBuffer->graphicBuffer(), + : mCurrentTextureBuffer->getBuffer(), getCurrentCropLocked(), mCurrentTransform, mFilteringEnabled); } @@ -360,7 +361,8 @@ int BufferLayerConsumer::getCurrentApi() const { return mCurrentApi; } -sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp<Fence>* outFence) const { +std::shared_ptr<renderengine::ExternalTexture> BufferLayerConsumer::getCurrentBuffer( + int* outSlot, sp<Fence>* outFence) const { Mutex::Autolock lock(mMutex); if (outSlot != nullptr) { @@ -371,7 +373,7 @@ sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp<Fence>* *outFence = mCurrentFence; } - return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer->graphicBuffer(); + return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer; } Rect BufferLayerConsumer::getCurrentCrop() const { @@ -456,10 +458,12 @@ void BufferLayerConsumer::onSidebandStreamChanged() { void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) { std::lock_guard<std::mutex> lock(mImagesMutex); - const std::shared_ptr<Image>& oldImage = mImages[item.mSlot]; - if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr || - oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) { - mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE); + const std::shared_ptr<renderengine::ExternalTexture>& oldImage = mImages[item.mSlot]; + if (oldImage == nullptr || oldImage->getBuffer() == nullptr || + oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) { + mImages[item.mSlot] = std::make_shared< + renderengine::ExternalTexture>(item.mGraphicBuffer, mRE, + renderengine::ExternalTexture::Usage::READABLE); } } } @@ -499,22 +503,6 @@ void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const ConsumerBase::dumpLocked(result, prefix); } - -BufferLayerConsumer::Image::Image(const sp<GraphicBuffer>& graphicBuffer, - renderengine::RenderEngine& engine) - : mGraphicBuffer(graphicBuffer), mRE(engine) { - if (graphicBuffer != nullptr && (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED)) { - return; - } - mRE.cacheExternalTextureBuffer(mGraphicBuffer); -} - -BufferLayerConsumer::Image::~Image() { - if (mGraphicBuffer != nullptr) { - ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId()); - mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId()); - } -} }; // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index dd39214aff..9ed80b46bd 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -21,12 +21,11 @@ #include <gui/BufferQueueDefs.h> #include <gui/ConsumerBase.h> #include <gui/HdrMetadata.h> - +#include <renderengine/ExternalTexture.h> #include <ui/FenceTime.h> #include <ui/GraphicBuffer.h> #include <ui/GraphicTypes.h> #include <ui/Region.h> - #include <utils/String8.h> #include <utils/Vector.h> #include <utils/threads.h> @@ -39,7 +38,6 @@ class String8; namespace renderengine { class RenderEngine; -class Image; } // namespace renderengine /* @@ -153,7 +151,8 @@ public: // When outSlot is not nullptr, the current buffer slot index is also // returned. Simiarly, when outFence is not nullptr, the current output // fence is returned. - sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const; + std::shared_ptr<renderengine::ExternalTexture> getCurrentBuffer( + int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const; // getCurrentCrop returns the cropping rectangle of the current buffer. Rect getCurrentCrop() const; @@ -258,7 +257,7 @@ private: // mCurrentTextureBuffer is the buffer containing the current texture. It's // possible that this buffer is not associated with any buffer slot, so we // must track it separately in order to support the getCurrentBuffer method. - std::shared_ptr<Image> mCurrentTextureBuffer; + std::shared_ptr<renderengine::ExternalTexture> mCurrentTextureBuffer; // mCurrentCrop is the crop rectangle that applies to the current texture. // It gets set each time updateTexImage is called. @@ -337,7 +336,8 @@ private: int mCurrentTexture; // Shadow buffer cache for cleaning up renderengine references. - std::shared_ptr<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); + std::shared_ptr<renderengine::ExternalTexture> + mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); // Separate mutex guarding the shadow buffer cache. // mImagesMutex can be manipulated with binder threads (e.g. onBuffersAllocated) diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 700c19689d..471a551432 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -74,14 +74,8 @@ BufferStateLayer::~BufferStateLayer() { // original layer and the clone should be removed at the same time so there shouldn't be any // issue with the clone layer trying to use the texture. if (mBufferInfo.mBuffer != nullptr && !isClone()) { - // Ensure that mBuffer is uncached from RenderEngine here, as - // RenderEngine may have been using the buffer as an external texture - // after the client uncached the buffer. - auto& engine(mFlinger->getRenderEngine()); - const uint64_t bufferId = mBufferInfo.mBuffer->getId(); - engine.unbindExternalTextureBuffer(bufferId); - callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer, - mBufferInfo.mFence); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, + mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence); } } @@ -289,17 +283,8 @@ bool BufferStateLayer::isBufferDue(nsecs_t expectedPresentTime) const { return isDue; } -bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) { - mCurrentStateModified = mCurrentState.modified; - bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit); - mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified; - mCurrentState.modified = false; - return stateUpdateAvailable; -} - -// Crop that applies to the window -Rect BufferStateLayer::getCrop(const Layer::State& /*s*/) const { - return Rect::INVALID_RECT; +Rect BufferStateLayer::getCrop(const Layer::State& s) const { + return s.crop; } bool BufferStateLayer::setTransform(uint32_t transform) { @@ -320,57 +305,53 @@ bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInver } bool BufferStateLayer::setCrop(const Rect& crop) { - Rect c = crop; - if (c.left < 0) { - c.left = 0; - } - if (c.top < 0) { - c.top = 0; - } - // If the width and/or height are < 0, make it [0, 0, -1, -1] so the equality comparision below - // treats all invalid rectangles the same. - if (!c.isValid()) { - c.makeInvalid(); - } + if (mCurrentState.crop == crop) return false; + mCurrentState.sequence++; + mCurrentState.crop = crop; - if (mCurrentState.crop == c) return false; - mCurrentState.crop = c; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } -bool BufferStateLayer::setFrame(const Rect& frame) { - int x = frame.left; - int y = frame.top; - int w = frame.getWidth(); - int h = frame.getHeight(); - - if (x < 0) { - x = 0; - w = frame.right; +bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix, + bool allowNonRectPreservingTransforms) { + if (mCurrentState.transform.dsdx() == matrix.dsdx && + mCurrentState.transform.dtdy() == matrix.dtdy && + mCurrentState.transform.dtdx() == matrix.dtdx && + mCurrentState.transform.dsdy() == matrix.dsdy) { + return false; } - if (y < 0) { - y = 0; - h = frame.bottom; - } + ui::Transform t; + t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y && - mCurrentState.width == w && mCurrentState.height == h) { + if (!allowNonRectPreservingTransforms && !t.preserveRects()) { + ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor " + "ROTATE_SURFACE_FLINGER ignored"); return false; } - if (!frame.isValid()) { - x = y = w = h = 0; + mCurrentState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); + + mCurrentState.sequence++; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + + return true; +} + +bool BufferStateLayer::setPosition(float x, float y) { + if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) { + return false; } + mCurrentState.transform.set(x, y); - mCurrentState.width = w; - mCurrentState.height = h; mCurrentState.sequence++; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); + return true; } @@ -387,8 +368,9 @@ bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t post return true; } -bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, - nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, +bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& buffer, + 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>& releaseBufferListener) { @@ -396,12 +378,14 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence if (mCurrentState.buffer) { mReleasePreviousBuffer = true; - if (mCurrentState.buffer != mDrawingState.buffer) { + if (!mDrawingState.buffer || + mCurrentState.buffer->getBuffer() != mDrawingState.buffer->getBuffer()) { // If mCurrentState 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 // call any release buffer callbacks if set. - callReleaseBufferCallback(mCurrentState.releaseBufferListener, mCurrentState.buffer, + callReleaseBufferCallback(mCurrentState.releaseBufferListener, + mCurrentState.buffer->getBuffer(), mCurrentState.acquireFence); decrementPendingBufferCount(); if (mCurrentState.bufferSurfaceFrameTX != nullptr) { @@ -439,8 +423,8 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence setFrameTimelineVsyncForBufferTransaction(info, postTime); - if (dequeueTime && *dequeueTime != 0) { - const uint64_t bufferId = buffer->getId(); + if (buffer && dequeueTime && *dequeueTime != 0) { + const uint64_t bufferId = buffer->getBuffer()->getId(); mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime, FrameTracer::FrameEvent::DEQUEUE); @@ -448,6 +432,9 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence FrameTracer::FrameEvent::QUEUE); } + mCurrentState.width = mCurrentState.buffer->getBuffer()->getWidth(); + mCurrentState.height = mCurrentState.buffer->getBuffer()->getHeight(); + if (mFlinger->mSmoMo) { smomo::SmomoBufferStats bufferStats; bufferStats.id = getSequence(); @@ -709,7 +696,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse } const int32_t layerId = getSequence(); - const uint64_t bufferId = mDrawingState.buffer->getId(); + const uint64_t bufferId = mDrawingState.buffer->getBuffer()->getId(); const uint64_t frameNumber = mDrawingState.frameNumber; const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence); mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence); @@ -731,6 +718,11 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse latchTime); } + std::deque<sp<CallbackHandle>> remainingHandles; + mFlinger->getTransactionCallbackInvoker() + .finalizeOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles); + mDrawingState.callbackHandles = remainingHandles; + mCurrentStateModified = false; return NO_ERROR; @@ -743,7 +735,7 @@ status_t BufferStateLayer::updateActiveBuffer() { return BAD_VALUE; } - if (s.buffer != mBufferInfo.mBuffer) { + if (!mBufferInfo.mBuffer || s.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) { decrementPendingBufferCount(); } @@ -847,7 +839,7 @@ void BufferStateLayer::gatherBufferInfo() { mBufferInfo.mFence = s.acquireFence; mBufferInfo.mTransform = s.bufferTransform; mBufferInfo.mDataspace = translateDataspace(s.dataspace); - mBufferInfo.mCrop = computeCrop(s); + mBufferInfo.mCrop = computeBufferCrop(s); mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion; mBufferInfo.mHdrMetadata = s.hdrMetadata; @@ -860,27 +852,11 @@ uint32_t BufferStateLayer::getEffectiveScalingMode() const { return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; } -Rect BufferStateLayer::computeCrop(const State& s) { - if (s.crop.isEmpty() && s.buffer) { - return s.buffer->getBounds(); - } else if (s.buffer) { - Rect crop = s.crop; - crop.left = std::max(crop.left, 0); - crop.top = std::max(crop.top, 0); - uint32_t bufferWidth = s.buffer->getWidth(); - uint32_t bufferHeight = s.buffer->getHeight(); - if (bufferHeight <= std::numeric_limits<int32_t>::max() && - bufferWidth <= std::numeric_limits<int32_t>::max()) { - crop.right = std::min(crop.right, static_cast<int32_t>(bufferWidth)); - crop.bottom = std::min(crop.bottom, static_cast<int32_t>(bufferHeight)); - } - if (!crop.isValid()) { - // Crop rect is out of bounds, return whole buffer - return s.buffer->getBounds(); - } - return crop; +Rect BufferStateLayer::computeBufferCrop(const State& s) { + if (s.buffer) { + return s.buffer->getBuffer()->getBounds(); } - return s.crop; + return Rect::INVALID_RECT; } sp<Layer> BufferStateLayer::createClone() { @@ -892,41 +868,14 @@ sp<Layer> BufferStateLayer::createClone() { return layer; } -Layer::RoundedCornerState BufferStateLayer::getRoundedCornerState() const { - const auto& p = mDrawingParent.promote(); - if (p != nullptr) { - RoundedCornerState parentState = p->getRoundedCornerState(); - if (parentState.radius > 0) { - ui::Transform t = getActiveTransform(getDrawingState()); - t = t.inverse(); - parentState.cropRect = t.transform(parentState.cropRect); - // The rounded corners shader only accepts 1 corner radius for performance reasons, - // but a transform matrix can define horizontal and vertical scales. - // Let's take the average between both of them and pass into the shader, practically we - // never do this type of transformation on windows anyway. - parentState.radius *= (t[0][0] + t[1][1]) / 2.0f; - return parentState; - } - } - const float radius = getDrawingState().cornerRadius; - const State& s(getDrawingState()); - if (radius <= 0 || (getActiveWidth(s) == UINT32_MAX && getActiveHeight(s) == UINT32_MAX)) - return RoundedCornerState(); - return RoundedCornerState(FloatRect(static_cast<float>(s.transform.tx()), - static_cast<float>(s.transform.ty()), - static_cast<float>(s.transform.tx() + s.width), - static_cast<float>(s.transform.ty() + s.height)), - radius); -} - bool BufferStateLayer::bufferNeedsFiltering() const { const State& s(getDrawingState()); if (!s.buffer) { return false; } - uint32_t bufferWidth = s.buffer->width; - uint32_t bufferHeight = s.buffer->height; + uint32_t bufferWidth = s.buffer->getBuffer()->width; + uint32_t bufferHeight = s.buffer->getBuffer()->height; // Undo any transformations on the buffer and return the result. if (s.bufferTransform & ui::Transform::ROT_90) { @@ -953,14 +902,16 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); } -void BufferStateLayer::bufferMayChange(sp<GraphicBuffer>& newBuffer) { - if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer && - newBuffer != mDrawingState.buffer) { +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, - mDrawingState.acquireFence); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, + mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence); decrementPendingBufferCount(); } } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 3ae8597c73..46dfd7f6f6 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -50,10 +50,6 @@ public: uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override { return flags; } - /*TODO:vhau return to using BufferStateLayer override once WM - * has removed deferred transactions! - void pushPendingState() override;*/ - bool applyPendingStates(Layer::State* stateToCommit) override; uint32_t getActiveWidth(const Layer::State& s) const override { return s.width; } uint32_t getActiveHeight(const Layer::State& s) const override { return s.height; } @@ -66,10 +62,9 @@ public: bool setTransform(uint32_t transform) override; bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; - bool setFrame(const Rect& frame) override; - bool setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime, - nsecs_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& clientCacheId, uint64_t frameNumber, + bool setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& buffer, + 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; bool setAcquireFence(const sp<Fence>& fence) override; @@ -81,23 +76,16 @@ public: bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override; bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime) override; + bool setPosition(float /*x*/, float /*y*/) override; + bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, + bool /*allowNonRectPreservingTransforms*/); // Override to ignore legacy layer state properties that are not used by BufferStateLayer bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } - bool setPosition(float /*x*/, float /*y*/) override { return false; } bool setTransparentRegionHint(const Region& transparent) override; - bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, - bool /*allowNonRectPreservingTransforms*/) override { - return false; - } - void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/, - uint64_t /*frameNumber*/) override {} - void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/, - uint64_t /*frameNumber*/) override {} Rect getBufferSize(const State& s) const override; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; - Layer::RoundedCornerState getRoundedCornerState() const override; void setAutoRefresh(bool autoRefresh) override; // ----------------------------------------------------------------------- @@ -112,7 +100,7 @@ public: // See mPendingBufferTransactions void decrementPendingBufferCount(); - void bufferMayChange(sp<GraphicBuffer>& newBuffer) override; + void bufferMayChange(const sp<GraphicBuffer>& newBuffer) override; std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } @@ -152,7 +140,7 @@ private: sp<Layer> createClone() override; // Crop that applies to the buffer - Rect computeCrop(const State& s); + Rect computeBufferCrop(const State& s); bool willPresentCurrentTransaction() const; @@ -169,7 +157,6 @@ private: uint64_t mPreviousBufferId = 0; uint64_t mPreviousReleasedFrameNumber = 0; - mutable bool mCurrentStateModified = false; bool mReleasePreviousBuffer = false; // Stores the last set acquire fence signal time used to populate the callback handle's acquire diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp index 44b33ef43d..f310738423 100644 --- a/services/surfaceflinger/ClientCache.cpp +++ b/services/surfaceflinger/ClientCache.cpp @@ -102,7 +102,12 @@ bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& bu return false; } - processBuffers[id].buffer = buffer; + LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr, + "Attempted to build the ClientCache before a RenderEngine instance was " + "ready!"); + processBuffers[id].buffer = std::make_shared< + renderengine::ExternalTexture>(buffer, *mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE); return true; } @@ -132,7 +137,7 @@ void ClientCache::erase(const client_cache_t& cacheId) { } } -sp<GraphicBuffer> ClientCache::get(const client_cache_t& cacheId) { +std::shared_ptr<renderengine::ExternalTexture> ClientCache::get(const client_cache_t& cacheId) { std::lock_guard lock(mMutex); ClientCacheBuffer* buf = nullptr; @@ -213,8 +218,8 @@ void ClientCache::dump(std::string& result) { auto &buffers = i.second.second; for (auto& [id, clientCacheBuffer] : buffers) { StringAppendF(&result, "\t ID: %d, Width/Height: %d,%d\n", (int)id, - (int)clientCacheBuffer.buffer->getWidth(), - (int)clientCacheBuffer.buffer->getHeight()); + (int)clientCacheBuffer.buffer->getBuffer()->getWidth(), + (int)clientCacheBuffer.buffer->getBuffer()->getHeight()); } } } diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h index 0d597c8e05..a9b8177d70 100644 --- a/services/surfaceflinger/ClientCache.h +++ b/services/surfaceflinger/ClientCache.h @@ -19,6 +19,7 @@ #include <android-base/thread_annotations.h> #include <binder/IBinder.h> #include <gui/LayerState.h> +#include <renderengine/RenderEngine.h> #include <ui/GraphicBuffer.h> #include <utils/RefBase.h> #include <utils/Singleton.h> @@ -39,7 +40,11 @@ public: bool add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer); void erase(const client_cache_t& cacheId); - sp<GraphicBuffer> get(const client_cache_t& cacheId); + std::shared_ptr<renderengine::ExternalTexture> get(const client_cache_t& cacheId); + + // Always called immediately after setup. Will be set to non-null, and then should never be + // called again. + void setRenderEngine(renderengine::RenderEngine* renderEngine) { mRenderEngine = renderEngine; } void removeProcess(const wp<IBinder>& processToken); @@ -59,7 +64,7 @@ private: std::mutex mMutex; struct ClientCacheBuffer { - sp<GraphicBuffer> buffer; + std::shared_ptr<renderengine::ExternalTexture> buffer; std::set<wp<ErasedRecipient>> recipients; }; std::map<wp<IBinder> /*caching process*/, @@ -73,6 +78,7 @@ private: }; sp<CacheDeathRecipient> mDeathRecipient; + renderengine::RenderEngine* mRenderEngine = nullptr; bool getBuffer(const client_cache_t& cacheId, ClientCacheBuffer** outClientCacheBuffer) REQUIRES(mMutex); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index a0606b48f0..289cb119ca 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -79,6 +79,9 @@ struct CompositionRefreshArgs { // If set, causes the dirty regions to flash with the delay std::optional<std::chrono::microseconds> devOptFlashDirtyRegionsDelay; + + // The earliest time to send the present command to the HAL + std::chrono::steady_clock::time_point earliestPresentTime; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 1fd07b01f4..791e7db75c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -138,6 +138,9 @@ public: // Gets the sequence number: a serial number that uniquely identifies a Layer virtual int32_t getSequence() const = 0; + + // Whether the layer should be rendered with rounded corners. + virtual bool hasRoundedCorners() const = 0; }; // TODO(b/121291683): Specialize std::hash<> for sp<T> so these and others can diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index 27d0291caf..d0f7238a6a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -16,6 +16,7 @@ #pragma once +#include <cstdint> #include <optional> #include <string> @@ -95,8 +96,13 @@ public: // Writes the geometry state to the HWC, or does nothing if this layer does // not use the HWC. If includeGeometry is false, the geometry state can be // skipped. If skipLayer is true, then the alpha of the layer is forced to - // 0 so that HWC will ignore it. - virtual void writeStateToHWC(bool includeGeometry, bool skipLayer) = 0; + // 0 so that HWC will ignore it. z specifies the order to draw the layer in + // (starting with 0 for the back layer, and increasing for each following + // layer). zIsOverridden specifies whether the layer has been reordered. + // isPeekingThrough specifies whether this layer will be shown through a + // hole punch in a layer above it. + virtual void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, + bool zIsOverridden, bool isPeekingThrough) = 0; // Updates the cursor position with the HWC virtual void writeCursorPositionToHWC() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index 4ef3973973..7d345907d9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -16,15 +16,16 @@ #pragma once -#include <cstdint> -#include <vector> - +#include <renderengine/ExternalTexture.h> #include <ui/Fence.h> #include <ui/GraphicTypes.h> #include <ui/Size.h> #include <utils/Errors.h> #include <utils/StrongPointer.h> +#include <cstdint> +#include <vector> + namespace android { class GraphicBuffer; @@ -82,7 +83,8 @@ public: virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0; // Allocates a buffer as scratch space for GPU composition - virtual sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) = 0; + virtual std::shared_ptr<renderengine::ExternalTexture> dequeueBuffer( + base::unique_fd* bufferFence) = 0; // Queues the drawn buffer for consumption by HWC. readyFence is the fence // which will fire when the buffer is ready for consumption. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h index a1230b3c4d..a8d372c562 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h @@ -45,6 +45,8 @@ struct RenderSurfaceCreationArgs { // The DisplaySurface for this surface sp<DisplaySurface> displaySurface; + + size_t maxTextureCacheSize; }; /** @@ -81,6 +83,11 @@ public: return *this; } + RenderSurfaceCreationArgsBuilder& setMaxTextureCacheSize(size_t maxTextureCacheSize) { + mArgs.maxTextureCacheSize = maxTextureCacheSize; + return *this; + } + private: RenderSurfaceCreationArgs mArgs; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 8f767d37f6..f0ef6d6e7d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -115,6 +115,9 @@ struct OutputCompositionState { // Current target dataspace ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN}; + // The earliest time to send the present command to the HAL + std::chrono::steady_clock::time_point earliestPresentTime; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 83bca2d058..4dc7a3afe9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -16,6 +16,7 @@ #pragma once +#include <cstdint> #include <memory> #include <string> @@ -47,7 +48,8 @@ public: void updateCompositionState(bool includeGeometry, bool forceClientComposition, ui::Transform::RotationFlags) override; - void writeStateToHWC(bool includeGeometry, bool skipLayer) override; + void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden, + bool isPeekingThrough) override; void writeCursorPositionToHWC() const override; #ifdef QTI_UNIFIED_DRAW void writeLayerFlagToHWC(IQtiComposerClient::LayerFlag) override; @@ -73,7 +75,8 @@ protected: private: Rect calculateInitialCrop() const; - void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition); + void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition, + uint32_t z); void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&, bool skipLayer); void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*); @@ -81,7 +84,8 @@ private: void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&); void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&); void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&); - void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition); + void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition, + bool isPeekingThrough); void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 4c065ec112..356965cf48 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -18,7 +18,7 @@ #include <compositionengine/ProjectionSpace.h> #include <compositionengine/impl/HwcBufferCache.h> -#include <renderengine/Mesh.h> +#include <renderengine/ExternalTexture.h> #include <ui/FloatRect.h> #include <ui/GraphicTypes.h> #include <ui/Rect.h> @@ -46,6 +46,10 @@ class Layer; class HWComposer; +namespace compositionengine { +class OutputLayer; +} // namespace compositionengine + namespace compositionengine::impl { // Note that fields that affect HW composer state may need to be mirrored into @@ -84,18 +88,21 @@ struct OutputLayerCompositionState { // The dataspace for this layer ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; - // The Z order index of this layer on this output - uint32_t z{0}; - // Overrides the buffer, acquire fence, and display frame stored in LayerFECompositionState struct { - sp<GraphicBuffer> buffer = nullptr; + std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr; sp<Fence> acquireFence = nullptr; Rect displayFrame = {}; ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; ProjectionSpace displaySpace; Region damageRegion = Region::INVALID_REGION; Region visibleRegion; + + // The OutputLayer pointed to by this field will be rearranged to draw + // behind the OutputLayer represented by this CompositionState and will + // be visible through it. Unowned - the OutputLayer's lifetime will + // outlast this.) + OutputLayer* peekThroughLayer = nullptr; } overrideInfo; /* @@ -115,6 +122,9 @@ struct OutputLayerCompositionState { // The buffer cache for this layer. This is used to lower the // cost of sending reused buffers to the HWC. HwcBufferCache hwcBufferCache; + + // Set to true when overridden info has been sent to HW composer + bool stateOverridden = false; }; // The HWC state is optional, and is only set up if there is any potential diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index ba5edc7fb9..6de7886180 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -16,12 +16,16 @@ #pragma once -#include <memory> - #include <android-base/unique_fd.h> #include <compositionengine/RenderSurface.h> #include <utils/StrongPointer.h> +#include <memory> +#include <vector> + +#include "renderengine/ExternalTexture.h" +#include "renderengine/RenderEngine.h" + struct ANativeWindow; namespace android { @@ -56,7 +60,8 @@ public: void setProtected(bool useProtected) override; status_t beginFrame(bool mustRecompose) override; void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override; - sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override; + std::shared_ptr<renderengine::ExternalTexture> dequeueBuffer( + base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd readyFence) override; void onPresentDisplayCompleted() override; void flip() override; @@ -68,7 +73,7 @@ public: // Testing void setPageFlipCountForTest(std::uint32_t); void setSizeForTest(const ui::Size&); - sp<GraphicBuffer>& mutableGraphicBufferForTest(); + std::shared_ptr<renderengine::ExternalTexture>& mutableTextureForTest(); base::unique_fd& mutableBufferReadyForTest(); void flipClientTarget(bool flip) override; void setViewportAndProjection() override; @@ -79,10 +84,13 @@ private: // ANativeWindow being rendered into const sp<ANativeWindow> mNativeWindow; - // Current buffer being rendered into - sp<GraphicBuffer> mGraphicBuffer; + + std::vector<std::shared_ptr<renderengine::ExternalTexture>> mTextureCache; + // Current texture being rendered into + std::shared_ptr<renderengine::ExternalTexture> mTexture; const sp<DisplaySurface> mDisplaySurface; ui::Size mSize; + const size_t mMaxTextureCacheSize; bool mProtected{false}; bool mFlipClientTarget{false}; std::uint32_t mPageFlipCount{0}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index afa02cd0c2..a6c4eafbab 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -66,10 +66,11 @@ public: const Rect& getBounds() const { return mBounds; } const Region& getVisibleRegion() const { return mVisibleRegion; } size_t getAge() const { return mAge; } - const sp<GraphicBuffer>& getBuffer() const { return mTexture.getBuffer(); } + const std::shared_ptr<renderengine::ExternalTexture>& getBuffer() const { return mTexture; } const sp<Fence>& getDrawFence() const { return mDrawFence; } const ProjectionSpace& getOutputSpace() const { return mOutputSpace; } ui::Dataspace getOutputDataspace() const { return mOutputDataspace; } + const std::vector<Layer>& getConstituentLayers() const { return mLayers; } NonBufferHash getNonBufferHash() const; @@ -87,7 +88,7 @@ public: void setLastUpdate(std::chrono::steady_clock::time_point now) { mLastUpdate = now; } void append(const CachedSet& other) { - mTexture.setBuffer(nullptr, nullptr); + mTexture = nullptr; mOutputDataspace = ui::Dataspace::UNKNOWN; mDrawFence = nullptr; @@ -105,41 +106,37 @@ public: void dump(std::string& result) const; + // Whether this represents a single layer with a buffer and rounded corners. + // If it is, we may be able to draw it by placing it behind another + // CachedSet and punching a hole. + bool requiresHolePunch() const; + + // Add a layer that will be drawn behind this one. ::render() will render a + // hole in this CachedSet's buffer, allowing the supplied layer to peek + // through. Must be called before ::render(). + // Will do nothing if this CachedSet is not opaque where the hole punch + // layer is displayed. + // If isFirstLayer is true, this CachedSet can be considered opaque because + // nothing (besides the hole punch layer) will be drawn behind it. + void addHolePunchLayerIfFeasible(const CachedSet&, bool isFirstLayer); + + // Retrieve the layer that will be drawn behind this one. + OutputLayer* getHolePunchLayer() const; + private: CachedSet() = default; - NonBufferHash mFingerprint = 0; + const NonBufferHash mFingerprint; std::chrono::steady_clock::time_point mLastUpdate = std::chrono::steady_clock::now(); std::vector<Layer> mLayers; + + // Unowned. + const LayerState* mHolePunchLayer = nullptr; Rect mBounds = Rect::EMPTY_RECT; Region mVisibleRegion; size_t mAge = 0; - class Texture { - public: - ~Texture() { setBuffer(nullptr, nullptr); } - - void setBuffer(const sp<GraphicBuffer>& buffer, renderengine::RenderEngine* re) { - if (mRE && mBuffer) { - mRE->unbindExternalTextureBuffer(mBuffer->getId()); - } - - mBuffer = buffer; - mRE = re; - - if (mRE && mBuffer) { - mRE->cacheExternalTextureBuffer(mBuffer); - } - } - - const sp<GraphicBuffer>& getBuffer() const { return mBuffer; } - - private: - sp<GraphicBuffer> mBuffer = nullptr; - renderengine::RenderEngine* mRE = nullptr; - }; - - Texture mTexture; + std::shared_ptr<renderengine::ExternalTexture> mTexture; sp<Fence> mDrawFence; ProjectionSpace mOutputSpace; ui::Dataspace mOutputDataspace; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h index 313a180f4f..942592a9eb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h @@ -36,7 +36,8 @@ class Predictor; class Flattener { public: - Flattener(Predictor& predictor) : mPredictor(predictor) {} + Flattener(Predictor& predictor, bool enableHolePunch = false) + : mEnableHolePunch(enableHolePunch), mPredictor(predictor) {} void setDisplaySize(ui::Size size) { mDisplaySize = size; } @@ -54,13 +55,14 @@ private: void resetActivities(NonBufferHash, std::chrono::steady_clock::time_point now); - void updateLayersHash(); + NonBufferHash computeLayersHash() const; bool mergeWithCachedSets(const std::vector<const LayerState*>& layers, std::chrono::steady_clock::time_point now); void buildCachedSets(std::chrono::steady_clock::time_point now); + const bool mEnableHolePunch; Predictor& mPredictor; ui::Size mDisplaySize; @@ -69,7 +71,6 @@ private: std::chrono::steady_clock::time_point mLastGeometryUpdate; std::vector<CachedSet> mLayers; - NonBufferHash mLayersHash = 0; std::optional<CachedSet> mNewCachedSet; // Statistics diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index 050e2643e5..3391273679 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -53,20 +53,19 @@ enum class LayerStateField : uint32_t { Name = 1u << 1, DisplayFrame = 1u << 2, SourceCrop = 1u << 3, - ZOrder = 1u << 4, - BufferTransform = 1u << 5, - BlendMode = 1u << 6, - Alpha = 1u << 7, - LayerMetadata = 1u << 8, - VisibleRegion = 1u << 9, - Dataspace = 1u << 10, - PixelFormat = 1u << 11, - ColorTransform = 1u << 12, - SurfaceDamage = 1u << 13, - CompositionType = 1u << 14, - SidebandStream = 1u << 15, - Buffer = 1u << 16, - SolidColor = 1u << 17, + BufferTransform = 1u << 4, + BlendMode = 1u << 5, + Alpha = 1u << 6, + LayerMetadata = 1u << 7, + VisibleRegion = 1u << 8, + Dataspace = 1u << 9, + PixelFormat = 1u << 10, + ColorTransform = 1u << 11, + SurfaceDamage = 1u << 12, + CompositionType = 1u << 13, + SidebandStream = 1u << 14, + Buffer = 1u << 15, + SolidColor = 1u << 16, }; // clang-format on @@ -271,9 +270,6 @@ private: rect.top, rect.right, rect.bottom)}; }}; - OutputLayerState<uint32_t, LayerStateField::ZOrder> mZOrder{ - [](auto layer) { return layer->getState().z; }}; - using BufferTransformState = OutputLayerState<hardware::graphics::composer::hal::Transform, LayerStateField::BufferTransform>; BufferTransformState mBufferTransform{[](auto layer) { @@ -360,14 +356,6 @@ private: OutputLayerState<mat4, LayerStateField::ColorTransform> mColorTransform; - using SurfaceDamageState = OutputLayerState<Region, LayerStateField::SurfaceDamage>; - SurfaceDamageState - mSurfaceDamage{[](auto layer) { - return layer->getLayerFE().getCompositionState()->surfaceDamage; - }, - SurfaceDamageState::getRegionToStrings(), - SurfaceDamageState::getRegionEquals()}; - using CompositionTypeState = OutputLayerState<hardware::graphics::composer::hal::Composition, LayerStateField::CompositionType>; CompositionTypeState @@ -410,7 +398,7 @@ private: return std::vector<std::string>{stream.str()}; }}; - static const constexpr size_t kNumNonUniqueFields = 16; + static const constexpr size_t kNumNonUniqueFields = 14; std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() { std::array<const StateInterface*, kNumNonUniqueFields> constFields = @@ -425,10 +413,10 @@ private: std::array<const StateInterface*, kNumNonUniqueFields> getNonUniqueFields() const { return { - &mDisplayFrame, &mSourceCrop, &mZOrder, &mBufferTransform, - &mBlendMode, &mAlpha, &mLayerMetadata, &mVisibleRegion, - &mOutputDataspace, &mPixelFormat, &mColorTransform, &mSurfaceDamage, - &mCompositionType, &mSidebandStream, &mBuffer, &mSolidColor, + &mDisplayFrame, &mSourceCrop, &mBufferTransform, &mBlendMode, + &mAlpha, &mLayerMetadata, &mVisibleRegion, &mOutputDataspace, + &mPixelFormat, &mColorTransform, &mCompositionType, &mSidebandStream, + &mBuffer, &mSolidColor, }; } }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h index e6d2b636a3..c2037a899e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h @@ -41,7 +41,7 @@ namespace compositionengine::impl::planner { // as a more efficient representation of parts of the layer stack. class Planner { public: - Planner() : mFlattener(mPredictor) {} + Planner(); void setDisplaySize(ui::Size); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index dde8999524..d215bda891 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -43,6 +43,7 @@ public: MOCK_CONST_METHOD0(getDebugName, const char*()); MOCK_CONST_METHOD0(getSequence, int32_t()); + MOCK_CONST_METHOD0(hasRoundedCorners, bool()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 04c316e7dc..2942200d45 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -22,9 +22,11 @@ #include <compositionengine/OutputLayer.h> #include <compositionengine/impl/OutputLayerCompositionState.h> #include <gmock/gmock.h> +#include <cstdint> #ifdef QTI_UNIFIED_DRAW #include <vendor/qti/hardware/display/composer/3.1/IQtiComposerClient.h> #endif + namespace android::compositionengine::mock { #ifdef QTI_UNIFIED_DRAW using vendor::qti::hardware::display::composer::V3_1::IQtiComposerClient; @@ -43,7 +45,8 @@ public: MOCK_METHOD0(editState, impl::OutputLayerCompositionState&()); MOCK_METHOD3(updateCompositionState, void(bool, bool, ui::Transform::RotationFlags)); - MOCK_METHOD2(writeStateToHWC, void(bool, bool)); + + MOCK_METHOD5(writeStateToHWC, void(bool, bool, uint32_t, bool, bool)); #ifdef QTI_UNIFIED_DRAW MOCK_METHOD1(writeLayerFlagToHWC, void(IQtiComposerClient::LayerFlag)); #endif diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index 2f9c0875f0..29ebb44564 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -41,7 +41,7 @@ public: MOCK_METHOD1(setBufferPixelFormat, void(ui::PixelFormat)); MOCK_METHOD1(beginFrame, status_t(bool mustRecompose)); MOCK_METHOD2(prepareFrame, void(bool, bool)); - MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*)); + MOCK_METHOD1(dequeueBuffer, std::shared_ptr<renderengine::ExternalTexture>(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd)); MOCK_METHOD1(flipClientTarget, void(bool flip)); MOCK_METHOD0(onPresentDisplayCompleted, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index be8f3214fe..82dfc9fbb6 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -411,6 +411,11 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { return fences; } + { + ATRACE_NAME("wait for earliest present time"); + std::this_thread::sleep_until(getState().earliestPresentTime); + } + auto& hwc = getCompositionEngine().getHwComposer(); hwc.presentAndGetReleaseFences(*halDisplayIdOpt); diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index 430945ab4c..ff7d430531 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -78,6 +78,20 @@ void LayerFECompositionState::dump(std::string& out) const { dumpVal(out, "stretchEffect", stretchEffect); } + if (!blurRegions.empty()) { + out.append("\n blurRegions {"); + for (const auto& region : blurRegions) { + out.append("\n "); + base::StringAppendF(&out, + "{radius=%du, cornerRadii=[%f, %f, %f, %f], alpha=%f, rect=[%d, " + "%d, %d, %d]", + region.blurRadius, region.cornerRadiusTL, region.cornerRadiusTR, + region.cornerRadiusBL, region.cornerRadiusBR, region.alpha, + region.left, region.top, region.right, region.bottom); + } + out.append("\n }\n "); + } + if (!metadata.empty()) { out.append("\n metadata {"); for (const auto& [key, entry] : metadata) { diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 708956d4e9..23b3ec4b49 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -14,8 +14,7 @@ * limitations under the License. */ -#include <thread> - +#include <SurfaceFlingerProperties.sysprop.h> #include <android-base/stringprintf.h> #include <compositionengine/CompositionEngine.h> #include <compositionengine/CompositionRefreshArgs.h> @@ -29,7 +28,9 @@ #include <compositionengine/impl/OutputLayerCompositionState.h> #include <compositionengine/impl/planner/Planner.h> -#include <SurfaceFlingerProperties.sysprop.h> +#include <thread> + +#include "renderengine/ExternalTexture.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -458,12 +459,6 @@ void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArg setReleasedLayers(refreshArgs); finalizePendingOutputLayers(); - - // Generate a simple Z-order values to each visible output layer - uint32_t zOrder = 0; - for (auto* outputLayer : getOutputLayersOrderedByZ()) { - outputLayer->editState().z = zOrder++; - } } void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, @@ -728,6 +723,9 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr return; } + editState().earliestPresentTime = refreshArgs.earliestPresentTime; + + OutputLayer* peekThroughLayer = nullptr; bool hasSecureCamera = false; bool hasSecureDisplay = false; bool needsProtected = false; @@ -744,22 +742,43 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr } sp<GraphicBuffer> previousOverride = nullptr; + bool includeGeometry = refreshArgs.updatingGeometryThisFrame; + uint32_t z = 0; + bool overrideZ = false; for (auto* layer : getOutputLayersOrderedByZ()) { + if (layer == peekThroughLayer) { + // No longer needed, although it should not show up again, so + // resetting it is not truly needed either. + peekThroughLayer = nullptr; + + // peekThroughLayer was already drawn ahead of its z order. + continue; + } bool skipLayer = false; - if (layer->getState().overrideInfo.buffer != nullptr) { - if (previousOverride != nullptr && - layer->getState().overrideInfo.buffer == previousOverride) { + const auto& overrideInfo = layer->getState().overrideInfo; + if (overrideInfo.buffer != nullptr) { + if (previousOverride && overrideInfo.buffer->getBuffer() == previousOverride) { ALOGV("Skipping redundant buffer"); skipLayer = true; + } else { + // First layer with the override buffer. + if (overrideInfo.peekThroughLayer) { + peekThroughLayer = overrideInfo.peekThroughLayer; + + // Draw peekThroughLayer first. + overrideZ = true; + includeGeometry = true; + constexpr bool isPeekingThrough = true; + peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ, + isPeekingThrough); + } + + previousOverride = overrideInfo.buffer->getBuffer(); } - previousOverride = layer->getState().overrideInfo.buffer; } - // TODO(b/181172795): We now update geometry for all flattened layers. We should update it - // only when the geometry actually changes - const bool includeGeometry = refreshArgs.updatingGeometryThisFrame || - layer->getState().overrideInfo.buffer != nullptr || skipLayer; - layer->writeStateToHWC(includeGeometry, skipLayer); + constexpr bool isPeekingThrough = false; + layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough); #ifdef QTI_UNIFIED_DRAW if (hasSecureCamera || hasSecureDisplay || needsProtected) { layer->writeLayerFlagToHWC(IQtiComposerClient::LayerFlag::DEFAULT); @@ -1041,14 +1060,15 @@ std::optional<base::unique_fd> Output::composeSurfaces( } base::unique_fd fd; - sp<GraphicBuffer> buf; + + std::shared_ptr<renderengine::ExternalTexture> tex; // If we aren't doing client composition on this output, but do have a // flipClientTarget request for this frame on this output, we still need to // dequeue a buffer. if (hasClientComposition || outputState.flipClientTarget) { - buf = mRenderSurface->dequeueBuffer(&fd); - if (buf == nullptr) { + tex = mRenderSurface->dequeueBuffer(&fd); + if (tex == nullptr) { ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " "client composition for this frame", mName.c_str()); @@ -1093,13 +1113,14 @@ std::optional<base::unique_fd> Output::composeSurfaces( // Check if the client composition requests were rendered into the provided graphic buffer. If // so, we can reuse the buffer and avoid client composition. if (mClientCompositionRequestCache) { - if (mClientCompositionRequestCache->exists(buf->getId(), clientCompositionDisplay, + if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(), + clientCompositionDisplay, clientCompositionLayers)) { outputCompositionState.reusedClientComposition = true; setExpensiveRenderingExpected(false); return readyFence; } - mClientCompositionRequestCache->add(buf->getId(), clientCompositionDisplay, + mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay, clientCompositionLayers); } @@ -1132,12 +1153,12 @@ std::optional<base::unique_fd> Output::composeSurfaces( // 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, buf, + renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, useFramebufferCache, std::move(fd), &readyFence); if (status != NO_ERROR && mClientCompositionRequestCache) { // If rendering was not successful, remove the request from the cache. - mClientCompositionRequestCache->remove(buf->getId()); + mClientCompositionRequestCache->remove(tex->getBuffer()->getId()); } auto& timeStats = getCompositionEngine().getTimeStats(); @@ -1214,9 +1235,9 @@ std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests( std::vector<LayerFE::LayerSettings> results; if (layer->getState().overrideInfo.buffer != nullptr) { - if (layer->getState().overrideInfo.buffer != previousOverrideBuffer) { + if (layer->getState().overrideInfo.buffer->getBuffer() != previousOverrideBuffer) { results = layer->getOverrideCompositionList(); - previousOverrideBuffer = layer->getState().overrideInfo.buffer; + previousOverrideBuffer = layer->getState().overrideInfo.buffer->getBuffer(); ALOGV("Replacing [%s] with override in RE", layer->getLayerFE().getDebugName()); } else { ALOGV("Skipping redundant override buffer for [%s] in RE", diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 0df25401c3..7b1376c0b7 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -21,6 +21,7 @@ #include <compositionengine/impl/OutputCompositionState.h> #include <compositionengine/impl/OutputLayer.h> #include <compositionengine/impl/OutputLayerCompositionState.h> +#include <cstdint> // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -317,7 +318,8 @@ void OutputLayer::updateCompositionState( } } -void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) { +void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, + bool zIsOverridden, bool isPeekingThrough) { const auto& state = getState(); // Skip doing this if there is no HWC interface if (!state.hwc) { @@ -338,8 +340,13 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) { auto requestedCompositionType = outputIndependentState->compositionType; - if (includeGeometry) { - writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType); + // TODO(b/181172795): We now update geometry for all flattened layers. We should update it + // only when the geometry actually changes + const bool isOverridden = + state.overrideInfo.buffer != nullptr || isPeekingThrough || zIsOverridden; + const bool prevOverridden = state.hwc->stateOverridden; + if (isOverridden || prevOverridden || skipLayer || includeGeometry) { + writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType, z); writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), *outputIndependentState, skipLayer); } @@ -347,14 +354,17 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) { writeOutputDependentPerFrameStateToHWC(hwcLayer.get()); writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState); - writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType); + writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough); // Always set the layer color after setting the composition type. writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState); + + editState().hwc->stateOverridden = isOverridden; } -void OutputLayer::writeOutputDependentGeometryStateToHWC( - HWC2::Layer* hwcLayer, hal::Composition requestedCompositionType) { +void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer, + hal::Composition requestedCompositionType, + uint32_t z) { const auto& outputDependentState = getState(); Rect displayFrame = outputDependentState.displayFrame; @@ -362,7 +372,12 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( if (outputDependentState.overrideInfo.buffer != nullptr) { displayFrame = outputDependentState.overrideInfo.displayFrame; - sourceCrop = displayFrame.toFloatRect(); + sourceCrop = + FloatRect(0.f, 0.f, + static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer() + ->getWidth()), + static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer() + ->getHeight())); } ALOGV("Writing display frame [%d, %d, %d, %d]", displayFrame.left, displayFrame.top, @@ -381,9 +396,9 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( sourceCrop.bottom, to_string(error).c_str(), static_cast<int32_t>(error)); } - if (auto error = hwcLayer->setZOrder(outputDependentState.z); error != hal::Error::NONE) { - ALOGE("[%s] Failed to set Z %u: %s (%d)", getLayerFE().getDebugName(), - outputDependentState.z, to_string(error).c_str(), static_cast<int32_t>(error)); + if (auto error = hwcLayer->setZOrder(z); error != hal::Error::NONE) { + ALOGE("[%s] Failed to set Z %u: %s (%d)", getLayerFE().getDebugName(), z, + to_string(error).c_str(), static_cast<int32_t>(error)); } // Solid-color layers and overridden buffers should always use an identity transform. @@ -402,7 +417,10 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( void OutputLayer::writeOutputIndependentGeometryStateToHWC( HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState, bool skipLayer) { - const auto blendMode = getState().overrideInfo.buffer + // If there is a peekThroughLayer, then this layer has a hole in it. We need to use + // PREMULTIPLIED so it will peek through. + const auto& overrideInfo = getState().overrideInfo; + const auto blendMode = overrideInfo.buffer || overrideInfo.peekThroughLayer ? hardware::graphics::composer::hal::BlendMode::PREMULTIPLIED : outputIndependentState.blendMode; if (auto error = hwcLayer->setBlendMode(blendMode); error != hal::Error::NONE) { @@ -542,7 +560,7 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, sp<GraphicBuffer> buffer = outputIndependentState.buffer; sp<Fence> acquireFence = outputIndependentState.acquireFence; if (getState().overrideInfo.buffer != nullptr) { - buffer = getState().overrideInfo.buffer; + buffer = getState().overrideInfo.buffer->getBuffer(); acquireFence = getState().overrideInfo.acquireFence; } @@ -563,11 +581,13 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, } void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer, - hal::Composition requestedCompositionType) { + hal::Composition requestedCompositionType, + bool isPeekingThrough) { auto& outputDependentState = editState(); // If we are forcing client composition, we need to tell the HWC - if (outputDependentState.forceClientComposition) { + if (outputDependentState.forceClientComposition || + (!isPeekingThrough && getLayerFE().hasRoundedCorners())) { requestedCompositionType = hal::Composition::CLIENT; } @@ -720,7 +740,7 @@ std::vector<LayerFE::LayerSettings> OutputLayer::getOverrideCompositionList() co settings.geometry = renderengine::Geometry{ .boundaries = boundaries.toFloatRect(), }; - settings.bufferId = getState().overrideInfo.buffer->getId(); + settings.bufferId = getState().overrideInfo.buffer->getBuffer()->getId(); settings.source = renderengine::PixelSource{ .buffer = renderengine::Buffer{ .buffer = getState().overrideInfo.buffer, diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp index efd23dce98..b4c314c8d4 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp @@ -67,7 +67,6 @@ void OutputLayerCompositionState::dump(std::string& out) const { dumpVal(out, "sourceCrop", sourceCrop); dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform); dumpVal(out, "dataspace", toString(dataspace), dataspace); - dumpVal(out, "z-index", z); dumpVal(out, "override buffer", overrideInfo.buffer.get()); dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get()); dumpVal(out, "override display frame", overrideInfo.displayFrame); diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index eca34729ae..ead245d85d 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -25,8 +25,8 @@ #include <compositionengine/impl/DumpHelpers.h> #include <compositionengine/impl/OutputCompositionState.h> #include <compositionengine/impl/RenderSurface.h> - #include <log/log.h> +#include <renderengine/ExternalTexture.h> #include <renderengine/RenderEngine.h> #include <system/window.h> #include <ui/GraphicBuffer.h> @@ -63,7 +63,8 @@ RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display mDisplay(display), mNativeWindow(args.nativeWindow), mDisplaySurface(args.displaySurface), - mSize(args.displayWidth, args.displayHeight) { + mSize(args.displayWidth, args.displayHeight), + mMaxTextureCacheSize(args.maxTextureCacheSize) { LOG_ALWAYS_FATAL_IF(!mNativeWindow); } @@ -154,7 +155,8 @@ void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComp } } -sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { +std::shared_ptr<renderengine::ExternalTexture> RenderSurface::dequeueBuffer( + base::unique_fd* bufferFence) { ATRACE_CALL(); int fd = -1; ANativeWindowBuffer* buffer = nullptr; @@ -166,16 +168,41 @@ sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { mDisplay.getName().c_str(), result); // Return fast here as we can't do much more - any rendering we do // now will just be wrong. - return mGraphicBuffer; + return mTexture; + } + + ALOGW_IF(mTexture != nullptr, "Clobbering a non-null pointer to a buffer [%p].", + mTexture->getBuffer()->getNativeBuffer()->handle); + + sp<GraphicBuffer> newBuffer = GraphicBuffer::from(buffer); + + std::shared_ptr<renderengine::ExternalTexture> texture; + + for (auto it = mTextureCache.begin(); it != mTextureCache.end(); it++) { + const auto& cachedTexture = *it; + if (cachedTexture->getBuffer()->getId() == newBuffer->getId()) { + texture = cachedTexture; + mTextureCache.erase(it); + break; + } } - ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].", - mGraphicBuffer->getNativeBuffer()->handle); - mGraphicBuffer = GraphicBuffer::from(buffer); + if (texture) { + mTexture = texture; + } else { + mTexture = std::make_shared< + renderengine::ExternalTexture>(GraphicBuffer::from(buffer), + mCompositionEngine.getRenderEngine(), + renderengine::ExternalTexture::Usage::WRITEABLE); + } + mTextureCache.push_back(mTexture); + if (mTextureCache.size() > mMaxTextureCacheSize) { + mTextureCache.erase(mTextureCache.begin()); + } *bufferFence = base::unique_fd(fd); - return mGraphicBuffer; + return mTexture; } void RenderSurface::queueBuffer(base::unique_fd readyFence) { @@ -186,24 +213,24 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) { // hasFlipClientTargetRequest could return true even if we haven't // dequeued a buffer before. Try dequeueing one if we don't have a // buffer ready. - if (mGraphicBuffer == nullptr) { + if (mTexture == nullptr) { ALOGI("Attempting to queue a client composited buffer without one " "previously dequeued for display [%s]. Attempting to dequeue " "a scratch buffer now", mDisplay.getName().c_str()); - // We shouldn't deadlock here, since mGraphicBuffer == nullptr only + // We shouldn't deadlock here, since mTexture == nullptr only // after a successful call to queueBuffer, or if dequeueBuffer has // never been called. base::unique_fd unused; dequeueBuffer(&unused); } - if (mGraphicBuffer == nullptr) { + if (mTexture == nullptr) { ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str()); } else { status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), + mTexture->getBuffer()->getNativeBuffer(), mFlipClientTarget ? -1 : dup(readyFence)); if (result != NO_ERROR) { ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(), @@ -214,12 +241,12 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) { LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result); } else { mNativeWindow->cancelBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), + mTexture->getBuffer()->getNativeBuffer(), mFlipClientTarget ? -1 : dup(readyFence)); } } - mGraphicBuffer = nullptr; + mTexture = nullptr; } } @@ -273,8 +300,8 @@ void RenderSurface::setSizeForTest(const ui::Size& size) { mSize = size; } -sp<GraphicBuffer>& RenderSurface::mutableGraphicBufferForTest() { - return mGraphicBuffer; +std::shared_ptr<renderengine::ExternalTexture>& RenderSurface::mutableTextureForTest() { + return mTexture; } void RenderSurface::flipClientTarget(bool flip) { diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index dcb75556e3..b31e89e247 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -130,7 +130,7 @@ bool CachedSet::hasBufferUpdate() const { } bool CachedSet::hasReadyBuffer() const { - return mTexture.getBuffer() != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled; + return mTexture != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled; } std::vector<CachedSet> CachedSet::decompose() const { @@ -193,6 +193,23 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, std::transform(layerSettings.cbegin(), layerSettings.cend(), std::back_inserter(layerSettingsPointers), [](const renderengine::LayerSettings& settings) { return &settings; }); + renderengine::LayerSettings holePunchSettings; + if (mHolePunchLayer) { + auto clientCompositionList = + mHolePunchLayer->getOutputLayer()->getLayerFE().prepareClientCompositionList( + targetSettings); + // Assume that the final layer contains the buffer that we want to + // replace with a hole punch. + holePunchSettings = clientCompositionList.back(); + LOG_ALWAYS_FATAL_IF(!holePunchSettings.source.buffer.buffer, "Expected to have a buffer!"); + // This mimics Layer::prepareClearClientComposition + holePunchSettings.source.buffer.buffer = nullptr; + holePunchSettings.source.solidColor = half3(0.0f, 0.0f, 0.0f); + holePunchSettings.disableBlending = true; + holePunchSettings.alpha = 0.0f; + holePunchSettings.name = std::string("hole punch layer"); + layerSettingsPointers.push_back(&holePunchSettings); + } if (sDebugHighlighLayers) { highlight = { @@ -217,22 +234,78 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, sp<GraphicBuffer> buffer = new GraphicBuffer(static_cast<uint32_t>(mBounds.getWidth()), static_cast<uint32_t>(mBounds.getHeight()), HAL_PIXEL_FORMAT_RGBA_8888, 1, usageFlags); + const auto texture = std::make_shared< + renderengine::ExternalTexture>(buffer, renderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); LOG_ALWAYS_FATAL_IF(buffer->initCheck() != OK); base::unique_fd drawFence; - status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, buffer, false, - base::unique_fd(), &drawFence); + status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture, + false, base::unique_fd(), &drawFence); if (result == NO_ERROR) { - mTexture.setBuffer(buffer, &renderEngine); mDrawFence = new Fence(drawFence.release()); mOutputSpace = ProjectionSpace(ui::Size(outputState.framebufferSpace.bounds.getWidth(), outputState.framebufferSpace.bounds.getHeight()), mBounds); + mTexture = std::move(texture); mOutputSpace.orientation = outputState.framebufferSpace.orientation; mOutputDataspace = outputDataspace; mOrientation = orientation; + } else { + mTexture = nullptr; + } +} + +bool CachedSet::requiresHolePunch() const { + // In order for the hole punch to be beneficial, the layer must be updating + // regularly, meaning it should not have been merged with other layers. + if (getLayerCount() != 1) { + return false; } + + // There is no benefit to a hole punch unless the layer has a buffer. + if (!mLayers[0].getBuffer()) { + return false; + } + + const auto& layerFE = mLayers[0].getState()->getOutputLayer()->getLayerFE(); + if (layerFE.getCompositionState()->forceClientComposition) { + return false; + } + + return layerFE.hasRoundedCorners(); +} + +namespace { +bool contains(const Rect& outer, const Rect& inner) { + return outer.left <= inner.left && outer.right >= inner.right && outer.top <= inner.top && + outer.bottom >= inner.bottom; +} +}; // namespace + +void CachedSet::addHolePunchLayerIfFeasible(const CachedSet& holePunchLayer, bool isFirstLayer) { + // Verify that this CachedSet is opaque where the hole punch layer + // will draw. + const Rect& holePunchBounds = holePunchLayer.getBounds(); + for (const auto& layer : mLayers) { + // The first layer is considered opaque because nothing is behind it. + // Note that isOpaque is always false for a layer with rounded + // corners, even if the interior is opaque. In theory, such a layer + // could be used for a hole punch, but this is unlikely to happen in + // practice. + const auto* outputLayer = layer.getState()->getOutputLayer(); + if (contains(outputLayer->getState().displayFrame, holePunchBounds) && + (isFirstLayer || outputLayer->getLayerFE().getCompositionState()->isOpaque)) { + mHolePunchLayer = holePunchLayer.getFirstLayer().getState(); + return; + } + } +} + +OutputLayer* CachedSet::getHolePunchLayer() const { + return mHolePunchLayer ? mHolePunchLayer->getOutputLayer() : nullptr; } void CachedSet::dump(std::string& result) const { @@ -242,6 +315,11 @@ void CachedSet::dump(std::string& result) const { std::chrono::duration_cast<std::chrono::milliseconds>(now - mLastUpdate); base::StringAppendF(&result, " + Fingerprint %016zx, last update %sago, age %zd\n", mFingerprint, durationString(lastUpdate).c_str(), mAge); + { + const auto b = mTexture ? mTexture->getBuffer().get() : nullptr; + base::StringAppendF(&result, " Override buffer: %p\n", b); + } + base::StringAppendF(&result, " HolePunchLayer: %p\n", mHolePunchLayer); if (mLayers.size() == 1) { base::StringAppendF(&result, " Layer [%s]\n", mLayers[0].getName().c_str()); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index ffca5baab7..b4e761004f 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -27,12 +27,44 @@ using namespace std::chrono_literals; namespace android::compositionengine::impl::planner { +namespace { + +// True if the underlying layer stack is the same modulo state that would be expected to be +// different like specific buffers, false otherwise. +bool isSameStack(const std::vector<const LayerState*>& incomingLayers, + const std::vector<CachedSet>& cachedSets) { + std::vector<const LayerState*> existingLayers; + for (auto& cachedSet : cachedSets) { + for (auto& layer : cachedSet.getConstituentLayers()) { + existingLayers.push_back(layer.getState()); + } + } + + if (incomingLayers.size() != existingLayers.size()) { + return false; + } + + for (size_t i = 0; i < incomingLayers.size(); i++) { + if (incomingLayers[i]->getDifferingFields(*(existingLayers[i])) != LayerStateField::None) { + return false; + } + } + return true; +} + +} // namespace + NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash hash, time_point now) { const size_t unflattenedDisplayCost = calculateDisplayCost(layers); mUnflattenedDisplayCost += unflattenedDisplayCost; - if (mCurrentGeometry != hash) { + // We invalidate the layer cache if: + // 1. We're not tracking any layers, or + // 2. The last seen hashed geometry changed between frames, or + // 3. A stricter equality check demonstrates that the layer stack really did change, since the + // hashed geometry does not guarantee uniqueness. + if (mCurrentGeometry != hash || (!mLayers.empty() && !isSameStack(layers, mLayers))) { resetActivities(hash, now); mFlattenedDisplayCost += unflattenedDisplayCost; return hash; @@ -40,13 +72,17 @@ NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& lay ++mInitialLayerCounts[layers.size()]; - if (mergeWithCachedSets(layers, now)) { - hash = mLayersHash; - } + // Only buildCachedSets if these layers are already stored in mLayers. + // Otherwise (i.e. mergeWithCachedSets returns false), the time has not + // changed, so buildCachedSets will never find any runs. + const bool alreadyHadCachedSets = mergeWithCachedSets(layers, now); ++mFinalLayerCounts[mLayers.size()]; - buildCachedSets(now); + if (alreadyHadCachedSets) { + buildCachedSets(now); + hash = computeLayersHash(); + } return hash; } @@ -157,14 +193,17 @@ void Flattener::resetActivities(NonBufferHash hash, time_point now) { } } -void Flattener::updateLayersHash() { +NonBufferHash Flattener::computeLayersHash() const{ size_t hash = 0; for (const auto& layer : mLayers) { android::hashCombineSingleHashed(hash, layer.getNonBufferHash()); } - mLayersHash = hash; + return hash; } +// Only called if the geometry matches the last frame. Return true if mLayers +// was already populated with these layers, i.e. on the second and following +// calls with the same geometry. bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers, time_point now) { std::vector<CachedSet> merged; @@ -202,6 +241,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers ALOGV("[%s] Found ready buffer", __func__); size_t skipCount = mNewCachedSet->getLayerCount(); while (skipCount != 0) { + auto* peekThroughLayer = mNewCachedSet->getHolePunchLayer(); const size_t layerCount = currentLayerIter->getLayerCount(); for (size_t i = 0; i < layerCount; ++i) { OutputLayer::CompositionState& state = @@ -214,6 +254,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers .displaySpace = mNewCachedSet->getOutputSpace(), .damageRegion = Region::INVALID_REGION, .visibleRegion = mNewCachedSet->getVisibleRegion(), + .peekThroughLayer = peekThroughLayer, }; ++incomingLayerIter; } @@ -237,6 +278,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers // Skip the incoming layers corresponding to this valid current layer const size_t layerCount = currentLayerIter->getLayerCount(); + auto* peekThroughLayer = currentLayerIter->getHolePunchLayer(); for (size_t i = 0; i < layerCount; ++i) { OutputLayer::CompositionState& state = (*incomingLayerIter)->getOutputLayer()->editState(); @@ -248,6 +290,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers .displaySpace = currentLayerIter->getOutputSpace(), .damageRegion = Region(), .visibleRegion = currentLayerIter->getVisibleRegion(), + .peekThroughLayer = peekThroughLayer, }; ++incomingLayerIter; } @@ -272,7 +315,6 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers } mLayers = std::move(merged); - updateLayersHash(); return true; } @@ -292,6 +334,11 @@ void Flattener::buildCachedSets(time_point now) { std::vector<Run> runs; bool isPartOfRun = false; + + // Keep track of the layer that follows a run. It's possible that we will + // render it with a hole-punch. + const CachedSet* holePunchLayer = nullptr; + for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) { if (now - currentSet->getLastUpdate() > kActiveLayerTimeout) { // Layer is inactive @@ -306,10 +353,20 @@ void Flattener::buildCachedSets(time_point now) { isPartOfRun = true; } } - } else { + } else if (isPartOfRun) { // Runs must be at least 2 sets long or there's nothing to combine - if (isPartOfRun && runs.back().start->getLayerCount() == runs.back().length) { + if (runs.back().start->getLayerCount() == runs.back().length) { runs.pop_back(); + } else { + // The prior run contained at least two sets. Currently, we'll + // only possibly merge a single run, so only keep track of a + // holePunchLayer if this is the first run. + if (runs.size() == 1) { + holePunchLayer = &(*currentSet); + } + + // TODO(b/185114532: Break out of the loop? We may find more runs, but we + // won't do anything with them. } isPartOfRun = false; @@ -335,6 +392,13 @@ void Flattener::buildCachedSets(time_point now) { mNewCachedSet->append(*currentSet); } + if (mEnableHolePunch && holePunchLayer && holePunchLayer->requiresHolePunch()) { + // Add the pip layer to mNewCachedSet, but in a special way - it should + // replace the buffer with a clear round rect. + mNewCachedSet->addHolePunchLayerIfFeasible(*holePunchLayer, + runs[0].start == mLayers.cbegin()); + } + // TODO(b/181192467): Actually compute new LayerState vector and corresponding hash for each run mPredictor.getPredictedPlan({}, 0); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index 7c32e944fc..8423a124cf 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -155,13 +155,11 @@ std::optional<std::string> LayerState::compare(const LayerState& other) const { bool operator==(const LayerState& lhs, const LayerState& rhs) { return lhs.mId == rhs.mId && lhs.mName == rhs.mName && lhs.mDisplayFrame == rhs.mDisplayFrame && - lhs.mSourceCrop == rhs.mSourceCrop && lhs.mZOrder == rhs.mZOrder && - lhs.mBufferTransform == rhs.mBufferTransform && lhs.mBlendMode == rhs.mBlendMode && - lhs.mAlpha == rhs.mAlpha && lhs.mLayerMetadata == rhs.mLayerMetadata && - lhs.mVisibleRegion == rhs.mVisibleRegion && + lhs.mSourceCrop == rhs.mSourceCrop && lhs.mBufferTransform == rhs.mBufferTransform && + lhs.mBlendMode == rhs.mBlendMode && lhs.mAlpha == rhs.mAlpha && + lhs.mLayerMetadata == rhs.mLayerMetadata && lhs.mVisibleRegion == rhs.mVisibleRegion && lhs.mOutputDataspace == rhs.mOutputDataspace && lhs.mPixelFormat == rhs.mPixelFormat && lhs.mColorTransform == rhs.mColorTransform && - lhs.mSurfaceDamage == rhs.mSurfaceDamage && lhs.mCompositionType == rhs.mCompositionType && lhs.mSidebandStream == rhs.mSidebandStream && lhs.mBuffer == rhs.mBuffer && (lhs.mCompositionType.get() != hal::Composition::SOLID_COLOR || diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index ad7555730d..7d2bf06133 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -19,12 +19,17 @@ #undef LOG_TAG #define LOG_TAG "Planner" +#include <android-base/properties.h> #include <compositionengine/LayerFECompositionState.h> #include <compositionengine/impl/OutputLayerCompositionState.h> #include <compositionengine/impl/planner/Planner.h> namespace android::compositionengine::impl::planner { +Planner::Planner() + : mFlattener(mPredictor, + base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), false)) {} + void Planner::setDisplaySize(ui::Size size) { mFlattener.setDisplaySize(size); } @@ -111,7 +116,12 @@ void Planner::reportFinalPlan( const GraphicBuffer* currentOverrideBuffer = nullptr; bool hasSkippedLayers = false; for (auto layer : layers) { - const GraphicBuffer* overrideBuffer = layer->getState().overrideInfo.buffer.get(); + if (!layer->getState().overrideInfo.buffer) { + continue; + } + + const GraphicBuffer* overrideBuffer = + layer->getState().overrideInfo.buffer->getBuffer().get(); if (overrideBuffer != nullptr && overrideBuffer == currentOverrideBuffer) { // Skip this layer since it is part of a previous cached set hasSkippedLayers = true; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 8a4d161289..fb8ffcedf3 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -23,6 +23,8 @@ #include <gtest/gtest.h> #include <log/log.h> +#include <renderengine/mock/RenderEngine.h> +#include <ui/PixelFormat.h> #include "MockHWC2.h" #include "MockHWComposer.h" #include "RegionMatcher.h" @@ -688,7 +690,6 @@ TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromArgumen struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static constexpr hal::Error kError = hal::Error::UNSUPPORTED; static constexpr FloatRect kSourceCrop{11.f, 12.f, 13.f, 14.f}; - static constexpr uint32_t kZOrder = 21u; static constexpr Hwc2::Transform kBufferTransform = static_cast<Hwc2::Transform>(31); static constexpr Hwc2::Transform kOverrideBufferTransform = static_cast<Hwc2::Transform>(0); static constexpr Hwc2::IComposerClient::BlendMode kBlendMode = @@ -707,6 +708,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static const half4 kColor; static const Rect kDisplayFrame; static const Rect kOverrideDisplayFrame; + static const FloatRect kOverrideSourceCrop; static const Region kOutputSpaceVisibleRegion; static const Region kOverrideVisibleRegion; static const mat4 kColorTransform; @@ -729,7 +731,6 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { outputLayerState.displayFrame = kDisplayFrame; outputLayerState.sourceCrop = kSourceCrop; - outputLayerState.z = kZOrder; outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform); outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion; outputLayerState.dataspace = kDataspace; @@ -764,7 +765,11 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { void includeOverrideInfo() { auto& overrideInfo = mOutputLayer.editState().overrideInfo; - overrideInfo.buffer = kOverrideBuffer; + overrideInfo.buffer = std::make_shared< + renderengine::ExternalTexture>(kOverrideBuffer, mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage:: + WRITEABLE); overrideInfo.acquireFence = kOverrideFence; overrideInfo.displayFrame = kOverrideDisplayFrame; overrideInfo.dataspace = kOverrideDataspace; @@ -779,7 +784,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { float alpha = kAlpha) { EXPECT_CALL(*mHwcLayer, setDisplayFrame(displayFrame)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setSourceCrop(sourceCrop)).WillOnce(Return(kError)); - EXPECT_CALL(*mHwcLayer, setZOrder(kZOrder)).WillOnce(Return(kError)); + EXPECT_CALL(*mHwcLayer, setZOrder(_)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setTransform(bufferTransform)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setBlendMode(blendMode)).WillOnce(Return(kError)); @@ -839,12 +844,14 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()}; StrictMock<mock::DisplayColorProfile> mDisplayColorProfile; + renderengine::mock::RenderEngine mRenderEngine; }; const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f, 84.f / 255.f}; const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044}; const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044}; +const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{0.f, 0.f, 4.f, 5.f}; const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{ Rect{1005, 1006, 1007, 1008}}; const Region OutputLayerWriteStateToHWCTest::kOverrideVisibleRegion{Rect{1006, 1007, 1008, 1009}}; @@ -858,7 +865,10 @@ const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattena native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle = reinterpret_cast<native_handle_t*>(1031); const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer; -const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kOverrideBuffer = new GraphicBuffer(); +const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kOverrideBuffer = + new GraphicBuffer(4, 5, PIXEL_FORMAT_RGBA_8888, + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN); const sp<Fence> OutputLayerWriteStateToHWCTest::kFence; const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence(); const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key = @@ -872,19 +882,22 @@ const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) { EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr)); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) { mOutputLayer.editState().hwc.reset(); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCLayer) { mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc(nullptr); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { @@ -892,8 +905,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { expectPerFrameCommonCalls(); expectNoSetCompositionTypeCall(); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerTest, displayInstallOrientationBufferTransformSetTo90) { @@ -915,6 +930,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; expectPerFrameCommonCalls(); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); // Setting the composition type should happen before setting the color. We // check this in this test only by setting up an testing::InSeqeuence @@ -923,7 +939,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR); expectSetColorCall(); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { @@ -933,7 +950,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { expectSetSidebandHandleCall(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SIDEBAND); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { @@ -943,7 +963,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { expectSetHdrMetadataAndBufferCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CURSOR); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { @@ -953,7 +976,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { expectSetHdrMetadataAndBufferCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { @@ -966,7 +992,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { expectSetColorCall(); expectNoSetCompositionTypeCall(); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) { @@ -976,7 +1005,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransf expectSetColorCall(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) { @@ -988,7 +1018,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo expectSetColorCall(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { @@ -1001,7 +1032,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { expectGenericLayerMetadataCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) { @@ -1012,21 +1046,27 @@ TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPres expectSetHdrMetadataAndBufferCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; includeOverrideInfo(); - expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideDisplayFrame.toFloatRect(), - kOverrideBufferTransform, kOverrideBlendMode, kOverrideAlpha); + expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform, + kOverrideBlendMode, kOverrideAlpha); expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, kOverrideSurfaceDamage); expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 5f0b0eea15..7b71957021 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#include <cmath> - #include <android-base/stringprintf.h> #include <compositionengine/LayerFECompositionState.h> #include <compositionengine/impl/Output.h> @@ -31,9 +29,13 @@ #include <ui/Rect.h> #include <ui/Region.h> +#include <cmath> +#include <cstdint> + #include "CallOrderStateMachineHelper.h" #include "MockHWC2.h" #include "RegionMatcher.h" +#include "renderengine/ExternalTexture.h" namespace android::compositionengine { namespace { @@ -782,15 +784,19 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); injectOutputLayer(layer1); injectOutputLayer(layer2); @@ -812,15 +818,19 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); injectOutputLayer(layer1); injectOutputLayer(layer2); @@ -841,15 +851,19 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); injectOutputLayer(layer1); injectOutputLayer(layer2); @@ -1143,11 +1157,6 @@ TEST_F(OutputCollectVisibleLayersTest, processesCandidateLayersReversedAndSetsOu EXPECT_CALL(mOutput, finalizePendingOutputLayers()); mOutput.collectVisibleLayers(mRefreshArgs, mCoverageState); - - // Ensure all output layers have been assigned a simple/flattened z-order. - EXPECT_EQ(0u, mLayer1.outputLayerState.z); - EXPECT_EQ(1u, mLayer2.outputLayerState.z); - EXPECT_EQ(2u, mLayer3.outputLayerState.z); } /* @@ -2960,7 +2969,10 @@ struct OutputComposeSurfacesTest : public testing::Test { mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>(); mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>(); StrictMock<OutputPartialMock> mOutput; - sp<GraphicBuffer> mOutputBuffer = new GraphicBuffer(); + std::shared_ptr<renderengine::ExternalTexture> mOutputBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); std::optional<base::unique_fd> mReadyFence; }; @@ -3173,7 +3185,10 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _)) .WillRepeatedly(Return()); - sp<GraphicBuffer> otherOutputBuffer = new GraphicBuffer(); + const auto otherOutputBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)) .WillOnce(Return(mOutputBuffer)) .WillOnce(Return(otherOutputBuffer)); @@ -3494,7 +3509,8 @@ struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur EXPECT_CALL(mLayer.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(mLayer.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace)) .WillOnce(Return(std::vector<LayerFE::LayerSettings>{})); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR)); @@ -4073,16 +4089,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; // Layer requesting blur, or below, should request client composition. EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); layer2.layerFEState.backgroundBlurRadius = 10; @@ -4105,16 +4125,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; // Layer requesting blur, or below, should request client composition. EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); BlurRegion region; layer2.layerFEState.blurRegions.push_back(region); diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 5ef5d7b5cb..9aeb290eb5 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -15,6 +15,8 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues +#include "renderengine/ExternalTexture.h" +#include "ui/GraphicBuffer.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wextra" @@ -239,9 +241,9 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR))); base::unique_fd fence; - EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence).get()); + EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence)->getBuffer().get()); - EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest()->getBuffer().get()); } /* @@ -249,8 +251,11 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { */ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { - sp<GraphicBuffer> buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = false; @@ -261,43 +266,45 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { - sp<GraphicBuffer> buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(), + mRenderEngine, false); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = true; state.flipClientTarget = false; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { - sp<GraphicBuffer> buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(), + mRenderEngine, false); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = false; state.flipClientTarget = true; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) { @@ -317,27 +324,28 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferY mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) { - sp<GraphicBuffer> buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(), + mRenderEngine, false); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = true; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(INVALID_OPERATION)); EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true)); - EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index f01fe27b38..283c69270f 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -305,8 +305,8 @@ TEST_F(CachedSetTest, render) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, const std::vector<const renderengine::LayerSettings*>& layers, - const sp<GraphicBuffer>&, const bool, base::unique_fd&&, - base::unique_fd*) -> size_t { + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&, base::unique_fd*) -> size_t { EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation), @@ -321,7 +321,6 @@ TEST_F(CachedSetTest, render) { EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1)); EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers)); - EXPECT_CALL(mRenderEngine, cacheExternalTextureBuffer(_)); cachedSet.render(mRenderEngine, mOutputState); expectReadyBuffer(cachedSet); @@ -331,7 +330,6 @@ TEST_F(CachedSetTest, render) { cachedSet.getOutputSpace().bounds); // Now check that appending a new cached set properly cleans up RenderEngine resources. - EXPECT_CALL(mRenderEngine, unbindExternalTextureBuffer(_)); CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get(); cachedSet.append(CachedSet(layer3)); } diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp index 47b1ae8959..948c850735 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp @@ -41,8 +41,6 @@ const Rect sRectOne = Rect(10, 20, 30, 40); const Rect sRectTwo = Rect(40, 30, 20, 10); const FloatRect sFloatRectOne = FloatRect(100.f, 200.f, 300.f, 400.f); const FloatRect sFloatRectTwo = FloatRect(400.f, 300.f, 200.f, 100.f); -const constexpr int32_t sZOne = 100; -const constexpr int32_t sZTwo = 101; const constexpr float sAlphaOne = 0.25f; const constexpr float sAlphaTwo = 0.5f; const Region sRegionOne = Region(sRectOne); @@ -408,45 +406,6 @@ TEST_F(LayerStateTest, compareSourceCrop) { EXPECT_TRUE(otherLayerState->compare(*mLayerState)); } -TEST_F(LayerStateTest, updateZOrder) { - OutputLayerCompositionState outputLayerCompositionState; - outputLayerCompositionState.z = sZOne; - LayerFECompositionState layerFECompositionState; - setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, - layerFECompositionState); - mLayerState = std::make_unique<LayerState>(&mOutputLayer); - - mock::OutputLayer newOutputLayer; - mock::LayerFE newLayerFE; - OutputLayerCompositionState outputLayerCompositionStateTwo; - outputLayerCompositionStateTwo.z = sZTwo; - setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo, - layerFECompositionState); - Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ZOrder), updates); -} - -TEST_F(LayerStateTest, compareZOrder) { - OutputLayerCompositionState outputLayerCompositionState; - outputLayerCompositionState.z = sZOne; - LayerFECompositionState layerFECompositionState; - setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, - layerFECompositionState); - mLayerState = std::make_unique<LayerState>(&mOutputLayer); - mock::OutputLayer newOutputLayer; - mock::LayerFE newLayerFE; - OutputLayerCompositionState outputLayerCompositionStateTwo; - outputLayerCompositionStateTwo.z = sZTwo; - setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo, - layerFECompositionState); - auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - - verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::ZOrder); - - EXPECT_TRUE(mLayerState->compare(*otherLayerState)); - EXPECT_TRUE(otherLayerState->compare(*mLayerState)); -} - TEST_F(LayerStateTest, updateBufferTransform) { OutputLayerCompositionState outputLayerCompositionState; outputLayerCompositionState.bufferTransform = Hwc2::Transform::FLIP_H; @@ -793,47 +752,6 @@ TEST_F(LayerStateTest, compareColorTransform) { EXPECT_TRUE(otherLayerState->compare(*mLayerState)); } -TEST_F(LayerStateTest, updateSurfaceDamage) { - OutputLayerCompositionState outputLayerCompositionState; - LayerFECompositionState layerFECompositionState; - layerFECompositionState.surfaceDamage = sRegionOne; - setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, - layerFECompositionState); - mLayerState = std::make_unique<LayerState>(&mOutputLayer); - - mock::OutputLayer newOutputLayer; - mock::LayerFE newLayerFE; - OutputLayerCompositionState outputLayerCompositionStateTwo; - LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.surfaceDamage = sRegionTwo; - setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo, - layerFECompositionStateTwo); - Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SurfaceDamage), updates); -} - -TEST_F(LayerStateTest, compareSurfaceDamage) { - OutputLayerCompositionState outputLayerCompositionState; - LayerFECompositionState layerFECompositionState; - layerFECompositionState.surfaceDamage = sRegionOne; - setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, - layerFECompositionState); - mLayerState = std::make_unique<LayerState>(&mOutputLayer); - mock::OutputLayer newOutputLayer; - mock::LayerFE newLayerFE; - OutputLayerCompositionState outputLayerCompositionStateTwo; - LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.surfaceDamage = sRegionTwo; - setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo, - layerFECompositionStateTwo); - auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - - verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SurfaceDamage); - - EXPECT_TRUE(mLayerState->compare(*otherLayerState)); - EXPECT_TRUE(otherLayerState->compare(*mLayerState)); -} - TEST_F(LayerStateTest, updateSidebandStream) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; @@ -995,4 +913,4 @@ TEST_F(LayerStateTest, getNonBufferHash_filtersOutBuffers) { } } // namespace -} // namespace android::compositionengine::impl::planner
\ No newline at end of file +} // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp index 43e119fc11..1492707ad2 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp @@ -31,8 +31,6 @@ const FloatRect sFloatRectOne = FloatRect(100.f, 200.f, 300.f, 400.f); const FloatRect sFloatRectTwo = FloatRect(400.f, 300.f, 200.f, 100.f); const Rect sRectOne = Rect(1, 2, 3, 4); const Rect sRectTwo = Rect(4, 3, 2, 1); -const constexpr int32_t sZOne = 100; -const constexpr int32_t sZTwo = 101; const constexpr float sAlphaOne = 0.25f; const constexpr float sAlphaTwo = 0.5f; const Region sRegionOne = Region(sRectOne); @@ -194,11 +192,11 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchManyDifferences) { .displayFrame = sRectOne, .sourceCrop = sFloatRectOne, .dataspace = ui::Dataspace::SRGB, - .z = sZOne, }; LayerFECompositionState layerFECompositionStateOne; layerFECompositionStateOne.alpha = sAlphaOne; layerFECompositionStateOne.colorTransformIsIdentity = true; + layerFECompositionStateOne.blendMode = hal::BlendMode::NONE; setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne, layerFECompositionStateOne); LayerState layerStateOne(&outputLayerOne); @@ -210,12 +208,12 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchManyDifferences) { .displayFrame = sRectTwo, .sourceCrop = sFloatRectTwo, .dataspace = ui::Dataspace::DISPLAY_P3, - .z = sZTwo, }; LayerFECompositionState layerFECompositionStateTwo; layerFECompositionStateTwo.alpha = sAlphaTwo; layerFECompositionStateTwo.colorTransformIsIdentity = false; layerFECompositionStateTwo.colorTransform = sMat4One; + layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED; setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo, layerFECompositionStateTwo); LayerState layerStateTwo(&outputLayerTwo); @@ -264,7 +262,6 @@ TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) { .displayFrame = sRectOne, .sourceCrop = sFloatRectOne, .dataspace = ui::Dataspace::SRGB, - .z = sZOne, }; LayerFECompositionState layerFECompositionStateOne; layerFECompositionStateOne.buffer = new GraphicBuffer(); @@ -282,7 +279,6 @@ TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) { .displayFrame = sRectTwo, .sourceCrop = sFloatRectTwo, .dataspace = ui::Dataspace::DISPLAY_P3, - .z = sZTwo, }; LayerFECompositionState layerFECompositionStateTwo; layerFECompositionStateTwo.buffer = new GraphicBuffer(); @@ -346,6 +342,32 @@ struct PredictionTest : public testing::Test { } }; +TEST_F(LayerStackTest, reorderingChangesNonBufferHash) { + mock::OutputLayer outputLayerOne; + mock::LayerFE layerFEOne; + OutputLayerCompositionState outputLayerCompositionStateOne{ + .sourceCrop = sFloatRectOne, + }; + LayerFECompositionState layerFECompositionStateOne; + setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne, + layerFECompositionStateOne); + LayerState layerStateOne(&outputLayerOne); + + mock::OutputLayer outputLayerTwo; + mock::LayerFE layerFETwo; + OutputLayerCompositionState outputLayerCompositionStateTwo{ + .sourceCrop = sFloatRectTwo, + }; + LayerFECompositionState layerFECompositionStateTwo; + setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo, + layerFECompositionStateTwo); + LayerState layerStateTwo(&outputLayerTwo); + + NonBufferHash hash = getNonBufferHash({&layerStateOne, &layerStateTwo}); + NonBufferHash hashReverse = getNonBufferHash({&layerStateTwo, &layerStateOne}); + EXPECT_NE(hash, hashReverse); +} + TEST_F(PredictionTest, constructPrediction) { Plan plan; plan.addLayerType(hal::Composition::DEVICE); @@ -525,4 +547,4 @@ TEST_F(PredictorTest, recordMissedPlan_skipsApproximateMatch) { } } // namespace -} // namespace android::compositionengine::impl::planner
\ No newline at end of file +} // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index fd0371787f..2c09ebdead 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -71,11 +71,13 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mIsPowerModeOverride(false){ mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( - compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth( - args.nativeWindow.get()), - ANativeWindow_getHeight( - args.nativeWindow.get()), - args.nativeWindow, args.displaySurface}); + compositionengine:: + RenderSurfaceCreationArgs{ANativeWindow_getWidth(args.nativeWindow.get()), + ANativeWindow_getHeight(args.nativeWindow.get()), + args.nativeWindow, args.displaySurface, + static_cast<size_t>( + SurfaceFlinger:: + maxFrameBufferAcquiredBuffers)}); if (!mFlinger->mDisableClientCompositionCache && SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) { diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index bf81b74a75..0f4d0dd119 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -20,11 +20,7 @@ #undef LOG_TAG #define LOG_TAG "HwcComposer" - -#include <log/log.h> - -#include <algorithm> -#include <cinttypes> +#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "ComposerHal.h" @@ -32,6 +28,11 @@ #include <gui/BufferQueue.h> #include <hidl/HidlTransportSupport.h> #include <hidl/HidlTransportUtils.h> +#include <log/log.h> +#include <utils/Trace.h> + +#include <algorithm> +#include <cinttypes> #ifdef QTI_UNIFIED_DRAW #include <vendor/qti/hardware/display/composer/3.1/IQtiComposerClient.h> @@ -604,6 +605,7 @@ Error Composer::getReleaseFences(Display display, Error Composer::presentDisplay(Display display, int* outPresentFence) { + ATRACE_NAME("HwcPresentDisplay"); mWriter.selectDisplay(display); mWriter.presentDisplay(); @@ -727,6 +729,7 @@ Error Composer::setClientTargetSlotCount(Display display) Error Composer::validateDisplay(Display display, uint32_t* outNumTypes, uint32_t* outNumRequests) { + ATRACE_NAME("HwcValidateDisplay"); mWriter.selectDisplay(display); mWriter.validateDisplay(); @@ -742,13 +745,14 @@ Error Composer::validateDisplay(Display display, uint32_t* outNumTypes, Error Composer::presentOrValidateDisplay(Display display, uint32_t* outNumTypes, uint32_t* outNumRequests, int* outPresentFence, uint32_t* state) { - mWriter.selectDisplay(display); - mWriter.presentOrvalidateDisplay(); + ATRACE_NAME("HwcPresentOrValidateDisplay"); + mWriter.selectDisplay(display); + mWriter.presentOrvalidateDisplay(); - Error error = execute(); - if (error != Error::NONE) { - return error; - } + Error error = execute(); + if (error != Error::NONE) { + return error; + } mReader.takePresentOrValidateStage(display, state); diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 6485265c17..be552c6435 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -653,8 +653,10 @@ void SurfaceFrame::traceActuals(int64_t displayFrameToken) const { // If prediction is expired, we can't use the predicted start time. Instead, just use a // start time a little earlier than the end time so that we have some info about this // frame in the trace. + nsecs_t endTime = + (mPresentState == PresentState::Dropped ? mDropTime : mActuals.endTime); packet->set_timestamp( - static_cast<uint64_t>(mActuals.endTime - kPredictionExpiredStartTimeDelta)); + static_cast<uint64_t>(endTime - kPredictionExpiredStartTimeDelta)); } else { packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime)); } @@ -752,14 +754,13 @@ void TokenManager::flushTokens(nsecs_t flushTime) { } FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, - JankClassificationThresholds thresholds, nsecs_t hwcDuration) + JankClassificationThresholds thresholds) : mMaxDisplayFrames(kDefaultMaxDisplayFrames), mTimeStats(std::move(timeStats)), mSurfaceFlingerPid(surfaceFlingerPid), - mJankClassificationThresholds(thresholds), - mHwcDuration(hwcDuration) { - mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, thresholds, hwcDuration, - &mTraceCookieCounter); + mJankClassificationThresholds(thresholds) { + mCurrentDisplayFrame = + std::make_shared<DisplayFrame>(mTimeStats, thresholds, &mTraceCookieCounter); } void FrameTimeline::onBootFinished() { @@ -804,13 +805,11 @@ std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken( FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds, - nsecs_t hwcDuration, TraceCookieCounter* traceCookieCounter) : mSurfaceFlingerPredictions(TimelineItem()), mSurfaceFlingerActuals(TimelineItem()), mTimeStats(timeStats), mJankClassificationThresholds(thresholds), - mHwcDuration(hwcDuration), mTraceCookieCounter(*traceCookieCounter) { mSurfaceFrames.reserve(kNumSurfaceFramesInitial); } @@ -830,13 +829,11 @@ void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRa void FrameTimeline::setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence, - bool gpuComposition) { + const std::shared_ptr<FenceTime>& gpuFence) { ATRACE_CALL(); std::scoped_lock lock(mMutex); mCurrentDisplayFrame->setActualEndTime(sfPresentTime); - if (gpuComposition) { - mCurrentDisplayFrame->setGpuComposition(); - } + mCurrentDisplayFrame->setGpuFence(gpuFence); mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame)); flushPendingPresentFences(); finalizeCurrentDisplayFrame(); @@ -874,25 +871,32 @@ void FrameTimeline::DisplayFrame::setActualEndTime(nsecs_t actualEndTime) { mSurfaceFlingerActuals.endTime = actualEndTime; } -void FrameTimeline::DisplayFrame::setGpuComposition() { - mGpuComposition = true; +void FrameTimeline::DisplayFrame::setGpuFence(const std::shared_ptr<FenceTime>& gpuFence) { + mGpuFence = gpuFence; } void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync) { if (mPredictionState == PredictionState::Expired || mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) { - // Cannot do jank classification with expired predictions or invalid signal times. + // Cannot do jank classification with expired predictions or invalid signal times. Set the + // deltas to 0 as both negative and positive deltas are used as real values. mJankType = JankType::Unknown; - deadlineDelta = -1; - deltaToVsync = -1; + deadlineDelta = 0; + deltaToVsync = 0; return; } // Delta between the expected present and the actual present const nsecs_t presentDelta = mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime; - deadlineDelta = - mSurfaceFlingerActuals.endTime - (mSurfaceFlingerPredictions.endTime - mHwcDuration); + // Sf actual end time represents the CPU end time. In case of HWC, SF's end time would have + // included the time for composition. However, for GPU composition, the final end time is max(sf + // end time, gpu fence time). + nsecs_t combinedEndTime = mSurfaceFlingerActuals.endTime; + if (mGpuFence != FenceTime::NO_FENCE) { + combinedEndTime = std::max(combinedEndTime, mGpuFence->getSignalTime()); + } + deadlineDelta = combinedEndTime - mSurfaceFlingerPredictions.endTime; // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there // was a prediction error or not. @@ -907,9 +911,7 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& mFramePresentMetadata = FramePresentMetadata::OnTimePresent; } - if (mSurfaceFlingerActuals.endTime > mSurfaceFlingerPredictions.endTime - mHwcDuration) { - // SF needs to have finished at least mHwcDuration ahead of the deadline for it to be - // on time. + if (combinedEndTime > mSurfaceFlingerPredictions.endTime) { mFrameReadyMetadata = FrameReadyMetadata::LateFinish; } else { mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish; @@ -966,7 +968,15 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& mJankType = JankType::SurfaceFlingerScheduling; } else { // OnTime start, Finish late, Present late - mJankType = JankType::SurfaceFlingerCpuDeadlineMissed; + if (mGpuFence != FenceTime::NO_FENCE && + mSurfaceFlingerActuals.endTime - mSurfaceFlingerActuals.startTime < + mRefreshRate.getPeriodNsecs()) { + // If SF was in GPU composition and the CPU work finished before the vsync + // period, classify it as GPU deadline missed. + mJankType = JankType::SurfaceFlingerGpuDeadlineMissed; + } else { + mJankType = JankType::SurfaceFlingerCpuDeadlineMissed; + } } } else { // Finish time unknown @@ -1041,7 +1051,7 @@ void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid) const { actualDisplayFrameStartEvent->set_present_type(toProto(mFramePresentMetadata)); actualDisplayFrameStartEvent->set_on_time_finish(mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish); - actualDisplayFrameStartEvent->set_gpu_composition(mGpuComposition); + actualDisplayFrameStartEvent->set_gpu_composition(mGpuFence != FenceTime::NO_FENCE); actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType)); actualDisplayFrameStartEvent->set_prediction_type(toProto(mPredictionState)); }); @@ -1164,7 +1174,7 @@ void FrameTimeline::finalizeCurrentDisplayFrame() { mDisplayFrames.push_back(mCurrentDisplayFrame); mCurrentDisplayFrame.reset(); mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, mJankClassificationThresholds, - mHwcDuration, &mTraceCookieCounter); + &mTraceCookieCounter); } nsecs_t FrameTimeline::DisplayFrame::getBaseTime() const { diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index 3f04592b6e..41f4978543 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -293,11 +293,12 @@ public: // the token and sets the actualSfWakeTime for the current DisplayFrame. virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0; - // Sets the sfPresentTime, gpuComposition and finalizes the current DisplayFrame. Tracks the + // Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the // given present fence until it's signaled, and updates the present timestamps of all presented - // SurfaceFrames in that vsync. + // SurfaceFrames in that vsync. If a gpuFence was also provided, its tracked in the + // corresponding DisplayFrame. virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence, - bool gpuComposition) = 0; + const std::shared_ptr<FenceTime>& gpuFence) = 0; // Args: // -jank : Dumps only the Display Frames that are either janky themselves @@ -355,7 +356,7 @@ public: class DisplayFrame { public: DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds, - nsecs_t hwcDuration, TraceCookieCounter* traceCookieCounter); + TraceCookieCounter* traceCookieCounter); virtual ~DisplayFrame() = default; // Dumpsys interface - dumps only if the DisplayFrame itself is janky or is at least one // SurfaceFrame is janky. @@ -376,7 +377,7 @@ public: void setPredictions(PredictionState predictionState, TimelineItem predictions); void setActualStartTime(nsecs_t actualStartTime); void setActualEndTime(nsecs_t actualEndTime); - void setGpuComposition(); + void setGpuFence(const std::shared_ptr<FenceTime>& gpuFence); // BaseTime is the smallest timestamp in a DisplayFrame. // Used for dumping all timestamps relative to the oldest, making it easy to read. @@ -410,7 +411,6 @@ public: TimelineItem mSurfaceFlingerActuals; std::shared_ptr<TimeStats> mTimeStats; const JankClassificationThresholds mJankClassificationThresholds; - const nsecs_t mHwcDuration; // Collection of predictions and actual values sent over by Layers std::vector<std::shared_ptr<SurfaceFrame>> mSurfaceFrames; @@ -418,8 +418,8 @@ public: PredictionState mPredictionState = PredictionState::None; // Bitmask for the type of jank int32_t mJankType = JankType::None; - // Indicates if this frame was composited by the GPU or not - bool mGpuComposition = false; + // A valid gpu fence indicates that the DisplayFrame was composited by the GPU + std::shared_ptr<FenceTime> mGpuFence = FenceTime::NO_FENCE; // Enum for the type of present FramePresentMetadata mFramePresentMetadata = FramePresentMetadata::UnknownPresent; // Enum for the type of finish @@ -436,8 +436,7 @@ public: }; FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, - JankClassificationThresholds thresholds = {}, - nsecs_t hwcDuration = kDefaultHwcDuration); + JankClassificationThresholds thresholds = {}); ~FrameTimeline() = default; frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } @@ -447,7 +446,7 @@ public: void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence, - bool gpuComposition = false) override; + const std::shared_ptr<FenceTime>& gpuFence = FenceTime::NO_FENCE) override; void parseArgs(const Vector<String16>& args, std::string& result) override; void setMaxDisplayFrames(uint32_t size) override; float computeFps(const std::unordered_set<int32_t>& layerIds) override; @@ -482,11 +481,6 @@ private: std::shared_ptr<TimeStats> mTimeStats; const pid_t mSurfaceFlingerPid; const JankClassificationThresholds mJankClassificationThresholds; - // In SF Predictions, both end & present are the same. The predictions consider the time used by - // composer as well, but we have no way to estimate how much time the composer needs. We are - // assuming an arbitrary time for the composer work. - const nsecs_t mHwcDuration; - static constexpr nsecs_t kDefaultHwcDuration = std::chrono::nanoseconds(3ms).count(); static constexpr uint32_t kDefaultMaxDisplayFrames = 64; // The initial container size for the vector<SurfaceFrames> inside display frame. Although // this number doesn't represent any bounds on the number of surface frames that can go in a diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index cb152e42b9..41b7ecc740 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -204,19 +204,6 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, */ void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {} -void Layer::removeRemoteSyncPoints() { - for (auto& point : mRemoteSyncPoints) { - point->setTransactionApplied(); - } - mRemoteSyncPoints.clear(); - - { - for (State pendingState : mPendingStates) { - pendingState.barrierLayer_legacy = nullptr; - } - } -} - void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) { if (mCurrentState.zOrderRelativeOf == nullptr) { return; @@ -238,21 +225,6 @@ void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) { void Layer::removeFromCurrentState() { mRemovedFromCurrentState = true; - // Since we are no longer reachable from CurrentState SurfaceFlinger - // will no longer invoke doTransaction for us, and so we will - // never finish applying transactions. We signal the sync point - // now so that another layer will not become indefinitely - // blocked. - removeRemoteSyncPoints(); - - { - Mutex::Autolock syncLock(mLocalSyncPointMutex); - for (auto& point : mLocalSyncPoints) { - point->setFrameAvailable(); - } - mLocalSyncPoints.clear(); - } - mFlinger->markLayerPendingRemovalLocked(this); } @@ -566,7 +538,9 @@ void Layer::preparePerFrameCompositionState() { isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf; // Force client composition for special cases known only to the front-end. - if (isHdrY410() || usesRoundedCorners || drawShadows() || drawingState.blurRegions.size() > 0 || + // Rounded corners no longer force client composition, since we may use a + // hole punch so that the layer will appear to have rounded corners. + if (isHdrY410() || drawShadows() || drawingState.blurRegions.size() > 0 || compositionState->stretchEffect.hasEffect()) { compositionState->forceClientComposition = true; } @@ -782,21 +756,6 @@ Hwc2::IComposerClient::Composition Layer::getCompositionType(const DisplayDevice } } -bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) { - if (point->getFrameNumber() <= mCurrentFrameNumber) { - // Don't bother with a SyncPoint, since we've already latched the - // relevant frame - return false; - } - if (isRemovedFromCurrentState()) { - return false; - } - - Mutex::Autolock lock(mLocalSyncPointMutex); - mLocalSyncPoints.push_back(point); - return true; -} - // ---------------------------------------------------------------------------- // local state // ---------------------------------------------------------------------------- @@ -832,132 +791,6 @@ bool Layer::isScreenshot() const { // transaction // ---------------------------------------------------------------------------- -void Layer::pushPendingState() { - if (!mCurrentState.modified) { - return; - } - ATRACE_CALL(); - - // If this transaction is waiting on the receipt of a frame, generate a sync - // point and send it to the remote layer. - // We don't allow installing sync points after we are removed from the current state - // as we won't be able to signal our end. - if (mCurrentState.barrierLayer_legacy != nullptr && !isRemovedFromCurrentState()) { - sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote(); - if (barrierLayer == nullptr) { - ALOGE("[%s] Unable to promote barrier Layer.", getDebugName()); - // If we can't promote the layer we are intended to wait on, - // then it is expired or otherwise invalid. Allow this transaction - // to be applied as per normal (no synchronization). - mCurrentState.barrierLayer_legacy = nullptr; - } else { - auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.barrierFrameNumber, this, - barrierLayer); - if (barrierLayer->addSyncPoint(syncPoint)) { - std::stringstream ss; - ss << "Adding sync point " << mCurrentState.barrierFrameNumber; - ATRACE_NAME(ss.str().c_str()); - mRemoteSyncPoints.push_back(std::move(syncPoint)); - } else { - // We already missed the frame we're supposed to synchronize - // on, so go ahead and apply the state update - mCurrentState.barrierLayer_legacy = nullptr; - } - } - - // Wake us up to check if the frame has been received - setTransactionFlags(eTransactionNeeded); - mFlinger->setTransactionFlags(eTraversalNeeded); - } - if (mCurrentState.bufferlessSurfaceFramesTX.size() >= State::kStateSurfaceFramesThreshold) { - // Ideally, the currentState would only contain one SurfaceFrame per transaction (assuming - // each Tx uses a different token). We don't expect the current state to hold a huge amount - // of SurfaceFrames. However, in the event it happens, this debug statement will leave a - // trail that can help in debugging. - ALOGW("Bufferless SurfaceFrames size on current state of layer %s is %" PRIu32 "", - mName.c_str(), static_cast<uint32_t>(mCurrentState.bufferlessSurfaceFramesTX.size())); - } - mPendingStates.push_back(mCurrentState); - // Since the current state along with the SurfaceFrames has been pushed into the pendingState, - // we no longer need to retain them. If multiple states are pushed and applied together, we have - // a merging logic to address the SurfaceFrames at mergeSurfaceFrames(). - mCurrentState.bufferlessSurfaceFramesTX.clear(); - ATRACE_INT(mTransactionName.c_str(), mPendingStates.size()); -} - -void Layer::mergeSurfaceFrames(State& source, State& target) { - // No need to merge BufferSurfaceFrame as the target's surfaceFrame, if it exists, will be used - // directly. Dropping of source's SurfaceFrame is taken care of at setBuffer(). - target.bufferlessSurfaceFramesTX.merge(source.bufferlessSurfaceFramesTX); - source.bufferlessSurfaceFramesTX.clear(); -} - -void Layer::popPendingState(State* stateToCommit) { - ATRACE_CALL(); - - mergeSurfaceFrames(*stateToCommit, mPendingStates[0]); - *stateToCommit = mPendingStates[0]; - mPendingStates.pop_front(); - ATRACE_INT(mTransactionName.c_str(), mPendingStates.size()); -} - -bool Layer::applyPendingStates(State* stateToCommit) { - bool stateUpdateAvailable = false; - while (!mPendingStates.empty()) { - if (mPendingStates[0].barrierLayer_legacy != nullptr) { - if (mRemoteSyncPoints.empty()) { - // If we don't have a sync point for this, apply it anyway. It - // will be visually wrong, but it should keep us from getting - // into too much trouble. - ALOGV("[%s] No local sync point found", getDebugName()); - popPendingState(stateToCommit); - stateUpdateAvailable = true; - continue; - } - - if (mRemoteSyncPoints.front()->getFrameNumber() != - mPendingStates[0].barrierFrameNumber) { - ALOGE("[%s] Unexpected sync point frame number found", getDebugName()); - - // Signal our end of the sync point and then dispose of it - mRemoteSyncPoints.front()->setTransactionApplied(); - mRemoteSyncPoints.pop_front(); - continue; - } - - if (mRemoteSyncPoints.front()->frameIsAvailable()) { - ATRACE_NAME("frameIsAvailable"); - // Apply the state update - popPendingState(stateToCommit); - stateUpdateAvailable = true; - - // Signal our end of the sync point and then dispose of it - mRemoteSyncPoints.front()->setTransactionApplied(); - mRemoteSyncPoints.pop_front(); - } else { - ATRACE_NAME("!frameIsAvailable"); - mRemoteSyncPoints.front()->checkTimeoutAndLog(); - break; - } - } else { - popPendingState(stateToCommit); - stateUpdateAvailable = true; - } - } - - // If we still have pending updates, we need to ensure SurfaceFlinger - // will keep calling doTransaction, and so we force a traversal. - // However, our pending states won't clear until a frame is available, - // and so there is no need to specifically trigger a wakeup. - if (!mPendingStates.empty()) { - setTransactionFlags(eTransactionNeeded); - mFlinger->setTraversalNeeded(); - } - - mCurrentState.modified = false; - return stateUpdateAvailable; -} - uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) { const State& s(getDrawingState()); @@ -1038,15 +871,14 @@ uint32_t Layer::doTransaction(uint32_t flags) { mChildrenChanged = false; } - pushPendingState(); - State c = getCurrentState(); - if (!applyPendingStates(&c)) { - return flags; - } + // TODO: This is unfortunate. + mCurrentStateModified = mCurrentState.modified; + mCurrentState.modified = false; - flags = doTransactionResize(flags, &c); + flags = doTransactionResize(flags, &mCurrentState); const State& s(getDrawingState()); + State& c(getCurrentState()); if (getActiveGeometry(c) != getActiveGeometry(s)) { // invalidate and recompute the visible regions if needed @@ -1074,11 +906,10 @@ uint32_t Layer::doTransaction(uint32_t flags) { } // Allow BufferStateLayer to release any unlatched buffers in drawing state. - bufferMayChange(c.buffer); + bufferMayChange(c.buffer->getBuffer()); // Commit the transaction commitTransaction(c); - mPendingStatesSnapshot = mPendingStates; mCurrentState.callbackHandles = {}; return flags; @@ -1086,7 +917,11 @@ uint32_t Layer::doTransaction(uint32_t flags) { void Layer::commitTransaction(State& stateToCommit) { if (auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX; - mDrawingState.buffer != stateToCommit.buffer && bufferSurfaceFrame != nullptr && + ((mDrawingState.buffer && stateToCommit.buffer && + mDrawingState.buffer->getBuffer() != stateToCommit.buffer->getBuffer()) || + (mDrawingState.buffer && !stateToCommit.buffer) || + (!mDrawingState.buffer && stateToCommit.buffer)) && + bufferSurfaceFrame != nullptr && bufferSurfaceFrame->getPresentState() != PresentState::Presented) { // If the previous buffer was committed but not latched (refreshPending - happens during // back to back invalidates), it gets silently dropped here. Mark the corresponding @@ -1692,25 +1527,6 @@ Layer::FrameRate Layer::getFrameRateForLayerTree() const { return frameRate; } -void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) { - ATRACE_CALL(); - - mCurrentState.barrierLayer_legacy = barrierLayer; - mCurrentState.barrierFrameNumber = frameNumber; - // We don't set eTransactionNeeded, because just receiving a deferral - // request without any other state updates shouldn't actually induce a delay - mCurrentState.modified = true; - pushPendingState(); - mCurrentState.barrierLayer_legacy = nullptr; - mCurrentState.barrierFrameNumber = 0; - mCurrentState.modified = false; -} - -void Layer::deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle, uint64_t frameNumber) { - sp<Handle> handle = static_cast<Handle*>(barrierHandle.get()); - deferTransactionUntil_legacy(handle->owner.promote(), frameNumber); -} - // ---------------------------------------------------------------------------- // pageflip handling... // ---------------------------------------------------------------------------- @@ -2296,8 +2112,13 @@ int32_t Layer::getBackgroundBlurRadius() const { return parentAlpha * getDrawingState().backgroundBlurRadius; } -const std::vector<BlurRegion>& Layer::getBlurRegions() const { - return getDrawingState().blurRegions; +const std::vector<BlurRegion> Layer::getBlurRegions() const { + auto regionsCopy(getDrawingState().blurRegions); + int layerAlpha = getAlpha(); + for (auto& region : regionsCopy) { + region.alpha = region.alpha * layerAlpha; + } + return regionsCopy; } Layer::RoundedCornerState Layer::getRoundedCornerState() const { @@ -2319,8 +2140,8 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const { } } const float radius = getDrawingState().cornerRadius; - return radius > 0 && getCrop(getDrawingState()).isValid() - ? RoundedCornerState(getCrop(getDrawingState()).toFloatRect(), radius) + return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid() + ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius) : RoundedCornerState(); } @@ -2394,14 +2215,6 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const ui::Transform transform = getTransform(); if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { - for (const auto& pendingState : mPendingStatesSnapshot) { - auto barrierLayer = pendingState.barrierLayer_legacy.promote(); - if (barrierLayer != nullptr) { - BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer(); - barrierLayerProto->set_id(barrierLayer->sequence); - barrierLayerProto->set_frame_number(pendingState.barrierFrameNumber); - } - } auto buffer = getBuffer(); if (buffer != nullptr) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4d3fb550d0..7118513717 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -166,11 +166,6 @@ public: Rect crop; Rect requestedCrop; - // If set, defers this state update until the identified Layer - // receives a frame with the given frameNumber - wp<Layer> barrierLayer_legacy; - uint64_t barrierFrameNumber; - // the transparentRegion hint is a bit special, it's latched only // when we receive a buffer -- this is because it's "content" // dependent. @@ -208,7 +203,7 @@ public: Region transparentRegionHint; - sp<GraphicBuffer> buffer; + std::shared_ptr<renderengine::ExternalTexture> buffer; client_cache_t clientCacheId; sp<Fence> acquireFence; std::shared_ptr<FenceTime> acquireFenceTime; @@ -398,9 +393,6 @@ public: virtual bool setFlags(uint32_t flags, uint32_t mask); virtual bool setLayerStack(uint32_t layerStack); virtual uint32_t getLayerStack() const; - virtual void deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle, - uint64_t frameNumber); - virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber); virtual bool setMetadata(const LayerMetadata& data); virtual void setChildrenDrawingParent(const sp<Layer>&); virtual bool reparent(const sp<IBinder>& newParentHandle); @@ -412,11 +404,11 @@ public: // Used only to set BufferStateLayer state virtual bool setTransform(uint32_t /*transform*/) { return false; }; virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; - virtual bool setFrame(const Rect& /*frame*/) { return false; }; - virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, 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 */, + virtual bool setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& /*buffer*/, + 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>& /* releaseBufferListener */) { return false; @@ -580,14 +572,6 @@ public: virtual int32_t getQueuedFrameCount() const { return 0; } - virtual void pushPendingState(); - - /* - * Merges the BufferlessSurfaceFrames from source with the target. If the same token exists in - * both source and target, target's SurfaceFrame will be retained. - */ - void mergeSurfaceFrames(State& source, State& target); - /** * Returns active buffer size in the correct orientation. Buffer size is determined by undoing * any buffer transformations. If the layer has no buffer then return INVALID_RECT. @@ -617,7 +601,8 @@ public: // ignored. virtual RoundedCornerState getRoundedCornerState() const; - virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {} + bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; } + virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; } /** * Return whether this layer needs an input info. For most layer types @@ -732,7 +717,7 @@ public: * Called before updating the drawing state buffer. Used by BufferStateLayer to release any * unlatched buffers in the drawing state. */ - virtual void bufferMayChange(sp<GraphicBuffer>& /* newBuffer */){}; + virtual void bufferMayChange(const sp<GraphicBuffer>& /* newBuffer */){}; /* * Remove relative z for the layer if its relative parent is not part of the @@ -909,65 +894,6 @@ public: virtual std::string getPendingBufferCounterName() { return ""; } protected: - class SyncPoint { - public: - explicit SyncPoint(uint64_t frameNumber, wp<Layer> requestedSyncLayer, - wp<Layer> barrierLayer_legacy) - : mFrameNumber(frameNumber), - mFrameIsAvailable(false), - mTransactionIsApplied(false), - mRequestedSyncLayer(requestedSyncLayer), - mBarrierLayer_legacy(barrierLayer_legacy) {} - uint64_t getFrameNumber() const { return mFrameNumber; } - - bool frameIsAvailable() const { return mFrameIsAvailable; } - - void setFrameAvailable() { mFrameIsAvailable = true; } - - bool transactionIsApplied() const { return mTransactionIsApplied; } - - void setTransactionApplied() { mTransactionIsApplied = true; } - - sp<Layer> getRequestedSyncLayer() { return mRequestedSyncLayer.promote(); } - - sp<Layer> getBarrierLayer() const { return mBarrierLayer_legacy.promote(); } - - bool isTimeout() const { - using namespace std::chrono_literals; - static constexpr std::chrono::nanoseconds TIMEOUT_THRESHOLD = 1s; - - return std::chrono::steady_clock::now() - mCreateTimeStamp > TIMEOUT_THRESHOLD; - } - - void checkTimeoutAndLog() { - using namespace std::chrono_literals; - static constexpr std::chrono::nanoseconds LOG_PERIOD = 1s; - - if (!frameIsAvailable() && isTimeout()) { - const auto now = std::chrono::steady_clock::now(); - if (now - mLastLogTime > LOG_PERIOD) { - mLastLogTime = now; - sp<Layer> requestedSyncLayer = getRequestedSyncLayer(); - sp<Layer> barrierLayer = getBarrierLayer(); - ALOGW("[%s] sync point %" PRIu64 " wait timeout %lld for %s", - requestedSyncLayer ? requestedSyncLayer->getDebugName() : "Removed", - mFrameNumber, (now - mCreateTimeStamp).count(), - barrierLayer ? barrierLayer->getDebugName() : "Removed"); - } - } - } - - private: - const uint64_t mFrameNumber; - std::atomic<bool> mFrameIsAvailable; - std::atomic<bool> mTransactionIsApplied; - wp<Layer> mRequestedSyncLayer; - wp<Layer> mBarrierLayer_legacy; - const std::chrono::time_point<std::chrono::steady_clock> mCreateTimeStamp = - std::chrono::steady_clock::now(); - std::chrono::time_point<std::chrono::steady_clock> mLastLogTime; - }; - friend class impl::SurfaceInterceptor; // For unit tests @@ -986,7 +912,6 @@ protected: ui::Dataspace outputDataspace); virtual void preparePerFrameCompositionState(); virtual void commitTransaction(State& stateToCommit); - virtual bool applyPendingStates(State* stateToCommit); virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit); virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {} @@ -1035,21 +960,6 @@ protected: virtual ui::Transform getInputTransform() const; virtual Rect getInputBounds() const; - // SyncPoints which will be signaled when the correct frame is at the head - // of the queue and dropped after the frame has been latched. Protected by - // mLocalSyncPointMutex. - Mutex mLocalSyncPointMutex; - std::list<std::shared_ptr<SyncPoint>> mLocalSyncPoints; - - // SyncPoints which will be signaled and then dropped when the transaction - // is applied - std::list<std::shared_ptr<SyncPoint>> mRemoteSyncPoints; - - // Returns false if the relevant frame has already been latched - bool addSyncPoint(const std::shared_ptr<SyncPoint>& point); - - void popPendingState(State* stateToCommit); - // constant sp<SurfaceFlinger> mFlinger; @@ -1059,14 +969,10 @@ protected: // These are only accessed by the main thread or the tracing thread. State mDrawingState; - // Store a copy of the pending state so that the drawing thread can access the - // states without a lock. - std::deque<State> mPendingStatesSnapshot; // these are protected by an external lock (mStateLock) State mCurrentState; std::atomic<uint32_t> mTransactionFlags{0}; - std::deque<State> mPendingStates; // Timestamp history for UIAutomation. Thread safe. FrameTracker mFrameTracker; @@ -1130,6 +1036,8 @@ protected: // Used in buffer stuffing analysis in FrameTimeline. nsecs_t mLastLatchTime = 0; + mutable bool mCurrentStateModified = false; + private: virtual void setTransformHint(ui::Transform::RotationFlags) {} @@ -1154,7 +1062,6 @@ private: void updateTreeHasFrameRateVote(); void setZOrderRelativeOf(const wp<Layer>& relativeOf); - void removeRemoteSyncPoints(); // Find the root of the cloned hierarchy, this means the first non cloned parent. // This will return null if first non cloned parent is not found. @@ -1204,7 +1111,7 @@ private: mutable int32_t mPriority = Layer::PRIORITY_UNSET; // A list of regions on this layer that should have blurs. - const std::vector<BlurRegion>& getBlurRegions() const; + const std::vector<BlurRegion> getBlurRegions() const; }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 1d00cc38f2..a9fd16cb75 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -208,7 +208,8 @@ bool RefreshRateOverlay::createLayer() { return true; } -const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { +const std::vector<std::shared_ptr<renderengine::ExternalTexture>>& +RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { if (mBufferCache.find(fps) == mBufferCache.end()) { // Ensure the range is > 0, so we don't divide by 0. const auto rangeLength = std::max(1u, mHighFps - mLowFps); @@ -222,7 +223,17 @@ const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uin color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale); color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale); color.a = ALPHA; - mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner)); + auto buffers = SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner); + std::vector<std::shared_ptr<renderengine::ExternalTexture>> textures; + std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures), + [&](const auto& buffer) -> std::shared_ptr<renderengine::ExternalTexture> { + return std::make_shared< + renderengine::ExternalTexture>(buffer, + mFlinger.getRenderEngine(), + renderengine::ExternalTexture:: + Usage::READABLE); + }); + mBufferCache.emplace(fps, textures); } return mBufferCache[fps]; @@ -231,8 +242,14 @@ const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uin void RefreshRateOverlay::setViewport(ui::Size viewport) { Rect frame((3 * viewport.width) >> 4, viewport.height >> 5); frame.offsetBy(viewport.width >> 5, viewport.height >> 4); - mLayer->setFrame(frame); + layer_state_t::matrix22_t matrix; + matrix.dsdx = frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth()); + matrix.dtdx = 0; + matrix.dtdy = 0; + matrix.dsdy = frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight()); + mLayer->setMatrix(matrix, true); + mLayer->setPosition(frame.left, frame.top); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index c16cfa07a4..aa8329c46a 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -16,13 +16,14 @@ #pragma once -#include <unordered_map> - #include <math/vec4.h> +#include <renderengine/RenderEngine.h> #include <ui/Rect.h> #include <ui/Size.h> #include <utils/StrongPointer.h> +#include <unordered_map> + #include "Fps.h" namespace android { @@ -70,7 +71,8 @@ private: }; bool createLayer(); - const std::vector<sp<GraphicBuffer>>& getOrCreateBuffers(uint32_t fps); + const std::vector<std::shared_ptr<renderengine::ExternalTexture>>& getOrCreateBuffers( + uint32_t fps); SurfaceFlinger& mFlinger; const sp<Client> mClient; @@ -78,7 +80,8 @@ private: sp<IBinder> mIBinder; sp<IGraphicBufferProducer> mGbp; - std::unordered_map<int, std::vector<sp<GraphicBuffer>>> mBufferCache; + std::unordered_map<int, std::vector<std::shared_ptr<renderengine::ExternalTexture>>> + mBufferCache; std::optional<int> mCurrentFps; int mFrame = 0; static constexpr float ALPHA = 0.8f; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index d0032ac7fd..00090d948a 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -438,18 +438,22 @@ void RegionSamplingThread::captureSample() { mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor); }; - sp<GraphicBuffer> buffer = nullptr; - if (mCachedBuffer && mCachedBuffer->getWidth() == sampledBounds.getWidth() && - mCachedBuffer->getHeight() == sampledBounds.getHeight()) { + std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr; + if (mCachedBuffer && mCachedBuffer->getBuffer()->getWidth() == sampledBounds.getWidth() && + mCachedBuffer->getBuffer()->getHeight() == sampledBounds.getHeight()) { buffer = mCachedBuffer; } else { const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), - PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); - const status_t bufferStatus = buffer->initCheck(); + sp<GraphicBuffer> graphicBuffer = + new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), + PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); + const status_t bufferStatus = graphicBuffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d", bufferStatus); + buffer = std::make_shared< + renderengine::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(), + renderengine::ExternalTexture::Usage::WRITEABLE); } const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); @@ -465,8 +469,8 @@ void RegionSamplingThread::captureSample() { } ALOGV("Sampling %zu descriptors", activeDescriptors.size()); - std::vector<float> lumas = - sampleBuffer(buffer, sampledBounds.leftTop(), activeDescriptors, orientation); + std::vector<float> lumas = sampleBuffer(buffer->getBuffer(), sampledBounds.leftTop(), + activeDescriptors, orientation); if (lumas.size() != activeDescriptors.size()) { ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(), activeDescriptors.size()); @@ -477,16 +481,6 @@ void RegionSamplingThread::captureSample() { activeDescriptors[d].listener->onSampleCollected(lumas[d]); } - // Extend the lifetime of mCachedBuffer from the previous frame to here to ensure that: - // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer - // happens in this thread, as opposed to the main thread. - // 2) The listener(s) receive their notifications prior to freeing the buffer. - if (mCachedBuffer != nullptr && mCachedBuffer != buffer) { - if (mFlinger.getRenderEngine().getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { - mFlinger.getRenderEngine().unbindExternalTextureBuffer(mCachedBuffer->getId()); - } - } mCachedBuffer = buffer; ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded)); } diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 0defdb3fcb..86632db490 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -16,17 +16,19 @@ #pragma once +#include <android-base/thread_annotations.h> +#include <binder/IBinder.h> +#include <renderengine/ExternalTexture.h> +#include <ui/GraphicBuffer.h> +#include <ui/Rect.h> +#include <utils/StrongPointer.h> + #include <chrono> #include <condition_variable> #include <mutex> #include <thread> #include <unordered_map> -#include <android-base/thread_annotations.h> -#include <binder/IBinder.h> -#include <ui/GraphicBuffer.h> -#include <ui/Rect.h> -#include <utils/StrongPointer.h> #include "Scheduler/OneShotTimer.h" namespace android { @@ -122,7 +124,8 @@ private: std::mutex mSamplingMutex; std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mSamplingMutex); - sp<GraphicBuffer> mCachedBuffer GUARDED_BY(mSamplingMutex) = nullptr; + std::shared_ptr<renderengine::ExternalTexture> mCachedBuffer GUARDED_BY(mSamplingMutex) = + nullptr; }; } // namespace android diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 716bd59dfc..f4b87dd9f5 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -218,12 +218,18 @@ namespace impl { EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource, android::frametimeline::TokenManager* tokenManager, InterceptVSyncsCallback interceptVSyncsCallback, - ThrottleVsyncCallback throttleVsyncCallback) + ThrottleVsyncCallback throttleVsyncCallback, + GetVsyncPeriodFunction getVsyncPeriodFunction) : mVSyncSource(std::move(vsyncSource)), mTokenManager(tokenManager), mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)), mThrottleVsyncCallback(std::move(throttleVsyncCallback)), + mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)), mThreadName(mVSyncSource->getName()) { + + LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr, + "getVsyncPeriodFunction must not be null"); + mVSyncSource->setCallback(this); mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS { @@ -595,9 +601,13 @@ void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { const uint8_t num_attempts = 3; for (const auto& consumer : consumers) { + DisplayEventReceiver::Event copy = event; + if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { + copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); + } bool needs_retry = true; for (uint8_t attempt = 0; needs_retry && (attempt < num_attempts); attempt++) { - switch (consumer->postEvent(event)) { + switch (consumer->postEvent(copy)) { case NO_ERROR: needs_retry = false; break; diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 2b85a43d8d..07fa805d6c 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -152,9 +152,10 @@ class EventThread : public android::EventThread, private VSyncSource::Callback { public: using InterceptVSyncsCallback = std::function<void(nsecs_t)>; using ThrottleVsyncCallback = std::function<bool(nsecs_t, uid_t)>; + using GetVsyncPeriodFunction = std::function<nsecs_t(uid_t)>; EventThread(std::unique_ptr<VSyncSource>, frametimeline::TokenManager*, InterceptVSyncsCallback, - ThrottleVsyncCallback); + ThrottleVsyncCallback, GetVsyncPeriodFunction); ~EventThread(); sp<EventThreadConnection> createEventConnection( @@ -210,6 +211,7 @@ private: const InterceptVSyncsCallback mInterceptVSyncsCallback; const ThrottleVsyncCallback mThrottleVsyncCallback; + const GetVsyncPeriodFunction mGetVsyncPeriodFunction; const char* const mThreadName; std::thread mThread; diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp index ce3b0c6cfa..d659398394 100644 --- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp +++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp @@ -40,13 +40,21 @@ void calculateTimeoutTime(std::chrono::nanoseconds timestamp, timespec* spec) { namespace android { namespace scheduler { +std::chrono::steady_clock::time_point OneShotTimer::Clock::now() const { + return std::chrono::steady_clock::now(); +} + OneShotTimer::OneShotTimer(std::string name, const Interval& interval, const ResetCallback& resetCallback, - const TimeoutCallback& timeoutCallback) - : mName(std::move(name)), + const TimeoutCallback& timeoutCallback, + std::unique_ptr<OneShotTimer::Clock> clock) + : mClock(std::move(clock)), + mName(std::move(name)), mInterval(interval), mResetCallback(resetCallback), - mTimeoutCallback(timeoutCallback) {} + mTimeoutCallback(timeoutCallback) { + LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided"); +} OneShotTimer::~OneShotTimer() { stop(); @@ -112,7 +120,7 @@ void OneShotTimer::loop() { break; } - auto triggerTime = std::chrono::steady_clock::now() + mInterval; + auto triggerTime = mClock->now() + mInterval; state = TimerState::WAITING; while (state == TimerState::WAITING) { constexpr auto zero = std::chrono::steady_clock::duration::zero(); @@ -128,10 +136,9 @@ void OneShotTimer::loop() { state = checkForResetAndStop(state); if (state == TimerState::RESET) { - triggerTime = std::chrono::steady_clock::now() + mInterval; + triggerTime = mClock->now() + mInterval; state = TimerState::WAITING; - } else if (state == TimerState::WAITING && - (triggerTime - std::chrono::steady_clock::now()) <= zero) { + } else if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) { triggerTimeout = true; state = TimerState::IDLE; } diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h index 3690ce7542..7285427abb 100644 --- a/services/surfaceflinger/Scheduler/OneShotTimer.h +++ b/services/surfaceflinger/Scheduler/OneShotTimer.h @@ -36,8 +36,17 @@ public: using ResetCallback = std::function<void()>; using TimeoutCallback = std::function<void()>; + class Clock { + public: + Clock() = default; + virtual ~Clock() = default; + + virtual std::chrono::steady_clock::time_point now() const; + }; + OneShotTimer(std::string name, const Interval& interval, const ResetCallback& resetCallback, - const TimeoutCallback& timeoutCallback); + const TimeoutCallback& timeoutCallback, + std::unique_ptr<OneShotTimer::Clock> = std::make_unique<OneShotTimer::Clock>()); ~OneShotTimer(); // Initializes and turns on the idle timer. @@ -78,6 +87,9 @@ private: // Thread waiting for timer to expire. std::thread mThread; + // Clock object for the timer. Mocked in unit tests. + std::unique_ptr<Clock> mClock; + // Semaphore to keep mThread synchronized. sem_t mSemaphore; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 43c7666031..8d25898f9e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -248,15 +248,34 @@ impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() }; } +impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const { + return [this](uid_t uid) { + nsecs_t basePeriod = mRefreshRateConfigs.getCurrentRefreshRate().getVsyncPeriod(); + const auto frameRate = getFrameRateOverride(uid); + if (!frameRate.has_value()) { + return basePeriod; + } + + const auto divider = scheduler::RefreshRateConfigs::getFrameRateDivider( + mRefreshRateConfigs.getCurrentRefreshRate().getFps(), *frameRate); + if (divider <= 1) { + return basePeriod; + } + return basePeriod * divider; + }; +} + Scheduler::ConnectionHandle Scheduler::createConnection( const char* connectionName, frametimeline::TokenManager* tokenManager, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, impl::EventThread::InterceptVSyncsCallback interceptCallback) { auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration); auto throttleVsync = makeThrottleVsyncCallback(); + auto getVsyncPeriod = makeGetVsyncPeriodFunction(); auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager, std::move(interceptCallback), - std::move(throttleVsync)); + std::move(throttleVsync), + std::move(getVsyncPeriod)); bool triggerRefresh = !strcmp(connectionName, "app"); return createConnection(std::move(eventThread), triggerRefresh); } @@ -453,7 +472,8 @@ Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { std::make_unique<impl::EventThread>(std::move(vsyncSource), /*tokenManager=*/nullptr, impl::EventThread::InterceptVSyncsCallback(), - impl::EventThread::ThrottleVsyncCallback()); + impl::EventThread::ThrottleVsyncCallback(), + impl::EventThread::GetVsyncPeriodFunction()); // EventThread does not dispatch VSYNC unless the display is connected and powered on. eventThread->onHotplugReceived(PhysicalDisplayId::fromPort(0), true); @@ -930,6 +950,13 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid } } +std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom( + nsecs_t expectedPresentTime) const { + const auto presentTime = std::chrono::nanoseconds(expectedPresentTime); + const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule.tracker->currentPeriod()); + return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod); +} + void Scheduler::setIdleState() { mDisplayIdle = true; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 95235725e8..29cbd86e47 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -150,6 +150,8 @@ public: bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const EXCLUDES(mFrameRateOverridesMutex); + std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const; + void dump(std::string&) const; void dump(ConnectionHandle, std::string&) const; void dumpVsync(std::string&) const; @@ -242,6 +244,7 @@ private: EXCLUDES(mFrameRateOverridesMutex); impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const; + impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. struct Connection { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f01e99cbeb..4c512590fc 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -64,7 +64,6 @@ #include <private/android_filesystem_config.h> #include <private/gui/SyncFeatures.h> #include <renderengine/RenderEngine.h> -#include <statslog.h> #include <sys/types.h> #include <sys/stat.h> #include <fstream> @@ -346,19 +345,6 @@ bool SurfaceFlinger::sDirectStreaming; ::DisplayConfig::ClientInterface *mDisplayConfigIntf = nullptr; DisplayConfigCallbackHandler *mDisplayConfigCallbackhandler = nullptr; #endif -std::string getHwcServiceName() { - char value[PROPERTY_VALUE_MAX] = {}; - property_get("debug.sf.hwc_service_name", value, "default"); - ALOGI("Using HWComposer service: '%s'", value); - return std::string(value); -} - -bool useTrebleTestingOverride() { - char value[PROPERTY_VALUE_MAX] = {}; - property_get("debug.sf.treble_testing_override", value, "false"); - ALOGI("Treble testing override: '%s'", value); - return std::string(value) == "true"; -} std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { switch(displayColorSetting) { @@ -382,8 +368,6 @@ bool callingThreadHasRotateSurfaceFlingerAccess() { PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid); } -SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {} - bool SmomoWrapper::init() { mSmoMoLibHandle = dlopen(SMOMO_LIBRARY_NAME, RTLD_NOW); if (!mSmoMoLibHandle) { @@ -470,8 +454,11 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())), mEventQueue(mFactory.createMessageQueue()), mCompositionEngine(mFactory.createCompositionEngine()), + mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)), mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)), mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)) { + ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); + mSetInputWindowsListener = new SetInputWindowsListener([&]() { setInputWindowsFinished(); }); } @@ -603,12 +590,13 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI // comes online to attempt to read the property. The property is // instead read after the boot animation - if (useTrebleTestingOverride()) { + if (base::GetBoolProperty("debug.sf.treble_testing_override"s, false)) { // Without the override SurfaceFlinger cannot connect to HIDL // services that are not listed in the manifests. Considered // deriving the setting from the set service name, but it // would be brittle if the name that's not 'default' is used // for production purposes later on. + ALOGI("Enabling Treble testing override"); android::hardware::details::setTrebleTestingOverride(true); } @@ -843,7 +831,6 @@ void SurfaceFlinger::bootFinished() { ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); mFrameTracer->initialize(); - mTimeStats->onBootFinished(); mFrameTimeline->onBootFinished(); // wait patiently for the window manager death @@ -910,12 +897,16 @@ uint32_t SurfaceFlinger::getNewTexture() { // The pool was empty, so we need to get a new texture name directly using a // blocking call to the main thread - return schedule([this] { + auto genTextures = [this] { uint32_t name = 0; getRenderEngine().genTextures(1, &name); return name; - }) - .get(); + }; + if (std::this_thread::get_id() == mMainThreadId) { + return genTextures(); + } else { + return schedule(genTextures).get(); + } } void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { @@ -950,8 +941,9 @@ void SurfaceFlinger::init() { : renderengine::RenderEngine::ContextPriority::MEDIUM) .build())); mCompositionEngine->setTimeStats(mTimeStats); - mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName)); + mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName)); mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId); + ClientCache::getInstance().setRenderEngine(&getRenderEngine()); // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); @@ -1599,6 +1591,11 @@ status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken, return NO_ERROR; } +status_t SurfaceFlinger::onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) { + *success = mTimeStats->onPullAtom(atomId, pulledData); + return NO_ERROR; +} + status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, @@ -2472,6 +2469,8 @@ void SurfaceFlinger::onMessageRefresh() { std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0); } + refreshArgs.earliestPresentTime = mScheduler->getPreviousVsyncFrom(mExpectedPresentTime); + mGeometryInvalid = false; // Store the present time just before calling to the composition engine so we could notify @@ -2549,6 +2548,9 @@ bool SurfaceFlinger::handleMessageInvalidate() { ATRACE_CALL(); bool refreshNeeded = handlePageFlip(); + // Send on commit callbacks + mTransactionCallbackInvoker.sendCallbacks(); + if (mVisibleRegionsDirty) { computeLayerBounds(); } @@ -2651,7 +2653,7 @@ void SurfaceFlinger::postComposition() { // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. mFrameTimeline->setSfPresent(systemTime(), mPreviousPresentFences[0].fenceTime, - glCompositionDoneFenceTime != FenceTime::NO_FENCE); + glCompositionDoneFenceTime); nsecs_t dequeueReadyTime = systemTime(); for (const auto& layer : mLayersWithQueuedFrames) { @@ -3461,6 +3463,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, display->setProjection(currentState.orientation, currentState.layerStackSpaceRect, currentState.orientedDisplaySpaceRect); } + mDefaultDisplayTransformHint = display->getTransformHint(); } if (currentState.width != drawingState.width || currentState.height != drawingState.height) { @@ -3547,13 +3550,6 @@ void SurfaceFlinger::processDisplayChangesLocked() { } void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { - const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); - - // Notify all layers of available frames - mCurrentState.traverse([expectedPresentTime](Layer* layer) { - layer->notifyAvailableFrames(expectedPresentTime); - }); - /* * Traversal of the children * (perform the transaction for each of them if needed) @@ -4011,76 +4007,44 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBind const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer, bool addToCurrentState, uint32_t* outTransformHint) { - // add this layer to the current state list - { - Mutex::Autolock _l(mStateLock); - sp<Layer> parent; - if (parentHandle != nullptr) { - parent = fromHandleLocked(parentHandle).promote(); - if (parent == nullptr) { - return NAME_NOT_FOUND; - } - } else { - parent = parentLayer; - } - - if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { - ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), - ISurfaceComposer::MAX_LAYERS); - mCurrentState.traverseInZOrder([&](Layer* layer) { - const auto& p = layer->getParent(); - ALOGE("layer (%s) :: parent (%s).", - layer->getName().c_str(), - (p != nullptr) ? p->getName().c_str() : "no-parent"); - }); - return NO_MEMORY; - } + if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { + ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), + ISurfaceComposer::MAX_LAYERS); + mCurrentState.traverseInZOrder([&](Layer* layer) { + const auto& p = layer->getParent(); + ALOGE("layer (%s) :: parent (%s).", + layer->getName().c_str(), + (p != nullptr) ? p->getName().c_str() : "no-parent"); + }); + return NO_MEMORY; + } - mLayersByLocalBinderToken.emplace(handle->localBinder(), lbc); + wp<IBinder> initialProducer; + if (gbc != nullptr) { + initialProducer = IInterface::asBinder(gbc); + } + setLayerCreatedState(handle, lbc, parentHandle, parentLayer, initialProducer); - if (parent == nullptr && addToCurrentState) { - mCurrentState.layersSortedByZ.add(lbc); - } else if (parent == nullptr) { - lbc->onRemovedFromCurrentState(); - } else if (parent->isRemovedFromCurrentState()) { - parent->addChild(lbc); - lbc->onRemovedFromCurrentState(); - } else { - parent->addChild(lbc); - } - - if (gbc != nullptr) { - mGraphicBufferProducerList.insert(IInterface::asBinder(gbc).get()); - LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > - mMaxGraphicBufferProducerListSize, - "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", - mGraphicBufferProducerList.size(), - mMaxGraphicBufferProducerListSize, mNumLayers.load()); - if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) { - ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize, - mNumLayers.load()); - } - } + // Create a transaction includes the initial parent and producer. + Vector<ComposerState> states; + Vector<DisplayState> displays; - if (const auto token = getInternalDisplayTokenLocked()) { - const ssize_t index = mCurrentState.displays.indexOfKey(token); - if (index >= 0) { - const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); - lbc->updateTransformHint(ui::Transform::toRotationFlags(state.orientation)); - } - } - if (outTransformHint) { - *outTransformHint = lbc->getTransformHint(); - } + ComposerState composerState; + composerState.state.what = layer_state_t::eLayerCreated; + composerState.state.surface = handle; + states.add(composerState); - mLayersAdded = true; + lbc->updateTransformHint(mDefaultDisplayTransformHint); + if (outTransformHint) { + *outTransformHint = mDefaultDisplayTransformHint; } - // attach this layer to the client client->attachLayer(handle, lbc); - return NO_ERROR; + return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr, + InputWindowCommands{}, -1 /* desiredPresentTime */, + true /* isAutoTimestamp */, {}, false /* hasListenerCallbacks */, {}, + 0 /* Undefined transactionId */); } void SurfaceFlinger::removeGraphicBufferProducerAsync(const wp<IBinder>& binder) { @@ -4457,7 +4421,6 @@ void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin if (uncacheBuffer.isValid()) { ClientCache::getInstance().erase(uncacheBuffer); - getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id); } // If a synchronous transaction is explicitly requested without any changes, force a transaction @@ -4595,19 +4558,47 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis uint32_t SurfaceFlinger::setClientStateLocked( const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions, - std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) { + std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& outListenerCallbacks) { const layer_state_t& s = composerState.state; const bool privileged = permissions & Permission::ACCESS_SURFACE_FLINGER; + + std::vector<ListenerCallbacks> filteredListeners; for (auto& listener : s.listeners) { + // Starts a registration but separates the callback ids according to callback type. This + // allows the callback invoker to send on latch callbacks earlier. // note that startRegistration will not re-register if the listener has // already be registered for a prior surface control - mTransactionCallbackInvoker.startRegistration(listener); - listenerCallbacks.insert(listener); + + ListenerCallbacks onCommitCallbacks = listener.filter(CallbackId::Type::ON_COMMIT); + if (!onCommitCallbacks.callbackIds.empty()) { + mTransactionCallbackInvoker.startRegistration(onCommitCallbacks); + filteredListeners.push_back(onCommitCallbacks); + outListenerCallbacks.insert(onCommitCallbacks); + } + + ListenerCallbacks onCompleteCallbacks = listener.filter(CallbackId::Type::ON_COMPLETE); + if (!onCompleteCallbacks.callbackIds.empty()) { + mTransactionCallbackInvoker.startRegistration(onCompleteCallbacks); + filteredListeners.push_back(onCompleteCallbacks); + outListenerCallbacks.insert(onCompleteCallbacks); + } } + const uint64_t what = s.what; + uint32_t flags = 0; sp<Layer> layer = nullptr; if (s.surface) { - layer = fromHandleLocked(s.surface).promote(); + if (what & layer_state_t::eLayerCreated) { + layer = handleLayerCreatedLocked(s.surface, privileged); + if (layer) { + // put the created layer into mLayersByLocalBinderToken. + mLayersByLocalBinderToken.emplace(s.surface->localBinder(), layer); + flags |= eTransactionNeeded | eTraversalNeeded; + mLayersAdded = true; + } + } else { + layer = fromHandleLocked(s.surface).promote(); + } } else { // The client may provide us a null handle. Treat it as if the layer was removed. ALOGW("Attempt to set client state with a null layer handle"); @@ -4620,16 +4611,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( return 0; } - uint32_t flags = 0; - - const uint64_t what = s.what; - - // If we are deferring transaction, make sure to push the pending state, as otherwise the - // pending state will also be deferred. - if (what & layer_state_t::eDeferTransaction_legacy) { - layer->pushPendingState(); - } - // Only set by BLAST adapter layers if (what & layer_state_t::eProducerDisconnect) { layer->onDisconnect(); @@ -4764,12 +4745,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTransactionNeeded | eTraversalNeeded | eTransformHintUpdateNeeded; } } - if (what & layer_state_t::eDeferTransaction_legacy) { - layer->deferTransactionUntil_legacy(s.barrierSurfaceControl_legacy->getHandle(), - s.barrierFrameNumber); - // We don't trigger a traversal here because if no other state is - // changed, we don't want this to cause any more work - } if (what & layer_state_t::eTransformChanged) { if (layer->setTransform(s.transform)) flags |= eTraversalNeeded; } @@ -4780,9 +4755,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & layer_state_t::eCropChanged) { if (layer->setCrop(s.crop)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eFrameChanged) { - if (layer->setFrame(s.orientedDisplaySpaceRect)) flags |= eTraversalNeeded; - } if (what & layer_state_t::eAcquireFenceChanged) { if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded; } @@ -4870,30 +4842,23 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } std::vector<sp<CallbackHandle>> callbackHandles; - if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!s.listeners.empty())) { - for (auto& [listener, callbackIds] : s.listeners) { + if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { + for (auto& [listener, callbackIds] : filteredListeners) { callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); } } bool bufferChanged = what & layer_state_t::eBufferChanged; bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged; - sp<GraphicBuffer> buffer; + std::shared_ptr<renderengine::ExternalTexture> buffer; if (bufferChanged && cacheIdChanged && s.buffer != nullptr) { - buffer = s.buffer; - bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer); - if (success) { - getRenderEngine().cacheExternalTextureBuffer(s.buffer); - success = ClientCache::getInstance() - .registerErasedRecipient(s.cachedBuffer, - wp<ClientCache::ErasedRecipient>(this)); - if (!success) { - getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId()); - } - } + ClientCache::getInstance().add(s.cachedBuffer, s.buffer); + buffer = ClientCache::getInstance().get(s.cachedBuffer); } else if (cacheIdChanged) { buffer = ClientCache::getInstance().get(s.cachedBuffer); - } else if (bufferChanged) { - buffer = s.buffer; + } else if (bufferChanged && s.buffer != nullptr) { + buffer = std::make_shared< + renderengine::ExternalTexture>(s.buffer, getRenderEngine(), + renderengine::ExternalTexture::Usage::READABLE); } if (buffer) { const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged; @@ -4976,10 +4941,6 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: - result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), format, handle, gbp, &layer); - - break; case ISurfaceComposerClient::eFXSurfaceBufferState: { result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, std::move(metadata), handle, &layer); @@ -5103,14 +5064,7 @@ status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, std::s sp<Layer>* outLayer) { LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata)); args.textureName = getNewTexture(); - sp<BufferStateLayer> layer; - { - // TODO (b/173538294): Investigate why we need mStateLock here and above in - // createBufferQueue layer. Is it the renderengine::Image? - Mutex::Autolock lock(mStateLock); - layer = getFactory().createBufferStateLayer(args); - - } + sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args); *handle = layer->getHandle(); *outLayer = layer; @@ -5198,7 +5152,7 @@ void SurfaceFlinger::onInitializeDisplays() { setPowerModeInternal(display, hal::PowerMode::ON); const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod); - + mDefaultDisplayTransformHint = display->getTransformHint(); // Use phase of 0 since phase is not known. // Use latency of 0, which will snap to the ideal latency. DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod}; @@ -6156,13 +6110,16 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { #pragma clang diagnostic push #pragma clang diagnostic error "-Wswitch-enum" switch (static_cast<ISurfaceComposerTag>(code)) { + case ENABLE_VSYNC_INJECTIONS: + case INJECT_VSYNC: + if (!hasMockHwc()) return PERMISSION_DENIED; + [[fallthrough]]; // These methods should at minimum make sure that the client requested // access to SF. case BOOT_FINISHED: case CLEAR_ANIMATION_FRAME_STATS: case CREATE_DISPLAY: case DESTROY_DISPLAY: - case ENABLE_VSYNC_INJECTIONS: case GET_ANIMATION_FRAME_STATS: case OVERRIDE_HDR_TYPES: case GET_HDR_CAPABILITIES: @@ -6173,7 +6130,6 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_AUTO_LOW_LATENCY_MODE: case GET_GAME_CONTENT_TYPE_SUPPORT: case SET_GAME_CONTENT_TYPE: - case INJECT_VSYNC: case SET_POWER_MODE: case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: @@ -6237,17 +6193,15 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // captureLayers and captureDisplay will handle the permission check in the function case CAPTURE_LAYERS: case CAPTURE_DISPLAY: - case SET_DISPLAY_BRIGHTNESS: case SET_FRAME_TIMELINE_INFO: case GET_GPU_CONTEXT_PRIORITY: case GET_EXTRA_BUFFER_COUNT: { // This is not sensitive information, so should not require permission control. return OK; } + case SET_DISPLAY_BRIGHTNESS: case ADD_HDR_LAYER_INFO_LISTENER: case REMOVE_HDR_LAYER_INFO_LISTENER: { - // TODO (b/183985553): Should getting & setting brightness be part of this...? - // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); @@ -6282,6 +6236,13 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return PERMISSION_DENIED; } + case ON_PULL_ATOM: { + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid == AID_SYSTEM) { + return OK; + } + return PERMISSION_DENIED; + } } // These codes are used for the IBinder protocol to either interrogate the recipient @@ -6611,9 +6572,24 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r const int modeId = data.readInt32(); mDebugDisplayModeSetByBackdoor = false; - const auto displayId = getInternalDisplayId(); + const auto displayId = [&]() -> std::optional<PhysicalDisplayId> { + uint64_t inputDisplayId = 0; + if (data.readUint64(&inputDisplayId) == NO_ERROR) { + const auto token = getPhysicalDisplayToken( + static_cast<PhysicalDisplayId>(inputDisplayId)); + if (!token) { + ALOGE("No display with id: %" PRIu64, inputDisplayId); + return std::nullopt; + } + + return std::make_optional<PhysicalDisplayId>(inputDisplayId); + } + + return getInternalDisplayId(); + }(); + if (!displayId) { - ALOGE("No internal display found."); + ALOGE("No display found"); return NO_ERROR; } @@ -7248,15 +7224,17 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d", bufferStatus); - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + const auto texture = std::make_shared< + renderengine::ExternalTexture>(buffer, getRenderEngine(), + renderengine::ExternalTexture::Usage::WRITEABLE); + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, texture, false /* regionSampling */, grayscale, captureListener); } -status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, - TraverseLayersFunction traverseLayers, - sp<GraphicBuffer>& buffer, bool regionSampling, - bool grayscale, - const sp<IScreenCaptureListener>& captureListener) { +status_t SurfaceFlinger::captureScreenCommon( + RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, + const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, + bool grayscale, const sp<IScreenCaptureListener>& captureListener) { ATRACE_CALL(); if (captureListener == nullptr) { @@ -7289,15 +7267,6 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, regionSampling, grayscale, captureResults); }); - // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine - // Only do this when we're not doing region sampling, to allow the region sampling thread to - // manage buffer lifecycle itself. - if (!regionSampling && - getRenderEngine().getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { - getRenderEngine().unbindExternalTextureBuffer(buffer->getId()); - } - captureResults.result = result; captureListener->onScreenCaptureCompleted(captureResults); })); @@ -7305,11 +7274,10 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, return NO_ERROR; } -status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - const sp<GraphicBuffer>& buffer, bool forSystem, - bool regionSampling, bool grayscale, - ScreenCaptureResults& captureResults) { +status_t SurfaceFlinger::renderScreenImplLocked( + const RenderArea& renderArea, TraverseLayersFunction traverseLayers, + const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool forSystem, + bool regionSampling, bool grayscale, ScreenCaptureResults& captureResults) { ATRACE_CALL(); traverseLayers([&](Layer* layer) { @@ -7317,7 +7285,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure()); }); - const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED; + const bool useProtected = buffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED; // We allow the system server to take screenshots of secure layers for // use in situations like the Screen-rotation animation and place @@ -7327,7 +7295,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, return PERMISSION_DENIED; } - captureResults.buffer = buffer; + captureResults.buffer = buffer->getBuffer(); captureResults.capturedDataspace = renderArea.getReqDataSpace(); const auto reqWidth = renderArea.getReqWidth(); @@ -7421,11 +7389,9 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, base::unique_fd drawFence; getRenderEngine().useProtectedContext(useProtected); - // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine - const bool useFramebufferCache = getRenderEngine().getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED; + const constexpr bool kUseFramebufferCache = false; getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, - useFramebufferCache, std::move(bufferFence), &drawFence); + kUseFramebufferCache, std::move(bufferFence), &drawFence); if (drawFence >= 0) { sp<Fence> releaseFence = new Fence(dup(drawFence)); @@ -7493,6 +7459,11 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( "Can only set override policy on the primary display"); LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy"); + if (mDebugDisplayModeSetByBackdoor) { + // ignore this request as mode is overridden by backdoor + return NO_ERROR; + } + if (!display->isPrimary()) { if (!isInternalDisplay(display)) { return NO_ERROR; @@ -7529,11 +7500,6 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( return NO_ERROR; } - if (mDebugDisplayModeSetByBackdoor) { - // ignore this request as mode is overridden by backdoor - return NO_ERROR; - } - status_t setPolicyResult = overridePolicy ? mRefreshRateConfigs->setOverridePolicy(policy) : mRefreshRateConfigs->setDisplayManagerPolicy(*policy); @@ -7725,10 +7691,6 @@ void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) { mOffscreenLayers.erase(layer); } -void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) { - getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id); -} - status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) { @@ -7940,6 +7902,88 @@ void SurfaceFlinger::TransactionState::traverseStatesWithBuffers( } } +void SurfaceFlinger::setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer, + const wp<IBinder>& parent, const wp<Layer> parentLayer, + const wp<IBinder>& producer) { + Mutex::Autolock lock(mCreatedLayersLock); + mCreatedLayers[handle->localBinder()] = + std::make_unique<LayerCreatedState>(layer, parent, parentLayer, producer); +} + +auto SurfaceFlinger::getLayerCreatedState(const sp<IBinder>& handle) { + Mutex::Autolock lock(mCreatedLayersLock); + BBinder* b = nullptr; + if (handle) { + b = handle->localBinder(); + } + + if (b == nullptr) { + return std::unique_ptr<LayerCreatedState>(nullptr); + } + + auto it = mCreatedLayers.find(b); + if (it == mCreatedLayers.end()) { + ALOGE("Can't find layer from handle %p", handle.get()); + return std::unique_ptr<LayerCreatedState>(nullptr); + } + + auto state = std::move(it->second); + mCreatedLayers.erase(it); + return state; +} + +sp<Layer> SurfaceFlinger::handleLayerCreatedLocked(const sp<IBinder>& handle, bool privileged) { + const auto& state = getLayerCreatedState(handle); + if (!state) { + return nullptr; + } + + sp<Layer> layer = state->layer.promote(); + if (!layer) { + ALOGE("Invalid layer %p", state->layer.unsafe_get()); + return nullptr; + } + + sp<Layer> parent; + bool allowAddRoot = privileged; + if (state->initialParent != nullptr) { + parent = fromHandleLocked(state->initialParent.promote()).promote(); + if (parent == nullptr) { + ALOGE("Invalid parent %p", state->initialParent.unsafe_get()); + allowAddRoot = false; + } + } else if (state->initialParentLayer != nullptr) { + parent = state->initialParentLayer.promote(); + allowAddRoot = false; + } + + if (parent == nullptr && allowAddRoot) { + mCurrentState.layersSortedByZ.add(layer); + } else if (parent == nullptr) { + layer->onRemovedFromCurrentState(); + } else if (parent->isRemovedFromCurrentState()) { + parent->addChild(layer); + layer->onRemovedFromCurrentState(); + } else { + parent->addChild(layer); + } + + if (state->initialProducer != nullptr) { + mGraphicBufferProducerList.insert(state->initialProducer); + LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > mMaxGraphicBufferProducerListSize, + "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", + mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize, + mNumLayers.load()); + if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) { + ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", + mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize, + mNumLayers.load()); + } + } + + return layer; +} + void SurfaceFlinger::setContentFps(uint32_t contentFps) { if (mBootFinished && !mSetActiveModePending) { if (mDisplayExtnIntf) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ec5dfc4054..3e0fba0855 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -159,13 +159,7 @@ enum { using DisplayColorSetting = compositionengine::OutputColorSetting; -class SurfaceFlingerBE -{ -public: - SurfaceFlingerBE(); - - const std::string mHwcServiceName; // "default" for real use, something else for testing. - +struct SurfaceFlingerBE { FenceTimeline mGlCompositionDoneTimeline; FenceTimeline mDisplayTimeline; @@ -255,7 +249,6 @@ private: class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, - public ClientCache::ErasedRecipient, private IBinder::DeathRecipient, private HWC2::ComposerCallback, private ISchedulerCallback { @@ -405,9 +398,6 @@ public: wp<Layer> fromHandle(const sp<IBinder>& handle); wp<Layer> fromHandleLocked(const sp<IBinder>& handle) const REQUIRES(mStateLock); - // Inherit from ClientCache::ErasedRecipient - void bufferErased(const client_cache_t& clientCacheId) override; - // If set, disables reusing client composition buffers. This can be set by // debug.sf.disable_client_composition_cache bool mDisableClientCompositionCache = false; @@ -723,6 +713,7 @@ private: status_t getAnimationFrameStats(FrameStats* outStats) const override; status_t overrideHdrTypes(const sp<IBinder>& displayToken, const std::vector<ui::Hdr>& hdrTypes) override; + status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) override; status_t enableVSyncInjections(bool enable) override; status_t injectVSync(nsecs_t when) override; status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override; @@ -990,12 +981,14 @@ private: status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>&); - status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&, + status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, + const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, bool grayscale, const sp<IScreenCaptureListener>&); status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, - const sp<GraphicBuffer>&, bool forSystem, bool regionSampling, - bool grayscale, ScreenCaptureResults&); + const std::shared_ptr<renderengine::ExternalTexture>&, + bool forSystem, bool regionSampling, bool grayscale, + ScreenCaptureResults&); sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp<DisplayDevice> getDisplayById(DisplayId displayId) const REQUIRES(mStateLock); @@ -1462,6 +1455,10 @@ private: SurfaceFlingerBE mBE; std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine; + const std::string mHwcServiceName; + + bool hasMockHwc() const { return mHwcServiceName == "mock"; } + /* * Scheduler */ @@ -1534,6 +1531,35 @@ private: std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners GUARDED_BY(mStateLock); + mutable Mutex mCreatedLayersLock; + struct LayerCreatedState { + LayerCreatedState(const wp<Layer>& layer, const wp<IBinder>& parent, + const wp<Layer> parentLayer, const wp<IBinder>& producer) + : layer(layer), + initialParent(parent), + initialParentLayer(parentLayer), + initialProducer(producer) {} + wp<Layer> layer; + // Indicates the initial parent of the created layer, only used for creating layer in + // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers. + wp<IBinder> initialParent; + wp<Layer> initialParentLayer; + // Indicates the initial graphic buffer producer of the created layer, only used for + // creating layer in SurfaceFlinger. + wp<IBinder> initialProducer; + }; + + // A temporay pool that store the created layers and will be added to current state in main + // thread. + std::unordered_map<BBinder*, std::unique_ptr<LayerCreatedState>> mCreatedLayers; + void setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer, + const wp<IBinder>& parent, const wp<Layer> parentLayer, + const wp<IBinder>& producer); + auto getLayerCreatedState(const sp<IBinder>& handle); + sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle, bool privileged) + REQUIRES(mStateLock); + + std::atomic<ui::Transform::RotationFlags> mDefaultDisplayTransformHint; SmomoWrapper mSmoMo; LayerExtWrapper mLayerExt; diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index b49562a0a5..113f463c39 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -141,11 +141,6 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius); addBackgroundBlurRadiusLocked(transaction, layerId, layer->mCurrentState.backgroundBlurRadius); addBlurRegionsLocked(transaction, layerId, layer->mCurrentState.blurRegions); - if (layer->mCurrentState.barrierLayer_legacy != nullptr) { - addDeferTransactionLocked(transaction, layerId, - layer->mCurrentState.barrierLayer_legacy.promote(), - layer->mCurrentState.barrierFrameNumber); - } addFlagsLocked(transaction, layerId, layer->mCurrentState.flags, layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque | layer_state_t::eLayerSecure); @@ -380,20 +375,6 @@ void SurfaceInterceptor::addBlurRegionsLocked(Transaction* transaction, int32_t } } -void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId, - const sp<const Layer>& layer, uint64_t frameNumber) -{ - SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); - if (layer == nullptr) { - ALOGE("An existing layer could not be retrieved with the handle" - " for the deferred transaction"); - return; - } - DeferredTransactionChange* deferTransaction(change->mutable_deferred_transaction()); - deferTransaction->set_layer_id(getLayerId(layer)); - deferTransaction->set_frame_number(frameNumber); -} - void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId) { SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); @@ -464,15 +445,6 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, if (state.what & layer_state_t::eBlurRegionsChanged) { addBlurRegionsLocked(transaction, layerId, state.blurRegions); } - if (state.what & layer_state_t::eDeferTransaction_legacy) { - sp<Layer> otherLayer = nullptr; - if (state.barrierSurfaceControl_legacy != nullptr) { - otherLayer = static_cast<Layer::Handle*>( - state.barrierSurfaceControl_legacy->getHandle().get()) - ->owner.promote(); - } - addDeferTransactionLocked(transaction, layerId, otherLayer, state.barrierFrameNumber); - } if (state.what & layer_state_t::eReparent) { auto parentHandle = (state.parentSurfaceControlForChild) ? state.parentSurfaceControlForChild->getHandle() diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index d2cbf40426..30aca8340e 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -167,8 +167,6 @@ private: int32_t backgroundBlurRadius); void addBlurRegionsLocked(Transaction* transaction, int32_t layerId, const std::vector<BlurRegion>& effectRegions); - void addDeferTransactionLocked(Transaction* transaction, int32_t layerId, - const sp<const Layer>& layer, uint64_t frameNumber); void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state); void addTransactionLocked(Increment* increment, const Vector<ComposerState>& stateUpdates, const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays, diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp index 62fddb4f47..bcc3e4e52a 100644 --- a/services/surfaceflinger/TimeStats/Android.bp +++ b/services/surfaceflinger/TimeStats/Android.bp @@ -18,20 +18,13 @@ cc_library { "libcutils", "liblog", "libprotobuf-cpp-lite", - "libprotoutil", - "libstatslog", - "libstatspull", - "libstatssocket", + "libtimestats_atoms_proto", "libtimestats_proto", "libui", "libutils", ], export_include_dirs: ["."], export_shared_lib_headers: [ - "libprotoutil", - "libstatslog", - "libstatspull", - "libstatssocket", "libtimestats_proto", ], cppflags: [ diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 2094972ed0..3d82afa43a 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -19,11 +19,9 @@ #define LOG_TAG "TimeStats" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "TimeStats.h" - #include <android-base/stringprintf.h> -#include <android/util/ProtoOutputStream.h> #include <log/log.h> +#include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h> #include <utils/String8.h> #include <utils/Timers.h> #include <utils/Trace.h> @@ -31,147 +29,102 @@ #include <algorithm> #include <chrono> +#include "TimeStats.h" #include "timestatsproto/TimeStatsHelper.h" namespace android { namespace impl { -AStatsManager_PullAtomCallbackReturn TimeStats::pullAtomCallback(int32_t atom_tag, - AStatsEventList* data, - void* cookie) { - impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie); - AStatsManager_PullAtomCallbackReturn result = AStatsManager_PULL_SKIP; - if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) { - result = timeStats->populateGlobalAtom(data); - } else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) { - result = timeStats->populateLayerAtom(data); - } - - // Enable timestats now. The first full pull for a given build is expected to - // have empty or very little stats, as stats are first enabled after the - // first pull is completed for either the global or layer stats. - timeStats->enable(); - return result; -} - namespace { -// Histograms align with the order of fields in SurfaceflingerStatsLayerInfo. -const std::array<std::string, 6> kHistogramNames = { - "present2present", "post2present", "acquire2present", - "latch2present", "desired2present", "post2acquire", -}; - -std::string histogramToProtoByteString(const std::unordered_map<int32_t, int32_t>& histogram, - size_t maxPulledHistogramBuckets) { + +FrameTimingHistogram histogramToProto(const std::unordered_map<int32_t, int32_t>& histogram, + size_t maxPulledHistogramBuckets) { auto buckets = std::vector<std::pair<int32_t, int32_t>>(histogram.begin(), histogram.end()); std::sort(buckets.begin(), buckets.end(), [](std::pair<int32_t, int32_t>& left, std::pair<int32_t, int32_t>& right) { return left.second > right.second; }); - util::ProtoOutputStream proto; + FrameTimingHistogram histogramProto; int histogramSize = 0; for (const auto& bucket : buckets) { if (++histogramSize > maxPulledHistogramBuckets) { break; } - proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED | - 1 /* field id */, - (int32_t)bucket.first); - proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED | - 2 /* field id */, - (int64_t)bucket.second); + histogramProto.add_time_millis_buckets((int32_t)bucket.first); + histogramProto.add_frame_counts((int64_t)bucket.second); } - - std::string byteString; - proto.serializeToString(&byteString); - return byteString; + return histogramProto; } -std::string frameRateVoteToProtoByteString( - float refreshRate, - TimeStats::SetFrameRateVote::FrameRateCompatibility frameRateCompatibility, - TimeStats::SetFrameRateVote::Seamlessness seamlessness) { - util::ProtoOutputStream proto; - proto.write(android::util::FIELD_TYPE_FLOAT | 1 /* field id */, refreshRate); - proto.write(android::util::FIELD_TYPE_ENUM | 2 /* field id */, - static_cast<int>(frameRateCompatibility)); - proto.write(android::util::FIELD_TYPE_ENUM | 3 /* field id */, static_cast<int>(seamlessness)); - - std::string byteString; - proto.serializeToString(&byteString); - return byteString; +SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto( + const TimeStats::SetFrameRateVote& setFrameRateVote) { + using FrameRateCompatibilityEnum = + SurfaceflingerStatsLayerInfo::SetFrameRateVote::FrameRateCompatibility; + using SeamlessnessEnum = SurfaceflingerStatsLayerInfo::SetFrameRateVote::Seamlessness; + + SurfaceflingerStatsLayerInfo_SetFrameRateVote proto; + proto.set_frame_rate(setFrameRateVote.frameRate); + proto.set_frame_rate_compatibility( + static_cast<FrameRateCompatibilityEnum>(setFrameRateVote.frameRateCompatibility)); + proto.set_seamlessness(static_cast<SeamlessnessEnum>(setFrameRateVote.seamlessness)); + return proto; } } // namespace -AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) { +bool TimeStats::populateGlobalAtom(std::string* pulledData) { std::lock_guard<std::mutex> lock(mMutex); if (mTimeStats.statsStartLegacy == 0) { - return AStatsManager_PULL_SKIP; + return false; } flushPowerTimeLocked(); - + SurfaceflingerStatsGlobalInfoWrapper atomList; for (const auto& globalSlice : mTimeStats.stats) { - AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data); - mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFramesLegacy); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFramesLegacy); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFramesLegacy); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTimeLegacy); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresentLegacy.totalTime()); - mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCountLegacy); - std::string frameDurationBytes = - histogramToProtoByteString(mTimeStats.frameDurationLegacy.hist, - mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(), - frameDurationBytes.size()); - std::string renderEngineTimingBytes = - histogramToProtoByteString(mTimeStats.renderEngineTimingLegacy.hist, - mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, - (const uint8_t*)renderEngineTimingBytes.c_str(), - renderEngineTimingBytes.size()); - - mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalFrames); - mStatsDelegate->statsEventWriteInt32(event, - globalSlice.second.jankPayload.totalJankyFrames); - mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongCpu); - mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongGpu); - mStatsDelegate->statsEventWriteInt32(event, - globalSlice.second.jankPayload.totalSFUnattributed); - mStatsDelegate->statsEventWriteInt32(event, - globalSlice.second.jankPayload.totalAppUnattributed); - mStatsDelegate->statsEventWriteInt32(event, - globalSlice.second.jankPayload.totalSFScheduling); - mStatsDelegate->statsEventWriteInt32(event, - globalSlice.second.jankPayload.totalSFPredictionError); - mStatsDelegate->statsEventWriteInt32(event, - globalSlice.second.jankPayload.totalAppBufferStuffing); - mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.displayRefreshRateBucket); - std::string sfDeadlineMissedBytes = - histogramToProtoByteString(globalSlice.second.displayDeadlineDeltas.hist, - mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, - (const uint8_t*)sfDeadlineMissedBytes.c_str(), - sfDeadlineMissedBytes.size()); - std::string sfPredictionErrorBytes = - histogramToProtoByteString(globalSlice.second.displayPresentDeltas.hist, - mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, - (const uint8_t*)sfPredictionErrorBytes.c_str(), - sfPredictionErrorBytes.size()); - mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.renderRateBucket); - mStatsDelegate->statsEventBuild(event); + SurfaceflingerStatsGlobalInfo* atom = atomList.add_atom(); + atom->set_total_frames(mTimeStats.totalFramesLegacy); + atom->set_missed_frames(mTimeStats.missedFramesLegacy); + atom->set_client_composition_frames(mTimeStats.clientCompositionFramesLegacy); + atom->set_display_on_millis(mTimeStats.displayOnTimeLegacy); + atom->set_animation_millis(mTimeStats.presentToPresentLegacy.totalTime()); + atom->set_event_connection_count(mTimeStats.displayEventConnectionsCountLegacy); + *atom->mutable_frame_duration() = + histogramToProto(mTimeStats.frameDurationLegacy.hist, mMaxPulledHistogramBuckets); + *atom->mutable_render_engine_timing() = + histogramToProto(mTimeStats.renderEngineTimingLegacy.hist, + mMaxPulledHistogramBuckets); + atom->set_total_timeline_frames(globalSlice.second.jankPayload.totalFrames); + atom->set_total_janky_frames(globalSlice.second.jankPayload.totalJankyFrames); + atom->set_total_janky_frames_with_long_cpu(globalSlice.second.jankPayload.totalSFLongCpu); + atom->set_total_janky_frames_with_long_gpu(globalSlice.second.jankPayload.totalSFLongGpu); + atom->set_total_janky_frames_sf_unattributed( + globalSlice.second.jankPayload.totalSFUnattributed); + atom->set_total_janky_frames_app_unattributed( + globalSlice.second.jankPayload.totalAppUnattributed); + atom->set_total_janky_frames_sf_scheduling( + globalSlice.second.jankPayload.totalSFScheduling); + atom->set_total_jank_frames_sf_prediction_error( + globalSlice.second.jankPayload.totalSFPredictionError); + atom->set_total_jank_frames_app_buffer_stuffing( + globalSlice.second.jankPayload.totalAppBufferStuffing); + atom->set_display_refresh_rate_bucket(globalSlice.first.displayRefreshRateBucket); + *atom->mutable_sf_deadline_misses() = + histogramToProto(globalSlice.second.displayDeadlineDeltas.hist, + mMaxPulledHistogramBuckets); + *atom->mutable_sf_prediction_errors() = + histogramToProto(globalSlice.second.displayPresentDeltas.hist, + mMaxPulledHistogramBuckets); + atom->set_render_rate_bucket(globalSlice.first.renderRateBucket); } + // Always clear data. clearGlobalLocked(); - return AStatsManager_PULL_SUCCESS; + return atomList.SerializeToString(pulledData); } -AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) { +bool TimeStats::populateLayerAtom(std::string* pulledData) { std::lock_guard<std::mutex> lock(mMutex); std::vector<TimeStatsHelper::TimeStatsLayer*> dumpStats; @@ -198,69 +151,73 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis dumpStats.resize(mMaxPulledLayers); } + SurfaceflingerStatsLayerInfoWrapper atomList; for (auto& layer : dumpStats) { - AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data); - mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_LAYER_INFO); - mStatsDelegate->statsEventWriteString8(event, layer->layerName.c_str()); - mStatsDelegate->statsEventWriteInt64(event, layer->totalFrames); - mStatsDelegate->statsEventWriteInt64(event, layer->droppedFrames); - - for (const auto& name : kHistogramNames) { - const auto& histogram = layer->deltas.find(name); - if (histogram == layer->deltas.cend()) { - mStatsDelegate->statsEventWriteByteArray(event, nullptr, 0); - } else { - std::string bytes = histogramToProtoByteString(histogram->second.hist, - mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)bytes.c_str(), - bytes.size()); - } + SurfaceflingerStatsLayerInfo* atom = atomList.add_atom(); + atom->set_layer_name(layer->layerName); + atom->set_total_frames(layer->totalFrames); + atom->set_dropped_frames(layer->droppedFrames); + const auto& present2PresentHist = layer->deltas.find("present2present"); + if (present2PresentHist != layer->deltas.cend()) { + *atom->mutable_present_to_present() = + histogramToProto(present2PresentHist->second.hist, mMaxPulledHistogramBuckets); + } + const auto& post2presentHist = layer->deltas.find("post2present"); + if (post2presentHist != layer->deltas.cend()) { + *atom->mutable_post_to_present() = + histogramToProto(post2presentHist->second.hist, mMaxPulledHistogramBuckets); + } + const auto& acquire2presentHist = layer->deltas.find("acquire2present"); + if (acquire2presentHist != layer->deltas.cend()) { + *atom->mutable_acquire_to_present() = + histogramToProto(acquire2presentHist->second.hist, mMaxPulledHistogramBuckets); + } + const auto& latch2presentHist = layer->deltas.find("latch2present"); + if (latch2presentHist != layer->deltas.cend()) { + *atom->mutable_latch_to_present() = + histogramToProto(latch2presentHist->second.hist, mMaxPulledHistogramBuckets); + } + const auto& desired2presentHist = layer->deltas.find("desired2present"); + if (desired2presentHist != layer->deltas.cend()) { + *atom->mutable_desired_to_present() = + histogramToProto(desired2presentHist->second.hist, mMaxPulledHistogramBuckets); + } + const auto& post2acquireHist = layer->deltas.find("post2acquire"); + if (post2acquireHist != layer->deltas.cend()) { + *atom->mutable_post_to_acquire() = + histogramToProto(post2acquireHist->second.hist, mMaxPulledHistogramBuckets); } - mStatsDelegate->statsEventWriteInt64(event, layer->lateAcquireFrames); - mStatsDelegate->statsEventWriteInt64(event, layer->badDesiredPresentFrames); - mStatsDelegate->statsEventWriteInt32(event, layer->uid); - mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalFrames); - mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalJankyFrames); - mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongCpu); - mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongGpu); - mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFUnattributed); - mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppUnattributed); - mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFScheduling); - mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFPredictionError); - mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppBufferStuffing); - mStatsDelegate->statsEventWriteInt32( - event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket - mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket - std::string frameRateVoteBytes = - frameRateVoteToProtoByteString(layer->setFrameRateVote.frameRate, - layer->setFrameRateVote.frameRateCompatibility, - layer->setFrameRateVote.seamlessness); - mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameRateVoteBytes.c_str(), - frameRateVoteBytes.size()); // set_frame_rate_vote - std::string appDeadlineMissedBytes = - histogramToProtoByteString(layer->deltas["appDeadlineDeltas"].hist, - mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, - (const uint8_t*)appDeadlineMissedBytes.c_str(), - appDeadlineMissedBytes.size()); - - mStatsDelegate->statsEventBuild(event); + atom->set_late_acquire_frames(layer->lateAcquireFrames); + atom->set_bad_desired_present_frames(layer->badDesiredPresentFrames); + atom->set_uid(layer->uid); + atom->set_total_timeline_frames(layer->jankPayload.totalFrames); + atom->set_total_janky_frames(layer->jankPayload.totalJankyFrames); + atom->set_total_janky_frames_with_long_cpu(layer->jankPayload.totalSFLongCpu); + atom->set_total_janky_frames_with_long_gpu(layer->jankPayload.totalSFLongGpu); + atom->set_total_janky_frames_sf_unattributed(layer->jankPayload.totalSFUnattributed); + atom->set_total_janky_frames_app_unattributed(layer->jankPayload.totalAppUnattributed); + atom->set_total_janky_frames_sf_scheduling(layer->jankPayload.totalSFScheduling); + atom->set_total_jank_frames_sf_prediction_error(layer->jankPayload.totalSFPredictionError); + atom->set_total_jank_frames_app_buffer_stuffing(layer->jankPayload.totalAppBufferStuffing); + atom->set_display_refresh_rate_bucket(layer->displayRefreshRateBucket); + atom->set_render_rate_bucket(layer->renderRateBucket); + *atom->mutable_set_frame_rate_vote() = frameRateVoteToProto(layer->setFrameRateVote); + *atom->mutable_app_deadline_misses() = + histogramToProto(layer->deltas["appDeadlineDeltas"].hist, + mMaxPulledHistogramBuckets); } + + // Always clear data. clearLayersLocked(); - return AStatsManager_PULL_SUCCESS; + return atomList.SerializeToString(pulledData); } -TimeStats::TimeStats() : TimeStats(nullptr, std::nullopt, std::nullopt) {} +TimeStats::TimeStats() : TimeStats(std::nullopt, std::nullopt) {} -TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate, - std::optional<size_t> maxPulledLayers, +TimeStats::TimeStats(std::optional<size_t> maxPulledLayers, std::optional<size_t> maxPulledHistogramBuckets) { - if (statsDelegate != nullptr) { - mStatsDelegate = std::move(statsDelegate); - } - if (maxPulledLayers) { mMaxPulledLayers = *maxPulledLayers; } @@ -270,18 +227,19 @@ TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate, } } -TimeStats::~TimeStats() { - std::lock_guard<std::mutex> lock(mMutex); - mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); - mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO); -} +bool TimeStats::onPullAtom(const int atomId, std::string* pulledData) { + bool success = false; + if (atomId == 10062) { // SURFACEFLINGER_STATS_GLOBAL_INFO + success = populateGlobalAtom(pulledData); + } else if (atomId == 10063) { // SURFACEFLINGER_STATS_LAYER_INFO + success = populateLayerAtom(pulledData); + } -void TimeStats::onBootFinished() { - std::lock_guard<std::mutex> lock(mMutex); - mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - nullptr, TimeStats::pullAtomCallback, this); - mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, - nullptr, TimeStats::pullAtomCallback, this); + // Enable timestats now. The first full pull for a given build is expected to + // have empty or very little stats, as stats are first enabled after the + // first pull is completed for either the global or layer stats. + enable(); + return success; } void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) { @@ -787,7 +745,7 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL | JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed | JankType::PredictionError | - JankType::SurfaceFlingerScheduling | JankType::BufferStuffing; + JankType::SurfaceFlingerScheduling; template <class T> static void updateJankPayload(T& t, int32_t reasons) { @@ -813,9 +771,11 @@ static void updateJankPayload(T& t, int32_t reasons) { if ((reasons & JankType::SurfaceFlingerScheduling) != 0) { t.jankPayload.totalSFScheduling++; } - if ((reasons & JankType::BufferStuffing) != 0) { - t.jankPayload.totalAppBufferStuffing++; - } + } + + // We want to track BufferStuffing separately as it can provide info on latency issues + if (reasons & JankType::BufferStuffing) { + t.jankPayload.totalAppBufferStuffing++; } } diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index a87b7cb4a6..5b0f5bd13d 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -29,9 +29,6 @@ #include <../Fps.h> #include <gui/JankInfo.h> -#include <stats_event.h> -#include <stats_pull_atom_callback.h> -#include <statslog.h> #include <timestatsproto/TimeStatsHelper.h> #include <timestatsproto/TimeStatsProtoHeader.h> #include <ui/FenceTime.h> @@ -54,9 +51,8 @@ public: virtual ~TimeStats() = default; - // Called once boot has been finished to perform additional capabilities, - // e.g. registration to statsd. - virtual void onBootFinished() = 0; + // Process a pull request from statsd. + virtual bool onPullAtom(const int atomId, std::string* pulledData); virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0; virtual bool isEnabled() = 0; @@ -232,58 +228,11 @@ class TimeStats : public android::TimeStats { public: TimeStats(); - - // Delegate to the statsd service and associated APIs. - // Production code may use this class directly, whereas unit test may define - // a subclass for ease of testing. - class StatsEventDelegate { - public: - virtual ~StatsEventDelegate() = default; - virtual AStatsEvent* addStatsEventToPullData(AStatsEventList* data) { - return AStatsEventList_addStatsEvent(data); - } - virtual void setStatsPullAtomCallback(int32_t atom_tag, - AStatsManager_PullAtomMetadata* metadata, - AStatsManager_PullAtomCallback callback, - void* cookie) { - return AStatsManager_setPullAtomCallback(atom_tag, metadata, callback, cookie); - } - - virtual void clearStatsPullAtomCallback(int32_t atom_tag) { - return AStatsManager_clearPullAtomCallback(atom_tag); - } - - virtual void statsEventSetAtomId(AStatsEvent* event, uint32_t atom_id) { - return AStatsEvent_setAtomId(event, atom_id); - } - - virtual void statsEventWriteInt32(AStatsEvent* event, int32_t field) { - return AStatsEvent_writeInt32(event, field); - } - - virtual void statsEventWriteInt64(AStatsEvent* event, int64_t field) { - return AStatsEvent_writeInt64(event, field); - } - - virtual void statsEventWriteString8(AStatsEvent* event, const char* field) { - return AStatsEvent_writeString(event, field); - } - - virtual void statsEventWriteByteArray(AStatsEvent* event, const uint8_t* buf, - size_t numBytes) { - return AStatsEvent_writeByteArray(event, buf, numBytes); - } - - virtual void statsEventBuild(AStatsEvent* event) { return AStatsEvent_build(event); } - }; // For testing only for injecting custom dependencies. - TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate, - std::optional<size_t> maxPulledLayers, + TimeStats(std::optional<size_t> maxPulledLayers, std::optional<size_t> maxPulledHistogramBuckets); - ~TimeStats() override; - - void onBootFinished() override; + bool onPullAtom(const int atomId, std::string* pulledData) override; void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override; bool isEnabled() override; std::string miniDump() override; @@ -332,11 +281,8 @@ public: static const size_t MAX_NUM_TIME_RECORDS = 64; private: - static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atom_tag, - AStatsEventList* data, - void* cookie); - AStatsManager_PullAtomCallbackReturn populateGlobalAtom(AStatsEventList* data); - AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data); + bool populateGlobalAtom(std::string* pulledData); + bool populateLayerAtom(std::string* pulledData); bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord); void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, std::optional<Fps> renderRate, @@ -366,7 +312,6 @@ private: static const size_t RENDER_RATE_BUCKET_WIDTH = REFRESH_RATE_BUCKET_WIDTH; static const size_t MAX_NUM_LAYER_STATS = 200; static const size_t MAX_NUM_PULLED_LAYERS = MAX_NUM_LAYER_STATS; - std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>(); size_t mMaxPulledLayers = MAX_NUM_PULLED_LAYERS; size_t mMaxPulledHistogramBuckets = 6; }; diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp new file mode 100644 index 0000000000..0cf086fe01 --- /dev/null +++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/Android.bp @@ -0,0 +1,36 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_library { + name: "libtimestats_atoms_proto", + export_include_dirs: ["include"], + + srcs: [ + "timestats_atoms.proto", + ], + + proto: { + type: "lite", + export_proto_headers: true, + }, + + cppflags: [ + "-Werror", + "-Wno-c++98-compat-pedantic", + "-Wno-disabled-macro-expansion", + "-Wno-float-conversion", + "-Wno-float-equal", + "-Wno-format", + "-Wno-old-style-cast", + "-Wno-padded", + "-Wno-sign-conversion", + "-Wno-undef", + "-Wno-unused-parameter", + ], +}
\ No newline at end of file diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/include/timestatsatomsproto/TimeStatsAtomsProtoHeader.h b/services/surfaceflinger/TimeStats/timestatsatomsproto/include/timestatsatomsproto/TimeStatsAtomsProtoHeader.h new file mode 100644 index 0000000000..d305cb403c --- /dev/null +++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/include/timestatsatomsproto/TimeStatsAtomsProtoHeader.h @@ -0,0 +1,23 @@ +/* + * 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 is used here to disable the warnings emitted from the protobuf +// headers. By adding #pragma before including layer.pb.h, it suppresses +// protobuf warnings, but allows the rest of the files to continuing using +// the current flags. +// This file should be included instead of directly including timestats_atoms.b.h +#pragma GCC system_header +#include <timestats_atoms.pb.h> diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto new file mode 100644 index 0000000000..133a5419b5 --- /dev/null +++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto @@ -0,0 +1,289 @@ +/* + * 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. + */ +syntax = "proto2"; +option optimize_for = LITE_RUNTIME; +package android.surfaceflinger; + +// This is a copy of surfaceflinger's atoms from frameworks/proto_logging/stats/atoms.proto. +// Pulled atoms for surfaceflinger must be routed through system server since surfaceflinger is +// in the bootstrap namespace. This copy is used to pass the atoms as protos to system server using +// proto lite to serialize/deserialize the atoms. + +// These wrappers are so that we can pass a List<Atom> as a single byte string. +// They are not in atoms.proto +message SurfaceflingerStatsGlobalInfoWrapper { + repeated SurfaceflingerStatsGlobalInfo atom = 1; +} + +message SurfaceflingerStatsLayerInfoWrapper { + repeated SurfaceflingerStatsLayerInfo atom = 1; +} + +/** + * Global display pipeline metrics reported by SurfaceFlinger. + * Metrics exist beginning in Android 11. + * Pulled from: + * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp + */ +message SurfaceflingerStatsGlobalInfo { + // Aggregated refresh rate buckets that layers were presenting at. Buckets + // are defined in SurfaceFlinger and are tracked per device. + // Introduced in Android 12. + // This is intended to be used as a dimenstion in collecting per-refresh rate + // jank statistics. + optional int32 display_refresh_rate_bucket = 18; + // Aggregated render rate buckets that layers were overridden to run at. + // Buckets are defined in SurfaceFlinger and are tracked per device. + // Introduced in Android 12. + // This is intended to be used as a dimension in collecting per-render rate + // jank statistics. + optional int32 render_rate_bucket = 21; + // Total number of frames presented during the tracing period + // Note: This stat is not sliced by dimension. It will be duplicated for metrics + // using render_rate_bucket as a dimension. + optional int64 total_frames = 1; + // Total number of frames missed + // Note: This stat is not sliced by dimension. It will be duplicated for metrics + // using render_rate_bucket as a dimension. + optional int64 missed_frames = 2; + // Total number of frames that fell back to client composition + // Note: This stat is not sliced by dimension. It will be duplicated for metrics + // using render_rate_bucket as a dimension. + optional int64 client_composition_frames = 3; + // Total time the display was turned on + // Note: This stat is not sliced by dimension. It will be duplicated for metrics + // using render_rate_bucket as a dimension. + optional int64 display_on_millis = 4; + // Total time that was spent performing animations. + // This is derived from the present-to-present layer histogram. + // Note: This stat is not sliced by dimension. It will be duplicated for metrics + // using render_rate_bucket as a dimension. + optional int64 animation_millis = 5; + // Total number of event connections tracked by SurfaceFlinger at the time + // of this pull. If this number grows prohibitively large, then this can + // cause jank due to resource contention. + // Note: This stat is not sliced by dimension. It will be duplicated for metrics + // using render_rate_bucket as a dimension. + optional int32 event_connection_count = 6; + // Set of timings measured from when SurfaceFlinger began compositing a + // frame, until the frame was requested to be presented to the display. This + // measures SurfaceFlinger's total CPU walltime on the critical path per + // frame. + // Note: This stat is not sliced by dimension. It will be duplicated for metrics + // using render_rate_bucket as a dimension. + optional FrameTimingHistogram frame_duration = 7; + // Set of timings measured from when SurfaceFlinger first began using the + // GPU to composite a frame, until the GPU has finished compositing that + // frame. This measures the total additional time SurfaceFlinger needed to + // perform due to falling back into GPU composition. + // Note: This stat is not sliced by dimension. It will be duplicated for metrics + // using render_rate_bucket as a dimension. + optional FrameTimingHistogram render_engine_timing = 8; + // Number of frames where SF saw a frame, based on its frame timeline. + // Frame timelines may include transactions without updating buffer contents. + // Introduced in Android 12. + optional int32 total_timeline_frames = 9; + // Number of frames where SF saw a janky frame. + // Introduced in Android 12. + optional int32 total_janky_frames = 10; + // Number of janky frames where SF spent a long time on the CPU. + // Introduced in Android 12. + optional int32 total_janky_frames_with_long_cpu = 11; + // Number of janky frames where SF spent a long time on the GPU. + // Introduced in Android 12. + optional int32 total_janky_frames_with_long_gpu = 12; + // Number of janky frames where SF missed the frame deadline, but there + // was not an attributed reason (e.g., maybe HWC missed?) + // Introduced in Android 12. + optional int32 total_janky_frames_sf_unattributed = 13; + // Number of janky frames where the app missed the frame deadline, but + // there was not an attributed reason + // Introduced in Android 12. + optional int32 total_janky_frames_app_unattributed = 14; + // Number of janky frames that were caused because of scheduling errors in + // SF that resulted in early present (e.g., SF sending a buffer to the + // composition engine earlier than expected, resulting in a present that is + // one vsync early) + // Introduced in Android 12. + optional int32 total_janky_frames_sf_scheduling = 15; + // Number of frames that were classified as jank because of possible drift in + // vsync predictions. + // Introduced in Android 12. + optional int32 total_jank_frames_sf_prediction_error = 16; + // Number of janky frames where the app was in a buffer stuffed state (more + // than one buffer ready to be presented at the same vsync). Usually caused + // when the first frame is unusually long, the following frames enter into a + // stuffed state. + // Introduced in Android 12. + optional int32 total_jank_frames_app_buffer_stuffing = 17; + // Buckets of timings in ms by which SurfaceFlinger's deadline was missed + // while latching and presenting frames. + // Introduced in Android 12. + optional FrameTimingHistogram sf_deadline_misses = 19; + // Buckets of timings in ms by which the Vsync prediction drifted, when + // compared to the actual hardware vsync. + // Introduced in Android 12. + optional FrameTimingHistogram sf_prediction_errors = 20; + + // Next ID: 22 +} + +/** + * Per-layer display pipeline metrics reported by SurfaceFlinger. + * Metrics exist beginning in Android 11. + * The number of layers uploaded may be restricted due to size limitations. + * Pulled from: + * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp + */ +message SurfaceflingerStatsLayerInfo { + // UID of the application who submitted this layer for presentation + // This is intended to be used as a dimension for surfacing rendering + // statistics to applications. + // Introduced in Android 12. + optional int32 uid = 12; + // Refresh rate bucket that the layer was presenting at. Buckets are + // defined in SurfaceFlinger and are tracked per device. + // Introduced in Android 12. + // This is intended to be used as a dimension in collecting per-refresh rate + // jank statistics + optional int32 display_refresh_rate_bucket = 22; + // Render rate bucket that the layer was submitting frames at. Buckets are + // defined in SurfaceFlinger and are tracked per device. + // Introduced in Android 12. + // This is intended to be used as a dimension in collecting per-render rate + // jank statistics. + optional int32 render_rate_bucket = 23; + // The layer for this set of metrics + // In many scenarios the package name is included in the layer name, e.g., + // layers created by Window Manager. But this is not a guarantee - in the + // general case layer names are arbitrary debug names. + optional string layer_name = 1; + // Total number of frames presented + optional int64 total_frames = 2; + // Total number of dropped frames while latching a buffer for this layer. + optional int64 dropped_frames = 3; + // Set of timings measured between successive presentation timestamps. + optional FrameTimingHistogram present_to_present = 4; + // Set of timings measured from when an app queued a buffer for + // presentation, until the buffer was actually presented to the + // display. + optional FrameTimingHistogram post_to_present = 5; + // Set of timings measured from when a buffer is ready to be presented, + // until the buffer was actually presented to the display. + optional FrameTimingHistogram acquire_to_present = 6; + // Set of timings measured from when a buffer was latched by + // SurfaceFlinger, until the buffer was presented to the display + optional FrameTimingHistogram latch_to_present = 7; + // Set of timings measured from the desired presentation to the actual + // presentation time + optional FrameTimingHistogram desired_to_present = 8; + // Set of timings measured from when an app queued a buffer for + // presentation, until the buffer was ready to be presented. + optional FrameTimingHistogram post_to_acquire = 9; + // Frames missed latch because the acquire fence didn't fire + optional int64 late_acquire_frames = 10; + // Frames latched early because the desired present time was bad + optional int64 bad_desired_present_frames = 11; + // Number of frames where SF saw a frame, based on its frame timeline. + // Frame timelines may include transactions without updating buffer contents. + // Introduced in Android 12. + optional int32 total_timeline_frames = 13; + // Number of frames where SF saw a janky frame. + // Introduced in Android 12. + optional int32 total_janky_frames = 14; + // Number of janky frames where SF spent a long time on the CPU. + // Introduced in Android 12. + optional int32 total_janky_frames_with_long_cpu = 15; + // Number of janky frames where SF spent a long time on the GPU. + // Introduced in Android 12. + optional int32 total_janky_frames_with_long_gpu = 16; + // Number of janky frames where SF missed the frame deadline, but there + // was not an attributed reason (e.g., maybe HWC missed?) + // Introduced in Android 12. + optional int32 total_janky_frames_sf_unattributed = 17; + // Number of janky frames where the app missed the frame deadline, but + // there was not an attributed reason + // Introduced in Android 12. + optional int32 total_janky_frames_app_unattributed = 18; + // Number of janky frames that were caused because of scheduling errors in + // SF that resulted in early present (e.g., SF sending a buffer to the + // composition engine earlier than expected, resulting in a present that is + // one vsync early) + // Introduced in Android 12. + optional int32 total_janky_frames_sf_scheduling = 19; + // Number of frames that were classified as jank because of possible drift in + // vsync predictions. + // Introduced in Android 12. + optional int32 total_jank_frames_sf_prediction_error = 20; + // Number of janky frames where the app was in a buffer stuffed state (more + // than one buffer ready to be presented at the same vsync). Usually caused + // when the first frame is unusually long, the following frames enter into a + // stuffed state. + // Introduced in Android 12. + optional int32 total_jank_frames_app_buffer_stuffing = 21; + + /** + * Encapsulates the FrameRateVote information sent by the application while + * calling setFrameRate. + * Metrics exist beginning in Android 12. + */ + message SetFrameRateVote { + // The desired frame rate the application wishes to run on. + optional float frame_rate = 1; + + enum FrameRateCompatibility { + FRAME_RATE_UNDEFINED = 0; + FRAME_RATE_DEFAULT = 1; + FRAME_RATE_EXACT_OR_MULTIPLE = 2; + } + + // Specifies how to interpret the frame rate associated with the layer. + // Defined in Layer.h + optional FrameRateCompatibility frame_rate_compatibility = 2; + + enum Seamlessness { + SEAMLESS_UNDEFINED = 0; + SEAMLESS_SHOULD_BE_SEAMLESS = 1; + SEAMLESS_NOT_REQUIRED = 2; + } + // Indicates whether seamless refresh rate switch is required or not. + optional Seamlessness seamlessness = 3; + } + + // The last frame rate vote set by the application. + // Introduced in Android 12. + optional SetFrameRateVote set_frame_rate_vote = 24; + // Buckets of timings in ms by which the app deadline was missed while + // submitting work for a frame. + // Introduced in Android 12. + optional FrameTimingHistogram app_deadline_misses = 25; + + // Next ID: 26 +} + +/** + * Histogram of frame counts bucketed by time in milliseconds. + * Because of size limitations, we hard-cap the number of buckets, with + * buckets for corresponding to larger milliseconds being less precise. + */ +message FrameTimingHistogram { + // Timings in milliseconds that describes a set of histogram buckets + repeated int32 time_millis_buckets = 1; + // Number of frames that match to each time_millis, i.e. the bucket + // contents + // It's required that len(time_millis) == len(frame_count) + repeated int64 frame_counts = 2; +} diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index 3590e76cb9..4f4c02be6c 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -36,13 +36,17 @@ namespace android { // <0 if the first id that doesn't match is lower in c2 or all ids match but c2 is shorter // >0 if the first id that doesn't match is greater in c2 or all ids match but c2 is longer // -// See CallbackIdsHash for a explaniation of why this works +// See CallbackIdsHash for a explanation of why this works static int compareCallbackIds(const std::vector<CallbackId>& c1, const std::vector<CallbackId>& c2) { if (c1.empty()) { return !c2.empty(); } - return c1.front() - c2.front(); + return c1.front().id - c2.front().id; +} + +static bool containsOnCommitCallbacks(const std::vector<CallbackId>& callbacks) { + return !callbacks.empty() && callbacks.front().type == CallbackId::Type::ON_COMMIT; } TransactionCallbackInvoker::~TransactionCallbackInvoker() { @@ -114,39 +118,69 @@ status_t TransactionCallbackInvoker::registerPendingCallbackHandle( return NO_ERROR; } -status_t TransactionCallbackInvoker::finalizePendingCallbackHandles( - const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) { +status_t TransactionCallbackInvoker::finalizeCallbackHandle(const sp<CallbackHandle>& handle, + const std::vector<JankData>& jankData) { + auto listener = mPendingTransactions.find(handle->listener); + if (listener != mPendingTransactions.end()) { + auto& pendingCallbacks = listener->second; + auto pendingCallback = pendingCallbacks.find(handle->callbackIds); + + if (pendingCallback != pendingCallbacks.end()) { + auto& pendingCount = pendingCallback->second; + + // Decrease the pending count for this listener + if (--pendingCount == 0) { + pendingCallbacks.erase(pendingCallback); + } + } else { + ALOGW("there are more latched callbacks than there were registered callbacks"); + } + if (listener->second.size() == 0) { + mPendingTransactions.erase(listener); + } + } else { + ALOGW("cannot find listener in mPendingTransactions"); + } + + status_t err = addCallbackHandle(handle, jankData); + if (err != NO_ERROR) { + ALOGE("could not add callback handle"); + return err; + } + return NO_ERROR; +} + +status_t TransactionCallbackInvoker::finalizeOnCommitCallbackHandles( + const std::deque<sp<CallbackHandle>>& handles, + std::deque<sp<CallbackHandle>>& outRemainingHandles) { if (handles.empty()) { return NO_ERROR; } std::lock_guard lock(mMutex); - + const std::vector<JankData>& jankData = std::vector<JankData>(); for (const auto& handle : handles) { - auto listener = mPendingTransactions.find(handle->listener); - if (listener != mPendingTransactions.end()) { - auto& pendingCallbacks = listener->second; - auto pendingCallback = pendingCallbacks.find(handle->callbackIds); - - if (pendingCallback != pendingCallbacks.end()) { - auto& pendingCount = pendingCallback->second; - - // Decrease the pending count for this listener - if (--pendingCount == 0) { - pendingCallbacks.erase(pendingCallback); - } - } else { - ALOGW("there are more latched callbacks than there were registered callbacks"); - } - if (listener->second.size() == 0) { - mPendingTransactions.erase(listener); - } - } else { - ALOGW("cannot find listener in mPendingTransactions"); + if (!containsOnCommitCallbacks(handle->callbackIds)) { + outRemainingHandles.push_back(handle); + continue; } + status_t err = finalizeCallbackHandle(handle, jankData); + if (err != NO_ERROR) { + return err; + } + } - status_t err = addCallbackHandle(handle, jankData); + return NO_ERROR; +} + +status_t TransactionCallbackInvoker::finalizePendingCallbackHandles( + const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) { + if (handles.empty()) { + return NO_ERROR; + } + std::lock_guard lock(mMutex); + for (const auto& handle : handles) { + status_t err = finalizeCallbackHandle(handle, jankData); if (err != NO_ERROR) { - ALOGE("could not add callback handle"); return err; } } @@ -243,7 +277,8 @@ void TransactionCallbackInvoker::sendCallbacks() { } // If the transaction has been latched - if (transactionStats.latchTime >= 0) { + if (transactionStats.latchTime >= 0 && + !containsOnCommitCallbacks(transactionStats.callbackIds)) { if (!mPresentFence) { break; } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index caa8a4fb45..184b15103e 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -74,6 +74,8 @@ public: // Notifies the TransactionCallbackInvoker that a pending CallbackHandle has been presented. status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData); + status_t finalizeOnCommitCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, + std::deque<sp<CallbackHandle>>& outRemainingHandles); // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and // presented this frame. @@ -95,6 +97,9 @@ private: status_t addCallbackHandle(const sp<CallbackHandle>& handle, const std::vector<JankData>& jankData) REQUIRES(mMutex); + status_t finalizeCallbackHandle(const sp<CallbackHandle>& handle, + const std::vector<JankData>& jankData) REQUIRES(mMutex); + class CallbackDeathRecipient : public IBinder::DeathRecipient { public: // This function is a no-op. isBinderAlive needs a linked DeathRecipient to work. diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index 2b8424c987..9686523525 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -89,13 +89,47 @@ int main(int, char**) { // binder threads to 4. ProcessState::self()->setThreadPoolMaxThreadCount(4); + // The binder threadpool we start will inherit sched policy and priority + // of (this) creating thread. We want the binder thread pool to have + // SCHED_FIFO policy and priority 1 (lowest RT priority) + // Once the pool is created we reset this thread's priority back to + // original. + int newPriority = 0; + int origPolicy = sched_getscheduler(0); + struct sched_param origSchedParam; + + int errorInPriorityModification = sched_getparam(0, &origSchedParam); + if (errorInPriorityModification == 0) { + int policy = SCHED_FIFO; + newPriority = sched_get_priority_min(policy); + + struct sched_param param; + param.sched_priority = newPriority; + + errorInPriorityModification = sched_setscheduler(0, policy, ¶m); + } + // start the thread pool sp<ProcessState> ps(ProcessState::self()); ps->startThreadPool(); + // Reset current thread's policy and priority + if (errorInPriorityModification == 0) { + errorInPriorityModification = sched_setscheduler(0, origPolicy, &origSchedParam); + } else { + ALOGE("Failed to set SurfaceFlinger binder threadpool priority to SCHED_FIFO"); + } + // instantiate surfaceflinger sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger(); + // Set the minimum policy of surfaceflinger node to be SCHED_FIFO. + // So any thread with policy/priority lower than {SCHED_FIFO, 1}, will run + // at least with SCHED_FIFO policy and priority 1. + if (errorInPriorityModification == 0) { + flinger->setMinSchedulerPolicy(SCHED_FIFO, newPriority); + } + setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY); set_sched_policy(0, SP_FOREGROUND); diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp index 03f8e1afba..47a150dd35 100644 --- a/services/surfaceflinger/tests/BufferGenerator.cpp +++ b/services/surfaceflinger/tests/BufferGenerator.cpp @@ -296,12 +296,12 @@ private: BufferGenerator::BufferGenerator() : mSurfaceManager(new SurfaceManager), mEglManager(new EglManager), mProgram(new Program) { - const float width = 1000.0; - const float height = 1000.0; + mBufferSize.set(1000.0, 1000.0); auto setBufferWithContext = std::bind(setBuffer, std::placeholders::_1, std::placeholders::_2, this); - mSurfaceManager->initialize(width, height, HAL_PIXEL_FORMAT_RGBA_8888, setBufferWithContext); + mSurfaceManager->initialize(mBufferSize.width, mBufferSize.height, HAL_PIXEL_FORMAT_RGBA_8888, + setBufferWithContext); if (!mEglManager->initialize(mSurfaceManager->getSurface())) return; @@ -309,7 +309,9 @@ BufferGenerator::BufferGenerator() if (!mProgram->initialize(VERTEX_SHADER, FRAGMENT_SHADER)) return; mProgram->use(); - mProgram->bindVec4(0, vec4{width, height, 1.0f / width, 1.0f / height}); + mProgram->bindVec4(0, + vec4{mBufferSize.width, mBufferSize.height, 1.0f / mBufferSize.width, + 1.0f / mBufferSize.height}); mProgram->bindVec3(2, &SPHERICAL_HARMONICS[0], 4); glEnableVertexAttribArray(0); @@ -372,6 +374,10 @@ status_t BufferGenerator::get(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) return NO_ERROR; } +ui::Size BufferGenerator::getSize() { + return mBufferSize; +} + // static void BufferGenerator::setBuffer(const sp<GraphicBuffer>& buffer, int32_t fence, void* bufferGenerator) { diff --git a/services/surfaceflinger/tests/BufferGenerator.h b/services/surfaceflinger/tests/BufferGenerator.h index a3ffe86572..f7d548b6bf 100644 --- a/services/surfaceflinger/tests/BufferGenerator.h +++ b/services/surfaceflinger/tests/BufferGenerator.h @@ -37,6 +37,7 @@ public: /* Static callback that sets the fence on a particular instance */ static void setBuffer(const sp<GraphicBuffer>& buffer, int32_t fence, void* fenceGenerator); + ui::Size getSize(); private: bool mInitialized = false; @@ -53,6 +54,7 @@ private: using Epoch = std::chrono::time_point<std::chrono::steady_clock>; Epoch mEpoch = std::chrono::steady_clock::now(); + ui::Size mBufferSize; }; } // namespace android diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 6246321fab..fa3f0e7239 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -305,25 +305,6 @@ TEST_F(CredentialsTest, CaptureLayersTest) { /** * The following tests are for methods accessible directly through SurfaceFlinger. */ - -/** - * An app can pass a buffer queue to the media server and ask the media server to decode a DRM video - * to that buffer queue. The media server is the buffer producer in this case. Because the app may create - * its own buffer queue and act as the buffer consumer, the media server wants to be careful to avoid - * sending decoded video frames to the app. This is where authenticateSurfaceTexture call comes in, to check - * the consumer of a buffer queue is SurfaceFlinger. - */ -TEST_F(CredentialsTest, AuthenticateSurfaceTextureTest) { - setupBackgroundSurface(); - sp<IGraphicBufferProducer> producer = - mBGSurfaceControl->getSurface()->getIGraphicBufferProducer(); - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - - std::function<bool()> condition = [=]() { return sf->authenticateSurfaceTexture(producer); }; - // Anyone should be able to check if the consumer of the buffer queue is SF. - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true)); -} - TEST_F(CredentialsTest, GetLayerDebugInfo) { setupBackgroundSurface(); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp index f470eda7d3..af00ec7fc9 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -149,7 +149,6 @@ TEST_F(EffectLayerTest, BlurEffectLayerIsVisible) { t.reparent(blurLayer, mParentLayer); t.setBackgroundBlurRadius(blurLayer, blurRadius); t.setCrop(blurLayer, blurRect); - t.setFrame(blurLayer, blurRect); t.setAlpha(blurLayer, 0.0f); t.show(blurLayer); }); diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index a8647c3e50..9fa3d4c417 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -161,7 +161,6 @@ public: Color::RED); transaction->setLayerStack(mSurfaceControl, 0) .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max()) - .setFrame(mSurfaceControl, Rect(0, 0, width, height)) .setBuffer(mSurfaceControl, gb) .setAcquireFence(mSurfaceControl, fence) .show(mSurfaceControl) diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp index 58b039e5d5..9cf7c0909b 100644 --- a/services/surfaceflinger/tests/InvalidHandles_test.cpp +++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp @@ -52,12 +52,15 @@ protected: } }; -TEST_F(InvalidHandleTest, createSurfaceInvalidHandle) { - auto notSc = makeNotSurfaceControl(); - ASSERT_EQ(nullptr, - mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0, - notSc->getHandle()) - .get()); +TEST_F(InvalidHandleTest, createSurfaceInvalidParentHandle) { + // The createSurface is scheduled now, we could still get a created surface from createSurface. + // Should verify if it actually added into current state by checking the screenshot. + auto notSc = mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0, + mNotSc->getHandle()); + LayerCaptureArgs args; + args.layerHandle = notSc->getHandle(); + ScreenCaptureResults captureResults; + ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults)); } TEST_F(InvalidHandleTest, captureLayersInvalidHandle) { diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 158801a705..011ff70409 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -164,7 +164,10 @@ TEST_F(LayerCallbackTest, NoBufferNoColor) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, @@ -184,7 +187,10 @@ TEST_F(LayerCallbackTest, BufferNoColor) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -203,7 +209,10 @@ TEST_F(LayerCallbackTest, NoBufferColor) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, @@ -238,7 +247,10 @@ TEST_F(LayerCallbackTest, OffScreen) { return; } - transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(-100, -100, 100, 100)); + transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -263,8 +275,15 @@ TEST_F(LayerCallbackTest, MergeBufferNoColor) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -290,8 +309,15 @@ TEST_F(LayerCallbackTest, MergeNoBufferColor) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -318,8 +344,15 @@ TEST_F(LayerCallbackTest, MergeOneBufferOneColor) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1); @@ -405,8 +438,15 @@ TEST_F(LayerCallbackTest, Merge_DifferentClients) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -491,7 +531,11 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { } } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expected; expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED @@ -523,8 +567,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -564,8 +616,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) { return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, @@ -606,8 +666,15 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -661,8 +728,15 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC return; } - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + ui::Size bufferSize = getBufferSize(); + + TransactionUtils::setFrame(transaction1, layer1, + Rect(0, 0, bufferSize.width, bufferSize.height), Rect(0, 0, 32, 32)); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + + transaction2.merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); @@ -682,7 +756,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC return; } - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); + TransactionUtils::setFrame(transaction2, layer2, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(32, 32, 64, 64)); + transaction2.merge(std::move(transaction1)).apply(); expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2, ExpectedResult::Buffer::NOT_ACQUIRED); @@ -762,7 +839,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + ui::Size bufferSize = getBufferSize(); + TransactionUtils::setFrame(transaction, layer, Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); ExpectedResult expectedResult; expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer); @@ -781,7 +861,10 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { return; } - transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); + TransactionUtils::setFrame(transaction, layer, + Rect(0, 0, bufferSize.width, bufferSize.height), + Rect(0, 0, 32, 32)); + transaction.apply(); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 7505e6ea9b..7581cd3af4 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -135,53 +135,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQue } } -TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) { - sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setPosition is applied immediately by default, with or without resize - // pending - Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply(); - { - SCOPED_TRACE("resize pending"); - auto shot = getScreenCapture(); - const Rect rect(5, 10, 37, 42); - shot->expectColor(rect, Color::RED); - shot->expectBorder(rect, Color::BLACK); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("resize applied"); - getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED); - } -} - -TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) { - sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - Transaction().setSize(layer, 64, 64).apply(); - { - SCOPED_TRACE("resize pending"); - auto shot = getScreenCapture(); - const Rect rect(0, 0, 32, 32); - shot->expectColor(rect, Color::RED); - shot->expectBorder(rect, Color::BLACK); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("resize applied"); - auto shot = getScreenCapture(); - const Rect rect(0, 0, 64, 64); - shot->expectColor(rect, Color::RED); - shot->expectBorder(rect, Color::BLACK); - } -} - TEST_P(LayerRenderTypeTransactionTest, CreateLayer_BufferState) { uint32_t transformHint = ui::Transform::ROT_INVALID; sp<SurfaceControl> layer; @@ -204,11 +157,7 @@ void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply(); break; case ISurfaceComposerClient::eFXSurfaceBufferState: - Transaction() - .setFrame(layerR, Rect(0, 0, 32, 32)) - .setFrame(layerG, Rect(16, 16, 48, 48)) - .setRelativeLayer(layerG, layerR, 1) - .apply(); + Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply(); break; default: ASSERT_FALSE(true) << "Unsupported layer type"; @@ -260,10 +209,9 @@ void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) break; case ISurfaceComposerClient::eFXSurfaceBufferState: Transaction() - .setFrame(layerR, Rect(0, 0, 32, 32)) - .setFrame(layerG, Rect(8, 8, 40, 40)) + .setPosition(layerG, 8, 8) .setRelativeLayer(layerG, layerR, 3) - .setFrame(layerB, Rect(16, 16, 48, 48)) + .setPosition(layerB, 16, 16) .setLayer(layerB, mLayerZBase + 2) .apply(); break; @@ -388,7 +336,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState Transaction() .setTransparentRegionHint(layer, Region(top)) .setBuffer(layer, buffer) - .setFrame(layer, Rect(0, 0, 32, 32)) .apply(); { SCOPED_TRACE("top transparent"); @@ -447,7 +394,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_Buffe // check that transparent region hint is bound by the layer size Transaction() .setTransparentRegionHint(layerTransparent, Region(mDisplayRect)) - .setFrame(layerR, Rect(16, 16, 48, 48)) + .setPosition(layerR, 16, 16) .setLayer(layerR, mLayerZBase + 1) .apply(); ASSERT_NO_FATAL_FAILURE( @@ -477,8 +424,7 @@ void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) { Transaction() .setAlpha(layer1, 0.25f) .setAlpha(layer2, 0.75f) - .setFrame(layer1, Rect(0, 0, 32, 32)) - .setFrame(layer2, Rect(16, 0, 48, 32)) + .setPosition(layer2, 16, 0) .setLayer(layer2, mLayerZBase + 1) .apply(); break; @@ -573,7 +519,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height)); expectedColor = fillColor; } - Transaction().setFrame(layer, Rect(0, 0, width, height)).apply(); + Transaction().setCrop(layer, Rect(0, 0, width, height)).apply(); break; default: GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper"; @@ -614,44 +560,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) { } TEST_P(LayerRenderTypeTransactionTest, - SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) { - bool priorColor = false; - bool bufferFill = true; - float alpha = 1.0f; - Color finalColor = Color::RED; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, - priorColor, bufferFill, alpha, finalColor)); -} - -TEST_P(LayerRenderTypeTransactionTest, - SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) { - bool priorColor = false; - bool bufferFill = false; - float alpha = 1.0f; - Color finalColor = Color::GREEN; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, - priorColor, bufferFill, alpha, finalColor)); -} - -TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) { - bool priorColor = true; - bool bufferFill = true; - float alpha = 1.0f; - Color finalColor = Color::RED; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, - priorColor, bufferFill, alpha, finalColor)); -} - -TEST_P(LayerRenderTypeTransactionTest, - SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) { - bool priorColor = true; - bool bufferFill = false; - float alpha = 1.0f; - Color finalColor = Color::GREEN; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, - priorColor, bufferFill, alpha, finalColor)); -} -TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) { bool priorColor = false; bool bufferFill = false; @@ -849,42 +757,39 @@ TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE)); - Transaction() - .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f) - .setFrame(layer, Rect(0, 0, 32, 32)) - .apply(); + Transaction().setPosition(layer, 32, 32).setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).apply(); { SCOPED_TRACE("IDENTITY"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, + getScreenCapture()->expectQuadrant(Rect(32, 32, 64, 64), Color::RED, Color::GREEN, Color::BLUE, Color::WHITE); } Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply(); { SCOPED_TRACE("FLIP_H"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::GREEN, Color::RED, + Color::WHITE, Color::BLUE); } Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply(); { SCOPED_TRACE("FLIP_V"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(32, 0, 64, 32), Color::BLUE, Color::WHITE, + Color::RED, Color::GREEN); } Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply(); { SCOPED_TRACE("ROT_90"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(0, 32, 32, 64), Color::BLUE, Color::RED, + Color::WHITE, Color::GREEN); } Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply(); { SCOPED_TRACE("SCALE"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE); + getScreenCapture()->expectQuadrant(Rect(32, 32, 96, 96), Color::RED, Color::GREEN, + Color::BLUE, Color::WHITE, 1 /* tolerance */); } } @@ -911,29 +816,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) { shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE); } -TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) { - sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setMatrix is applied after any pending resize, unlike setPosition - Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply(); - { - SCOPED_TRACE("resize pending"); - auto shot = getScreenCapture(); - const Rect rect(0, 0, 32, 32); - shot->expectColor(rect, Color::RED); - shot->expectBorder(rect, Color::BLACK); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("resize applied"); - const Rect rect(0, 0, 128, 128); - getScreenCapture()->expectColor(rect, Color::RED); - } -} - TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); @@ -955,8 +837,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) { Transaction().setCrop(layer, crop).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(crop, Color::RED); + shot->expectBorder(crop, Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) { @@ -986,13 +868,13 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) { { SCOPED_TRACE("empty rect"); Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } { SCOPED_TRACE("negative rect"); Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } } @@ -1016,8 +898,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED); - Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply(); - Transaction().setBuffer(layer, buffer).apply(); // Partially out of bounds in the negative (upper left) direction @@ -1025,8 +905,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("out of bounds, negative (upper left) direction"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE); - shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 16), Color::BLUE); + shot->expectBorder(Rect(0, 0, 32, 16), Color::BLACK); } // Partially out of bounds in the positive (lower right) direction @@ -1034,8 +914,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("out of bounds, positive (lower right) direction"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 64), Color::RED); - shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 16, 32, 64), Color::RED); + shot->expectBorder(Rect(0, 16, 32, 64), Color::BLACK); } // Fully out of buffer space bounds @@ -1043,9 +923,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { { SCOPED_TRACE("Fully out of bounds"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE); - shot->expectColor(Rect(0, 16, 64, 64), Color::RED); - shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); + shot->expectColor(Rect(0, 0, 64, 64), Color::BLACK); } } @@ -1068,12 +946,11 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); - const Rect frame(32, 32, 64, 64); const Rect crop(8, 8, 24, 24); - Transaction().setFrame(layer, frame).setCrop(layer, crop).apply(); + Transaction().setPosition(layer, 32, 32).setCrop(layer, crop).apply(); auto shot = getScreenCapture(); - shot->expectColor(frame, Color::RED); - shot->expectBorder(frame, Color::BLACK); + shot->expectColor(Rect(40, 40, 56, 56), Color::RED); + shot->expectBorder(Rect(40, 40, 56, 56), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) { @@ -1091,29 +968,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) { shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK); } -TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) { - sp<SurfaceControl> layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setCrop is applied immediately by default, with or without resize pending - Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply(); - { - SCOPED_TRACE("resize pending"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(8, 8, 24, 24), Color::RED); - shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16)); - { - SCOPED_TRACE("resize applied"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(8, 8, 16, 16), Color::RED); - shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK); - } -} - TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { sp<SurfaceControl> layer; ASSERT_NO_FATAL_FAILURE( @@ -1121,7 +975,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); const Rect frame(8, 8, 24, 24); - Transaction().setFrame(layer, frame).apply(); + Transaction t; + TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), frame); + t.apply(); + auto shot = getScreenCapture(); shot->expectColor(frame, Color::RED); shot->expectBorder(frame, Color::BLACK); @@ -1133,16 +990,23 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + Transaction t; { SCOPED_TRACE("empty rect"); - Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply(); + TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 8, 8)); + t.apply(); + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); } { SCOPED_TRACE("negative rect"); - Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply(); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); + TransactionUtils::setFrame(t, layer, Rect(0, 0, 32, 32), Rect(8, 8, 0, 0)); + t.apply(); + + auto shot = getScreenCapture(); + shot->expectColor(Rect(0, 0, 8, 8), Color::RED); + shot->expectBorder(Rect(0, 0, 8, 8), Color::BLACK); } } @@ -1152,10 +1016,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) { layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10)); - // A parentless layer will default to a frame with the same size as the buffer + // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 10, 10), Color::RED); + shot->expectBorder(Rect(0, 0, 10, 10), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { @@ -1163,17 +1027,16 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { ASSERT_NO_FATAL_FAILURE( parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); - Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply(); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); - // A layer will default to the frame of its parent + // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1183,14 +1046,14 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); Transaction().reparent(child, parent).apply(); - // A layer will default to the frame of its parent + // A layer with a buffer will have a computed size that matches the buffer size. auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectColor(Rect(0, 0, 10, 10), Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1199,11 +1062,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) { ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); - Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply(); std::this_thread::sleep_for(500ms); - Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply(); + Transaction().setPosition(layer, 16, 16).apply(); auto shot = getScreenCapture(); shot->expectColor(Rect(16, 16, 48, 48), Color::RED); @@ -1215,18 +1077,20 @@ TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) { ASSERT_NO_FATAL_FAILURE( parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); ASSERT_NO_FATAL_FAILURE( - child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + child = createLayer("test", 10, 10, ISurfaceComposerClient::eFXSurfaceBufferState)); Transaction().reparent(child, parent).apply(); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); - Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply(); ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); - Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply(); + Rect childDst(0, 16, 32, 32); + Transaction t; + TransactionUtils::setFrame(t, child, Rect(0, 0, 10, 10), childDst); + t.apply(); auto shot = getScreenCapture(); shot->expectColor(Rect(0, 0, 32, 16), Color::RED); - shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE); + shot->expectColor(childDst, Color::BLUE); shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } @@ -1238,8 +1102,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { @@ -1252,8 +1116,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 1"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32)); @@ -1261,8 +1125,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 2"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); @@ -1270,8 +1134,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) { { SCOPED_TRACE("set buffer 3"); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } } @@ -1286,7 +1150,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64)); - Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply(); { SCOPED_TRACE("set layer 1 buffer red"); auto shot = getScreenCapture(); @@ -1295,7 +1158,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32)); - Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply(); { SCOPED_TRACE("set layer 2 buffer blue"); auto shot = getScreenCapture(); @@ -1350,8 +1212,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) { Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } idx++; } @@ -1383,8 +1245,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_Buffer Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } idx++; } @@ -1416,8 +1278,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferSt Color color = colors[idx % colors.size()]; auto shot = screenshot(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } if (idx == 0) { buffers[0].clear(); @@ -1435,7 +1297,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) { Color::BLUE, Color::WHITE)); Transaction() - .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90) .apply(); @@ -1452,7 +1313,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) { Color::BLUE, Color::WHITE)); Transaction() - .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H) .apply(); @@ -1469,7 +1329,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) { Color::BLUE, Color::WHITE)); Transaction() - .setFrame(layer, Rect(0, 0, 32, 32)) .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V) .apply(); @@ -1518,8 +1377,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) { Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { @@ -1534,8 +1393,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { @@ -1552,8 +1411,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { Transaction().setBuffer(layer, buffer).setHdrMetadata(layer, hdrMetadata).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) { @@ -1570,8 +1429,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) Transaction().setBuffer(layer, buffer).setSurfaceDamageRegion(layer, region).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { @@ -1586,8 +1445,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply(); auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); - shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); } TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) { diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 87c7b7d829..0bc8fe7aa0 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -244,6 +244,11 @@ protected: return bufferGenerator.get(outBuffer, outFence); } + static ui::Size getBufferSize() { + static BufferGenerator bufferGenerator; + return bufferGenerator.getSize(); + } + sp<SurfaceComposerClient> mClient; bool deviceSupportsBlurs() { diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index ac5e297e43..2828d61a76 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -51,14 +51,9 @@ INSTANTIATE_TEST_CASE_P( LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest, ::testing::Combine( ::testing::Values( - static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue), static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)), ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT))); -TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) { - // cannot test robustness against invalid sizes (zero or really huge) -} - TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) { sp<SurfaceControl> layerR; sp<SurfaceControl> layerG; @@ -196,17 +191,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size)); - if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { - Transaction() - .setCornerRadius(layer, cornerRadius) - .setCrop(layer, Rect(0, 0, size, size)) - .apply(); - } else { - Transaction() - .setCornerRadius(layer, cornerRadius) - .setFrame(layer, Rect(0, 0, size, size)) - .apply(); - } + Transaction().setCornerRadius(layer, cornerRadius).apply(); { const uint8_t bottom = size - 1; const uint8_t right = size - 1; @@ -234,19 +219,13 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) { ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size)); - auto transaction = Transaction() - .setCornerRadius(parent, cornerRadius) - .setCrop(parent, Rect(0, 0, size, size)) - .reparent(child, parent) - .setPosition(child, 0, size) - // Rotate by half PI - .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f); - if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { - transaction.setCrop(parent, Rect(0, 0, size, size)); - } else { - transaction.setFrame(parent, Rect(0, 0, size, size)); - } - transaction.apply(); + Transaction() + .setCornerRadius(parent, cornerRadius) + .reparent(child, parent) + .setPosition(child, 0, size) + // Rotate by half PI + .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f) + .apply(); { const uint8_t bottom = size - 1; @@ -275,21 +254,12 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) { ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2)); - if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { - Transaction() - .setCornerRadius(parent, cornerRadius) - .setCrop(parent, Rect(0, 0, size, size)) - .reparent(child, parent) - .setPosition(child, 0, size / 2) - .apply(); - } else { - Transaction() - .setCornerRadius(parent, cornerRadius) - .setFrame(parent, Rect(0, 0, size, size)) - .reparent(child, parent) - .setFrame(child, Rect(0, size / 2, size, size)) - .apply(); - } + Transaction() + .setCornerRadius(parent, cornerRadius) + .reparent(child, parent) + .setPosition(child, 0, size / 2) + .apply(); + { const uint8_t bottom = size - 1; const uint8_t right = size - 1; @@ -331,12 +301,9 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { Transaction() .setLayer(greenLayer, mLayerZBase) - .setFrame(leftLayer, {0, 0, canvasSize * 2, canvasSize * 2}) .setLayer(leftLayer, mLayerZBase + 1) - .setFrame(leftLayer, leftRect) .setLayer(rightLayer, mLayerZBase + 2) .setPosition(rightLayer, rightRect.left, rightRect.top) - .setFrame(rightLayer, rightRect) .apply(); { @@ -352,8 +319,6 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) { .setLayer(blurLayer, mLayerZBase + 3) .setBackgroundBlurRadius(blurLayer, blurRadius) .setCrop(blurLayer, blurRect) - .setFrame(blurLayer, blurRect) - .setSize(blurLayer, blurRect.getWidth(), blurRect.getHeight()) .setAlpha(blurLayer, 0.0f) .apply(); @@ -435,10 +400,8 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA Transaction() .setLayer(left, mLayerZBase + 1) - .setFrame(left, {0, 0, size, size}) .setLayer(right, mLayerZBase + 2) .setPosition(right, size, 0) - .setFrame(right, {size, 0, size * 2, size}) .apply(); { @@ -457,7 +420,6 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurAffectedByParentA .setAlpha(blurParent, 0.5) .setLayer(blur, mLayerZBase + 4) .setBackgroundBlurRadius(blur, size) // set the blur radius to the size of one rect - .setFrame(blur, {0, 0, size * 2, size}) .reparent(blur, blurParent) .apply(); diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index 39d9206e1a..ee4d367f3d 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -127,15 +127,7 @@ protected: TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); waitForPostedBuffers(); } - void restoreInitialState() { - asTransaction([&](Transaction& t) { - t.setSize(mFGSurfaceControl, 64, 64); - t.setPosition(mFGSurfaceControl, 64, 64); - t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64)); - }); - EXPECT_INITIAL_STATE("After restoring initial state"); - } std::unique_ptr<ScreenCapture> sc; }; @@ -160,61 +152,6 @@ protected: } }; -TEST_F(LayerUpdateTest, DeferredTransactionTest) { - std::unique_ptr<ScreenCapture> sc; - { - SCOPED_TRACE("before anything"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(32, 32); - sc->expectFGColor(96, 96); - sc->expectBGColor(160, 160); - } - - // set up two deferred transactions on different frames - asTransaction([&](Transaction& t) { - t.setAlpha(mFGSurfaceControl, 0.75); - t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl, - mSyncSurfaceControl->getSurface()->getNextFrameNumber()); - }); - - asTransaction([&](Transaction& t) { - t.setPosition(mFGSurfaceControl, 128, 128); - t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl, - mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1); - }); - - { - SCOPED_TRACE("before any trigger"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(32, 32); - sc->expectFGColor(96, 96); - sc->expectBGColor(160, 160); - } - - // should trigger the first deferred transaction, but not the second one - TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); - { - SCOPED_TRACE("after first trigger"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(32, 32); - sc->checkPixel(96, 96, 162, 63, 96); - sc->expectBGColor(160, 160); - } - - // should show up immediately since it's not deferred - asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); }); - - // trigger the second deferred transaction - TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); - { - SCOPED_TRACE("after second trigger"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(32, 32); - sc->expectBGColor(96, 96); - sc->expectFGColor(160, 160); - } -} - TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) { std::unique_ptr<ScreenCapture> sc; @@ -517,221 +454,6 @@ TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) { } } -TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - }); - - { - mCapture = screenshot(); - // We've positioned the child in the top left. - mCapture->expectChildColor(0, 0); - // But it's only 10x15. - mCapture->expectFGColor(10, 15); - } - - asTransaction([&](Transaction& t) { - mFGSurfaceControl->getSurface()->setScalingMode( - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - // Resubmit buffer with new scaling mode - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - // We cause scaling by 2. - t.setSize(mFGSurfaceControl, 128, 128); - }); - - { - mCapture = screenshot(); - // We've positioned the child in the top left. - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(10, 10); - mCapture->expectChildColor(19, 29); - // And now it should be scaled all the way to 20x30 - mCapture->expectFGColor(20, 30); - } -} - -// Regression test for b/37673612 -TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - }); - - { - mCapture = screenshot(); - // We've positioned the child in the top left. - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(9, 14); - // But it's only 10x15. - mCapture->expectFGColor(10, 15); - } - // We set things up as in b/37673612 so that there is a mismatch between the buffer size and - // the WM specified state size. - asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); }); - sp<Surface> s = mFGSurfaceControl->getSurface(); - auto anw = static_cast<ANativeWindow*>(s.get()); - native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); - native_window_set_buffers_dimensions(anw, 64, 128); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - waitForPostedBuffers(); - - { - // The child should still be in the same place and not have any strange scaling as in - // b/37673612. - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectFGColor(10, 10); - } -} - -// A child with a buffer transform from its parents should be cropped by its parent bounds. -TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - t.setSize(mChild, 100, 100); - }); - TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200); - - { - mCapture = screenshot(); - - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(63, 63); - mCapture->expectBGColor(64, 64); - } - - asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); }); - sp<Surface> s = mFGSurfaceControl->getSurface(); - auto anw = static_cast<ANativeWindow*>(s.get()); - // Apply a 90 transform on the buffer. - native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); - native_window_set_buffers_dimensions(anw, 64, 128); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - waitForPostedBuffers(); - - // The child should be cropped by the new parent bounds. - { - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(99, 63); - mCapture->expectFGColor(100, 63); - mCapture->expectBGColor(128, 64); - } -} - -// A child with a scale transform from its parents should be cropped by its parent bounds. -TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - t.setSize(mChild, 200, 200); - }); - TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200); - - { - mCapture = screenshot(); - - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(63, 63); - mCapture->expectBGColor(64, 64); - } - - asTransaction([&](Transaction& t) { - mFGSurfaceControl->getSurface()->setScalingMode( - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - // Resubmit buffer with new scaling mode - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - // Set a scaling by 2. - t.setSize(mFGSurfaceControl, 128, 128); - }); - - // Child should inherit its parents scale but should be cropped by its parent bounds. - { - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(127, 127); - mCapture->expectBGColor(128, 128); - } -} - -// Regression test for b/127368943 -// Child should ignore the buffer transform but apply parent scale transform. -TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 0, 0); - t.setPosition(mFGSurfaceControl, 0, 0); - }); - - { - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(9, 14); - mCapture->expectFGColor(10, 15); - } - - // Change the size of the foreground to 128 * 64 so we can test rotation as well. - asTransaction([&](Transaction& t) { - mFGSurfaceControl->getSurface()->setScalingMode( - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - // Resubmit buffer with new scaling mode - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - t.setSize(mFGSurfaceControl, 128, 64); - }); - sp<Surface> s = mFGSurfaceControl->getSurface(); - auto anw = static_cast<ANativeWindow*>(s.get()); - // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we - // have an effective scale of 2.0 applied to the buffer along with a rotation transform. - native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); - native_window_set_buffers_dimensions(anw, 32, 64); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); - waitForPostedBuffers(); - - // The child should ignore the buffer transform but apply the 2.0 scale from parent. - { - mCapture = screenshot(); - mCapture->expectChildColor(0, 0); - mCapture->expectChildColor(19, 29); - mCapture->expectFGColor(20, 30); - } -} - -TEST_F(ChildLayerTest, Bug36858924) { - // Destroy the child layer - mChild.clear(); - - // Now recreate it as hidden - mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eHidden, mFGSurfaceControl.get()); - - // Show the child layer in a deferred transaction - asTransaction([&](Transaction& t) { - t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl, - mFGSurfaceControl->getSurface()->getNextFrameNumber()); - t.show(mChild); - }); - - // Render the foreground surface a few times - // - // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third - // frame because SurfaceFlinger would never process the deferred transaction and would therefore - // never acquire/release the first buffer - ALOGI("Filling 1"); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0); - ALOGI("Filling 2"); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255); - ALOGI("Filling 3"); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0); - ALOGI("Filling 4"); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0); -} - TEST_F(ChildLayerTest, Reparent) { asTransaction([&](Transaction& t) { t.show(mChild); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index 613b21ef04..ccf434d63a 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -195,7 +195,7 @@ TEST_F(MirrorLayerTest, MirrorBufferLayer) { createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState, mChildLayer.get()); fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200); - Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply(); + Transaction().show(bufferStateLayer).apply(); { SCOPED_TRACE("Initial Mirror BufferStateLayer"); diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index b0753c842e..2e9c10ce5c 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -350,7 +350,10 @@ TEST_F(ScreenCaptureTest, CaptureBoundlessLayerWithoutSourceCropFails) { TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) { sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10, - PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + mFGSurfaceControl.get()); + SurfaceComposerClient::Transaction().show(child).apply(true); sp<GraphicBuffer> outBuffer; @@ -361,7 +364,7 @@ TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) { ScreenCaptureResults captureResults; ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(args, captureResults)); - TransactionUtils::fillSurfaceRGBA8(child, Color::RED); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::RED, 32, 32)); SurfaceComposerClient::Transaction().apply(true); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(args, captureResults)); ScreenCapture sc(captureResults.buffer); @@ -432,12 +435,15 @@ TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) { } TEST_F(ScreenCaptureTest, CaptureCrop) { - sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0); + sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, + ISurfaceComposerClient::eFXSurfaceBufferState); sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30, - PIXEL_FORMAT_RGBA_8888, 0, redLayer.get()); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + redLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(blueLayer, Color::BLUE, 30, 30)); SurfaceComposerClient::Transaction() .setLayer(redLayer, INT32_MAX - 1) @@ -464,12 +470,15 @@ TEST_F(ScreenCaptureTest, CaptureCrop) { } TEST_F(ScreenCaptureTest, CaptureSize) { - sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0); + sp<SurfaceControl> redLayer = + createLayer(String8("Red surface"), 60, 60, ISurfaceComposerClient::eFXSurfaceBufferState); sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30, - PIXEL_FORMAT_RGBA_8888, 0, redLayer.get()); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + redLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(blueLayer, Color::BLUE, 30, 30)); SurfaceComposerClient::Transaction() .setLayer(redLayer, INT32_MAX - 1) @@ -489,6 +498,7 @@ TEST_F(ScreenCaptureTest, CaptureSize) { captureArgs.frameScaleX = 0.5f; captureArgs.frameScaleY = 0.5f; + sleep(1); ScreenCapture::captureLayers(&mCapture, captureArgs); // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area. @@ -519,14 +529,15 @@ TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { } TEST_F(ScreenCaptureTest, CaputureSecureLayer) { - sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0); + sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, + ISurfaceComposerClient::eFXSurfaceBufferState); sp<SurfaceControl> secureLayer = createLayer(String8("Secure surface"), 30, 30, ISurfaceComposerClient::eSecure | - ISurfaceComposerClient::eFXSurfaceBufferQueue, + ISurfaceComposerClient::eFXSurfaceBufferState, redLayer.get()); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(secureLayer, Color::BLUE, 30, 30)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(redLayer, Color::RED, 60, 60)); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(secureLayer, Color::BLUE, 30, 30)); auto redLayerHandle = redLayer->getHandle(); Transaction() @@ -874,4 +885,4 @@ TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 09bd775872..ee4e863474 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -44,7 +44,6 @@ constexpr uint32_t BUFFER_UPDATES = 18; constexpr uint32_t LAYER_UPDATE = INT_MAX - 2; constexpr uint32_t SIZE_UPDATE = 134; constexpr uint32_t STACK_UPDATE = 1; -constexpr uint64_t DEFERRED_UPDATE = 0; constexpr int32_t RELATIVE_Z = 42; constexpr float ALPHA_UPDATE = 0.29f; constexpr float CORNER_RADIUS_UPDATE = 0.2f; @@ -191,7 +190,6 @@ public: bool hiddenFlagUpdateFound(const SurfaceChange& change, bool foundHiddenFlag); bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag); bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag); - bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred); bool reparentUpdateFound(const SurfaceChange& change, bool found); bool relativeParentUpdateFound(const SurfaceChange& change, bool found); bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found); @@ -227,7 +225,6 @@ public: void hiddenFlagUpdate(Transaction&); void opaqueFlagUpdate(Transaction&); void secureFlagUpdate(Transaction&); - void deferredTransactionUpdate(Transaction&); void reparentUpdate(Transaction&); void relativeParentUpdate(Transaction&); void shadowRadiusUpdate(Transaction&); @@ -396,10 +393,6 @@ void SurfaceInterceptorTest::secureFlagUpdate(Transaction& t) { t.setFlags(mBGSurfaceControl, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure); } -void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) { - t.deferTransactionUntil_legacy(mBGSurfaceControl, mBGSurfaceControl, DEFERRED_UPDATE); -} - void SurfaceInterceptorTest::reparentUpdate(Transaction& t) { t.reparent(mBGSurfaceControl, mFGSurfaceControl); } @@ -437,7 +430,6 @@ void SurfaceInterceptorTest::runAllUpdates() { runInTransaction(&SurfaceInterceptorTest::hiddenFlagUpdate); runInTransaction(&SurfaceInterceptorTest::opaqueFlagUpdate); runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate); - runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate); runInTransaction(&SurfaceInterceptorTest::reparentUpdate); runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate); runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate); @@ -621,18 +613,6 @@ bool SurfaceInterceptorTest::secureFlagUpdateFound(const SurfaceChange& change, return foundSecureFlag; } -bool SurfaceInterceptorTest::deferredTransactionUpdateFound(const SurfaceChange& change, - bool foundDeferred) { - bool hasId(change.deferred_transaction().layer_id() == mBGLayerId); - bool hasFrameNumber(change.deferred_transaction().frame_number() == DEFERRED_UPDATE); - if (hasId && hasFrameNumber && !foundDeferred) { - foundDeferred = true; - } else if (hasId && hasFrameNumber && foundDeferred) { - [] () { FAIL(); }(); - } - return foundDeferred; -} - bool SurfaceInterceptorTest::reparentUpdateFound(const SurfaceChange& change, bool found) { bool hasId(change.reparent().parent_id() == mFGLayerId); if (hasId && !found) { @@ -715,9 +695,6 @@ bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace, case SurfaceChange::SurfaceChangeCase::kSecureFlag: foundUpdate = secureFlagUpdateFound(change, foundUpdate); break; - case SurfaceChange::SurfaceChangeCase::kDeferredTransaction: - foundUpdate = deferredTransactionUpdateFound(change, foundUpdate); - break; case SurfaceChange::SurfaceChangeCase::kReparent: foundUpdate = reparentUpdateFound(change, foundUpdate); break; @@ -749,7 +726,6 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) { ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kHiddenFlag)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOpaqueFlag)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSecureFlag)); - ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDeferredTransaction)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent)); } @@ -906,11 +882,6 @@ TEST_F(SurfaceInterceptorTest, InterceptSecureFlagUpdateWorks) { SurfaceChange::SurfaceChangeCase::kSecureFlag); } -TEST_F(SurfaceInterceptorTest, InterceptDeferredTransactionUpdateWorks) { - captureTest(&SurfaceInterceptorTest::deferredTransactionUpdate, - SurfaceChange::SurfaceChangeCase::kDeferredTransaction); -} - TEST_F(SurfaceInterceptorTest, InterceptReparentUpdateWorks) { captureTest(&SurfaceInterceptorTest::reparentUpdate, SurfaceChange::SurfaceChangeCase::kReparent); @@ -950,11 +921,6 @@ TEST_F(SurfaceInterceptorTest, InterceptDisplayDeletionWorks) { ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kDisplayDeletion)); } -TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) { - captureTest(&SurfaceInterceptorTest::nBufferUpdates, - &SurfaceInterceptorTest::bufferUpdatesFound); -} - // If the interceptor is enabled while buffer updates are being pushed, the interceptor should // first create a snapshot of the existing displays and surfaces and then start capturing // the buffer updates @@ -970,26 +936,6 @@ TEST_F(SurfaceInterceptorTest, InterceptWhileBufferUpdatesWorks) { const auto& firstIncrement = capturedTrace.mutable_increment(0); ASSERT_EQ(firstIncrement->increment_case(), Increment::IncrementCase::kDisplayCreation); } - -TEST_F(SurfaceInterceptorTest, InterceptSimultaneousUpdatesWorks) { - enableInterceptor(); - setupBackgroundSurface(); - std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this); - std::thread surfaceUpdates(&SurfaceInterceptorTest::runAllUpdates, this); - runInTransaction(&SurfaceInterceptorTest::surfaceCreation); - bufferUpdates.join(); - surfaceUpdates.join(); - disableInterceptor(); - - Trace capturedTrace; - ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace)); - preProcessTrace(capturedTrace); - - assertAllUpdatesFound(capturedTrace); - ASSERT_TRUE(bufferUpdatesFound(capturedTrace)); - ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation)); } -} - // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index c081f9b642..162711d6f5 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -91,7 +91,6 @@ constexpr static TestColor RED = {195, 63, 63, 255}; constexpr static TestColor LIGHT_RED = {255, 177, 177, 255}; constexpr static TestColor GREEN = {63, 195, 63, 255}; constexpr static TestColor BLUE = {63, 63, 195, 255}; -constexpr static TestColor DARK_GRAY = {63, 63, 63, 255}; constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255}; // Fill an RGBA_8888 formatted surface with a single color. @@ -1294,31 +1293,6 @@ protected: EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); } - void Test_LayerResize() { - ALOGD("TransactionTest::LayerResize"); - { - TransactionScope ts(*sFakeComposer); - ts.setSize(mFGSurfaceControl, 128, 128); - } - - fillSurfaceRGBA8(mFGSurfaceControl, GREEN); - sFakeComposer->runVSyncAndWait(); - - ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and - // there's no extra frames. - - auto frame1Ref = mBaseFrame; - // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size - // posted. - EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1))); - - auto frame2Ref = frame1Ref; - frame2Ref[FG_LAYER].mSwapCount++; - frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128}; - frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f}; - EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2))); - } - void Test_LayerCrop() { // TODO: Add scaling to confirm that crop happens in buffer space? { @@ -1469,77 +1443,6 @@ protected: } } - void Test_DeferredTransaction() { - // Synchronization surface - constexpr static int SYNC_LAYER = 2; - auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1, - PIXEL_FORMAT_RGBA_8888, 0); - ASSERT_TRUE(syncSurfaceControl != nullptr); - ASSERT_TRUE(syncSurfaceControl->isValid()); - - fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); - - { - TransactionScope ts(*sFakeComposer); - ts.setLayer(syncSurfaceControl, INT32_MAX - 1); - ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2); - ts.show(syncSurfaceControl); - } - auto referenceFrame = mBaseFrame; - referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2, - mDisplayWidth - 1, mDisplayHeight - 1)); - referenceFrame[SYNC_LAYER].mSwapCount = 1; - EXPECT_EQ(2, sFakeComposer->getFrameCount()); - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - // set up two deferred transactions on different frames - these should not yield composited - // frames - { - TransactionScope ts(*sFakeComposer); - ts.setAlpha(mFGSurfaceControl, 0.75); - ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl, - syncSurfaceControl->getSurface()->getNextFrameNumber()); - } - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - { - TransactionScope ts(*sFakeComposer); - ts.setPosition(mFGSurfaceControl, 128, 128); - ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl, - syncSurfaceControl->getSurface()->getNextFrameNumber() + - 1); - } - EXPECT_EQ(4, sFakeComposer->getFrameCount()); - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - // should trigger the first deferred transaction, but not the second one - fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); - sFakeComposer->runVSyncAndWait(); - EXPECT_EQ(5, sFakeComposer->getFrameCount()); - - referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f; - referenceFrame[SYNC_LAYER].mSwapCount++; - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - // should show up immediately since it's not deferred - { - TransactionScope ts(*sFakeComposer); - ts.setAlpha(mFGSurfaceControl, 1.0); - } - referenceFrame[FG_LAYER].mPlaneAlpha = 1.f; - EXPECT_EQ(6, sFakeComposer->getFrameCount()); - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - // trigger the second deferred transaction - fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); - sFakeComposer->runVSyncAndWait(); - // TODO: Compute from layer size? - referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64}; - referenceFrame[SYNC_LAYER].mSwapCount++; - EXPECT_EQ(7, sFakeComposer->getFrameCount()); - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - } - void Test_SetRelativeLayer() { constexpr int RELATIVE_LAYER = 2; auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, @@ -1589,10 +1492,6 @@ TEST_F(TransactionTest_2_1, DISABLED_LayerMove) { Test_LayerMove(); } -TEST_F(TransactionTest_2_1, DISABLED_LayerResize) { - Test_LayerResize(); -} - TEST_F(TransactionTest_2_1, DISABLED_LayerCrop) { Test_LayerCrop(); } @@ -1625,10 +1524,6 @@ TEST_F(TransactionTest_2_1, DISABLED_LayerSetMatrix) { Test_LayerSetMatrix(); } -TEST_F(TransactionTest_2_1, DISABLED_DeferredTransaction) { - Test_DeferredTransaction(); -} - TEST_F(TransactionTest_2_1, DISABLED_SetRelativeLayer) { Test_SetRelativeLayer(); } @@ -1766,77 +1661,6 @@ protected: EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame())); } - // Regression test for b/37673612 - void Test_ChildrenWithParentBufferTransform() { - { - TransactionScope ts(*Base::sFakeComposer); - ts.show(mChild); - ts.setPosition(mChild, 0, 0); - ts.setPosition(Base::mFGSurfaceControl, 0, 0); - } - - // We set things up as in b/37673612 so that there is a mismatch between the buffer size and - // the WM specified state size. - { - TransactionScope ts(*Base::sFakeComposer); - ts.setSize(Base::mFGSurfaceControl, 128, 64); - } - - sp<Surface> s = Base::mFGSurfaceControl->getSurface(); - auto anw = static_cast<ANativeWindow*>(s.get()); - native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); - native_window_set_buffers_dimensions(anw, 64, 128); - fillSurfaceRGBA8(Base::mFGSurfaceControl, RED); - Base::sFakeComposer->runVSyncAndWait(); - - // The child should still be in the same place and not have any strange scaling as in - // b/37673612. - auto referenceFrame = Base::mBaseFrame; - referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64}; - referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f}; - referenceFrame[Base::FG_LAYER].mSwapCount++; - referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10}; - EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame())); - } - - void Test_Bug36858924() { - // Destroy the child layer - mChild.clear(); - - // Now recreate it as hidden - mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10, - PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eHidden, - Base::mFGSurfaceControl->getHandle()); - - // Show the child layer in a deferred transaction - { - TransactionScope ts(*Base::sFakeComposer); - ts.deferTransactionUntil_legacy(mChild, Base::mFGSurfaceControl, - Base::mFGSurfaceControl->getSurface() - ->getNextFrameNumber()); - ts.show(mChild); - } - - // Render the foreground surface a few times - // - // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the - // third frame because SurfaceFlinger would never process the deferred transaction and would - // therefore never acquire/release the first buffer - ALOGI("Filling 1"); - fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN); - Base::sFakeComposer->runVSyncAndWait(); - ALOGI("Filling 2"); - fillSurfaceRGBA8(Base::mFGSurfaceControl, BLUE); - Base::sFakeComposer->runVSyncAndWait(); - ALOGI("Filling 3"); - fillSurfaceRGBA8(Base::mFGSurfaceControl, RED); - Base::sFakeComposer->runVSyncAndWait(); - ALOGI("Filling 4"); - fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN); - Base::sFakeComposer->runVSyncAndWait(); - } - sp<SurfaceControl> mChild; }; @@ -1862,15 +1686,6 @@ TEST_F(ChildLayerTest_2_1, DISABLED_LayerAlpha) { Test_LayerAlpha(); } -// Regression test for b/37673612 -TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) { - Test_ChildrenWithParentBufferTransform(); -} - -TEST_F(ChildLayerTest_2_1, DISABLED_Bug36858924) { - Test_Bug36858924(); -} - template <typename FakeComposerService> class ChildColorLayerTest : public ChildLayerTest<FakeComposerService> { using Base = ChildLayerTest<FakeComposerService>; @@ -1960,91 +1775,6 @@ TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerAlpha) { TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerZeroAlpha) { Test_LayerZeroAlpha(); } - -template <typename FakeComposerService> -class LatchingTest : public TransactionTest<FakeComposerService> { - using Base = TransactionTest<FakeComposerService>; - -protected: - void lockAndFillFGBuffer() { fillSurfaceRGBA8(Base::mFGSurfaceControl, RED, false); } - - void unlockFGBuffer() { - sp<Surface> s = Base::mFGSurfaceControl->getSurface(); - ASSERT_EQ(NO_ERROR, s->unlockAndPost()); - Base::sFakeComposer->runVSyncAndWait(); - } - - void completeFGResize() { - fillSurfaceRGBA8(Base::mFGSurfaceControl, RED); - Base::sFakeComposer->runVSyncAndWait(); - } - void restoreInitialState() { - TransactionScope ts(*Base::sFakeComposer); - ts.setSize(Base::mFGSurfaceControl, 64, 64); - ts.setPosition(Base::mFGSurfaceControl, 64, 64); - ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 64, 64)); - } - - void Test_SurfacePositionLatching() { - // By default position can be updated even while - // a resize is pending. - { - TransactionScope ts(*Base::sFakeComposer); - ts.setSize(Base::mFGSurfaceControl, 32, 32); - ts.setPosition(Base::mFGSurfaceControl, 100, 100); - } - - // The size should not have updated as we have not provided a new buffer. - auto referenceFrame1 = Base::mBaseFrame; - referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64}; - EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame())); - - restoreInitialState(); - - completeFGResize(); - - auto referenceFrame2 = Base::mBaseFrame; - referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32}; - referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f}; - referenceFrame2[Base::FG_LAYER].mSwapCount++; - EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame())); - } - - void Test_CropLatching() { - // Normally the crop applies immediately even while a resize is pending. - { - TransactionScope ts(*Base::sFakeComposer); - ts.setSize(Base::mFGSurfaceControl, 128, 128); - ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 63, 63)); - } - - auto referenceFrame1 = Base::mBaseFrame; - referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; - referenceFrame1[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; - EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame())); - - restoreInitialState(); - - completeFGResize(); - - auto referenceFrame2 = Base::mBaseFrame; - referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63}; - referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f}; - referenceFrame2[Base::FG_LAYER].mSwapCount++; - EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame())); - } -}; - -using LatchingTest_2_1 = LatchingTest<FakeComposerService_2_1>; - -TEST_F(LatchingTest_2_1, DISABLED_SurfacePositionLatching) { - Test_SurfacePositionLatching(); -} - -TEST_F(LatchingTest_2_1, DISABLED_CropLatching) { - Test_CropLatching(); -} - } // namespace int main(int argc, char** argv) { diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index af7d4da478..89ffee6952 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -119,6 +119,7 @@ cc_test { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", + "android.hardware.power-V1-cpp", "libcompositionengine_mocks", "libcompositionengine", "libframetimeline", @@ -130,6 +131,7 @@ cc_test { "librenderengine", "libserviceutils", "libtimestats", + "libtimestats_atoms_proto", "libtimestats_proto", "libtrace_proto", "perfetto_trace_protos", @@ -142,7 +144,6 @@ cc_test { "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.common@1.2", - "android.hardware.power-V1-cpp", "libbase", "libbinder", "libcutils", @@ -157,14 +158,10 @@ cc_test { "libnativewindow", "libprocessgroup", "libprotobuf-cpp-lite", - "libprotoutil", - "libstatslog", - "libstatssocket", "libSurfaceFlingerProp", "libsync", "libui", "libutils", - "libstatspull", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4e1c0c77ea..3042450f29 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -15,6 +15,7 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues +#include "renderengine/ExternalTexture.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" @@ -194,7 +195,7 @@ public: sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE; - sp<GraphicBuffer> mCaptureScreenBuffer; + std::shared_ptr<renderengine::ExternalTexture> mCaptureScreenBuffer; }; template <typename LayerCase> @@ -243,11 +244,15 @@ void CompositionTest::captureScreenComposition() { // TODO: Eliminate expensive/real allocation if possible. const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - mCaptureScreenBuffer = new GraphicBuffer(renderArea->getReqWidth(), renderArea->getReqHeight(), - HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot"); + mCaptureScreenBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(renderArea->getReqWidth(), + renderArea->getReqHeight(), + HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, + "screenshot"), + *mRenderEngine, true); status_t result = - mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(), + mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, forSystem, regionSampling); EXPECT_EQ(NO_ERROR, result); @@ -340,8 +345,8 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, const std::vector<const renderengine::LayerSettings*>&, - const sp<GraphicBuffer>&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr<renderengine::ExternalTexture>&, + const bool, base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -389,8 +394,8 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, const std::vector<const renderengine::LayerSettings*>&, - const sp<GraphicBuffer>&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr<renderengine::ExternalTexture>&, + const bool, base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -625,8 +630,8 @@ struct BaseLayerProperties { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector<const renderengine::LayerSettings*>& layerSettings, - const sp<GraphicBuffer>&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -674,8 +679,8 @@ struct BaseLayerProperties { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector<const renderengine::LayerSettings*>& layerSettings, - const sp<GraphicBuffer>&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -751,8 +756,8 @@ struct CommonSecureLayerProperties : public BaseLayerProperties<LayerProperties> EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector<const renderengine::LayerSettings*>& layerSettings, - const sp<GraphicBuffer>&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 7cc0032bc8..b4a1481e9c 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -44,7 +44,7 @@ namespace { constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID(111); constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID(222); constexpr PhysicalDisplayId DISPLAY_ID_64BIT(0xabcd12349876fedcULL); - +constexpr std::chrono::duration VSYNC_PERIOD(16ms); class MockVSyncSource : public VSyncSource { public: const char* getName() const override { return "test"; } @@ -166,11 +166,14 @@ void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) { mThrottleVsyncCallRecorder.getInvocable()(expectedVsyncTimestamp, uid); return (uid == mThrottledConnectionUid); }; + const auto getVsyncPeriod = [](uid_t uid) { + return VSYNC_PERIOD.count(); + }; mThread = std::make_unique<impl::EventThread>(std::move(source), /*tokenManager=*/nullptr, mInterceptVSyncCallRecorder.getInvocable(), - throttleVsync); + throttleVsync, getVsyncPeriod); // EventThread should register itself as VSyncSource callback. mCallback = expectVSyncSetCallbackCallReceived(); diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 982252f0be..8a3f561487 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -68,7 +68,7 @@ public: void SetUp() override { mTimeStats = std::make_shared<mock::TimeStats>(); mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid, - kTestThresholds, kHwcDuration); + kTestThresholds); mFrameTimeline->registerDataSource(); mTokenManager = &mFrameTimeline->mTokenManager; mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter; @@ -163,7 +163,6 @@ public: static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold, kDeadlineThreshold, kStartThreshold}; - static constexpr nsecs_t kHwcDuration = std::chrono::nanoseconds(3ns).count(); }; static const std::string sLayerNameOne = "layer1"; @@ -483,7 +482,6 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) { TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { Fps refreshRate = Fps::fromPeriodNsecs(11); - // Deadline delta is 2ms because, sf's adjusted deadline is 60 - composerTime(3) = 57ms. EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, @@ -504,7 +502,34 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest(70); - mFrameTimeline->setSfPresent(59, presentFence1); + mFrameTimeline->setSfPresent(62, presentFence1); +} + +TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { + Fps refreshRate = Fps::fromPeriodNsecs(11); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames( + TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, + sLayerNameOne, + JankType::SurfaceFlingerGpuDeadlineMissed, 4, 10, + 0})); + auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); + int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerIdOne, sLayerNameOne, + sLayerNameOne, /*isBuffer*/ true); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + surfaceFrame1->setAcquireFenceTime(20); + surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); + mFrameTimeline->addSurfaceFrame(surfaceFrame1); + gpuFence1->signalForTest(64); + presentFence1->signalForTest(70); + + mFrameTimeline->setSfPresent(59, presentFence1, gpuFence1); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { @@ -512,7 +537,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, JankType::DisplayHAL, - -1, 0, 0})); + -4, 0, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); @@ -536,7 +561,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, - JankType::AppDeadlineMissed, -1, 0, + JankType::AppDeadlineMissed, -4, 0, 25})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); @@ -563,7 +588,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, JankType::SurfaceFlingerScheduling, - -1, 0, -10})); + -4, 0, -10})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({40, 60, 92}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); @@ -588,7 +613,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, - JankType::PredictionError, -1, 5, + JankType::PredictionError, -4, 5, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 60}); @@ -614,7 +639,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, - JankType::BufferStuffing, -1, 0, + JankType::BufferStuffing, -4, 0, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 58}); @@ -642,7 +667,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne, - JankType::AppDeadlineMissed, -1, 0, 25})); + JankType::AppDeadlineMissed, -4, 0, 25})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); @@ -671,7 +696,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne, JankType::Unknown | JankType::AppDeadlineMissed, - -1, -1, 25})); + 0, 0, 25})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); @@ -1322,6 +1347,81 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpecte validateTraceEvent(actualSurfaceFrameEnd, protoActualSurfaceFrameEnd); } +TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTracedProperly) { + auto tracingSession = getTracingSessionForTest(); + auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + + tracingSession->StartBlocking(); + constexpr nsecs_t appStartTime = std::chrono::nanoseconds(10ms).count(); + constexpr nsecs_t appEndTime = std::chrono::nanoseconds(20ms).count(); + constexpr nsecs_t appPresentTime = std::chrono::nanoseconds(30ms).count(); + int64_t surfaceFrameToken = + mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime}); + + // Flush the token so that it would expire + flushTokens(systemTime() + maxTokenRetentionTime); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, + sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, + sLayerNameOne, /*isBuffer*/ true); + + constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(22ms).count(); + constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count(); + constexpr nsecs_t sfPresentTime = std::chrono::nanoseconds(30ms).count(); + int64_t displayFrameToken = + mTokenManager->generateTokenForPredictions({sfStartTime, sfEndTime, sfPresentTime}); + + // First 2 cookies will be used by the DisplayFrame + int64_t traceCookie = snoopCurrentTraceCookie() + 2; + + auto protoActualSurfaceFrameStart = + createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken, + displayFrameToken, sPidOne, sLayerNameOne, + FrameTimelineEvent::PRESENT_DROPPED, false, false, + FrameTimelineEvent::JANK_NONE, + FrameTimelineEvent::PREDICTION_EXPIRED); + auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1); + + // Set up the display frame + mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, Fps::fromPeriodNsecs(11)); + surfaceFrame1->setDropTime(sfStartTime); + surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped); + mFrameTimeline->addSurfaceFrame(surfaceFrame1); + mFrameTimeline->setSfPresent(sfEndTime, presentFence1); + presentFence1->signalForTest(sfPresentTime); + + addEmptyDisplayFrame(); + flushTrace(); + tracingSession->StopBlocking(); + + auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); + // Display Frame 4 packets + SurfaceFrame 2 packets + ASSERT_EQ(packets.size(), 6u); + + // Packet - 4 : ActualSurfaceFrameStart + const auto& packet4 = packets[4]; + ASSERT_TRUE(packet4.has_timestamp()); + EXPECT_EQ(packet4.timestamp(), + static_cast<uint64_t>(sfStartTime - SurfaceFrame::kPredictionExpiredStartTimeDelta)); + ASSERT_TRUE(packet4.has_frame_timeline_event()); + + const auto& event4 = packet4.frame_timeline_event(); + ASSERT_TRUE(event4.has_actual_surface_frame_start()); + const auto& actualSurfaceFrameStart = event4.actual_surface_frame_start(); + validateTraceEvent(actualSurfaceFrameStart, protoActualSurfaceFrameStart); + + // Packet - 5 : FrameEnd (ActualSurfaceFrame) + const auto& packet5 = packets[5]; + ASSERT_TRUE(packet5.has_timestamp()); + EXPECT_EQ(packet5.timestamp(), static_cast<uint64_t>(sfStartTime)); + ASSERT_TRUE(packet5.has_frame_timeline_event()); + + const auto& event5 = packet5.frame_timeline_event(); + ASSERT_TRUE(event5.has_frame_end()); + const auto& actualSurfaceFrameEnd = event5.frame_end(); + validateTraceEvent(actualSurfaceFrameEnd, protoActualSurfaceFrameEnd); +} + // Tests for Jank classification TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { // Layer specific increment @@ -1458,24 +1558,47 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent) } TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) { + /* + * Case 1 - cpu time > vsync period but combined time > deadline > deadline -> cpudeadlinemissed + * Case 2 - cpu time < vsync period but combined time > deadline -> gpudeadlinemissed + */ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + auto gpuFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40}); + int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + // case 1 - cpu time = 33 - 12 = 21, vsync period = 11 mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11)); - mFrameTimeline->setSfPresent(36, presentFence1); - auto displayFrame = getDisplayFrame(0); + mFrameTimeline->setSfPresent(33, presentFence1, gpuFence1); + auto displayFrame0 = getDisplayFrame(0); + gpuFence1->signalForTest(36); presentFence1->signalForTest(52); // Fences haven't been flushed yet, so it should be 0 - EXPECT_EQ(displayFrame->getActuals().presentTime, 0); + EXPECT_EQ(displayFrame0->getActuals().presentTime, 0); + + // case 2 - cpu time = 56 - 52 = 4, vsync period = 11 + mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfPresent(56, presentFence2, gpuFence2); + auto displayFrame1 = getDisplayFrame(1); + gpuFence2->signalForTest(66); + presentFence2->signalForTest(71); + + EXPECT_EQ(displayFrame1->getActuals().presentTime, 0); + // Fences have flushed for first displayFrame, so the present timestamps should be updated + EXPECT_EQ(displayFrame0->getActuals().presentTime, 52); + EXPECT_EQ(displayFrame0->getFramePresentMetadata(), FramePresentMetadata::LatePresent); + EXPECT_EQ(displayFrame0->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish); + EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed); addEmptyDisplayFrame(); - displayFrame = getDisplayFrame(0); - // Fences have flushed, so the present timestamps should be updated - EXPECT_EQ(displayFrame->getActuals().presentTime, 52); - EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent); - EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish); - EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed); + // Fences have flushed for second displayFrame, so the present timestamps should be updated + EXPECT_EQ(displayFrame1->getActuals().presentTime, 71); + EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::LatePresent); + EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish); + EXPECT_EQ(displayFrame1->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed); } TEST_F(FrameTimelineTest, jankClassification_displayFrameLateStartLateFinishLatePresent) { @@ -1562,7 +1685,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne, - sLayerNameOne, JankType::PredictionError, 0, 5, + sLayerNameOne, JankType::PredictionError, -3, 5, 0})); addEmptyDisplayFrame(); @@ -1642,7 +1765,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne, - sLayerNameOne, JankType::PredictionError, 0, 5, + sLayerNameOne, JankType::PredictionError, -3, 5, 0})); addEmptyDisplayFrame(); diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp index cfbb3f5e9f..a1f0588fc7 100644 --- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp +++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp @@ -19,6 +19,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <utils/Log.h> +#include <utils/Timers.h> #include "AsyncCallRecorder.h" #include "Scheduler/OneShotTimer.h" @@ -28,21 +29,22 @@ using namespace std::chrono_literals; namespace android { namespace scheduler { +class FakeClock : public OneShotTimer::Clock { +public: + virtual ~FakeClock() = default; + std::chrono::steady_clock::time_point now() const override { return mNow; } + + void advanceTime(std::chrono::nanoseconds delta) { mNow += delta; } + +private: + std::chrono::steady_clock::time_point mNow; +}; + class OneShotTimerTest : public testing::Test { protected: OneShotTimerTest() = default; ~OneShotTimerTest() override = default; - // This timeout should be used when a 3ms callback is expected. - // While the tests typically request a callback after 3ms, the scheduler - // does not always cooperate, at it can take significantly longer (observed - // 30ms). - static constexpr auto waitTimeForExpected3msCallback = 100ms; - - // This timeout should be used when an 3ms callback is not expected. - // Note that there can be false-negatives if the callback happens later. - static constexpr auto waitTimeForUnexpected3msCallback = 6ms; - AsyncCallRecorder<void (*)()> mResetTimerCallback; AsyncCallRecorder<void (*)()> mExpiredTimerCallback; @@ -56,162 +58,179 @@ protected: namespace { TEST_F(OneShotTimerTest, createAndDestroyTest) { + FakeClock* clock = new FakeClock(); mIdleTimer = std::make_unique<scheduler::OneShotTimer>( - "TestTimer", 3ms, [] {}, [] {}); + "TestTimer", 3ms, [] {}, [] {}, std::unique_ptr<FakeClock>(clock)); } TEST_F(OneShotTimerTest, startStopTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 30ms, + FakeClock* clock = new FakeClock(); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); - auto startTime = std::chrono::steady_clock::now(); + mExpiredTimerCallback.getInvocable(), + std::unique_ptr<FakeClock>(clock)); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); - // The idle timer fires after 30ms, so there should be no callback within - // 25ms (waiting for a callback for the full 30ms would be problematic). - bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value(); - // Under ideal conditions there should be no event. But occasionally - // it is possible that the wait just prior takes more than 30ms, and - // a callback is observed. We check the elapsed time since before the OneShotTimer - // thread was started as a sanity check to not have a flakey test. - EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms); - - std::this_thread::sleep_for(std::chrono::milliseconds(25)); - EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + + clock->advanceTime(2ms); + EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value()); + + clock->advanceTime(2ms); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); mIdleTimer->stop(); } TEST_F(OneShotTimerTest, resetTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms, + FakeClock* clock = new FakeClock(); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); + mExpiredTimerCallback.getInvocable(), + std::unique_ptr<FakeClock>(clock)); + mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); - // Observe any event that happens in about 25ms. We don't care if one was - // observed or not. - mExpiredTimerCallback.waitForCall(25ms).has_value(); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + clock->advanceTime(2ms); + EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value()); mIdleTimer->reset(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); - // There may have been a race with the reset. Clear any callbacks we - // received right afterwards. - clearPendingCallbacks(); - // A single callback should be generated after 30ms - EXPECT_TRUE( - mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback + 30ms).has_value()); - // After one event, it should be idle, and not generate another. - EXPECT_FALSE( - mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback * 10).has_value()); - mIdleTimer->stop(); - // Final quick check that no more callback were observed. - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value()); - EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); + clock->advanceTime(2ms); + EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value()); + + clock->advanceTime(2ms); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } TEST_F(OneShotTimerTest, resetBackToBackTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms, + FakeClock* clock = new FakeClock(); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); + mExpiredTimerCallback.getInvocable(), + std::unique_ptr<FakeClock>(clock)); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); mIdleTimer->reset(); - EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value()); - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); mIdleTimer->reset(); - EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value()); - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); mIdleTimer->reset(); - EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value()); - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); mIdleTimer->reset(); - EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value()); - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); + + clock->advanceTime(2ms); + EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value()); - // A single callback should be generated after 30ms - EXPECT_TRUE( - mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback + 30ms).has_value()); mIdleTimer->stop(); + clock->advanceTime(2ms); // Final quick check that no more callback were observed. - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value()); - EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } TEST_F(OneShotTimerTest, startNotCalledTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + FakeClock* clock = new FakeClock(); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); + mExpiredTimerCallback.getInvocable(), + std::unique_ptr<FakeClock>(clock)); // The start hasn't happened, so the callback does not happen. - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); - EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); mIdleTimer->stop(); + clock->advanceTime(2ms); // Final quick check that no more callback were observed. - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value()); - EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } TEST_F(OneShotTimerTest, idleTimerIdlesTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + FakeClock* clock = new FakeClock(); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); + mExpiredTimerCallback.getInvocable(), + std::unique_ptr<FakeClock>(clock)); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); + clock->advanceTime(2ms); + EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value()); + + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); - // A callback should be generated after 3ms - EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); - // After one event, it should be idle, and not generate another. - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); - // Once reset, it should generate another mIdleTimer->reset(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); - EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); + clock->advanceTime(2ms); + EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value()); mIdleTimer->stop(); + clock->advanceTime(2ms); // Final quick check that no more callback were observed. - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value()); - EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + FakeClock* clock = new FakeClock(); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); + mExpiredTimerCallback.getInvocable(), + std::unique_ptr<FakeClock>(clock)); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); - EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); + + clock->advanceTime(2ms); + EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value()); mIdleTimer->stop(); + clock->advanceTime(2ms); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + FakeClock* clock = new FakeClock(); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); + mExpiredTimerCallback.getInvocable(), + std::unique_ptr<FakeClock>(clock)); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); - EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); + clock->advanceTime(2ms); + EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value()); mIdleTimer->stop(); - clearPendingCallbacks(); mIdleTimer->reset(); - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); - EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); + clock->advanceTime(2ms); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms, + FakeClock* clock = new FakeClock(); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); + mExpiredTimerCallback.getInvocable(), + std::unique_ptr<FakeClock>(clock)); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); mIdleTimer->stop(); - clearPendingCallbacks(); mIdleTimer->reset(); + clock->advanceTime(2ms); // No more idle events should be observed - EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); - EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); + EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value()); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index abecd4b45b..9c6ad06e1d 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -118,11 +118,8 @@ void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) { } void RefreshRateSelectionTest::commitTransaction(Layer* layer) { - layer->pushPendingState(); auto c = layer->getCurrentState(); - if (layer->applyPendingStates(&c)) { - layer->commitTransaction(c); - } + layer->commitTransaction(c); } void RefreshRateSelectionTest::setupScheduler() { diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 0bb7e31194..c088ddc971 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -153,11 +153,8 @@ void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) { void SetFrameRateTest::commitTransaction() { for (auto layer : mLayers) { - layer->pushPendingState(); auto c = layer->getCurrentState(); - if (layer->applyPendingStates(&c)) { - layer->commitTransaction(c); - } + layer->commitTransaction(c); } } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 63baf7dee2..d004b9d9eb 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -352,8 +352,8 @@ public: auto renderScreenImplLocked(const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers, - const sp<GraphicBuffer>& buffer, bool forSystem, - bool regionSampling) { + const std::shared_ptr<renderengine::ExternalTexture>& buffer, + bool forSystem, bool regionSampling) { ScreenCaptureResults captureResults; return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem, regionSampling, false /* grayscale */, diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index c1f0c4ef03..188ea758d4 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -23,10 +23,10 @@ #define LOG_TAG "LibSurfaceFlingerUnittests" #include <TimeStats/TimeStats.h> -#include <android/util/ProtoOutputStream.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <log/log.h> +#include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h> #include <utils/String16.h> #include <utils/Vector.h> @@ -156,44 +156,8 @@ public: } std::mt19937 mRandomEngine = std::mt19937(std::random_device()()); - - class FakeStatsEventDelegate : public impl::TimeStats::StatsEventDelegate { - public: - FakeStatsEventDelegate() = default; - ~FakeStatsEventDelegate() override = default; - - struct AStatsEvent* addStatsEventToPullData(AStatsEventList*) override { - return mEvent; - } - void setStatsPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata*, - AStatsManager_PullAtomCallback callback, - void* cookie) override { - mAtomTags.push_back(atom_tag); - mCallback = callback; - mCookie = cookie; - } - - AStatsManager_PullAtomCallbackReturn makePullAtomCallback(int32_t atom_tag, void* cookie) { - return (*mCallback)(atom_tag, nullptr, cookie); - } - - MOCK_METHOD1(clearStatsPullAtomCallback, void(int32_t)); - MOCK_METHOD2(statsEventSetAtomId, void(AStatsEvent*, uint32_t)); - MOCK_METHOD2(statsEventWriteInt32, void(AStatsEvent*, int32_t)); - MOCK_METHOD2(statsEventWriteInt64, void(AStatsEvent*, int64_t)); - MOCK_METHOD2(statsEventWriteString8, void(AStatsEvent*, const char*)); - MOCK_METHOD3(statsEventWriteByteArray, void(AStatsEvent*, const uint8_t*, size_t)); - MOCK_METHOD1(statsEventBuild, void(AStatsEvent*)); - - AStatsEvent* mEvent = AStatsEvent_obtain(); - std::vector<int32_t> mAtomTags; - AStatsManager_PullAtomCallback mCallback = nullptr; - void* mCookie = nullptr; - }; - FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate; std::unique_ptr<TimeStats> mTimeStats = - std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), - std::nullopt, std::nullopt); + std::make_unique<impl::TimeStats>(std::nullopt, std::nullopt); }; std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) { @@ -278,21 +242,6 @@ TEST_F(TimeStatsTest, disabledByDefault) { ASSERT_FALSE(mTimeStats->isEnabled()); } -TEST_F(TimeStatsTest, setsCallbacksAfterBoot) { - mTimeStats->onBootFinished(); - EXPECT_THAT(mDelegate->mAtomTags, - UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); -} - -TEST_F(TimeStatsTest, clearsCallbacksOnDestruction) { - EXPECT_CALL(*mDelegate, - clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)); - EXPECT_CALL(*mDelegate, - clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - mTimeStats.reset(); -} - TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); ASSERT_TRUE(mTimeStats->isEnabled()); @@ -1012,61 +961,49 @@ TEST_F(TimeStatsTest, noInfInAverageFPS) { } namespace { -std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times, - const std::vector<int32_t>& frameCounts) { - util::ProtoOutputStream proto; +FrameTimingHistogram buildExpectedHistogram(const std::vector<int32_t>& times, + const std::vector<int32_t>& frameCounts) { + FrameTimingHistogram histogram; for (int i = 0; i < times.size(); i++) { ALOGE("Writing time: %d", times[i]); - proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */, - (int32_t)times[i]); + histogram.add_time_millis_buckets(times[i]); ALOGE("Writing count: %d", frameCounts[i]); - proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */, - (int64_t)frameCounts[i]); - } - std::string byteString; - proto.serializeToString(&byteString); - return byteString; -} - -std::string frameRateVoteToProtoByteString( - float refreshRate, - TimeStats::SetFrameRateVote::FrameRateCompatibility frameRateCompatibility, - TimeStats::SetFrameRateVote::Seamlessness seamlessness) { - util::ProtoOutputStream proto; - proto.write(android::util::FIELD_TYPE_FLOAT | 1 /* field id */, refreshRate); - proto.write(android::util::FIELD_TYPE_ENUM | 2 /* field id */, - static_cast<int>(frameRateCompatibility)); - proto.write(android::util::FIELD_TYPE_ENUM | 3 /* field id */, static_cast<int>(seamlessness)); - - std::string byteString; - proto.serializeToString(&byteString); - return byteString; -} - -std::string dumpByteStringHex(const std::string& str) { - std::stringstream ss; - ss << std::hex; - for (const char& c : str) { - ss << (int)c << " "; + histogram.add_frame_counts((int64_t)frameCounts[i]); } - - return ss.str(); + return histogram; } - } // namespace -MATCHER_P2(BytesEq, bytes, size, "") { - std::string expected; - expected.append((const char*)bytes, size); - std::string actual; - actual.append((const char*)arg, size); +MATCHER_P(HistogramEq, expected, "") { + *result_listener << "Histograms are not equal! \n"; - *result_listener << "Bytes are not equal! \n"; - *result_listener << "size: " << size << "\n"; - *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n"; - *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n"; + if (arg.time_millis_buckets_size() != expected.time_millis_buckets_size()) { + *result_listener << "Time millis bucket are different sizes. Expected: " + << expected.time_millis_buckets_size() << ". Actual " + << arg.time_millis_buckets_size(); + return false; + } + if (arg.frame_counts_size() != expected.frame_counts_size()) { + *result_listener << "Frame counts are different sizes. Expected: " + << expected.frame_counts_size() << ". Actual " << arg.frame_counts_size(); + return false; + } - return expected == actual; + for (int i = 0; i < expected.time_millis_buckets_size(); i++) { + if (arg.time_millis_buckets(i) != expected.time_millis_buckets(i)) { + *result_listener << "time_millis_bucket[" << i + << "] is different. Expected: " << expected.time_millis_buckets(i) + << ". Actual: " << arg.time_millis_buckets(i); + return false; + } + if (arg.frame_counts(i) != expected.frame_counts(i)) { + *result_listener << "frame_counts[" << i + << "] is different. Expected: " << expected.frame_counts(i) + << ". Actual: " << arg.frame_counts(i); + return false; + } + } + return true; } TEST_F(TimeStatsTest, globalStatsCallback) { @@ -1075,7 +1012,6 @@ TEST_F(TimeStatsTest, globalStatsCallback) { constexpr size_t CLIENT_COMPOSITION_FRAMES = 3; constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14; - mTimeStats->onBootFinished(); EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); for (size_t i = 0; i < TOTAL_FRAMES; i++) { @@ -1115,71 +1051,39 @@ TEST_F(TimeStatsTest, globalStatsCallback) { JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::BufferStuffing, 1, 2, 3}); + mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::None, 1, 2, 3}); - EXPECT_THAT(mDelegate->mAtomTags, - UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - EXPECT_NE(nullptr, mDelegate->mCallback); - EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie); - - std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1}); - std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1}); - std::string expectedEmptyHistogram = buildExpectedHistogramBytestring({}, {}); - std::string expectedSfDeadlineMissed = buildExpectedHistogramBytestring({1}, {7}); - std::string expectedSfPredictionErrors = buildExpectedHistogramBytestring({2}, {7}); - - { - InSequence seq; - EXPECT_CALL(*mDelegate, - statsEventSetAtomId(mDelegate->mEvent, - android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)); - EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES)); - EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES)); - EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES)); - EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _)); - EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS)); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*)expectedFrameDuration.c_str(), - expectedFrameDuration.size()), - expectedFrameDuration.size())); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedRenderEngineTiming.c_str(), - expectedRenderEngineTiming.size()), - expectedRenderEngineTiming.size())); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 8)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 7)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 2)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0)); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedSfDeadlineMissed.c_str(), - expectedSfDeadlineMissed.size()), - expectedSfDeadlineMissed.size())); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedSfPredictionErrors.c_str(), - expectedSfPredictionErrors.size()), - expectedSfPredictionErrors.size())); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0)); - - EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent)); - } - EXPECT_EQ(AStatsManager_PULL_SUCCESS, - mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - mDelegate->mCookie)); + std::string pulledData; + EXPECT_TRUE(mTimeStats->onPullAtom(10062 /*SURFACEFLINGER_STATS_GLOBAL_INFO*/, &pulledData)); + + android::surfaceflinger::SurfaceflingerStatsGlobalInfoWrapper atomList; + ASSERT_TRUE(atomList.ParseFromString(pulledData)); + ASSERT_EQ(atomList.atom_size(), 1); + const android::surfaceflinger::SurfaceflingerStatsGlobalInfo& atom = atomList.atom(0); + + EXPECT_EQ(atom.total_frames(), TOTAL_FRAMES); + EXPECT_EQ(atom.missed_frames(), MISSED_FRAMES); + EXPECT_EQ(atom.client_composition_frames(), CLIENT_COMPOSITION_FRAMES); + // Display on millis is not checked. + EXPECT_EQ(atom.animation_millis(), 2); + EXPECT_EQ(atom.event_connection_count(), DISPLAY_EVENT_CONNECTIONS); + EXPECT_THAT(atom.frame_duration(), HistogramEq(buildExpectedHistogram({2}, {1}))); + EXPECT_THAT(atom.render_engine_timing(), HistogramEq(buildExpectedHistogram({1, 2}, {1, 1}))); + EXPECT_EQ(atom.total_timeline_frames(), 9); + EXPECT_EQ(atom.total_janky_frames(), 7); + EXPECT_EQ(atom.total_janky_frames_with_long_cpu(), 1); + EXPECT_EQ(atom.total_janky_frames_with_long_gpu(), 1); + EXPECT_EQ(atom.total_janky_frames_sf_unattributed(), 1); + EXPECT_EQ(atom.total_janky_frames_app_unattributed(), 2); + EXPECT_EQ(atom.total_janky_frames_sf_scheduling(), 1); + EXPECT_EQ(atom.total_jank_frames_sf_prediction_error(), 1); + EXPECT_EQ(atom.total_jank_frames_app_buffer_stuffing(), 2); + EXPECT_EQ(atom.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0); + EXPECT_THAT(atom.sf_deadline_misses(), HistogramEq(buildExpectedHistogram({1}, {7}))); + EXPECT_THAT(atom.sf_prediction_errors(), HistogramEq(buildExpectedHistogram({2}, {7}))); + EXPECT_EQ(atom.render_rate_bucket(), RENDER_RATE_BUCKET_0); SFTimeStatsGlobalProto globalProto; ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO))); @@ -1194,7 +1098,7 @@ TEST_F(TimeStatsTest, globalStatsCallback) { const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); std::string expectedResult = "totalTimelineFrames = " + std::to_string(0); EXPECT_THAT(result, HasSubstr(expectedResult)); - expectedResult = "totalTimelineFrames = " + std::to_string(8); + expectedResult = "totalTimelineFrames = " + std::to_string(9); EXPECT_THAT(result, HasSubstr(expectedResult)); expectedResult = "jankyFrames = " + std::to_string(0); EXPECT_THAT(result, HasSubstr(expectedResult)); @@ -1226,7 +1130,7 @@ TEST_F(TimeStatsTest, globalStatsCallback) { EXPECT_THAT(result, HasSubstr(expectedResult)); expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(0); EXPECT_THAT(result, HasSubstr(expectedResult)); - expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(1); + expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(2); EXPECT_THAT(result, HasSubstr(expectedResult)); } @@ -1235,8 +1139,6 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3; EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - mTimeStats->onBootFinished(); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); @@ -1270,99 +1172,42 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::None, 1, 2, 3}); - EXPECT_THAT(mDelegate->mAtomTags, - UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - EXPECT_NE(nullptr, mDelegate->mCallback); - EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie); - - std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {1}); - std::string expectedPostToPresent = buildExpectedHistogramBytestring({4}, {1}); - std::string expectedAcquireToPresent = buildExpectedHistogramBytestring({3}, {1}); - std::string expectedLatchToPresent = buildExpectedHistogramBytestring({2}, {1}); - std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1}); - std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1}); - std::string expectedFrameRateOverride = - frameRateVoteToProtoByteString(frameRate60.frameRate, - frameRate60.frameRateCompatibility, - frameRate60.seamlessness); - std::string expectedAppDeadlineMissed = buildExpectedHistogramBytestring({3, 2}, {4, 3}); - { - InSequence seq; - EXPECT_CALL(*mDelegate, - statsEventSetAtomId(mDelegate->mEvent, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - EXPECT_CALL(*mDelegate, - statsEventWriteString8(mDelegate->mEvent, - StrEq(genLayerName(LAYER_ID_0).c_str()))); - EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 0)); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedPresentToPresent.c_str(), - expectedPresentToPresent.size()), - expectedPresentToPresent.size())); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*)expectedPostToPresent.c_str(), - expectedPostToPresent.size()), - expectedPostToPresent.size())); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedAcquireToPresent.c_str(), - expectedAcquireToPresent.size()), - expectedAcquireToPresent.size())); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*)expectedLatchToPresent.c_str(), - expectedLatchToPresent.size()), - expectedLatchToPresent.size())); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedDesiredToPresent.c_str(), - expectedDesiredToPresent.size()), - expectedDesiredToPresent.size())); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*)expectedPostToAcquire.c_str(), - expectedPostToAcquire.size()), - expectedPostToAcquire.size())); - EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, LATE_ACQUIRE_FRAMES)); - EXPECT_CALL(*mDelegate, - statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, UID_0)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 8)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 7)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 2)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0)); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedFrameRateOverride.c_str(), - expectedFrameRateOverride.size()), - expectedFrameRateOverride.size())); - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedAppDeadlineMissed.c_str(), - expectedAppDeadlineMissed.size()), - expectedAppDeadlineMissed.size())); - - EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent)); - } - EXPECT_EQ(AStatsManager_PULL_SUCCESS, - mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, - mDelegate->mCookie)); + std::string pulledData; + EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); + + android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + ASSERT_TRUE(atomList.ParseFromString(pulledData)); + ASSERT_EQ(atomList.atom_size(), 1); + const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); + + EXPECT_EQ(atom.layer_name(), genLayerName(LAYER_ID_0)); + EXPECT_EQ(atom.total_frames(), 1); + EXPECT_EQ(atom.dropped_frames(), 0); + EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {1}))); + EXPECT_THAT(atom.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {1}))); + EXPECT_THAT(atom.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {1}))); + EXPECT_THAT(atom.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_EQ(atom.late_acquire_frames(), LATE_ACQUIRE_FRAMES); + EXPECT_EQ(atom.bad_desired_present_frames(), BAD_DESIRED_PRESENT_FRAMES); + EXPECT_EQ(atom.uid(), UID_0); + EXPECT_EQ(atom.total_timeline_frames(), 8); + EXPECT_EQ(atom.total_janky_frames(), 7); + EXPECT_EQ(atom.total_janky_frames_with_long_cpu(), 1); + EXPECT_EQ(atom.total_janky_frames_with_long_gpu(), 1); + EXPECT_EQ(atom.total_janky_frames_sf_unattributed(), 1); + EXPECT_EQ(atom.total_janky_frames_app_unattributed(), 2); + EXPECT_EQ(atom.total_janky_frames_sf_scheduling(), 1); + EXPECT_EQ(atom.total_jank_frames_sf_prediction_error(), 1); + EXPECT_EQ(atom.total_jank_frames_app_buffer_stuffing(), 1); + EXPECT_EQ(atom.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0); + EXPECT_EQ(atom.render_rate_bucket(), RENDER_RATE_BUCKET_0); + EXPECT_THAT(atom.set_frame_rate_vote().frame_rate(), testing::FloatEq(frameRate60.frameRate)); + EXPECT_EQ((int)atom.set_frame_rate_vote().frame_rate_compatibility(), + (int)frameRate60.frameRateCompatibility); + EXPECT_EQ((int)atom.set_frame_rate_vote().seamlessness(), (int)frameRate60.seamlessness); + EXPECT_THAT(atom.app_deadline_misses(), HistogramEq(buildExpectedHistogram({3, 2}, {4, 3}))); SFTimeStatsGlobalProto globalProto; ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO))); @@ -1398,37 +1243,26 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - mTimeStats->onBootFinished(); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000); - EXPECT_THAT(mDelegate->mAtomTags, - UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - EXPECT_NE(nullptr, mDelegate->mCallback); - EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie); - - EXPECT_CALL(*mDelegate, - statsEventSetAtomId(mDelegate->mEvent, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)) - .Times(2); - EXPECT_CALL(*mDelegate, - statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_0).c_str()))); - EXPECT_CALL(*mDelegate, - statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str()))); - EXPECT_EQ(AStatsManager_PULL_SUCCESS, - mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, - mDelegate->mCookie)); + std::string pulledData; + EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); + + android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + ASSERT_TRUE(atomList.ParseFromString(pulledData)); + ASSERT_EQ(atomList.atom_size(), 2); + std::vector<std::string> actualLayerNames = {atomList.atom(0).layer_name(), + atomList.atom(1).layer_name()}; + EXPECT_THAT(actualLayerNames, + UnorderedElementsAre(genLayerName(LAYER_ID_0), genLayerName(LAYER_ID_1))); } TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - mTimeStats->onBootFinished(); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000); @@ -1438,102 +1272,53 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) { mTimeStats->setPowerMode(PowerMode::ON); mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000)); mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)); - EXPECT_THAT(mDelegate->mAtomTags, - UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - EXPECT_NE(nullptr, mDelegate->mCallback); - EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie); - - EXPECT_THAT(mDelegate->mAtomTags, - UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1, 2}, {2, 1}); - { - InSequence seq; - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedPresentToPresent.c_str(), - expectedPresentToPresent.size()), - expectedPresentToPresent.size())); - EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _)) - .Times(AnyNumber()); - } - EXPECT_EQ(AStatsManager_PULL_SUCCESS, - mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, - mDelegate->mCookie)); + + std::string pulledData; + EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); + + android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + ASSERT_TRUE(atomList.ParseFromString(pulledData)); + ASSERT_EQ(atomList.atom_size(), 1); + const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); + EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1, 2}, {2, 1}))); } TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) { - mDelegate = new FakeStatsEventDelegate; - mTimeStats = - std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), - std::nullopt, 1); + mTimeStats = std::make_unique<impl::TimeStats>(std::nullopt, 1); EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - mTimeStats->onBootFinished(); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000); - EXPECT_THAT(mDelegate->mAtomTags, - UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - EXPECT_NE(nullptr, mDelegate->mCallback); - EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie); - - EXPECT_THAT(mDelegate->mAtomTags, - UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {2}); - { - InSequence seq; - EXPECT_CALL(*mDelegate, - statsEventWriteByteArray(mDelegate->mEvent, - BytesEq((const uint8_t*) - expectedPresentToPresent.c_str(), - expectedPresentToPresent.size()), - expectedPresentToPresent.size())); - EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _)) - .Times(AnyNumber()); - } - EXPECT_EQ(AStatsManager_PULL_SUCCESS, - mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, - mDelegate->mCookie)); + std::string pulledData; + EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); + + android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + ASSERT_TRUE(atomList.ParseFromString(pulledData)); + ASSERT_EQ(atomList.atom_size(), 1); + const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); + EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {2}))); } TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) { - mDelegate = new FakeStatsEventDelegate; - mTimeStats = - std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), 1, - std::nullopt); + mTimeStats = std::make_unique<impl::TimeStats>(1, std::nullopt); EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - mTimeStats->onBootFinished(); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 4, 5000000); - EXPECT_THAT(mDelegate->mAtomTags, - UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)); - EXPECT_NE(nullptr, mDelegate->mCallback); - EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie); - - EXPECT_CALL(*mDelegate, - statsEventSetAtomId(mDelegate->mEvent, - android::util::SURFACEFLINGER_STATS_LAYER_INFO)) - .Times(1); - EXPECT_CALL(*mDelegate, - statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str()))); - EXPECT_EQ(AStatsManager_PULL_SUCCESS, - mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, - mDelegate->mCookie)); + std::string pulledData; + EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); + + android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + ASSERT_TRUE(atomList.ParseFromString(pulledData)); + ASSERT_EQ(atomList.atom_size(), 1); + EXPECT_EQ(atomList.atom(0).layer_name(), genLayerName(LAYER_ID_1)); } TEST_F(TimeStatsTest, canSurviveMonkey) { diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index b5ef0a1334..25001d3890 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -21,6 +21,8 @@ #include <gtest/gtest.h> #include <gui/SurfaceComposerClient.h> #include <log/log.h> +#include <renderengine/ExternalTexture.h> +#include <renderengine/mock/RenderEngine.h> #include <utils/String8.h> #include "TestableSurfaceFlinger.h" @@ -60,11 +62,8 @@ public: } void commitTransaction(Layer* layer) { - layer->pushPendingState(); auto c = layer->getCurrentState(); - if (layer->applyPendingStates(&c)) { - layer->commitTransaction(c); - } + layer->commitTransaction(c); } void setupScheduler() { @@ -102,6 +101,7 @@ public: TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; + renderengine::mock::RenderEngine mRenderEngine; FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; @@ -109,9 +109,12 @@ public: sp<BufferStateLayer> layer = createBufferStateLayer(); sp<Fence> fence(new Fence()); - sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); int32_t layerId = layer->getSequence(); - uint64_t bufferId = buffer->getId(); + uint64_t bufferId = buffer->getBuffer()->getId(); uint64_t frameNumber = 5; nsecs_t dequeueTime = 10; nsecs_t postTime = 20; @@ -151,4 +154,4 @@ TEST_F(TransactionFrameTracerTest, BLASTTransactionSendsFrameTracerEvents) { BLASTTransactionSendsFrameTracerEvents(); } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index c75538f476..b7917aa00e 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -21,6 +21,8 @@ #include <gtest/gtest.h> #include <gui/SurfaceComposerClient.h> #include <log/log.h> +#include <renderengine/ExternalTexture.h> +#include <renderengine/mock/RenderEngine.h> #include <utils/String8.h> #include "TestableSurfaceFlinger.h" @@ -60,13 +62,8 @@ public: } void commitTransaction(Layer* layer) { - layer->pushPendingState(); - // After pushing the state, the currentState should not store any BufferlessSurfaceFrames - EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); auto c = layer->getCurrentState(); - if (layer->applyPendingStates(&c)) { - layer->commitTransaction(c); - } + layer->commitTransaction(c); } void setupScheduler() { @@ -104,6 +101,7 @@ public: TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; + renderengine::mock::RenderEngine mRenderEngine; FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; @@ -124,7 +122,10 @@ public: sp<BufferStateLayer> layer = createBufferStateLayer(); sp<Fence> fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); @@ -149,7 +150,10 @@ public: sp<Fence> fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -158,7 +162,10 @@ public: sp<Fence> fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer2 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); nsecs_t start = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); @@ -196,8 +203,10 @@ public: sp<Fence> fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); @@ -222,8 +231,10 @@ public: sp<BufferStateLayer> layer = createBufferStateLayer(); sp<Fence> fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -252,8 +263,10 @@ public: sp<Fence> fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -283,75 +296,15 @@ public: EXPECT_EQ(PresentState::Presented, bufferSurfaceFrameTX->getPresentState()); } - void MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken() { - sp<BufferStateLayer> layer = createBufferStateLayer(); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); - EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); - const auto bufferlessSurfaceFrame1 = - layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); - - layer->pushPendingState(); - EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0}, - 12); - EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); - const auto bufferlessSurfaceFrame2 = - layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 2); - - commitTransaction(layer.get()); - - EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken()); - EXPECT_EQ(false, bufferlessSurfaceFrame1->getIsBuffer()); - EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame1->getPresentState()); - EXPECT_EQ(10, bufferlessSurfaceFrame1->getActuals().endTime); - - EXPECT_EQ(2, bufferlessSurfaceFrame2->getToken()); - EXPECT_EQ(false, bufferlessSurfaceFrame2->getIsBuffer()); - EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState()); - EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime); - } - - void MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken() { - sp<BufferStateLayer> layer = createBufferStateLayer(); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); - EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); - const auto bufferlessSurfaceFrame1 = - layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); - - layer->pushPendingState(); - EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 12); - EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); - const auto bufferlessSurfaceFrame2 = - layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); - - commitTransaction(layer.get()); - - EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken()); - EXPECT_EQ(false, bufferlessSurfaceFrame1->getIsBuffer()); - EXPECT_EQ(PresentState::Unknown, bufferlessSurfaceFrame1->getPresentState()); - - EXPECT_EQ(1, bufferlessSurfaceFrame2->getToken()); - EXPECT_EQ(false, bufferlessSurfaceFrame2->getIsBuffer()); - EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState()); - EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime); - } - void PendingSurfaceFramesRemovedAfterClassification() { sp<BufferStateLayer> layer = createBufferStateLayer(); sp<Fence> fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -359,7 +312,10 @@ public: sp<Fence> fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer2 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence2->signalForTest(12); @@ -386,7 +342,10 @@ public: sp<Fence> fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -395,7 +354,10 @@ public: sp<Fence> fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer2 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); auto dropStartTime1 = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}, @@ -407,7 +369,10 @@ public: sp<Fence> fence3(new Fence()); auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3); - sp<GraphicBuffer> buffer3{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer3 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); auto dropStartTime2 = systemTime(); layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); @@ -447,7 +412,11 @@ public: std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> bufferlessSurfaceFrames; for (int i = 0; i < 10; i += 2) { sp<Fence> fence1(new Fence()); - sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); @@ -529,16 +498,6 @@ TEST_F(TransactionSurfaceFrameTest, MultipleSurfaceFramesPresentedTogether) { MultipleSurfaceFramesPresentedTogether(); } -TEST_F(TransactionSurfaceFrameTest, - MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken) { - MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken(); -} - -TEST_F(TransactionSurfaceFrameTest, - MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken) { - MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken(); -} - TEST_F(TransactionSurfaceFrameTest, PendingSurfaceFramesRemovedAfterClassification) { PendingSurfaceFramesRemovedAfterClassification(); } @@ -552,4 +511,4 @@ TEST_F(TransactionSurfaceFrameTest, MultipleCommitsBeforeLatch) { MultipleCommitsBeforeLatch(); } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h index 570797861d..5dc48c3703 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h +++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h @@ -32,7 +32,9 @@ public: MOCK_METHOD0(onBootFinished, void()); MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>)); MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps)); - MOCK_METHOD3(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&, bool)); + MOCK_METHOD3(setSfPresent, + void(nsecs_t, const std::shared_ptr<FenceTime>&, + const std::shared_ptr<FenceTime>&)); MOCK_METHOD1(computeFps, float(const std::unordered_set<int32_t>&)); }; diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 37b74ed3a7..526a847614 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -27,7 +27,7 @@ public: TimeStats(); ~TimeStats() override; - MOCK_METHOD0(onBootFinished, void()); + MOCK_METHOD2(onPullAtom, bool(const int, std::string*)); MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&)); MOCK_METHOD0(isEnabled, bool()); MOCK_METHOD0(miniDump, std::string()); diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h index 3cbfed98f5..8c448e2f96 100644 --- a/services/surfaceflinger/tests/utils/TransactionUtils.h +++ b/services/surfaceflinger/tests/utils/TransactionUtils.h @@ -126,7 +126,7 @@ public: const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; for (int32_t i = 0; i < width; i++) { const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; - EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) + ASSERT_TRUE(std::equal(src, src + 4, expected, colorCompare)) << "pixel @ (" << x + i << ", " << y + j << "): " << "expected (" << color << "), " << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; @@ -161,6 +161,22 @@ public: ASSERT_EQ(NO_ERROR, s->unlockAndPost()); } } + + static void setFrame(Transaction& t, const sp<SurfaceControl>& sc, Rect source, Rect dest, + int32_t transform = 0) { + uint32_t sourceWidth = source.getWidth(); + uint32_t sourceHeight = source.getHeight(); + + if (transform & ui::Transform::ROT_90) { + std::swap(sourceWidth, sourceHeight); + } + + float dsdx = dest.getWidth() / static_cast<float>(sourceWidth); + float dsdy = dest.getHeight() / static_cast<float>(sourceHeight); + + t.setMatrix(sc, dsdx, 0, 0, dsdy); + t.setPosition(sc, dest.left, dest.top); + } }; enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY }; diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp index a9d499de1d..6e660e7e41 100644 --- a/services/vibratorservice/VibratorManagerHalWrapper.cpp +++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp @@ -30,7 +30,7 @@ constexpr int32_t SINGLE_VIBRATOR_ID = 0; const constexpr char* MISSING_VIBRATOR_MESSAGE_PREFIX = "No vibrator with id="; HalResult<void> LegacyManagerHalWrapper::ping() { - auto pingFn = [](std::shared_ptr<HalWrapper> hal) { return hal->ping(); }; + auto pingFn = [](HalWrapper* hal) { return hal->ping(); }; return mController->doWithRetry<void>(pingFn, "ping"); } diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h index 354e56ca68..6c31e2b882 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h @@ -30,7 +30,7 @@ namespace vibrator { std::shared_ptr<HalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler); template <typename T> -using HalFunction = std::function<T(std::shared_ptr<HalWrapper>)>; +using HalFunction = std::function<T(HalWrapper*)>; // Controller for Vibrator HAL handle. // This relies on a given Connector to connect to the underlying Vibrator HAL service and reconnects @@ -64,8 +64,7 @@ public: */ Info getInfo() { static Info sDefaultInfo = InfoCache().get(); - return apply<Info>([](std::shared_ptr<HalWrapper> hal) { return hal->getInfo(); }, - sDefaultInfo, "getInfo"); + return apply<Info>([](HalWrapper* hal) { return hal->getInfo(); }, sDefaultInfo, "getInfo"); } /* Calls given HAL function, applying automatic retries to reconnect with the HAL when the @@ -103,7 +102,7 @@ private: } for (int i = 0; i < MAX_RETRIES; i++) { - T result = halFn(hal); + T result = halFn(hal.get()); if (result.checkAndLogFailure(functionName)) { tryReconnect(); } else { @@ -111,7 +110,7 @@ private: } } - return halFn(hal); + return halFn(hal.get()); } }; diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp index 279496a8b8..8e77bc57f3 100644 --- a/services/vibratorservice/test/VibratorHalControllerTest.cpp +++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp @@ -40,11 +40,9 @@ using namespace android; using namespace std::chrono_literals; using namespace testing; -static const auto ON_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { - return hal->on(10ms, []() {}); -}; -static const auto OFF_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->off(); }; -static const auto PING_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->ping(); }; +static const auto ON_FN = [](vibrator::HalWrapper* hal) { return hal->on(10ms, []() {}); }; +static const auto OFF_FN = [](vibrator::HalWrapper* hal) { return hal->off(); }; +static const auto PING_FN = [](vibrator::HalWrapper* hal) { return hal->ping(); }; // ------------------------------------------------------------------------------------------------- @@ -233,7 +231,7 @@ TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) { std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); - auto onFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->on(10ms, callback); }; + auto onFn = [&](vibrator::HalWrapper* hal) { return hal->on(10ms, callback); }; ASSERT_TRUE(mController->doWithRetry<void>(onFn, "on").isOk()); ASSERT_TRUE(mController->doWithRetry<void>(PING_FN, "ping").isFailed()); mMockHal.reset(); diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp index d1db82b4ca..af0cdb85b1 100644 --- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp @@ -644,7 +644,6 @@ TEST_F(VibratorHalWrapperAidlTest, TestPerformPwleEffect) { .Times(Exactly(2)) .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status()))); - ; } std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp index 3de157667c..548d02817a 100644 --- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp +++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp @@ -40,7 +40,7 @@ using android::hardware::vibrator::PrimitivePwle; using namespace android; using namespace testing; -static const auto OFF_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->off(); }; +static const auto OFF_FN = [](vibrator::HalWrapper* hal) { return hal->off(); }; class MockBinder : public BBinder { public: diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 020b520a7c..8d6681c9f4 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -1086,7 +1086,8 @@ VkResult CreateSwapchainKHR(VkDevice device, ALOGW_IF(err != android::OK, "native_window_api_connect failed: %s (%d)", strerror(-err), err); - err = window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, -1); + err = + window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, nsecs_t{-1}); if (err != android::OK) { ALOGE("window->perform(SET_DEQUEUE_TIMEOUT) failed: %s (%d)", strerror(-err), err); |