Merge "Disable renderengine blur test" into sc-dev
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index f48f1fb..aff32c3 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -99,6 +99,7 @@
"libhidlbase",
"liblog",
"libutils",
+ "libbinderdebug",
],
srcs: [
"DumpstateService.cpp",
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 753ce2e..336c5a2 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2178,13 +2178,13 @@
}
/*
- * mount debugfs for non-user builds with ro.product.enforce_debugfs_restrictions
+ * mount debugfs for non-user builds with ro.product.debugfs_restrictions.enabled
* set to true and unmount it after invoking dumpstateBoard_* methods.
* This is to enable debug builds to not have debugfs mounted during runtime.
* It will also ensure that debugfs is only accessed by the dumpstate HAL.
*/
auto mount_debugfs =
- android::base::GetBoolProperty("ro.product.enforce_debugfs_restrictions", false);
+ android::base::GetBoolProperty("ro.product.debugfs_restrictions.enabled", false);
if (mount_debugfs) {
RunCommand("mount debugfs", {"mount", "-t", "debugfs", "debugfs", "/sys/kernel/debug"},
AS_ROOT_20);
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index 91aa018..6ab6b7f 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -32,6 +32,7 @@
"libutils",
"liblog",
"libbinder",
+ "libbinderdebug",
],
static_libs: [
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
index 2a9b681..4f6a89e 100644
--- a/cmds/dumpsys/OWNERS
+++ b/cmds/dumpsys/OWNERS
@@ -2,3 +2,6 @@
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 a017246..ba1c449 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 @@
"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 @@
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 @@
}
} 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 @@
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 @@
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 929c55c..349947c 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -52,13 +52,14 @@
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 6854c75..58fec30 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -19,6 +19,7 @@
"libbase",
"libbinder",
"libutils",
+ "libbinderdebug",
],
static_libs: [
@@ -26,6 +27,4 @@
"libgmock",
"libserviceutils",
],
-
- clang: true,
}
diff --git a/cmds/dumpsys/tests/AndroidTest.xml b/cmds/dumpsys/tests/AndroidTest.xml
index 1a8c67f..c2351d9 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 67a77f6..c9d2dbb 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 @@
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 @@
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 @@
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 @@
/* 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/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index d5110f6..2722e21 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -417,7 +417,7 @@
}
}
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 7c1ca91..6f08f74 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -47,8 +47,6 @@
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 @@
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 @@
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 @@
" </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 2f55249..b429fb3 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -58,22 +58,34 @@
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;
- }
- 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);
+struct AidlName {
+ std::string package;
+ std::string iface;
+ std::string instance;
- bool found = forEachManifest([&] (const ManifestWithDescription& mwd) {
- if (mwd.manifest->hasAidlInstance(package, iface, 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;
+ }
+};
+
+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(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 @@
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 @@
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 c089115..4f23c21 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -46,6 +46,8 @@
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/include/android/surface_control.h b/include/android/surface_control.h
index c5e3587..c349024 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -329,39 +329,53 @@
__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/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 406bd54..6fb1227 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -90,6 +90,8 @@
"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 @@
}
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 61f4581..f684cf6 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -75,6 +75,7 @@
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 {
@@ -388,4 +389,12 @@
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/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 7647a8c..0414e76 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";
@@ -358,6 +359,15 @@
return result;
}
+status_t ProcessState::enableOnewaySpamDetection(bool enable) {
+ uint32_t enableDetection = enable ? 1 : 0;
+ if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) {
+ ALOGE("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 @@
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) {
+ ALOGE("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 4aff92b..1388a80 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 @@
namespace android {
using base::unique_fd;
+using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
RpcConnection::SocketAddress::~SocketAddress() {}
@@ -51,6 +57,10 @@
}
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() {
@@ -120,6 +130,70 @@
#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)));
@@ -152,36 +226,35 @@
}
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(sp<RpcConnection>::fromExisting(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(), sp<RpcConnection>::fromExisting(this));
+ 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) {
@@ -246,11 +319,23 @@
mClients.push_back(connection);
}
-void RpcConnection::assignServerToThisThread(unique_fd&& fd) {
+sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd&& fd) {
std::lock_guard<std::mutex> _l(mSocketMutex);
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)
@@ -265,37 +350,31 @@
// 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);
+ // 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();
- }
+ // 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
@@ -309,8 +388,6 @@
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/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 2fabf94..75c4092 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -108,6 +108,11 @@
@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/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 5f0d056..3dbe2c4 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 @@
* 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/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 0919648..b9db5d7 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -58,6 +58,7 @@
void spawnPooledThread(bool isMain);
status_t setThreadPoolMaxThreadCount(size_t maxThreads);
+ status_t enableOnewaySpamDetection(bool enable);
void giveThreadPoolName();
String8 getDriverName();
diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
index dba47b4..2395e78 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -74,6 +74,16 @@
#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
@@ -118,11 +128,6 @@
friend sp<RpcConnection>;
RpcConnection();
- bool setupSocketServer(const SocketAddress& address);
- bool addSocketClient(const SocketAddress& address);
- void addClient(base::unique_fd&& fd);
- void assignServerToThisThread(base::unique_fd&& fd);
-
struct ConnectionSocket : public RefBase {
base::unique_fd fd;
@@ -131,11 +136,16 @@
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/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
index 1579199..151235c 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 @@
};
#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_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 5516914..a90b4aa 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 @@
__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 67c85b6..7d4b82e 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -118,14 +118,15 @@
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 1ccd0d2..7649a26 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -105,6 +105,14 @@
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 6a88401..62db3cf 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 @@
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/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index e2193fa..dc8c0f1 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -88,6 +88,7 @@
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 @@
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 @@
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/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 3340293..dd68fdb 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -80,11 +80,10 @@
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();
}
@@ -257,6 +256,7 @@
#ifdef __BIONIC__
VSOCK,
#endif // __BIONIC__
+ INET,
};
static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
switch (info.param) {
@@ -266,6 +266,8 @@
case SocketType::VSOCK:
return "vm_socket";
#endif // __BIONIC__
+ case SocketType::INET:
+ return "inet_socket";
default:
LOG_ALWAYS_FATAL("Unknown socket type");
return "";
@@ -305,6 +307,9 @@
CHECK(connection->setupVsockServer(port));
break;
#endif // __BIONIC__
+ case SocketType::INET:
+ CHECK(connection->setupInetServer(port));
+ break;
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
@@ -335,6 +340,9 @@
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");
}
@@ -740,7 +748,7 @@
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);
}
}));
@@ -749,6 +757,28 @@
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;
@@ -852,12 +882,13 @@
}
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/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index cb309bd..2ce13df 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -192,6 +192,8 @@
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 4ecbe53..761e45c 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -73,4 +73,9 @@
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 4ef47fb..e26c21b 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 @@
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/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 476617d..3d854c2 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -161,9 +161,9 @@
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 @@
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));
@@ -242,29 +243,49 @@
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;
}
- transactionCompleteCallback = std::move(mTransactionCompleteCallback);
- mTransactionCompleteFrameNumber = 0;
+
+ 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;
+ }
+
+ 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);
@@ -377,10 +398,11 @@
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
+ Rect crop = computeCrop(bufferItem);
mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
- bufferItem.mScalingMode);
+ bufferItem.mScalingMode, crop);
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
@@ -392,9 +414,10 @@
t->setAcquireFence(mSurfaceControl,
bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
+ mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
setMatrix(t, mLastBufferInfo);
- t->setCrop(mSurfaceControl, computeCrop(bufferItem));
+ t->setCrop(mSurfaceControl, crop);
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
if (!bufferItem.mIsAutoTimestamp) {
@@ -522,13 +545,15 @@
void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t,
const BufferInfo& bufferInfo) {
- uint32_t bufWidth = bufferInfo.width;
- uint32_t bufHeight = bufferInfo.height;
+ uint32_t bufWidth = bufferInfo.crop.getWidth();
+ uint32_t bufHeight = bufferInfo.crop.getHeight();
- float dsdx = mSize.width / static_cast<float>(bufWidth);
- float dsdy = mSize.height / static_cast<float>(bufHeight);
+ float sx = mSize.width / static_cast<float>(bufWidth);
+ float sy = mSize.height / static_cast<float>(bufHeight);
- t->setMatrix(mSurfaceControl, dsdx, 0, 0, dsdy);
+ 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(
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 454aa9e..6ca2487 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -497,6 +497,28 @@
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());
@@ -2021,6 +2043,19 @@
}
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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e6baba6..9b2e10b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -896,7 +896,7 @@
}
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
@@ -1147,8 +1147,11 @@
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;
@@ -1793,7 +1796,7 @@
}
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);
}
}
return err;
@@ -1946,6 +1949,11 @@
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 7e2f8f9..37750fa 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>
@@ -49,12 +50,17 @@
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) {}
+ mTransformHint(transform),
+ mWidth(w),
+ mHeight(h),
+ mFormat(format),
+ mCreateFlags(flags) {}
SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) {
mClient = other->mClient;
@@ -62,6 +68,9 @@
mGraphicBufferProducer = other->mGraphicBufferProducer;
mTransformHint = other->mTransformHint;
mLayerId = other->mLayerId;
+ mWidth = other->mWidth;
+ mHeight = other->mHeight;
+ mCreateFlags = other->mCreateFlags;
}
SurfaceControl::~SurfaceControl()
@@ -70,13 +79,13 @@
// 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);
}
}
@@ -118,21 +127,28 @@
{
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.
- 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) {
@@ -141,25 +157,42 @@
return mSurfaceData;
}
-sp<Surface> SurfaceControl::createSurface() const
+sp<Surface> SurfaceControl::createSurface()
{
- Mutex::Autolock _l(mLock);
- return generateSurfaceLocked();
+ return getSurface();
}
-sp<IBinder> SurfaceControl::getHandle() const
+void SurfaceControl::updateDefaultBufferSize(uint32_t width, uint32_t height) {
+ Mutex::Autolock _l(mLock);
+ mWidth = width; mHeight = height;
+ if (mBbq) {
+ mBbq->update(this, width, height, mFormat);
+ }
+
+}
+
+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
@@ -180,9 +213,11 @@
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;
}
@@ -191,21 +226,26 @@
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;
@@ -233,5 +273,12 @@
return NO_ERROR;
}
+sp<SurfaceControl> SurfaceControl::getParentingLayer() {
+ if (mBbqChild != nullptr) {
+ return mBbqChild;
+ }
+ return this;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index a48f95a..139dbb7 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -151,14 +151,20 @@
// 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) {
+ 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);
+ }
}
};
@@ -203,6 +209,10 @@
// 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/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index ccd6d4e..cb04689 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -275,6 +275,12 @@
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 @@
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/LayerState.h b/libs/gui/include/gui/LayerState.h
index d2d1e5b..b4f62f2 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -84,6 +84,7 @@
eLayerStackChanged = 0x00000080,
eReleaseBufferListenerChanged = 0x00000400,
eShadowRadiusChanged = 0x00000800,
+ eLayerCreated = 0x00001000,
/* was eDetachChildren, now available 0x00002000, */
eRelativeLayerChanged = 0x00004000,
eReparent = 0x00008000,
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index fe6a30a..d3f6ff0 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -567,6 +567,8 @@
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);
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 35bdfc1..9ee4636 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -37,6 +37,7 @@
class IGraphicBufferProducer;
class Surface;
class SurfaceComposerClient;
+class BLASTBufferQueue;
// ---------------------------------------------------------------------------
@@ -70,12 +71,13 @@
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 @@
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 @@
~SurfaceControl();
- sp<Surface> generateSurfaceLocked() const;
+ sp<Surface> generateSurfaceLocked();
status_t validate() const;
sp<SurfaceComposerClient> mClient;
@@ -110,8 +116,14 @@
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;
};
}; // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 9b1f0db..5a5da97 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -522,16 +522,146 @@
adapter.waitForCallbacks();
// capture screen and verify that it is red
ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
-
- Rect bounds;
- bounds.left = finalCropSideLength / 2;
- bounds.top = 0;
- bounds.right = bounds.left + finalCropSideLength;
- bounds.bottom = finalCropSideLength;
-
- ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, bounds));
+ 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, bounds, /*border*/ 0, /*outsideRegion*/ true));
+ 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 {
@@ -836,26 +966,6 @@
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;
};
@@ -911,55 +1021,6 @@
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;
@@ -1010,53 +1071,4 @@
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/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 751b95a..ea8c295 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -102,14 +102,13 @@
// 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 @@
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/permission/Android.bp b/libs/permission/Android.bp
index dd38224..a5712b3 100644
--- a/libs/permission/Android.bp
+++ b/libs/permission/Android.bp
@@ -1,3 +1,12 @@
+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: [
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index ec39137..f395ab4 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -48,6 +48,7 @@
name: "librenderengine_sources",
srcs: [
"Description.cpp",
+ "ExternalTexture.cpp",
"Mesh.cpp",
"RenderEngine.cpp",
"Texture.cpp",
diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp
new file mode 100644
index 0000000..eabff58
--- /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 a2963a7..d87315f 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -746,7 +746,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
}
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 = 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 @@
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 @@
// 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 cd7a86b..e7ed9c0 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -60,16 +60,14 @@
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 @@
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 0000000..07f0833
--- /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 7661233..c54c5ba 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 @@
// 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 8dd98c3..ddaa7c7 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 @@
namespace renderengine {
+class ExternalTexture;
class Image;
class Mesh;
class Texture;
@@ -104,23 +106,6 @@
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,
@@ -191,8 +176,9 @@
// 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
@@ -213,6 +199,31 @@
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;
};
@@ -297,7 +308,8 @@
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 228553d..27dbd1e 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -39,8 +39,6 @@
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());
@@ -50,12 +48,17 @@
MOCK_METHOD1(cleanupPostRender, bool(CleanupMode mode));
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 c535597..9ed759f 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -29,7 +29,8 @@
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 @@
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, isOutputBuffer, createProtectedImage, desc.format);
}
void AutoBackendTexture::unref(bool releaseLocalResources) {
@@ -92,13 +97,16 @@
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,7 +121,9 @@
}
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;
}
diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h
index bb75878..3133de6 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 @@
// 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();
- }
}
- AutoBackendTexture* getTexture() const { return mTexture; }
+ // 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);
+ }
+
+ // 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 @@
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 @@
// 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 @@
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 1db20c0..1c2b2fc 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -46,7 +46,7 @@
} // 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);
@@ -73,7 +73,7 @@
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
@@ -86,13 +86,14 @@
// 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{
@@ -103,7 +104,7 @@
},
.source = PixelSource{.buffer =
Buffer{
- .buffer = srcBuffer,
+ .buffer = srcTexture,
.maxMasteringLuminance = 1000.f,
.maxContentLuminance = 1000.f,
}},
@@ -126,7 +127,7 @@
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);
}
}
@@ -135,7 +136,7 @@
}
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{
@@ -143,11 +144,11 @@
Geometry{
.boundaries = rect,
},
- .alpha = 1,
.source =
PixelSource{
.solidColor = half3(0.1f, 0.2f, 0.3f),
},
+ .alpha = 1,
};
auto layers = std::vector<const LayerSettings*>{&layer};
@@ -155,14 +156,14 @@
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{
@@ -176,7 +177,7 @@
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);
}
}
@@ -214,6 +215,9 @@
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
@@ -222,11 +226,16 @@
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);
// should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
@@ -234,12 +243,12 @@
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, dstBuffer, externalBuffer);
- renderengine->unbindExternalTextureBuffer(externalBuffer->getId());
-
- renderengine->unbindExternalTextureBuffer(srcBuffer->getId());
+ 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 df40dd9..0a84754 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -329,8 +329,6 @@
}
SkiaGLRenderEngine::~SkiaGLRenderEngine() {
- cleanFramebufferCache();
-
std::lock_guard<std::mutex> lock(mRenderingMutex);
if (mBlurFilter) {
delete mBlurFilter;
@@ -484,7 +482,8 @@
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) {
@@ -505,25 +504,41 @@
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,
@@ -621,8 +636,8 @@
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");
@@ -645,38 +660,26 @@
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) {
@@ -876,26 +879,29 @@
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
@@ -1200,15 +1206,6 @@
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);
@@ -1281,6 +1278,12 @@
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");
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 8e77c16..e71c560 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 @@
~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 @@
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 @@
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 51ef088..308c5ff 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -42,15 +42,12 @@
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 {
@@ -60,6 +57,11 @@
virtual int getContextPriority() override { return 0; }
virtual void assertShadersCompiled(int numShaders) {}
virtual int reportShadersCompiled() { return 0; }
+
+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/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index a9e2174..34ef0a4 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 @@
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 @@
}
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 @@
}
}
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 @@
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 @@
break;
}
}
- mBuffer->unlock();
+ mBuffer->getBuffer()->unlock();
}
void expectAlpha(const Rect& rect, uint8_t a) {
@@ -387,7 +404,6 @@
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 @@
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 @@
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 @@
} else {
mRE = renderEngineFactory->createRenderEngine();
}
+ mBuffer = allocateDefaultBuffer();
}
struct ColorSourceVariant {
@@ -566,18 +577,18 @@
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 @@
}
}
- buf->unlock();
+ buf->getBuffer()->unlock();
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
@@ -1012,14 +1023,14 @@
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 @@
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 @@
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 @@
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_withoutBuffers_withColorTransform) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1295,7 +1305,6 @@
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 @@
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);
}
@@ -1577,98 +1585,6 @@
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();
@@ -1861,7 +1777,7 @@
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));
@@ -1969,16 +1885,16 @@
// 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 b093e88..e3917cc 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -162,15 +162,18 @@
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 190662b..c87a836 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -160,27 +160,28 @@
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();
@@ -242,7 +243,7 @@
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) {
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 61ae9b8..eb6098e 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -48,8 +48,6 @@
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;
@@ -60,14 +58,19 @@
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;
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 12f63db..d243989 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -188,7 +188,7 @@
const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
(isSecure() && !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",
@@ -213,7 +213,7 @@
? 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();
@@ -314,7 +314,7 @@
: Hwc2::IComposerClient::Composition::DEVICE;
}
- compositionState->buffer = mBufferInfo.mBuffer;
+ compositionState->buffer = mBufferInfo.mBuffer->getBuffer();
compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
? 0
: mBufferInfo.mBufferSlot;
@@ -442,7 +442,7 @@
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;
}
@@ -539,10 +539,10 @@
}
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;
}
}
@@ -563,8 +563,8 @@
}
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);
}
// As documented in libhardware header, formats in the range
@@ -651,8 +651,8 @@
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) {
@@ -683,8 +683,8 @@
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) {
@@ -726,7 +726,7 @@
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();
@@ -771,12 +771,14 @@
}
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 0a5235a..cd3d80e 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -132,7 +132,7 @@
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};
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 69d2d11..96b2247 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 @@
}
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
}
} else {
pendingRelease->currentTexture = mCurrentTexture;
- pendingRelease->graphicBuffer = mCurrentTextureBuffer->graphicBuffer();
+ pendingRelease->graphicBuffer = mCurrentTextureBuffer->getBuffer();
pendingRelease->isPending = true;
}
}
@@ -301,14 +302,14 @@
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 @@
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 @@
*outFence = mCurrentFence;
}
- return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer->graphicBuffer();
+ return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer;
}
Rect BufferLayerConsumer::getCurrentCrop() const {
@@ -456,10 +458,12 @@
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 @@
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 dd39214..9ed80b4 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 @@
namespace renderengine {
class RenderEngine;
-class Image;
} // namespace renderengine
/*
@@ -153,7 +151,8 @@
// 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 @@
// 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 @@
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 fa9cecf..a2915c9 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -71,14 +71,8 @@
// 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);
}
}
@@ -344,8 +338,9 @@
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) {
@@ -353,12 +348,14 @@
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) {
@@ -396,8 +393,8 @@
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);
@@ -405,8 +402,8 @@
FrameTracer::FrameEvent::QUEUE);
}
- mCurrentState.width = mCurrentState.buffer->width;
- mCurrentState.height = mCurrentState.buffer->height;
+ mCurrentState.width = mCurrentState.buffer->getBuffer()->getWidth();
+ mCurrentState.height = mCurrentState.buffer->getBuffer()->getHeight();
return true;
}
@@ -655,7 +652,7 @@
}
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);
@@ -689,7 +686,7 @@
return BAD_VALUE;
}
- if (s.buffer != mBufferInfo.mBuffer) {
+ if (!mBufferInfo.mBuffer || s.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) {
decrementPendingBufferCount();
}
@@ -793,7 +790,7 @@
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;
@@ -806,27 +803,11 @@
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() {
@@ -844,8 +825,8 @@
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) {
@@ -872,14 +853,16 @@
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 24e0ad2..af4fcae 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -62,9 +62,9 @@
bool setTransform(uint32_t transform) override;
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
bool setCrop(const Rect& crop) 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;
@@ -100,7 +100,7 @@
// 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; }
@@ -140,7 +140,7 @@
sp<Layer> createClone() override;
// Crop that applies to the buffer
- Rect computeCrop(const State& s);
+ Rect computeBufferCrop(const State& s);
bool willPresentCurrentTransaction() const;
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index 44b33ef..f310738 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -102,7 +102,12 @@
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 @@
}
}
-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 @@
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 0d597c8..a9b8177 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 @@
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 @@
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 @@
};
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 a0606b4..289cb11 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -79,6 +79,9 @@
// 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/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index f680460..daee83b 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;
@@ -80,7 +81,8 @@
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 a1230b3..a8d372c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
@@ -45,6 +45,8 @@
// The DisplaySurface for this surface
sp<DisplaySurface> displaySurface;
+
+ size_t maxTextureCacheSize;
};
/**
@@ -81,6 +83,11 @@
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 8f767d3..f0ef6d6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -115,6 +115,9 @@
// 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/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 48a54d6..c61ec59 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>
@@ -89,7 +89,7 @@
// 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};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 5127a6f..a8a5380 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 {
@@ -54,7 +58,8 @@
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;
@@ -66,7 +71,7 @@
// Testing
void setPageFlipCountForTest(std::uint32_t);
void setSizeForTest(const ui::Size&);
- sp<GraphicBuffer>& mutableGraphicBufferForTest();
+ std::shared_ptr<renderengine::ExternalTexture>& mutableTextureForTest();
base::unique_fd& mutableBufferReadyForTest();
private:
@@ -75,10 +80,13 @@
// 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};
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 c5d03a7..53f4a30 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -66,7 +66,7 @@
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; }
@@ -87,7 +87,7 @@
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;
@@ -115,31 +115,7 @@
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/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index a0cae6f..fe858c2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -39,7 +39,7 @@
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_METHOD0(onPresentDisplayCompleted, void());
MOCK_METHOD0(flip, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index a605fe1..1ffb1c8 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -367,6 +367,11 @@
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/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 3ac5433..faa4b74 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
@@ -710,16 +711,18 @@
return;
}
+ editState().earliestPresentTime = refreshArgs.earliestPresentTime;
+
sp<GraphicBuffer> previousOverride = nullptr;
for (auto* layer : getOutputLayersOrderedByZ()) {
bool skipLayer = false;
if (layer->getState().overrideInfo.buffer != nullptr) {
if (previousOverride != nullptr &&
- layer->getState().overrideInfo.buffer == previousOverride) {
+ layer->getState().overrideInfo.buffer->getBuffer() == previousOverride) {
ALOGV("Skipping redundant buffer");
skipLayer = true;
}
- previousOverride = layer->getState().overrideInfo.buffer;
+ previousOverride = layer->getState().overrideInfo.buffer->getBuffer();
}
const bool includeGeometry = refreshArgs.updatingGeometryThisFrame;
@@ -978,14 +981,15 @@
}
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());
@@ -1030,13 +1034,14 @@
// 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);
}
@@ -1069,12 +1074,12 @@
// 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();
@@ -1151,9 +1156,9 @@
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 f640f85..9ca8914 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -537,7 +537,7 @@
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;
}
@@ -699,7 +699,7 @@
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/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 3bef77d..ef50870 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 @@
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);
}
@@ -146,7 +147,8 @@
}
}
-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;
@@ -158,16 +160,41 @@
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(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
- mGraphicBuffer->getNativeBuffer()->handle);
- mGraphicBuffer = GraphicBuffer::from(buffer);
+ 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;
+ }
+ }
+
+ 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) {
@@ -177,24 +204,24 @@
// 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(), dup(readyFence));
+ status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ mTexture->getBuffer()->getNativeBuffer(),
+ dup(readyFence));
if (result != NO_ERROR) {
ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
result);
@@ -204,11 +231,12 @@
LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
} else {
mNativeWindow->cancelBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(), dup(readyFence));
+ mTexture->getBuffer()->getNativeBuffer(),
+ dup(readyFence));
}
}
- mGraphicBuffer = nullptr;
+ mTexture = nullptr;
}
}
@@ -256,8 +284,8 @@
mSize = size;
}
-sp<GraphicBuffer>& RenderSurface::mutableGraphicBufferForTest() {
- return mGraphicBuffer;
+std::shared_ptr<renderengine::ExternalTexture>& RenderSurface::mutableTextureForTest() {
+ return mTexture;
}
} // namespace impl
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index dcb7555..9955e29 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -130,7 +130,7 @@
}
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 {
@@ -217,21 +217,27 @@
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;
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index ad75557..3a2534b 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -111,7 +111,12 @@
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 8a4d161..4c3f494 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -26,6 +26,7 @@
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "RegionMatcher.h"
+#include "renderengine/mock/RenderEngine.h"
namespace android::compositionengine {
namespace {
@@ -715,7 +716,7 @@
static const HdrMetadata kHdrMetadata;
static native_handle_t* kSidebandStreamHandle;
static const sp<GraphicBuffer> kBuffer;
- static const sp<GraphicBuffer> kOverrideBuffer;
+ std::shared_ptr<renderengine::ExternalTexture> kOverrideBuffer;
static const sp<Fence> kFence;
static const sp<Fence> kOverrideFence;
static const std::string kLayerGenericMetadata1Key;
@@ -724,6 +725,11 @@
static const std::vector<uint8_t> kLayerGenericMetadata2Value;
OutputLayerWriteStateToHWCTest() {
+ kOverrideBuffer = std::make_shared<
+ renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::
+ WRITEABLE);
auto& outputLayerState = mOutputLayer.editState();
outputLayerState.hwc = impl::OutputLayerCompositionState::Hwc(mHwcLayer);
@@ -839,6 +845,7 @@
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,
@@ -858,7 +865,6 @@
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<Fence> OutputLayerWriteStateToHWCTest::kFence;
const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence();
const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key =
@@ -1023,7 +1029,7 @@
kOverrideBufferTransform, kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
kOverrideSurfaceDamage);
- expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence);
+ expectSetHdrMetadataAndBufferCalls(kOverrideBuffer->getBuffer(), kOverrideFence);
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 5f0b0ee..e80100c 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,12 @@
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <cmath>
+
#include "CallOrderStateMachineHelper.h"
#include "MockHWC2.h"
#include "RegionMatcher.h"
+#include "renderengine/ExternalTexture.h"
namespace android::compositionengine {
namespace {
@@ -2960,7 +2961,10 @@
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 +3177,10 @@
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));
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 5ef5d7b..9aeb290 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 @@
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, 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 @@
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 @@
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 f01fe27..283c692 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -305,8 +305,8 @@
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 @@
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 @@
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/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b7b2cc6..8692ee6 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -70,11 +70,13 @@
mIsPrimary(args.isPrimary) {
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/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b45f2bc..cf215ad 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -880,7 +880,7 @@
}
// Allow BufferStateLayer to release any unlatched buffers in drawing state.
- bufferMayChange(c.buffer);
+ bufferMayChange(c.buffer->getBuffer());
// Commit the transaction
commitTransaction(c);
@@ -891,7 +891,11 @@
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
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5379d74..9f3ea9a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -203,7 +203,7 @@
Region transparentRegionHint;
- sp<GraphicBuffer> buffer;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
client_cache_t clientCacheId;
sp<Fence> acquireFence;
std::shared_ptr<FenceTime> acquireFenceTime;
@@ -404,10 +404,11 @@
// Used only to set BufferStateLayer state
virtual bool setTransform(uint32_t /*transform*/) { return false; };
virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { 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;
@@ -709,7 +710,7 @@
* 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
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 7a3e433..a9fd16c 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -208,7 +208,8 @@
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 @@
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];
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index c16cfa0..aa8329c 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 @@
};
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 @@
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 d0032ac..00090d9 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -438,18 +438,22 @@
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 @@
}
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 @@
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 0defdb3..86632db 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 @@
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/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index ce3b0c6..d659398 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -40,13 +40,21 @@
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 @@
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 @@
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 3690ce7..7285427 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -36,8 +36,17 @@
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 @@
// 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 1d25c72..57bd045 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -927,4 +927,11 @@
}
}
+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);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 4d1f3c6..49d3d93 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -149,6 +149,8 @@
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;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a4803df..9da23a6 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 <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
@@ -627,7 +626,6 @@
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mFrameTracer->initialize();
- mTimeStats->onBootFinished();
mFrameTimeline->onBootFinished();
// wait patiently for the window manager death
@@ -727,6 +725,7 @@
mCompositionEngine->setTimeStats(mTimeStats);
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();
@@ -1298,6 +1297,11 @@
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,
@@ -1968,6 +1972,8 @@
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
@@ -2750,6 +2756,7 @@
(currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) {
display->setProjection(currentState.orientation, currentState.layerStackSpaceRect,
currentState.orientedDisplaySpaceRect);
+ mDefaultDisplayTransformHint = display->getTransformHint();
}
if (currentState.width != drawingState.width ||
currentState.height != drawingState.height) {
@@ -3256,70 +3263,38 @@
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);
- return NO_MEMORY;
- }
-
- mLayersByLocalBinderToken.emplace(handle->localBinder(), lbc);
-
- 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());
- }
- }
-
- 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();
- }
-
- mLayersAdded = true;
+ if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
+ ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
+ ISurfaceComposer::MAX_LAYERS);
+ return NO_MEMORY;
}
+ wp<IBinder> initialProducer;
+ if (gbc != nullptr) {
+ initialProducer = IInterface::asBinder(gbc);
+ }
+ setLayerCreatedState(handle, lbc, parentHandle, parentLayer, initialProducer);
+
+ // Create a transaction includes the initial parent and producer.
+ Vector<ComposerState> states;
+ Vector<DisplayState> displays;
+
+ ComposerState composerState;
+ composerState.state.what = layer_state_t::eLayerCreated;
+ composerState.state.surface = handle;
+ states.add(composerState);
+
+ 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) {
@@ -3692,7 +3667,6 @@
if (uncacheBuffer.isValid()) {
ClientCache::getInstance().erase(uncacheBuffer);
- getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id);
}
// If a synchronous transaction is explicitly requested without any changes, force a transaction
@@ -3799,9 +3773,21 @@
listenerCallbacks.insert(listener);
}
+ 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");
@@ -3814,10 +3800,6 @@
return 0;
}
- uint32_t flags = 0;
-
- const uint64_t what = s.what;
-
// Only set by BLAST adapter layers
if (what & layer_state_t::eProducerDisconnect) {
layer->onDisconnect();
@@ -4056,23 +4038,16 @@
}
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;
@@ -4155,10 +4130,6 @@
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);
@@ -4282,14 +4253,7 @@
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;
@@ -4377,7 +4341,7 @@
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};
@@ -5176,6 +5140,13 @@
}
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
@@ -5993,15 +5964,17 @@
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) {
@@ -6034,15 +6007,6 @@
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);
}));
@@ -6050,11 +6014,10 @@
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) {
@@ -6062,7 +6025,7 @@
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
@@ -6072,7 +6035,7 @@
return PERMISSION_DENIED;
}
- captureResults.buffer = buffer;
+ captureResults.buffer = buffer->getBuffer();
captureResults.capturedDataspace = renderArea.getReqDataSpace();
const auto reqWidth = renderArea.getReqWidth();
@@ -6163,11 +6126,9 @@
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));
@@ -6432,10 +6393,6 @@
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) {
@@ -6647,6 +6604,87 @@
}
}
+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;
+}
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9135632..cf1a545 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -178,7 +178,6 @@
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
- public ClientCache::ErasedRecipient,
private IBinder::DeathRecipient,
private HWC2::ComposerCallback,
private ISchedulerCallback {
@@ -326,9 +325,6 @@
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;
@@ -641,6 +637,7 @@
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;
@@ -901,12 +898,14 @@
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);
@@ -1393,6 +1392,35 @@
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;
};
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 62fddb4..bcc3e4e 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -18,20 +18,13 @@
"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 2094972..16c6bb3 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));
+SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto(
+ const TimeStats::SetFrameRateVote& setFrameRateVote) {
+ using FrameRateCompatibilityEnum =
+ SurfaceflingerStatsLayerInfo::SetFrameRateVote::FrameRateCompatibility;
+ using SeamlessnessEnum = SurfaceflingerStatsLayerInfo::SetFrameRateVote::Seamlessness;
- std::string byteString;
- proto.serializeToString(&byteString);
- return byteString;
+ 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 @@
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::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) {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index a87b7cb..5b0f5bd 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 @@
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 @@
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 @@
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 @@
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 0000000..0cf086f
--- /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 0000000..d305cb4
--- /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 0000000..133a541
--- /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/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 6246321..fa3f0e7 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -305,25 +305,6 @@
/**
* 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/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 58b039e..9cf7c09 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -52,12 +52,15 @@
}
};
-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/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 53d230a..7581cd3 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -135,53 +135,6 @@
}
}
-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;
@@ -607,44 +560,6 @@
}
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;
@@ -901,29 +816,6 @@
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));
@@ -1076,29 +968,6 @@
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(
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index edf55ea..2828d61 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -51,14 +51,9 @@
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;
@@ -324,7 +319,6 @@
.setLayer(blurLayer, mLayerZBase + 3)
.setBackgroundBlurRadius(blurLayer, blurRadius)
.setCrop(blurLayer, blurRect)
- .setSize(blurLayer, blurRect.getWidth(), blurRect.getHeight())
.setAlpha(blurLayer, 0.0f)
.apply();
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index adb5d58..ee4d367 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -127,15 +127,7 @@
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;
};
@@ -462,191 +454,6 @@
}
}
-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, Reparent) {
asTransaction([&](Transaction& t) {
t.show(mChild);
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index b0753c8..2e9c10c 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -350,7 +350,10 @@
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 @@
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, 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, 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 @@
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, 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 @@
} // 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 af23e2a..ee4e863 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -921,11 +921,6 @@
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
@@ -941,26 +936,6 @@
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 eb31e2e..162711d 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -1293,31 +1293,6 @@
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?
{
@@ -1517,10 +1492,6 @@
Test_LayerMove();
}
-TEST_F(TransactionTest_2_1, DISABLED_LayerResize) {
- Test_LayerResize();
-}
-
TEST_F(TransactionTest_2_1, DISABLED_LayerCrop) {
Test_LayerCrop();
}
@@ -1690,39 +1661,6 @@
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()));
- }
-
sp<SurfaceControl> mChild;
};
@@ -1748,11 +1686,6 @@
Test_LayerAlpha();
}
-// Regression test for b/37673612
-TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) {
- Test_ChildrenWithParentBufferTransform();
-}
-
template <typename FakeComposerService>
class ChildColorLayerTest : public ChildLayerTest<FakeComposerService> {
using Base = ChildLayerTest<FakeComposerService>;
@@ -1842,91 +1775,6 @@
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 4ac096b..88fb811 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -127,6 +127,7 @@
"librenderengine",
"libserviceutils",
"libtimestats",
+ "libtimestats_atoms_proto",
"libtimestats_proto",
"libtrace_proto",
"perfetto_trace_protos",
@@ -152,14 +153,10 @@
"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 4e1c0c7..3042450 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 @@
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
- sp<GraphicBuffer> mCaptureScreenBuffer;
+ std::shared_ptr<renderengine::ExternalTexture> mCaptureScreenBuffer;
};
template <typename LayerCase>
@@ -243,11 +244,15 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index cfbb3f5..a1f0588 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 @@
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 @@
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);
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
- std::this_thread::sleep_for(std::chrono::milliseconds(25));
- EXPECT_FALSE(mResetTimerCallback.waitForCall().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());
- // A single callback should be generated after 30ms
- EXPECT_TRUE(
- mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback + 30ms).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, 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());
- // 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
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+
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/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 63baf7d..d004b9d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -352,8 +352,8 @@
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 c1f0c4e..4e73cbc 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 @@
}
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 @@
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 @@
}
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]);
+ histogram.add_frame_counts((int64_t)frameCounts[i]);
}
- std::string byteString;
- proto.serializeToString(&byteString);
- return byteString;
+ return histogram;
}
-
-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 << " ";
- }
-
- return ss.str();
-}
-
} // 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 @@
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++) {
@@ -1117,69 +1053,35 @@
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 pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10062 /*SURFACEFLINGER_STATS_GLOBAL_INFO*/, &pulledData));
- 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});
+ android::surfaceflinger::SurfaceflingerStatsGlobalInfoWrapper atomList;
+ ASSERT_TRUE(atomList.ParseFromString(pulledData));
+ ASSERT_EQ(atomList.atom_size(), 1);
+ const android::surfaceflinger::SurfaceflingerStatsGlobalInfo& atom = atomList.atom(0);
- {
- 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));
+ 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(), 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_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)));
@@ -1235,8 +1137,6 @@
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 +1170,42 @@
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 pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
- 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()));
+ android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList;
+ ASSERT_TRUE(atomList.ParseFromString(pulledData));
+ ASSERT_EQ(atomList.atom_size(), 1);
+ const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0);
- EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
- }
- EXPECT_EQ(AStatsManager_PULL_SUCCESS,
- mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
- mDelegate->mCookie));
+ 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 +1241,26 @@
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);
+ std::string pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
- 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));
+ 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 +1270,53 @@
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);
+ std::string pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
- 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));
+ 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);
+ std::string pulledData;
+ EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));
- 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));
+ 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 ea1ce47..25001d3 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"
@@ -99,6 +101,7 @@
TestableSurfaceFlinger mFlinger;
Hwc2::mock::Composer* mComposer = nullptr;
+ renderengine::mock::RenderEngine mRenderEngine;
FenceToFenceTimeMap fenceFactory;
client_cache_t mClientCache;
@@ -106,9 +109,12 @@
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;
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 09a1c2a..b7917aa 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"
@@ -99,6 +101,7 @@
TestableSurfaceFlinger mFlinger;
Hwc2::mock::Composer* mComposer = nullptr;
+ renderengine::mock::RenderEngine mRenderEngine;
FenceToFenceTimeMap fenceFactory;
client_cache_t mClientCache;
@@ -119,7 +122,10 @@
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);
@@ -144,7 +150,10 @@
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());
@@ -153,7 +162,10 @@
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 */);
@@ -191,8 +203,10 @@
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);
@@ -217,8 +231,10 @@
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());
@@ -247,8 +263,10 @@
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,7 +301,10 @@
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);
@@ -291,7 +312,10 @@
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);
@@ -318,7 +342,10 @@
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());
@@ -327,7 +354,10 @@
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},
@@ -339,7 +369,10 @@
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 */);
@@ -379,7 +412,11 @@
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 */);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 37b74ed..526a847 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -27,7 +27,7 @@
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());