Merge "SurfaceFlinger: check fence when acquiring buffer with PTS"
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 62d2fa1..d398559 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -222,9 +222,9 @@
}
bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
- sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0);
+ const sp<IBinder> dpy = mSurfaceComposerClient->getInternalDisplayToken();
if (dpy == nullptr) {
- fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n");
+ fprintf(stderr, "SurfaceComposer::getInternalDisplayToken failed.\n");
return false;
}
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 488070d..e33b2a8 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -231,16 +231,16 @@
}
// OTA slot script
-cc_prebuilt_binary {
+sh_binary {
name: "otapreopt_slot",
- srcs: ["otapreopt_slot.sh"],
+ src: "otapreopt_slot.sh",
init_rc: ["otapreopt.rc"],
}
// OTA postinstall script
-cc_prebuilt_binary {
+sh_binary {
name: "otapreopt_script",
- srcs: ["otapreopt_script.sh"],
+ src: "otapreopt_script.sh",
// Let this depend on otapreopt, the chroot tool and the slot script,
// so we just have to mention one in a configuration.
required: [
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 1c99663..609ddaf 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -41,6 +41,23 @@
namespace android {
namespace installd {
+// Configuration for bind-mounted Bionic artifacts.
+
+static constexpr const char* kLinkerMountPoint = "/bionic/bin/linker";
+static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker";
+
+static constexpr const char* kBionicLibsMountPointDir = "/bionic/lib/";
+static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/";
+
+static constexpr const char* kLinkerMountPoint64 = "/bionic/bin/linker64";
+static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64";
+
+static constexpr const char* kBionicLibsMountPointDir64 = "/bionic/lib64/";
+static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/";
+
+static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"};
+
+
static void CloseDescriptor(int fd) {
if (fd >= 0) {
int result = close(fd);
@@ -79,6 +96,43 @@
}
}
+// Copied from system/core/init/mount_namespace.cpp.
+static bool BindMount(const std::string& source, const std::string& mount_point,
+ bool recursive = false) {
+ unsigned long mountflags = MS_BIND;
+ if (recursive) {
+ mountflags |= MS_REC;
+ }
+ if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+ PLOG(ERROR) << "Could not bind-mount " << source << " to " << mount_point;
+ return false;
+ }
+ return true;
+}
+
+// Copied from system/core/init/mount_namespace.cpp and and adjusted (bind
+// mounts are not made private, as the /postinstall is already private (see
+// `android::installd::otapreopt_chroot`).
+static bool BindMountBionic(const std::string& linker_source, const std::string& lib_dir_source,
+ const std::string& linker_mount_point,
+ const std::string& lib_mount_dir) {
+ if (access(linker_source.c_str(), F_OK) != 0) {
+ PLOG(INFO) << linker_source << " does not exist. Skipping mounting Bionic there.";
+ return true;
+ }
+ if (!BindMount(linker_source, linker_mount_point)) {
+ return false;
+ }
+ for (const auto& libname : kBionicLibFileNames) {
+ std::string mount_point = lib_mount_dir + libname;
+ std::string source = lib_dir_source + libname;
+ if (!BindMount(source, mount_point)) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Entry for otapreopt_chroot. Expected parameters are:
// [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
@@ -222,6 +276,23 @@
// the Android Runtime APEX, as it is required by otapreopt to run dex2oat.
std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
+ // Bind-mount Bionic artifacts from the Runtime APEX.
+ // This logic is copied and adapted from system/core/init/mount_namespace.cpp.
+ if (!BindMountBionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, kLinkerMountPoint,
+ kBionicLibsMountPointDir)) {
+ LOG(ERROR) << "Failed to mount 32-bit Bionic artifacts from the Runtime APEX.";
+ // Clean up and exit.
+ DeactivateApexPackages(active_packages);
+ exit(215);
+ }
+ if (!BindMountBionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, kLinkerMountPoint64,
+ kBionicLibsMountPointDir64)) {
+ LOG(ERROR) << "Failed to mount 64-bit Bionic artifacts from the Runtime APEX.";
+ // Clean up and exit.
+ DeactivateApexPackages(active_packages);
+ exit(216);
+ }
+
// Now go on and run otapreopt.
// Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index e2c5907..cc24ab3 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -451,12 +451,12 @@
TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) {
auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
- auto fake_package_ce_cache_path = read_path_inode(fake_package_ce_path,
- "cache", kXattrInodeCache);
- auto fake_package_ce_code_cache_path = read_path_inode(fake_package_ce_path,
- "code_cache", kXattrInodeCache);
+ auto fake_package_ce_cache_path = fake_package_ce_path + "/cache";
+ auto fake_package_ce_code_cache_path = fake_package_ce_path + "/code_cache";
auto fake_package_de_cache_path = fake_package_de_path + "/cache";
auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache";
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
@@ -464,20 +464,15 @@
ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 700));
ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 700));
ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 700));
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
auto deleter = [&fake_package_ce_path, &fake_package_de_path,
- &fake_package_ce_cache_path, &fake_package_ce_code_cache_path,
- &fake_package_de_cache_path, &fake_package_de_code_cache_path]() {
+ &rollback_ce_dir, &rollback_de_dir]() {
delete_dir_contents(fake_package_ce_path, true);
delete_dir_contents(fake_package_de_path, true);
- delete_dir_contents(fake_package_ce_cache_path, true);
- delete_dir_contents(fake_package_ce_code_cache_path, true);
- delete_dir_contents(fake_package_de_cache_path, true);
- delete_dir_contents(fake_package_de_code_cache_path, true);
- rmdir(fake_package_ce_cache_path.c_str());
- rmdir(fake_package_ce_code_cache_path.c_str());
- rmdir(fake_package_de_cache_path.c_str());
- rmdir(fake_package_de_code_cache_path.c_str());
+ delete_dir_contents_and_dir(rollback_ce_dir, true);
+ delete_dir_contents_and_dir(rollback_de_dir, true);
};
auto scope_guard = android::base::make_scope_guard(deleter);
diff --git a/data/etc/android.hardware.biometrics.fingerprint.xml b/data/etc/android.hardware.biometrics.fingerprint.xml
deleted file mode 100644
index e5af541..0000000
--- a/data/etc/android.hardware.biometrics.fingerprint.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<!-- This is the standard set of features for a biometric fingerprint sensor. -->
-<permissions>
- <feature name="android.hardware.biometrics.fingerprint" />
-</permissions>
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 34d164c..ce8db91 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -165,6 +165,13 @@
extern std::string getInputDeviceConfigurationFilePathByName(
const std::string& name, InputDeviceConfigurationFileType type);
+enum ReservedInputDeviceId : int32_t {
+ // Device id of a special "virtual" keyboard that is always present.
+ VIRTUAL_KEYBOARD_ID = -1,
+ // Device id of the "built-in" keyboard if there is one.
+ BUILT_IN_KEYBOARD_ID = 0,
+};
+
} // namespace android
#endif // _LIBINPUT_INPUT_DEVICE_H
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 49592a8..a595c01 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -181,7 +181,10 @@
if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
int size = ashmem_get_size_region(obj.handle);
if (size > 0) {
- *outAshmemSize -= size;
+ // ashmem size might have changed since last time it was accounted for, e.g.
+ // in acquire_object(). Value of *outAshmemSize is not critical since we are
+ // releasing the object anyway. Check for integer overflow condition.
+ *outAshmemSize -= std::min(*outAshmemSize, static_cast<size_t>(size));
}
}
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
index 3bfd462..5fa2ff6 100644
--- a/libs/binder/include/binder/SafeInterface.h
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -152,6 +152,12 @@
return callParcel("writeParcelableVector",
[&]() { return parcel->writeParcelableVector(v); });
}
+ status_t read(const Parcel& parcel, float* f) const {
+ return callParcel("readFloat", [&]() { return parcel.readFloat(f); });
+ }
+ status_t write(Parcel* parcel, float f) const {
+ return callParcel("writeFloat", [&]() { return parcel->writeFloat(f); });
+ }
// Templates to handle integral types. We use a struct template to require that the called
// function exactly matches the signedness and size of the argument (e.g., the argument isn't
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index 6a16e24..3b1db27 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -229,6 +229,7 @@
IncrementUint32,
IncrementInt64,
IncrementUint64,
+ IncrementFloat,
IncrementTwo,
Last,
};
@@ -259,6 +260,7 @@
virtual status_t increment(uint32_t a, uint32_t* aPlusOne) const = 0;
virtual status_t increment(int64_t a, int64_t* aPlusOne) const = 0;
virtual status_t increment(uint64_t a, uint64_t* aPlusOne) const = 0;
+ virtual status_t increment(float a, float* aPlusOne) const = 0;
// This tests that input/output parameter interleaving works correctly
virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b,
@@ -353,6 +355,11 @@
using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
return callRemote<Signature>(Tag::IncrementUint64, a, aPlusOne);
}
+ status_t increment(float a, float* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(float, float*) const;
+ return callRemote<Signature>(Tag::IncrementFloat, a, aPlusOne);
+ }
status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
using Signature =
@@ -474,6 +481,11 @@
*aPlusOne = a + 1;
return NO_ERROR;
}
+ status_t increment(float a, float* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = a + 1.0f;
+ return NO_ERROR;
+ }
status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
*aPlusOne = a + 1;
@@ -555,6 +567,10 @@
using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
}
+ case ISafeInterfaceTest::Tag::IncrementFloat: {
+ using Signature = status_t (ISafeInterfaceTest::*)(float, float*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
case ISafeInterfaceTest::Tag::IncrementTwo: {
using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t,
int32_t*) const;
@@ -804,6 +820,14 @@
ASSERT_EQ(a + 1, aPlusOne);
}
+TEST_F(SafeInterfaceTest, TestIncrementFloat) {
+ const float a = 1.0f;
+ float aPlusOne = 0.0f;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a + 1.0f, aPlusOne);
+}
+
TEST_F(SafeInterfaceTest, TestIncrementTwo) {
const int32_t a = 1;
int32_t aPlusOne = 0;
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index b8c6cfe..337308b 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -152,6 +152,20 @@
mDriverPath = path;
}
+void GraphicsEnv::setGpuStats(const std::string driverPackageName,
+ const std::string driverVersionName, const uint64_t driverVersionCode,
+ const std::string appPackageName) {
+ ALOGV("setGpuStats: drvPkgName[%s], drvVerName[%s], drvVerCode[%lld], appPkgName[%s]",
+ driverPackageName.c_str(), driverVersionName.c_str(), (long long)driverVersionCode,
+ appPackageName.c_str());
+ mGpuStats = {
+ .driverPackageName = driverPackageName,
+ .driverVersionName = driverVersionName,
+ .driverVersionCode = driverVersionCode,
+ .appPackageName = appPackageName,
+ };
+}
+
void* GraphicsEnv::loadLibrary(std::string name) {
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index ed08882..a247bec 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -28,6 +28,13 @@
struct NativeLoaderNamespace;
class GraphicsEnv {
+ struct GpuStats {
+ std::string driverPackageName;
+ std::string driverVersionName;
+ uint64_t driverVersionCode;
+ std::string appPackageName;
+ };
+
public:
static GraphicsEnv& getInstance();
@@ -40,6 +47,8 @@
// /data/app/com.example.driver/base.apk!/lib/arm64-v8a
void setDriverPath(const std::string path);
android_namespace_t* getDriverNamespace();
+ void setGpuStats(const std::string driverPackageName, const std::string driverVersionName,
+ const uint64_t versionCode, const std::string appPackageName);
bool shouldUseAngle(std::string appName);
bool shouldUseAngle();
@@ -70,6 +79,7 @@
GraphicsEnv() = default;
std::string mDriverPath;
+ GpuStats mGpuStats;
std::string mAnglePath;
std::string mAngleAppName;
std::string mAngleDeveloperOptIn;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index bef68ef..fc9185d 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -275,12 +275,25 @@
remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
}
- virtual sp<IBinder> getBuiltInDisplay(int32_t id)
- {
+ virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeInt32(id);
- remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply);
+ if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
+ NO_ERROR) {
+ std::vector<PhysicalDisplayId> displayIds;
+ if (reply.readUint64Vector(&displayIds) == NO_ERROR) {
+ return displayIds;
+ }
+ }
+
+ return {};
+ }
+
+ virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeUint64(displayId);
+ remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply);
return reply.readStrongBinder();
}
@@ -722,42 +735,6 @@
return error;
}
- virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
- int32_t* outBufferId) {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-
- data.writeStrongBinder(token);
- if (buffer) {
- data.writeBool(true);
- data.write(*buffer);
- } else {
- data.writeBool(false);
- }
-
- status_t result = remote()->transact(BnSurfaceComposer::CACHE_BUFFER, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
-
- int32_t id = -1;
- result = reply.readInt32(&id);
- if (result == NO_ERROR) {
- *outBufferId = id;
- }
- return result;
- }
-
- virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-
- data.writeStrongBinder(token);
- data.writeInt32(bufferId);
-
- return remote()->transact(BnSurfaceComposer::UNCACHE_BUFFER, data, &reply);
- }
-
virtual status_t isWideColorDisplay(const sp<IBinder>& token,
bool* outIsWideColorDisplay) const {
Parcel data, reply;
@@ -932,10 +909,10 @@
destroyDisplay(display);
return NO_ERROR;
}
- case GET_BUILT_IN_DISPLAY: {
+ case GET_PHYSICAL_DISPLAY_TOKEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int32_t id = data.readInt32();
- sp<IBinder> display(getBuiltInDisplay(id));
+ PhysicalDisplayId displayId = data.readUint64();
+ sp<IBinder> display = getPhysicalDisplayToken(displayId);
reply->writeStrongBinder(display);
return NO_ERROR;
}
@@ -1238,48 +1215,6 @@
}
return error;
}
- case CACHE_BUFFER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> token;
- status_t result = data.readStrongBinder(&token);
- if (result != NO_ERROR) {
- ALOGE("cache buffer failure in reading token: %d", result);
- return result;
- }
-
- sp<GraphicBuffer> buffer = new GraphicBuffer();
- if (data.readBool()) {
- result = data.read(*buffer);
- if (result != NO_ERROR) {
- ALOGE("cache buffer failure in reading buffer: %d", result);
- return result;
- }
- }
- int32_t bufferId = -1;
- status_t error = cacheBuffer(token, buffer, &bufferId);
- if (error == NO_ERROR) {
- reply->writeInt32(bufferId);
- }
- return error;
- }
- case UNCACHE_BUFFER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> token;
- status_t result = data.readStrongBinder(&token);
- if (result != NO_ERROR) {
- ALOGE("uncache buffer failure in reading token: %d", result);
- return result;
- }
-
- int32_t bufferId = -1;
- result = data.readInt32(&bufferId);
- if (result != NO_ERROR) {
- ALOGE("uncache buffer failure in reading buffer id: %d", result);
- return result;
- }
-
- return uncacheBuffer(token, bufferId);
- }
case IS_WIDE_COLOR_DISPLAY: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -1294,12 +1229,14 @@
}
return error;
}
+ case GET_PHYSICAL_DISPLAY_IDS: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ return reply->writeUint64Vector(getPhysicalDisplayIds());
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
}
}
-// ----------------------------------------------------------------------------
-
-};
+} // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1f726b2..3affa23 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -321,8 +321,11 @@
status_t Surface::getWideColorSupport(bool* supported) {
ATRACE_CALL();
- sp<IBinder> display(
- composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ if (display == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+
*supported = false;
status_t error = composerService()->isWideColorDisplay(display, supported);
return error;
@@ -331,8 +334,11 @@
status_t Surface::getHdrSupport(bool* supported) {
ATRACE_CALL();
- sp<IBinder> display(
- composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ if (display == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+
HdrCapabilities hdrCapabilities;
status_t err =
composerService()->getHdrCapabilities(display, &hdrCapabilities);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 51385b8..46b9128 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -48,6 +48,9 @@
#include <private/gui/ComposerService.h>
+// This server size should always be smaller than the server cache size
+#define BUFFER_CACHE_MAX_SIZE 64
+
namespace android {
using ui::ColorMode;
@@ -230,6 +233,113 @@
// ---------------------------------------------------------------------------
+class BufferCache : public Singleton<BufferCache> {
+public:
+ BufferCache() : token(new BBinder()) {}
+
+ sp<IBinder> getToken() {
+ return IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ }
+
+ int32_t getId(const sp<GraphicBuffer>& buffer) {
+ std::lock_guard lock(mMutex);
+
+ auto itr = mBuffers.find(buffer);
+ if (itr == mBuffers.end()) {
+ return -1;
+ }
+ itr->second.counter = getCounter();
+ return itr->second.id;
+ }
+
+ int32_t cache(const sp<GraphicBuffer>& buffer) {
+ std::lock_guard lock(mMutex);
+
+ int32_t bufferId = getNextAvailableId();
+
+ mBuffers[buffer].id = bufferId;
+ mBuffers[buffer].counter = getCounter();
+ return bufferId;
+ }
+
+private:
+ int32_t evictDestroyedBuffer() REQUIRES(mMutex) {
+ auto itr = mBuffers.begin();
+ while (itr != mBuffers.end()) {
+ auto& buffer = itr->first;
+ if (buffer == nullptr || buffer.promote() == nullptr) {
+ int32_t bufferId = itr->second.id;
+ mBuffers.erase(itr);
+ return bufferId;
+ }
+ itr++;
+ }
+ return -1;
+ }
+
+ int32_t evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) {
+ if (mBuffers.size() < 0) {
+ return -1;
+ }
+ auto itr = mBuffers.begin();
+ uint64_t minCounter = itr->second.counter;
+ auto minBuffer = itr;
+ itr++;
+
+ while (itr != mBuffers.end()) {
+ uint64_t counter = itr->second.counter;
+ if (counter < minCounter) {
+ minCounter = counter;
+ minBuffer = itr;
+ }
+ itr++;
+ }
+ int32_t minBufferId = minBuffer->second.id;
+ mBuffers.erase(minBuffer);
+ return minBufferId;
+ }
+
+ int32_t getNextAvailableId() REQUIRES(mMutex) {
+ static int32_t id = 0;
+ if (id + 1 < BUFFER_CACHE_MAX_SIZE) {
+ return id++;
+ }
+
+ // There are no more valid cache ids. To set additional buffers, evict existing buffers
+ // and reuse their cache ids.
+ int32_t bufferId = evictDestroyedBuffer();
+ if (bufferId > 0) {
+ return bufferId;
+ }
+ return evictLeastRecentlyUsedBuffer();
+ }
+
+ uint64_t getCounter() REQUIRES(mMutex) {
+ static uint64_t counter = 0;
+ return counter++;
+ }
+
+ struct Metadata {
+ // The cache id of a buffer that can be set to ISurfaceComposer. When ISurfaceComposer
+ // recieves this id, it can retrieve the buffer from its cache. Caching GraphicBuffers
+ // is important because sending them across processes is expensive.
+ int32_t id = 0;
+ // When a buffer is set, a counter is incremented and stored in the cache's metadata.
+ // When an buffer must be evicted, the entry with the lowest counter value is chosen.
+ uint64_t counter = 0;
+ };
+
+ std::mutex mMutex;
+ std::map<wp<GraphicBuffer>, Metadata> mBuffers GUARDED_BY(mMutex);
+
+ // Used by ISurfaceComposer to identify which process is sending the cached buffer.
+ sp<IBinder> token;
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache);
+
+// ---------------------------------------------------------------------------
+
SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
: mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
@@ -374,8 +484,20 @@
return ComposerService::getComposerService()->destroyDisplay(display);
}
-sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
- return ComposerService::getComposerService()->getBuiltInDisplay(id);
+std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() {
+ return ComposerService::getComposerService()->getPhysicalDisplayIds();
+}
+
+std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
+ return ComposerService::getComposerService()->getInternalDisplayId();
+}
+
+sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
+ return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId);
+}
+
+sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
+ return ComposerService::getComposerService()->getInternalDisplayToken();
}
void SurfaceComposerClient::Transaction::setAnimationTransaction() {
@@ -759,22 +881,17 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eBufferChanged;
- s->buffer = buffer;
- registerSurfaceControlForCallback(sc);
- return *this;
-}
+ int32_t bufferId = BufferCache::getInstance().getId(buffer);
+ if (bufferId < 0) {
+ bufferId = BufferCache::getInstance().cache(buffer);
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachedBuffer(
- const sp<SurfaceControl>& sc, int32_t bufferId) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
+ s->what |= layer_state_t::eBufferChanged;
+ s->buffer = buffer;
}
+
s->what |= layer_state_t::eCachedBufferChanged;
- s->cachedBuffer.token = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ s->cachedBuffer.token = BufferCache::getInstance().getToken();
s->cachedBuffer.bufferId = bufferId;
registerSurfaceControlForCallback(sc);
@@ -1217,26 +1334,6 @@
// ----------------------------------------------------------------------------
-status_t SurfaceComposerClient::cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- if (buffer == nullptr || outBufferId == nullptr) {
- return BAD_VALUE;
- }
- return sf->cacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
- buffer, outBufferId);
-}
-
-status_t SurfaceComposerClient::uncacheBuffer(int32_t bufferId) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- if (bufferId < 0) {
- return BAD_VALUE;
- }
- return sf->uncacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
- bufferId);
-}
-
-// ----------------------------------------------------------------------------
-
status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
return sf->enableVSyncInjections(enable);
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 008f520..55488da 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -63,23 +63,25 @@
SurfaceControl::~SurfaceControl()
{
+ // Avoid reparenting the server-side surface to null if we are not the owner of it,
+ // meaning that we retrieved it from another process.
if (mClient != nullptr && mHandle != nullptr && mOwned) {
SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient());
}
- mClient.clear();
- mHandle.clear();
- mGraphicBufferProducer.clear();
- IPCThreadState::self()->flushCommands();
+ release();
}
void SurfaceControl::destroy()
{
- // Avoid destroying the server-side surface if we are not the owner of it, meaning that we
- // retrieved it from another process.
- if (isValid() && mOwned) {
+ if (isValid()) {
SurfaceComposerClient::Transaction().reparent(this, nullptr).apply();
}
- // clear all references and trigger an IPC now, to make sure things
+ release();
+}
+
+void SurfaceControl::release()
+{
+ // Trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
mClient.clear();
mHandle.clear();
@@ -87,17 +89,6 @@
IPCThreadState::self()->flushCommands();
}
-void SurfaceControl::clear()
-{
- // here, the window manager tells us explicitly that we should destroy
- // the surface's resource. Soon after this call, it will also release
- // its last reference (which will call the dtor); however, it is possible
- // that a client living in the same process still holds references which
- // would delay the call to the dtor -- that is why we need this explicit
- // "clear()" call.
- destroy();
-}
-
void SurfaceControl::disconnect() {
if (mGraphicBufferProducer != nullptr) {
mGraphicBufferProducer->disconnect(
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index a4102df..8c3f463 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -58,7 +58,7 @@
struct Header {
uint32_t type;
- uint32_t id;
+ PhysicalDisplayId displayId;
nsecs_t timestamp __attribute__((aligned(8)));
};
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 3899f6a..a2db7bc 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -34,6 +34,7 @@
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
+#include <optional>
#include <vector>
namespace android {
@@ -71,11 +72,6 @@
eEarlyWakeup = 0x04
};
- enum {
- eDisplayIdMain = 0,
- eDisplayIdHdmi = 1
- };
-
enum Rotation {
eRotateNone = 0,
eRotate90 = 1,
@@ -88,7 +84,7 @@
eVsyncSourceSurfaceFlinger = 1
};
- /*
+ /*
* Create a connection with SurfaceFlinger.
*/
virtual sp<ISurfaceComposerClient> createConnection() = 0;
@@ -108,10 +104,26 @@
*/
virtual void destroyDisplay(const sp<IBinder>& display) = 0;
- /* get the token for the existing default displays. possible values
- * for id are eDisplayIdMain and eDisplayIdHdmi.
+ /* get stable IDs for connected physical displays.
*/
- virtual sp<IBinder> getBuiltInDisplay(int32_t id) = 0;
+ virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+ const auto displayIds = getPhysicalDisplayIds();
+ return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
+ }
+
+ /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
+ * DisplayEventReceiver hotplug event.
+ */
+ virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const = 0;
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+ }
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual void setTransactionState(const Vector<ComposerState>& state,
@@ -320,11 +332,6 @@
*/
virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
- virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
- int32_t* outBufferId) = 0;
-
- virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) = 0;
-
/*
* Queries whether the given display is a wide color display.
* Requires the ACCESS_SURFACE_FLINGER permission.
@@ -346,7 +353,7 @@
CREATE_DISPLAY_EVENT_CONNECTION,
CREATE_DISPLAY,
DESTROY_DISPLAY,
- GET_BUILT_IN_DISPLAY,
+ GET_PHYSICAL_DISPLAY_TOKEN,
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
GET_SUPPORTED_FRAME_TIMESTAMPS,
@@ -373,10 +380,9 @@
SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
GET_DISPLAYED_CONTENT_SAMPLE,
GET_PROTECTED_CONTENT_SUPPORT,
- CACHE_BUFFER,
- UNCACHE_BUFFER,
IS_WIDE_COLOR_DISPLAY,
GET_DISPLAY_NATIVE_PRIMARIES,
+ GET_PHYSICAL_DISPLAY_IDS,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index a95664b..aa99bd2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -152,12 +152,6 @@
static void doDropReferenceTransaction(const sp<IBinder>& handle,
const sp<ISurfaceComposerClient>& client);
- // Caches a buffer with the ISurfaceComposer so the buffer does not need to be resent across
- // processes
- static status_t cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId);
- // Uncaches a buffer set by cacheBuffer
- static status_t uncacheBuffer(int32_t bufferId);
-
// Queries whether a given display is wide color display.
static status_t isWideColorDisplay(const sp<IBinder>& display, bool* outIsWideColorDisplay);
@@ -202,9 +196,13 @@
//! Destroy a virtual display
static void destroyDisplay(const sp<IBinder>& display);
- //! Get the token for the existing default displays.
- //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
- static sp<IBinder> getBuiltInDisplay(int32_t id);
+ //! Get stable IDs for connected physical displays
+ static std::vector<PhysicalDisplayId> getPhysicalDisplayIds();
+ static std::optional<PhysicalDisplayId> getInternalDisplayId();
+
+ //! Get token for a physical display given its stable ID
+ static sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId);
+ static sp<IBinder> getInternalDisplayToken();
static status_t enableVSyncInjections(bool enable);
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index b584f36..55efcbf 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -58,8 +58,12 @@
static bool isSameSurface(
const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
- // release surface data from java
- void clear();
+ // Release the handles assosciated with the SurfaceControl, without reparenting
+ // them off-screen. At the moment if this isn't executed before ~SurfaceControl
+ // is called then the destructor will reparent the layer off-screen for you.
+ void release();
+ // Reparent off-screen and release. This is invoked by the destructor.
+ void destroy();
// disconnect any api that's connected
void disconnect();
@@ -98,7 +102,6 @@
sp<Surface> generateSurfaceLocked() const;
status_t validate() const;
- void destroy();
sp<SurfaceComposerClient> mClient;
sp<IBinder> mHandle;
diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp
index 5443812..b647aab 100644
--- a/libs/gui/tests/DisplayedContentSampling_test.cpp
+++ b/libs/gui/tests/DisplayedContentSampling_test.cpp
@@ -32,7 +32,7 @@
void SetUp() {
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(OK, mComposerClient->initCheck());
- mDisplayToken = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ mDisplayToken = mComposerClient->getInternalDisplayToken();
ASSERT_TRUE(mDisplayToken);
}
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index ac97733..4a78480 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -233,9 +233,11 @@
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+ const auto display = mComposerClient->getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- auto display = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info));
// After a new buffer is queued, SurfaceFlinger is notified and will
// latch the new buffer on next vsync. Let's heuristically wait for 3
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 1705fd7..bec9299 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -131,8 +131,10 @@
// Verify the screenshot works with no protected buffers.
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> display(sf->getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+
+ const sp<IBinder> display = sf->getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
sp<GraphicBuffer> outBuffer;
ASSERT_EQ(NO_ERROR,
sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
@@ -552,7 +554,8 @@
sp<IBinder> createDisplay(const String8& /*displayName*/,
bool /*secure*/) override { return nullptr; }
void destroyDisplay(const sp<IBinder>& /*display */) override {}
- sp<IBinder> getBuiltInDisplay(int32_t /*id*/) override { return nullptr; }
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
+ sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
void setTransactionState(const Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
const sp<IBinder>& /*applyToken*/,
@@ -664,11 +667,6 @@
status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
- status_t cacheBuffer(const sp<IBinder>& /*token*/, const sp<GraphicBuffer>& /*buffer*/,
- int32_t* /*outBufferId*/) {
- return NO_ERROR;
- }
- status_t uncacheBuffer(const sp<IBinder>& /*token*/, int32_t /*bufferId*/) { return NO_ERROR; }
status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
protected:
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 6ea1270..8ef4896 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -263,8 +263,17 @@
if (!desc) return 0;
if (!AHardwareBuffer_isValidDescription(desc, /*log=*/false)) return 0;
- // Make a trial allocation.
- // TODO(b/115660272): add implementation that uses a HAL query.
+ bool supported = false;
+ GraphicBuffer* gBuffer = new GraphicBuffer();
+ status_t err = gBuffer->isSupported(desc->width, desc->height, desc->format, desc->layers,
+ desc->usage, &supported);
+
+ if (err == NO_ERROR) {
+ return supported;
+ }
+
+ // function isSupported is not implemented on device or an error occurred during HAL
+ // query. Make a trial allocation.
AHardwareBuffer_Desc trialDesc = *desc;
trialDesc.width = 4;
trialDesc.height = desc->format == AHARDWAREBUFFER_FORMAT_BLOB ? 1 : 4;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index c137394..8f9071e 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -424,6 +424,7 @@
mTraceGpuCompletion = true;
mFlushTracer = std::make_unique<FlushTracer>(this);
}
+ mDrawingBuffer = createFramebuffer();
}
GLESRenderEngine::~GLESRenderEngine() {
@@ -439,6 +440,10 @@
return std::make_unique<GLImage>(*this);
}
+Framebuffer* GLESRenderEngine::getFramebufferForDrawing() {
+ return mDrawingBuffer.get();
+}
+
void GLESRenderEngine::primeCache() const {
ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
mFeatureFlags & USE_COLOR_MANAGEMENT);
@@ -546,6 +551,8 @@
}
void GLESRenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+ ATRACE_CALL();
+ glDisable(GL_BLEND);
glClearColor(red, green, blue, alpha);
glClear(GL_COLOR_BUFFER_BIT);
}
@@ -676,6 +683,7 @@
}
void GLESRenderEngine::evictImages(const std::vector<LayerSettings>& layers) {
+ ATRACE_CALL();
// destroy old image references that we're not going to draw with.
std::unordered_set<uint64_t> bufIds;
for (auto layer : layers) {
@@ -742,6 +750,7 @@
}
void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
+ ATRACE_CALL();
mFboHeight = 0;
// back to main framebuffer
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 34187f1..7b72666 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -88,6 +88,7 @@
EGLConfig getEGLConfig() const { return mEGLConfig; }
protected:
+ Framebuffer* getFramebufferForDrawing() override;
void dump(std::string& result) override;
void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
ui::Transform::orientation_flags rotation) override;
@@ -191,6 +192,8 @@
// more complicated interface.
std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache;
+ std::unique_ptr<Framebuffer> mDrawingBuffer;
+
class FlushTracer {
public:
FlushTracer(GLESRenderEngine* engine);
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index bc1a4da..b51ed22 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -174,37 +174,37 @@
// fence.
// @return An error code indicating whether drawing was successful. For
// now, this always returns NO_ERROR.
- // TODO(alecmouri): Consider making this a multi-display API, so that the
- // caller deoes not need to handle multiple fences.
virtual status_t drawLayers(const DisplaySettings& display,
const std::vector<LayerSettings>& layers,
ANativeWindowBuffer* buffer, base::unique_fd* drawFence) = 0;
- // TODO(alecmouri): Expose something like bindTexImage() so that devices
- // that don't support native sync fences can get rid of code duplicated
- // between BufferStateLayer and BufferQueueLayer for binding an external
- // texture.
-
- // TODO(alecmouri): Add API to help with managing a texture pool.
+protected:
+ // Gets a framebuffer to render to. This framebuffer may or may not be
+ // cached depending on the implementation.
+ //
+ // Note that this method does not transfer ownership, so the caller most not
+ // live longer than RenderEngine.
+ virtual Framebuffer* getFramebufferForDrawing() = 0;
+ friend class BindNativeBufferAsFramebuffer;
};
class BindNativeBufferAsFramebuffer {
public:
BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
- : mEngine(engine), mFramebuffer(mEngine.createFramebuffer()), mStatus(NO_ERROR) {
+ : mEngine(engine), mFramebuffer(mEngine.getFramebufferForDrawing()), mStatus(NO_ERROR) {
mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected())
- ? mEngine.bindFrameBuffer(mFramebuffer.get())
+ ? mEngine.bindFrameBuffer(mFramebuffer)
: NO_MEMORY;
}
~BindNativeBufferAsFramebuffer() {
mFramebuffer->setNativeWindowBuffer(nullptr, false);
- mEngine.unbindFrameBuffer(mFramebuffer.get());
+ mEngine.unbindFrameBuffer(mFramebuffer);
}
status_t getStatus() const { return mStatus; }
private:
RenderEngine& mEngine;
- std::unique_ptr<Framebuffer> mFramebuffer;
+ Framebuffer* mFramebuffer;
status_t mStatus;
};
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 4b86cfe..800eac3 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -36,6 +36,7 @@
MOCK_METHOD0(createFramebuffer, std::unique_ptr<renderengine::Framebuffer>());
MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
+ MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*());
MOCK_CONST_METHOD0(primeCache, void());
MOCK_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(useNativeFenceSync, bool());
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 0ee6153..f82beeb 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -178,6 +178,9 @@
template <typename SourceVariant>
void fillBufferWithRoundedCorners();
+ template <typename SourceVariant>
+ void overlayCorners();
+
void fillRedBufferTextureTransform();
void fillBufferTextureTransform();
@@ -543,6 +546,44 @@
255);
}
+template <typename SourceVariant>
+void RenderEngineTest::overlayCorners() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ std::vector<renderengine::LayerSettings> layersFirst;
+
+ renderengine::LayerSettings layerOne;
+ layerOne.geometry.boundaries =
+ FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0);
+ SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
+ layerOne.alpha = 0.2;
+
+ layersFirst.push_back(layerOne);
+ invokeDraw(settings, layersFirst, mBuffer);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 0, 0, 0, 0);
+
+ std::vector<renderengine::LayerSettings> layersSecond;
+ renderengine::LayerSettings layerTwo;
+ layerTwo.geometry.boundaries =
+ FloatRect(DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
+ SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
+ layerTwo.alpha = 1.0f;
+
+ layersSecond.push_back(layerTwo);
+ invokeDraw(settings, layersSecond, mBuffer);
+
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 0, 255, 0, 255);
+}
+
void RenderEngineTest::fillRedBufferTextureTransform() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
@@ -746,6 +787,10 @@
fillBufferWithRoundedCorners<ColorSourceVariant>();
}
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
+ overlayCorners<ColorSourceVariant>();
+}
+
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
@@ -794,6 +839,10 @@
fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
+ overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
@@ -842,6 +891,10 @@
fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
+ overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
TEST_F(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
fillBufferTextureTransform();
}
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 92ea07c..5dc4530 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -351,6 +351,12 @@
return releaseFence;
}
+status_t Gralloc2Mapper::isSupported(uint32_t /*width*/, uint32_t /*height*/,
+ android::PixelFormat /*format*/, uint32_t /*layerCount*/,
+ uint64_t /*usage*/, bool* /*outSupported*/) const {
+ return INVALID_OPERATION;
+}
+
Gralloc2Allocator::Gralloc2Allocator(const Gralloc2Mapper& mapper) : mMapper(mapper) {
mAllocator = IAllocator::getService();
if (mAllocator == nullptr) {
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
index 306a74b..7f8e57c 100644
--- a/libs/ui/Gralloc3.cpp
+++ b/libs/ui/Gralloc3.cpp
@@ -314,6 +314,36 @@
return releaseFence;
}
+status_t Gralloc3Mapper::isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ bool* outSupported) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ Error error;
+ auto ret = mMapper->isSupported(descriptorInfo,
+ [&](const auto& tmpError, const auto& tmpSupported) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ if (outSupported) {
+ *outSupported = tmpSupported;
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("isSupported(%u, %u, %d, %u, ...) failed with %d", width, height, format, layerCount,
+ error);
+ }
+
+ return static_cast<status_t>(error);
+}
+
Gralloc3Allocator::Gralloc3Allocator(const Gralloc3Mapper& mapper) : mMapper(mapper) {
mAllocator = IAllocator::getService();
if (mAllocator == nullptr) {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 15597eb..41ae253 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -286,22 +286,22 @@
return res;
}
-status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd)
-{
+status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
const Rect lockBounds(width, height);
- status_t res = lockAsync(inUsage, lockBounds, vaddr, fenceFd);
+ status_t res =
+ lockAsync(inUsage, lockBounds, vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
return res;
}
-status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect,
- void** vaddr, int fenceFd)
-{
- return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd);
+status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
+ return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
}
-status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage,
- uint64_t inConsumerUsage, const Rect& rect, void** vaddr, int fenceFd)
-{
+status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
+ const Rect& rect, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
if (rect.left < 0 || rect.right > width ||
rect.top < 0 || rect.bottom > height) {
ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
@@ -310,9 +310,9 @@
return BAD_VALUE;
}
- int32_t bytesPerPixel, bytesPerStride;
status_t res = getBufferMapper().lockAsync(handle, inProducerUsage, inConsumerUsage, rect,
- vaddr, fenceFd, &bytesPerPixel, &bytesPerStride);
+ vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
+
return res;
}
@@ -344,6 +344,13 @@
return res;
}
+status_t GraphicBuffer::isSupported(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage,
+ bool* outSupported) const {
+ return mBufferMapper.isSupported(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+ outSupported);
+}
+
size_t GraphicBuffer::getFlattenedSize() const {
return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
}
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 79c333f..06981c3 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -161,5 +161,10 @@
return NO_ERROR;
}
+status_t GraphicBufferMapper::isSupported(uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount,
+ uint64_t usage, bool* outSupported) {
+ return mMapper->isSupported(width, height, format, layerCount, usage, outSupported);
+}
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
index 1b8a930..6cc23f0 100644
--- a/libs/ui/include/ui/Gralloc.h
+++ b/libs/ui/include/ui/Gralloc.h
@@ -67,6 +67,15 @@
// unlock returns a fence sync object (or -1) and the fence sync object is
// owned by the caller
virtual int unlock(buffer_handle_t bufferHandle) const = 0;
+
+ // isSupported queries whether or not a buffer with the given width, height,
+ // format, layer count, and usage can be allocated on the device. If
+ // *outSupported is set to true, a buffer with the given specifications may be successfully
+ // allocated if resources are available. If false, a buffer with the given specifications will
+ // never successfully allocate on this device. Note that this function is not guaranteed to be
+ // supported on all devices, in which case a status_t of INVALID_OPERATION will be returned.
+ virtual status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported) const = 0;
};
// A wrapper to IAllocator
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 4ef9b51..948f597 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -61,6 +61,9 @@
int unlock(buffer_handle_t bufferHandle) const override;
+ status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported) const override;
+
private:
// Determines whether the passed info is compatible with the mapper.
status_t validateBufferDescriptorInfo(
diff --git a/libs/ui/include/ui/Gralloc3.h b/libs/ui/include/ui/Gralloc3.h
index 879e96e..0965f52 100644
--- a/libs/ui/include/ui/Gralloc3.h
+++ b/libs/ui/include/ui/Gralloc3.h
@@ -60,6 +60,9 @@
int unlock(buffer_handle_t bufferHandle) const override;
+ status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported) const override;
+
private:
// Determines whether the passed info is compatible with the mapper.
status_t validateBufferDescriptorInfo(
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 18a27a0..4d4ee68 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -180,17 +180,24 @@
status_t lockYCbCr(uint32_t inUsage, const Rect& rect,
android_ycbcr *ycbcr);
status_t unlock();
- status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd);
- status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr,
- int fenceFd);
- status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
- const Rect& rect, void** vaddr, int fenceFd);
+ // For the following three lockAsync functions, if bytesPerStride or bytesPerPixel
+ // are unknown or variable, -1 will be returned
+ status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+ status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+ status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage, const Rect& rect,
+ void** vaddr, int fenceFd, int32_t* outBytesPerPixel = nullptr,
+ int32_t* outBytesPerStride = nullptr);
status_t lockAsyncYCbCr(uint32_t inUsage, android_ycbcr *ycbcr,
int fenceFd);
status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
android_ycbcr *ycbcr, int fenceFd);
status_t unlockAsync(int *fenceFd);
+ status_t isSupported(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, bool* outSupported) const;
+
ANativeWindowBuffer* getNativeBuffer() const;
// for debugging
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 072926f..77c99cc 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -78,6 +78,9 @@
status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
+ status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported);
+
const GrallocMapper& getGrallocMapper() const {
return reinterpret_cast<const GrallocMapper&>(*mMapper);
}
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index 4b03e44..5dc56c8 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -16,13 +16,21 @@
#pragma once
+#include <cinttypes>
+#include <cstdint>
+
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/common/1.2/types.h>
#include <system/graphics.h>
+#define ANDROID_PHYSICAL_DISPLAY_ID_FORMAT PRIu64
+
+namespace android {
+
+using PhysicalDisplayId = uint64_t;
+
// android::ui::* in this header file will alias different types as
// the HIDL interface is updated.
-namespace android {
namespace ui {
using android::hardware::graphics::common::V1_1::RenderIntent;
diff --git a/libs/ui/tests/BufferHubEventFd_test.cpp b/libs/ui/tests/BufferHubEventFd_test.cpp
index 2c9aa57..ef1781f 100644
--- a/libs/ui/tests/BufferHubEventFd_test.cpp
+++ b/libs/ui/tests/BufferHubEventFd_test.cpp
@@ -35,6 +35,7 @@
const int kTimeout = 100;
const std::chrono::milliseconds kTimeoutMs(kTimeout);
+const int kTestRuns = 5;
using ::testing::Contains;
using BufferHubEventFdTest = ::testing::Test;
@@ -46,9 +47,9 @@
ASSERT_TRUE(eventFd.isValid());
base::unique_fd epollFd(epoll_create(64));
- epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
-
ASSERT_GE(epollFd.get(), 0);
+
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
std::array<epoll_event, 1> events;
@@ -59,6 +60,96 @@
// The epoll fd is edge triggered, so it only responds to the eventFd once.
EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ // Check that it can receive consecutive signal.
+ eventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ // Check that it can receive consecutive signal from a duplicated eventfd.
+ BufferHubEventFd dupEventFd(dup(eventFd.get()));
+ ASSERT_TRUE(dupEventFd.isValid());
+ dupEventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+ dupEventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testCreateEpollFdAndAddSignaledEventFd) {
+ BufferHubEventFd eventFd;
+ ASSERT_TRUE(eventFd.isValid());
+ eventFd.signal();
+
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+
+ // Make sure that the epoll set has not been signal yet.
+ std::array<epoll_event, 1> events;
+ ASSERT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ // Check that adding an signaled fd into this epoll set will trigger the epoll set.
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+ // The epoll fd is edge triggered, so it only responds to the eventFd once.
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testAddSignaledEventFdToEpollFd) {
+ BufferHubEventFd eventFd;
+ ASSERT_TRUE(eventFd.isValid());
+
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+
+ eventFd.signal();
+
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+ std::array<epoll_event, 1> events;
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+ // The epoll fd is edge triggered, so it only responds to the eventFd once.
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromAEventFd) {
+ BufferHubEventFd eventFd;
+ ASSERT_TRUE(eventFd.isValid());
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+ std::array<epoll_event, 1> events;
+ for (int i = 0; i < kTestRuns; ++i) {
+ eventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+ }
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromADuplicatedEventFd) {
+ BufferHubEventFd eventFd;
+ ASSERT_TRUE(eventFd.isValid());
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+ BufferHubEventFd dupEventFd(dup(eventFd.get()));
+ ASSERT_TRUE(dupEventFd.isValid());
+
+ std::array<epoll_event, 1> events;
+ for (int i = 0; i < kTestRuns; ++i) {
+ dupEventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+ }
}
TEST_F(BufferHubEventFdTest, EventFd_testClear) {
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index a47a98f..527a27d 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -10,6 +10,7 @@
#include <mutex>
#include <thread>
+namespace {
#define RETRY_EINTR(fnc_call) \
([&]() -> decltype(fnc_call) { \
decltype(fnc_call) result; \
@@ -30,6 +31,7 @@
using android::dvr::ProducerBuffer;
using android::pdx::LocalHandle;
using android::pdx::Status;
+using LibBufferHubTest = ::testing::Test;
const int kWidth = 640;
const int kHeight = 480;
@@ -41,7 +43,15 @@
android::BufferHubDefs::kMaxNumberOfClients - 1;
const int kPollTimeoutMs = 100;
-using LibBufferHubTest = ::testing::Test;
+// Helper function to poll the eventfd in BufferHubBase.
+template <class BufferHubBase>
+int PollBufferEvent(const std::unique_ptr<BufferHubBase>& buffer,
+ int timeout_ms = kPollTimeoutMs) {
+ pollfd p = {buffer->event_fd(), POLLIN, 0};
+ return poll(&p, 1, timeout_ms);
+}
+
+} // namespace
TEST_F(LibBufferHubTest, TestBasicUsage) {
std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
@@ -61,36 +71,36 @@
EXPECT_EQ(c2->client_state_mask(), kFirstClientBitMask << 2);
// Initial state: producer not available, consumers not available.
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
EXPECT_EQ(0, p->GainAsync());
EXPECT_EQ(0, p->Post(LocalHandle()));
// New state: producer not available, consumers available.
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_EQ(1, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(c2)));
LocalHandle fence;
EXPECT_EQ(0, c1->Acquire(&fence));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(c2)));
EXPECT_EQ(0, c2->Acquire(&fence));
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
EXPECT_EQ(0, c1->Release(LocalHandle()));
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, c2->Discard());
- EXPECT_EQ(1, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, p->Gain(&fence));
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
}
TEST_F(LibBufferHubTest, TestEpoll) {
@@ -225,7 +235,7 @@
// Release in acquired state should succeed.
EXPECT_EQ(0, c->Release(LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
// Acquire and post in released state should fail.
EXPECT_EQ(-EBUSY, c->Acquire(&fence));
@@ -266,7 +276,7 @@
EXPECT_FALSE(invalid_fence.IsValid());
// Acquire in posted state should succeed.
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
EXPECT_FALSE(invalid_fence.IsValid());
EXPECT_EQ(p->buffer_state(), c->buffer_state());
@@ -281,7 +291,7 @@
// Release in acquired state should succeed.
EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(p->buffer_state(), c->buffer_state());
EXPECT_TRUE(p->is_released());
@@ -387,7 +397,7 @@
for (size_t i = 0; i < kMaxConsumerCount; ++i) {
EXPECT_TRUE(
IsClientPosted(cs[i]->buffer_state(), cs[i]->client_state_mask()));
- EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(cs[i])));
EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence));
EXPECT_TRUE(
IsClientAcquired(p->buffer_state(), cs[i]->client_state_mask()));
@@ -400,7 +410,7 @@
EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence));
}
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_TRUE(p->is_released());
// Buffer state cross all clients must be consistent.
@@ -427,7 +437,7 @@
// Post the gained buffer should signal already created consumer.
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
EXPECT_TRUE(AnyClientPosted(p->buffer_state()));
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
EXPECT_TRUE(AnyClientAcquired(c->buffer_state()));
}
@@ -445,7 +455,7 @@
// Post the gained buffer before any consumer gets created.
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
EXPECT_TRUE(p->is_released());
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
// Newly created consumer will be signalled for the posted buffer although it
// is created after producer posting.
@@ -471,7 +481,7 @@
// Post, acquire, and release the buffer..
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
- EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c1)));
EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence));
EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence));
@@ -479,7 +489,7 @@
// executed before Release impulse gets executed by bufferhubd. Thus, here we
// need to wait until the releasd is confirmed before creating another
// consumer.
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_TRUE(p->is_released());
// Create another consumer immediately after the release, should not make the
@@ -507,14 +517,14 @@
EXPECT_EQ(0, p->GainAsync());
Metadata m = {1, 3};
EXPECT_EQ(0, p->Post(LocalHandle(), &m, sizeof(Metadata)));
- EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LE(0, RETRY_EINTR(PollBufferEvent(c)));
LocalHandle fence;
Metadata m2 = {};
EXPECT_EQ(0, c->Acquire(&fence, &m2, sizeof(m2)));
EXPECT_EQ(m.field1, m2.field1);
EXPECT_EQ(m.field2, m2.field2);
EXPECT_EQ(0, c->Release(LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p, /*timeout_ms=*/0)));
}
TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
@@ -539,7 +549,7 @@
// buffer allocation.
OverSizedMetadata evil_meta = {};
EXPECT_NE(0, p->Post(LocalHandle(), &evil_meta, sizeof(OverSizedMetadata)));
- EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_GE(0, RETRY_EINTR(PollBufferEvent(c)));
// It is ok to post metadata smaller than originally requested during
// buffer allocation.
@@ -651,7 +661,7 @@
// Should acquire a valid fence.
LocalHandle f2;
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&meta, &f2));
EXPECT_TRUE(f2.IsValid());
// The original fence and acquired fence should have different fd number.
@@ -668,7 +678,7 @@
// Should gain an invalid fence.
LocalHandle f3;
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, p->GainAsync(&meta, &f3));
EXPECT_FALSE(f3.IsValid());
@@ -677,7 +687,7 @@
// Should acquire a valid fence and it's already signalled.
LocalHandle f4;
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&meta, &f4));
EXPECT_TRUE(f4.IsValid());
EXPECT_LT(0, PollFd(f4.Get(), kPollTimeoutMs));
@@ -690,7 +700,7 @@
// Should gain a valid fence, which is already signaled.
LocalHandle f6;
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, p->GainAsync(&meta, &f6));
EXPECT_TRUE(f6.IsValid());
EXPECT_LT(0, PollFd(f6.Get(), kPollTimeoutMs));
@@ -710,14 +720,14 @@
EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
LocalHandle fence;
- EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c1)));
EXPECT_EQ(0, c1->AcquireAsync(&meta, &fence));
// Destroy the consumer who has acquired but not released the buffer.
c1 = nullptr;
// The buffer is now available for the producer to gain.
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
// Newly added consumer is not able to acquire the buffer.
std::unique_ptr<ConsumerBuffer> c2 =
@@ -725,7 +735,7 @@
ASSERT_TRUE(c2.get() != nullptr);
const uint32_t client_state_mask2 = c2->client_state_mask();
EXPECT_NE(client_state_mask1, client_state_mask2);
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
EXPECT_EQ(-EBUSY, c2->AcquireAsync(&meta, &fence));
// Producer should be able to gain.
@@ -744,7 +754,7 @@
EXPECT_EQ(0, p->GainAsync());
DvrNativeBufferMetadata meta;
EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c1)));
// c2 is created when the buffer is in posted state. buffer state for c1 is
// posted. Thus, c2 should be automatically set to posted and able to acquire.
@@ -753,7 +763,7 @@
ASSERT_TRUE(c2.get() != nullptr);
const uint32_t client_state_mask2 = c2->client_state_mask();
EXPECT_NE(client_state_mask1, client_state_mask2);
- EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c2)));
LocalHandle invalid_fence;
EXPECT_EQ(0, c2->AcquireAsync(&meta, &invalid_fence));
@@ -768,7 +778,7 @@
const uint32_t client_state_mask3 = c3->client_state_mask();
EXPECT_NE(client_state_mask1, client_state_mask3);
EXPECT_NE(client_state_mask2, client_state_mask3);
- EXPECT_LT(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c3)));
EXPECT_EQ(0, c3->AcquireAsync(&meta, &invalid_fence));
// Releasing c2 and c3 in normal ways.
@@ -779,7 +789,7 @@
c1 = nullptr;
// The buffer is now available for the producer to gain.
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
// C4 is created in released state. Thus, it cannot gain the just posted
// buffer.
@@ -788,7 +798,7 @@
ASSERT_TRUE(c4.get() != nullptr);
const uint32_t client_state_mask4 = c4->client_state_mask();
EXPECT_NE(client_state_mask3, client_state_mask4);
- EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
+ EXPECT_GE(0, RETRY_EINTR(PollBufferEvent(c3)));
EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &invalid_fence));
// Producer should be able to gain.
@@ -813,7 +823,7 @@
// Detach in posted state should fail.
EXPECT_EQ(0, p->GainAsync());
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
- EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(c)), 0);
auto s1 = p->Detach();
EXPECT_FALSE(s1);
@@ -824,7 +834,7 @@
// Detach in released state should fail.
EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
- EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(p)), 0);
s1 = p->Detach();
EXPECT_FALSE(s1);
@@ -837,12 +847,12 @@
EXPECT_TRUE(handle.valid());
// Both producer and consumer should have hangup.
- EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(p)), 0);
auto s2 = p->GetEventMask(POLLHUP);
EXPECT_TRUE(s2);
EXPECT_EQ(s2.get(), POLLHUP);
- EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(c)), 0);
s2 = p->GetEventMask(POLLHUP);
EXPECT_TRUE(s2);
EXPECT_EQ(s2.get(), POLLHUP);
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index 8497f3e..b28d101 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -196,12 +196,6 @@
return 0;
}
-int BufferHubBase::Poll(int timeout_ms) {
- ATRACE_NAME("BufferHubBase::Poll");
- pollfd p = {event_fd(), POLLIN, 0};
- return poll(&p, 1, timeout_ms);
-}
-
int BufferHubBase::Lock(int usage, int x, int y, int width, int height,
void** address) {
return buffer_.Lock(usage, x, y, width, height, address);
@@ -218,12 +212,5 @@
return ret;
}
-void BufferHubBase::GetBlobFds(int* fds, size_t* fds_count,
- size_t max_fds_count) const {
- size_t numFds = static_cast<size_t>(native_handle()->numFds);
- *fds_count = std::min(max_fds_count, numFds);
- std::copy(native_handle()->data, native_handle()->data + *fds_count, fds);
-}
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 889763a..fa39d08 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -21,19 +21,6 @@
// a file descriptor for the new channel or a negative error code.
Status<LocalChannelHandle> CreateConsumer();
- // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
- int Poll(int timeout_ms);
-
- // Locks the area specified by (x, y, width, height) for a specific usage. If
- // the usage is software then |addr| will be updated to point to the address
- // of the buffer in virtual memory. The caller should only access/modify the
- // pixels in the specified area. anything else is undefined behavior.
- int Lock(int usage, int x, int y, int width, int height, void** addr);
-
- // Must be called after Lock() when the caller has finished changing the
- // buffer.
- int Unlock();
-
// Gets a blob buffer that was created with ProducerBuffer::CreateBlob.
// Locking and Unlocking is handled internally. There's no need to Unlock
// after calling this method.
@@ -52,10 +39,6 @@
return LocalHandle(dup(native_handle()->data[0]));
}
- // Get up to |max_fds_count| file descriptors for accessing the blob shared
- // memory. |fds_count| will contain the actual number of file descriptors.
- void GetBlobFds(int* fds, size_t* fds_count, size_t max_fds_count) const;
-
using Client::event_fd;
Status<int> GetEventMask(int events) {
@@ -135,6 +118,16 @@
int UpdateSharedFence(const LocalHandle& new_fence,
const LocalHandle& shared_fence);
+ // Locks the area specified by (x, y, width, height) for a specific usage. If
+ // the usage is software then |addr| will be updated to point to the address
+ // of the buffer in virtual memory. The caller should only access/modify the
+ // pixels in the specified area. anything else is undefined behavior.
+ int Lock(int usage, int x, int y, int width, int height, void** addr);
+
+ // Must be called after Lock() when the caller has finished changing the
+ // buffer.
+ int Unlock();
+
// IonBuffer that is shared between bufferhubd, producer, and consumers.
size_t metadata_buf_size_{0};
size_t user_metadata_size_{0};
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
index 0eb7fec..7075e88 100644
--- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
@@ -205,9 +205,9 @@
ASSERT_EQ(buffer.get()->height(), metrics.get().display_height);
void* raw_buf = nullptr;
- ASSERT_GE(buffer.get()->Lock(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
- /*x=*/0, /*y=*/0, buffer.get()->width(),
- buffer.get()->height(), &raw_buf),
+ ASSERT_GE(buffer.get()->buffer()->Lock(
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, /*x=*/0, /*y=*/0,
+ buffer.get()->width(), buffer.get()->height(), &raw_buf),
0);
ASSERT_NE(raw_buf, nullptr);
uint32_t* pixels = static_cast<uint32_t*>(raw_buf);
@@ -216,7 +216,7 @@
pixels[i] = 0x0000ff00;
}
- ASSERT_GE(buffer.get()->Unlock(), 0);
+ ASSERT_GE(buffer.get()->buffer()->Unlock(), 0);
ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle()), 0);
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 79166a7..872631f 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -954,6 +954,22 @@
egl_context_t* const c = get_context(share_list);
share_list = c->context;
}
+ // b/111083885 - If we are presenting EGL 1.4 interface to apps
+ // error out on robust access attributes that are invalid
+ // in EGL 1.4 as the driver may be fine with them but dEQP expects
+ // tests to fail according to spec.
+ if (attrib_list && (cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0))) {
+ const EGLint* attrib_ptr = attrib_list;
+ while (*attrib_ptr != EGL_NONE) {
+ GLint attr = *attrib_ptr++;
+ GLint value = *attrib_ptr++;
+ if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR) {
+ // We are GL ES context with EGL 1.4, this is an invalid
+ // attribute
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
+ }
+ };
+ }
EGLContext context = cnx->egl.eglCreateContext(
dp->disp.dpy, config, share_list, attrib_list);
if (context != EGL_NO_CONTEXT) {
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index b06422a..a0bd4e2 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -34,8 +34,12 @@
}
// Get main display parameters.
- sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain);
+ const auto mainDpy = SurfaceComposerClient::getInternalDisplayToken();
+ if (mainDpy == nullptr) {
+ fprintf(stderr, "ERROR: no display\n");
+ return;
+ }
+
DisplayInfo mainDpyInfo;
err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
if (err != NO_ERROR) {
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index cf9d3c7..c13bac6 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -763,7 +763,7 @@
}
EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
- if (deviceId == BUILT_IN_KEYBOARD_ID) {
+ if (deviceId == ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID) {
deviceId = mBuiltInKeyboardId;
}
ssize_t index = mDevices.indexOfKey(deviceId);
@@ -835,7 +835,8 @@
device->id, device->path.c_str());
mClosingDevices = device->next;
event->when = now;
- event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
+ event->deviceId = (device->id == mBuiltInKeyboardId) ?
+ ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID : device->id;
event->type = DEVICE_REMOVED;
event += 1;
delete device;
@@ -1081,7 +1082,7 @@
ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
}
}
- if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
+ if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
createVirtualKeyboardLocked();
}
}
@@ -1580,7 +1581,8 @@
identifier.uniqueId = "<virtual>";
assignDescriptorLocked(identifier);
- Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, "<virtual>", identifier);
+ Device* device = new Device(-1, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, "<virtual>",
+ identifier);
device->classes = INPUT_DEVICE_CLASS_KEYBOARD
| INPUT_DEVICE_CLASS_ALPHAKEY
| INPUT_DEVICE_CLASS_DPAD
diff --git a/services/inputflinger/include/EventHub.h b/services/inputflinger/EventHub.h
similarity index 98%
rename from services/inputflinger/include/EventHub.h
rename to services/inputflinger/EventHub.h
index 295aca8..d176648 100644
--- a/services/inputflinger/include/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -46,13 +46,6 @@
namespace android {
-enum {
- // Device id of a special "virtual" keyboard that is always present.
- VIRTUAL_KEYBOARD_ID = -1,
- // Device id of the "built-in" keyboard if there is one.
- BUILT_IN_KEYBOARD_ID = 0,
-};
-
/*
* A raw event as retrieved from the EventHub.
*/
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 11427c3..7ade0d4 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -505,6 +505,11 @@
// Set the thread name for debugging
pthread_setname_np(mHalThread.native_handle(), "InputClassifier");
#endif
+ // Under normal operation, we do not need to reset the HAL here. But in the case where system
+ // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already
+ // have received events in the past. That means, that HAL could be in an inconsistent state
+ // once it receives events from the newly created MotionClassifier.
+ mEvents.push(ClassifierEvent::createHalResetEvent());
}
MotionClassifier::~MotionClassifier() {
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 1f7dd41..cb46494 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -162,15 +162,6 @@
std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/>
mLastDownTimes; //GUARDED_BY(mLock);
void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
- // Should only be accessed through isResetNeeded() and setResetNeeded()
- bool mResetNeeded = false; //GUARDED_BY(mLock);
- /**
- * Check whether reset should be performed. Reset should be performed
- * if the eventTime of the current event is older than mLastDownTime,
- * i.e. a new gesture has already begun, but an older gesture is still being processed.
- */
- bool isResetNeeded(nsecs_t eventTime);
- void setResetNeeded(bool isNeeded);
/**
* Exit the InputClassifier HAL thread.
@@ -188,11 +179,12 @@
class InputClassifier : public InputClassifierInterface {
public:
explicit InputClassifier(const sp<InputListenerInterface>& listener);
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
- virtual void notifyKey(const NotifyKeyArgs* args);
- virtual void notifyMotion(const NotifyMotionArgs* args);
- virtual void notifySwitch(const NotifySwitchArgs* args);
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
+
+ virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+ virtual void notifyKey(const NotifyKeyArgs* args) override;
+ virtual void notifyMotion(const NotifyMotionArgs* args) override;
+ virtual void notifySwitch(const NotifySwitchArgs* args) override;
+ virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
private:
std::unique_ptr<MotionClassifierInterface> mMotionClassifier = nullptr;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 4c4ee06..734ed6c 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -228,24 +228,6 @@
],
}
-cc_library_shared {
- name: "libsurfaceflinger_ddmconnection",
- defaults: ["surfaceflinger_defaults"],
- srcs: ["DdmConnection.cpp"],
- shared_libs: [
- "libcutils",
- "libdl",
- "liblog",
- "libprocessgroup",
- ],
- product_variables: {
- // uses jni which may not be available in PDK
- pdk: {
- enabled: false,
- },
- },
-}
-
subdirs = [
"layerproto",
"TimeStats/timestatsproto",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f986329..63748bf 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -372,20 +372,18 @@
return true;
}
-Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) {
+bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ const sp<Fence>& releaseFence) {
ATRACE_CALL();
- std::optional<Region> sidebandStreamDirtyRegion = latchSidebandStream(recomputeVisibleRegions);
+ bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
- if (sidebandStreamDirtyRegion) {
- return *sidebandStreamDirtyRegion;
+ if (refreshRequired) {
+ return refreshRequired;
}
- Region dirtyRegion;
-
if (!hasReadyFrame()) {
- return dirtyRegion;
+ return false;
}
// if we've already called updateTexImage() without going through
@@ -394,14 +392,14 @@
// compositionComplete() call.
// we'll trigger an update in onPreComposition().
if (mRefreshPending) {
- return dirtyRegion;
+ return false;
}
// If the head buffer's acquire fence hasn't signaled yet, return and
// try again later
if (!fenceHasSignaled()) {
mFlinger->signalLayerUpdate();
- return dirtyRegion;
+ return false;
}
// Capture the old state of the layer for comparisons later
@@ -411,24 +409,24 @@
if (!allTransactionsSignaled()) {
mFlinger->signalLayerUpdate();
- return dirtyRegion;
+ return false;
}
status_t err = updateTexImage(recomputeVisibleRegions, latchTime, releaseFence);
if (err != NO_ERROR) {
- return dirtyRegion;
+ return false;
}
err = updateActiveBuffer();
if (err != NO_ERROR) {
- return dirtyRegion;
+ return false;
}
mBufferLatched = true;
err = updateFrameNumber(latchTime);
if (err != NO_ERROR) {
- return dirtyRegion;
+ return false;
}
mRefreshPending = true;
@@ -468,11 +466,14 @@
Rect crop(getDrawingCrop());
const uint32_t transform(getDrawingTransform());
const uint32_t scalingMode(getDrawingScalingMode());
+ const bool transformToDisplayInverse(getTransformToDisplayInverse());
if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
- (scalingMode != mCurrentScalingMode)) {
+ (scalingMode != mCurrentScalingMode) ||
+ (transformToDisplayInverse != mTransformToDisplayInverse)) {
mCurrentCrop = crop;
mCurrentTransform = transform;
mCurrentScalingMode = scalingMode;
+ mTransformToDisplayInverse = transformToDisplayInverse;
recomputeVisibleRegions = true;
}
@@ -509,9 +510,7 @@
}
}
- // FIXME: postedRegion should be dirty & bounds
- // transform the dirty region to window-manager space
- return getTransform().transform(Region(getBufferSize(s)));
+ return true;
}
// transaction
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index d0c1b13..c118b78 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -96,8 +96,8 @@
// If there was a GL composition step rendering the previous frame, then
// releaseFence will be populated with a native fence that fires when
// composition has completed.
- Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) override;
+ bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ const sp<Fence>& releaseFence) override;
bool isBufferLatched() const override { return mRefreshPending; }
@@ -134,7 +134,8 @@
virtual bool getAutoRefresh() const = 0;
virtual bool getSidebandStreamChanged() const = 0;
- virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
+ // Latch sideband stream and returns true if the dirty region should be updated.
+ virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
virtual bool hasFrameUpdate() const = 0;
@@ -182,6 +183,8 @@
uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
+ bool mTransformToDisplayInverse{false};
+
// main thread.
bool mBufferLatched{false}; // TODO: Use mActiveBuffer?
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index b39116a..3915757 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -190,7 +190,7 @@
return mSidebandStreamChanged;
}
-std::optional<Region> BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
bool sidebandStreamChanged = true;
if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
// mSidebandStreamChanged was changed to false
@@ -202,10 +202,9 @@
}
recomputeVisibleRegions = true;
- const State& s(getDrawingState());
- return getTransform().transform(Region(Rect(s.active_legacy.w, s.active_legacy.h)));
+ return true;
}
- return {};
+ return false;
}
bool BufferQueueLayer::hasFrameUpdate() const {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 20992a4..d392a69 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -84,7 +84,7 @@
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
- std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+ bool latchSidebandStream(bool& recomputeVisibleRegions) override;
bool hasFrameUpdate() const override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 2005d20..b95cd2e 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -96,7 +96,8 @@
bool BufferStateLayer::willPresentCurrentTransaction() const {
// Returns true if the most recent Transaction applied to CurrentState will be presented.
return getSidebandStreamChanged() || getAutoRefresh() ||
- (mCurrentState.modified && mCurrentState.buffer != nullptr);
+ (mCurrentState.modified &&
+ (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr));
}
bool BufferStateLayer::getTransformToDisplayInverse() const {
@@ -420,7 +421,7 @@
return mSidebandStreamChanged.load();
}
-std::optional<Region> BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
if (mSidebandStreamChanged.exchange(false)) {
const State& s(getDrawingState());
// mSidebandStreamChanged was true
@@ -432,13 +433,14 @@
}
recomputeVisibleRegions = true;
- return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
+ return true;
}
- return {};
+ return false;
}
bool BufferStateLayer::hasFrameUpdate() const {
- return mCurrentStateModified && getCurrentState().buffer != nullptr;
+ const State& c(getCurrentState());
+ return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
}
void BufferStateLayer::setFilteringEnabled(bool enabled) {
@@ -458,6 +460,11 @@
const State& s(getDrawingState());
if (!s.buffer) {
+ if (s.bgColorLayer) {
+ for (auto& handle : mDrawingState.callbackHandles) {
+ handle->latchTime = latchTime;
+ }
+ }
return NO_ERROR;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 138bb4c..ef287b9 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -117,7 +117,7 @@
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
- std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+ bool latchSidebandStream(bool& recomputeVisibleRegions) override;
bool hasFrameUpdate() const override;
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
index c82ad7b..cb02d16 100644
--- a/services/surfaceflinger/BufferStateLayerCache.cpp
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -19,81 +19,84 @@
#define LOG_TAG "BufferStateLayerCache"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <cinttypes>
+
#include "BufferStateLayerCache.h"
-#define MAX_CACHE_SIZE 64
+#define VALID_CACHE_ID(id) ((id) >= 0 || (id) < (BUFFER_CACHE_MAX_SIZE))
namespace android {
-int32_t BufferStateLayerCache::add(const sp<IBinder>& processToken,
- const sp<GraphicBuffer>& buffer) {
- std::lock_guard lock(mMutex);
+ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache);
- auto& processCache = getProccessCache(processToken);
+BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {}
- int32_t slot = findSlot(processCache);
- if (slot < 0) {
- return slot;
+void BufferStateLayerCache::add(sp<IBinder> processToken, int32_t id,
+ const sp<GraphicBuffer>& buffer) {
+ if (!VALID_CACHE_ID(id)) {
+ ALOGE("failed to cache buffer: invalid buffer id");
+ return;
}
- processCache[slot] = buffer;
+ if (!processToken) {
+ ALOGE("failed to cache buffer: invalid process token");
+ return;
+ }
- return slot;
-}
-
-void BufferStateLayerCache::release(const sp<IBinder>& processToken, int32_t id) {
- if (id < 0) {
- ALOGE("invalid buffer id");
+ if (!buffer) {
+ ALOGE("failed to cache buffer: invalid buffer");
return;
}
std::lock_guard lock(mMutex);
- auto& processCache = getProccessCache(processToken);
- if (id >= processCache.size()) {
- ALOGE("invalid buffer id");
- return;
- }
- processCache[id] = nullptr;
-}
-
-sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, int32_t id) {
- if (id < 0) {
- ALOGE("invalid buffer id");
- return nullptr;
- }
-
- std::lock_guard lock(mMutex);
- auto& processCache = getProccessCache(processToken);
-
- if (id >= processCache.size()) {
- ALOGE("invalid buffer id");
- return nullptr;
- }
- return processCache[id];
-}
-
-std::vector<sp<GraphicBuffer>>& BufferStateLayerCache::getProccessCache(
- const sp<IBinder>& processToken) {
- return mBuffers[processToken];
-}
-
-int32_t BufferStateLayerCache::findSlot(std::vector<sp<GraphicBuffer>>& processCache) {
- int32_t slot = 0;
-
- for (const sp<GraphicBuffer> buffer : processCache) {
- if (!buffer) {
- return slot;
+ // If this is a new process token, set a death recipient. If the client process dies, we will
+ // get a callback through binderDied.
+ if (mBuffers.find(processToken) == mBuffers.end()) {
+ status_t err = processToken->linkToDeath(mDeathRecipient);
+ if (err != NO_ERROR) {
+ ALOGE("failed to cache buffer: could not link to death");
+ return;
}
- slot++;
}
- if (processCache.size() < MAX_CACHE_SIZE) {
- processCache.push_back(nullptr);
- return slot;
+ auto& processBuffers = mBuffers[processToken];
+ processBuffers[id] = buffer;
+}
+
+sp<GraphicBuffer> BufferStateLayerCache::get(sp<IBinder> processToken, int32_t id) {
+ if (!VALID_CACHE_ID(id)) {
+ ALOGE("failed to get buffer: invalid buffer id");
+ return nullptr;
}
- return -1;
+ if (!processToken) {
+ ALOGE("failed to cache buffer: invalid process token");
+ return nullptr;
+ }
+
+ std::lock_guard lock(mMutex);
+ auto itr = mBuffers.find(processToken);
+ if (itr == mBuffers.end()) {
+ ALOGE("failed to get buffer: process token not found");
+ return nullptr;
+ }
+
+ if (id >= itr->second.size()) {
+ ALOGE("failed to get buffer: id outside the bounds of the cache");
+ return nullptr;
+ }
+
+ return itr->second[id];
+}
+
+void BufferStateLayerCache::removeProcess(const wp<IBinder>& processToken) {
+ std::lock_guard lock(mMutex);
+ mBuffers.erase(processToken);
+}
+
+void BufferStateLayerCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) {
+ BufferStateLayerCache::getInstance().removeProcess(who);
}
}; // namespace android
diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
index 623f0c6..ede3feb 100644
--- a/services/surfaceflinger/BufferStateLayerCache.h
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -20,36 +20,36 @@
#include <binder/IBinder.h>
#include <ui/GraphicBuffer.h>
#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+#include <array>
+#include <map>
#include <mutex>
-#include <unordered_map>
-#include <vector>
+
+#define BUFFER_CACHE_MAX_SIZE 64
namespace android {
-class BufferStateLayerCache {
+class BufferStateLayerCache : public Singleton<BufferStateLayerCache> {
public:
- int32_t add(const sp<IBinder>& processToken, const sp<GraphicBuffer>& buffer);
- void release(const sp<IBinder>& processToken, int32_t id);
+ BufferStateLayerCache();
- sp<GraphicBuffer> get(const sp<IBinder>& processToken, int32_t id);
+ void add(sp<IBinder> processToken, int32_t id, const sp<GraphicBuffer>& buffer);
+ sp<GraphicBuffer> get(sp<IBinder> processToken, int32_t id);
+
+ void removeProcess(const wp<IBinder>& processToken);
private:
std::mutex mMutex;
+ std::map<wp<IBinder> /*caching process*/, std::array<sp<GraphicBuffer>, BUFFER_CACHE_MAX_SIZE>>
+ mBuffers GUARDED_BY(mMutex);
- std::vector<sp<GraphicBuffer>>& getProccessCache(const sp<IBinder>& processToken)
- REQUIRES(mMutex);
-
- int32_t findSlot(std::vector<sp<GraphicBuffer>>& proccessCache) REQUIRES(mMutex);
-
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& strongPointer) const {
- return std::hash<IBinder*>{}(strongPointer.get());
- }
+ class CacheDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ void binderDied(const wp<IBinder>& who) override;
};
- std::unordered_map<sp<IBinder> /*caching process*/, std::vector<sp<GraphicBuffer>>, IBinderHash>
- mBuffers GUARDED_BY(mMutex);
+ sp<CacheDeathRecipient> mDeathRecipient;
};
}; // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index f6c1a33..e103ebe 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -90,13 +90,25 @@
void Output::setColorTransform(const mat4& transform) {
const bool isIdentity = (transform == mat4());
-
- mState.colorTransform =
+ const auto newColorTransform =
isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+
+ if (mState.colorTransform == newColorTransform) {
+ return;
+ }
+
+ mState.colorTransform = newColorTransform;
+
+ dirtyEntireOutput();
}
void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
ui::RenderIntent renderIntent) {
+ if (mState.colorMode == mode && mState.dataspace == dataspace &&
+ mState.renderIntent == renderIntent) {
+ return;
+ }
+
mState.colorMode = mode;
mState.dataspace = dataspace;
mState.renderIntent = renderIntent;
@@ -106,6 +118,8 @@
ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
renderIntent);
+
+ dirtyEntireOutput();
}
void Output::dump(std::string& out) const {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 8cb6936..cd2d454 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -156,17 +156,17 @@
EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
// Otherwise if the values are different, updates happen
- EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+ EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
EXPECT_CALL(mHwComposer,
- setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::BT2100_PQ,
+ setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::DISPLAY_P3,
ui::RenderIntent::TONE_MAP_COLORIMETRIC))
.Times(1);
- mDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
ui::RenderIntent::TONE_MAP_COLORIMETRIC);
- EXPECT_EQ(ui::ColorMode::BT2100_PQ, mDisplay.getState().colorMode);
- EXPECT_EQ(ui::Dataspace::SRGB, mDisplay.getState().dataspace);
+ EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent);
}
@@ -174,7 +174,7 @@
impl::Display virtualDisplay{mCompositionEngine,
DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
- virtualDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
ui::RenderIntent::TONE_MAP_COLORIMETRIC);
EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 314d98b..cb71821 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -43,15 +43,21 @@
mOutput.setDisplayColorProfileForTest(
std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+
+ mOutput.editState().bounds = kDefaultDisplaySize;
}
~OutputTest() override = default;
+ static const Rect kDefaultDisplaySize;
+
StrictMock<mock::CompositionEngine> mCompositionEngine;
mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
impl::Output mOutput{mCompositionEngine};
};
+const Rect OutputTest::kDefaultDisplaySize{100, 200};
+
/* ------------------------------------------------------------------------
* Basic construction
*/
@@ -76,8 +82,6 @@
*/
TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
mOutput.editState().isEnabled = true;
mOutput.setCompositionEnabled(true);
@@ -87,25 +91,21 @@
}
TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
mOutput.editState().isEnabled = false;
mOutput.setCompositionEnabled(true);
EXPECT_TRUE(mOutput.getState().isEnabled);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
mOutput.editState().isEnabled = true;
mOutput.setCompositionEnabled(false);
EXPECT_FALSE(mOutput.getState().isEnabled);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
/* ------------------------------------------------------------------------
@@ -135,7 +135,7 @@
*/
TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
- const ui::Size displaySize{100, 200};
+ const ui::Size displaySize{200, 400};
EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
@@ -152,16 +152,13 @@
*/
TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
- const Rect displaySize{100, 200};
- mOutput.editState().bounds = displaySize;
-
const uint32_t layerStack = 123u;
mOutput.setLayerStackFilter(layerStack, true);
EXPECT_TRUE(mOutput.getState().layerStackInternal);
EXPECT_EQ(layerStack, mOutput.getState().layerStackId);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
/* ------------------------------------------------------------------------
@@ -176,27 +173,45 @@
EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
+ // Since identity is the default, the dirty region should be unchanged (empty)
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+
// Non-identity matrix sets a non-identity state value
const mat4 nonIdentity = mat4() * 2;
mOutput.setColorTransform(nonIdentity);
EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+
+ // Since this is a state change, the entire output should now be dirty.
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
/* ------------------------------------------------------------------------
* Output::setColorMode
*/
-TEST_F(OutputTest, setColorModeSetsModeUnlessNoChange) {
- EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) {
+ EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
- mOutput.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
ui::RenderIntent::TONE_MAP_COLORIMETRIC);
- EXPECT_EQ(ui::ColorMode::BT2100_PQ, mOutput.getState().colorMode);
- EXPECT_EQ(ui::Dataspace::SRGB, mOutput.getState().dataspace);
+ EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+}
+
+TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) {
+ mOutput.editState().colorMode = ui::ColorMode::DISPLAY_P3;
+ mOutput.editState().dataspace = ui::Dataspace::DISPLAY_P3;
+ mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC;
+
+ mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
}
/* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 9530398..941b4ad 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -32,6 +32,10 @@
}
bool ContainerLayer::isVisible() const {
+ return false;
+}
+
+bool ContainerLayer::canReceiveInput() const {
return !isHiddenByPolicy();
}
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 409cf22..fec82d7 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -31,6 +31,8 @@
const char* getTypeId() const override { return "ContainerLayer"; }
bool isVisible() const override;
+ bool canReceiveInput() const override;
+
void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
int32_t supportedPerFrameMetadata) override;
diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp
deleted file mode 100644
index 35d55f5..0000000
--- a/services/surfaceflinger/DdmConnection.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2011 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 <dlfcn.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "jni.h"
-#include "DdmConnection.h"
-
-namespace android {
-
-void DdmConnection_start(const char* name) {
- ALOGI("DdmConnection_start");
- DdmConnection::start(name);
-}
-
-void DdmConnection::start(const char* name) {
- JavaVM* vm;
- JNIEnv* env;
-
- // start a VM
- JavaVMInitArgs args;
- JavaVMOption opt;
-
- opt.optionString =
- "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
-
- args.version = JNI_VERSION_1_4;
- args.options = &opt;
- args.nOptions = 1;
- args.ignoreUnrecognized = JNI_FALSE;
-
-
- // TODO: Should this just link against libnativehelper and use its
- // JNI_CreateJavaVM wrapper that essential does this dlopen/dlsym
- // work based on the current system default runtime?
- void* libart_dso = dlopen("libart.so", RTLD_NOW);
- ALOGE_IF(!libart_dso, "DdmConnection: %s", dlerror());
-
- void* libandroid_runtime_dso = dlopen("libandroid_runtime.so", RTLD_NOW);
- ALOGE_IF(!libandroid_runtime_dso, "DdmConnection: %s", dlerror());
-
- if (!libart_dso || !libandroid_runtime_dso) {
- goto error;
- }
-
- jint (*JNI_CreateJavaVM)(JavaVM** p_vm, JNIEnv** p_env, void* vm_args);
- JNI_CreateJavaVM = reinterpret_cast<decltype(JNI_CreateJavaVM)>(
- dlsym(libart_dso, "JNI_CreateJavaVM"));
- ALOGE_IF(!JNI_CreateJavaVM, "DdmConnection: %s", dlerror());
-
- jint (*registerNatives)(JNIEnv* env, jclass clazz);
- registerNatives = reinterpret_cast<decltype(registerNatives)>(
- dlsym(libandroid_runtime_dso,
- "Java_com_android_internal_util_WithFramework_registerNatives"));
- ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror());
-
- if (!JNI_CreateJavaVM || !registerNatives) {
- goto error;
- }
-
- if (JNI_CreateJavaVM(&vm, &env, &args) == 0) {
- jclass startClass;
- jmethodID startMeth;
-
- // register native code
- if (registerNatives(env, 0) == 0) {
- // set our name by calling DdmHandleAppName.setAppName()
- startClass = env->FindClass("android/ddm/DdmHandleAppName");
- if (startClass) {
- startMeth = env->GetStaticMethodID(startClass,
- "setAppName", "(Ljava/lang/String;I)V");
- if (startMeth) {
- jstring str = env->NewStringUTF(name);
- env->CallStaticVoidMethod(startClass, startMeth, str, getuid());
- env->DeleteLocalRef(str);
- }
- }
-
- // initialize DDMS communication by calling
- // DdmRegister.registerHandlers()
- startClass = env->FindClass("android/ddm/DdmRegister");
- if (startClass) {
- startMeth = env->GetStaticMethodID(startClass,
- "registerHandlers", "()V");
- if (startMeth) {
- env->CallStaticVoidMethod(startClass, startMeth);
- }
- }
- }
- }
- return;
-
-error:
- if (libandroid_runtime_dso) {
- dlclose(libandroid_runtime_dso);
- }
- if (libart_dso) {
- dlclose(libart_dso);
- }
-}
-
-}; // namespace android
diff --git a/services/surfaceflinger/DdmConnection.h b/services/surfaceflinger/DdmConnection.h
deleted file mode 100644
index 938d14b..0000000
--- a/services/surfaceflinger/DdmConnection.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SF_DDM_CONNECTION
-#define ANDROID_SF_DDM_CONNECTION
-
-namespace android {
-
-// wrapper for dlsym
-extern "C" void DdmConnection_start(const char* name);
-
-class DdmConnection {
-public:
- // Creates a JVM and registers all handlers to DDMS.
- // This allows tools relying on DDMS to find surfaceflinger
- // (e.g: Memory Leak finder, heap analyzer, ...)
- static void start(const char* name);
-};
-
-}; // namespace android
-
-#endif /* ANDROID_SF_DDM_CONNECTION */
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 1599995..d63cd79 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -23,10 +23,12 @@
#include <string_view>
#include <vector>
+#include <ui/GraphicTypes.h>
+
namespace android {
struct DisplayId {
- using Type = uint64_t;
+ using Type = PhysicalDisplayId;
Type value;
uint16_t manufacturerId() const;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 185393e..5f6d2a7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1078,13 +1078,18 @@
ATRACE_CALL();
if (mLayerDetached) {
- return 0;
+ return flags;
+ }
+
+ if (mChildrenChanged) {
+ flags |= eVisibleRegion;
+ mChildrenChanged = false;
}
pushPendingState();
State c = getCurrentState();
if (!applyPendingStates(&c)) {
- return 0;
+ return flags;
}
flags = doTransactionResize(flags, &c);
@@ -1106,11 +1111,6 @@
mNeedsFiltering = (!getActiveTransform(c).preserveRects() || type >= ui::Transform::SCALE);
}
- if (mChildrenChanged) {
- flags |= eVisibleRegion;
- mChildrenChanged = false;
- }
-
// If the layer is hidden, signal and clear out all local sync points so
// that transactions for layers depending on this layer's frames becoming
// visible are not blocked
@@ -1280,7 +1280,12 @@
bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace) {
if (!mCurrentState.bgColorLayer && alpha == 0) {
return false;
- } else if (!mCurrentState.bgColorLayer && alpha != 0) {
+ }
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+
+ if (!mCurrentState.bgColorLayer && alpha != 0) {
// create background color layer if one does not yet exist
uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
const String8& name = mName + "BackgroundColorLayer";
@@ -1634,6 +1639,7 @@
void Layer::addChild(const sp<Layer>& layer) {
mChildrenChanged = true;
+ setTransactionFlags(eTransactionNeeded);
mCurrentChildren.add(layer);
layer->setParent(this);
@@ -1641,6 +1647,7 @@
ssize_t Layer::removeChild(const sp<Layer>& layer) {
mChildrenChanged = true;
+ setTransactionFlags(eTransactionNeeded);
layer->setParent(nullptr);
return mCurrentChildren.remove(layer);
@@ -2245,7 +2252,7 @@
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
- info.visible = isVisible();
+ info.visible = canReceiveInput();
return info;
}
@@ -2257,6 +2264,10 @@
return nullptr;
}
+bool Layer::canReceiveInput() const {
+ return isVisible();
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 4cead87..8b6d4c7 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -387,6 +387,11 @@
bool isHiddenByPolicy() const;
/*
+ * Returns whether this layer can receive input.
+ */
+ virtual bool canReceiveInput() const;
+
+ /*
* isProtected - true if the layer may contain protected content in the
* GRALLOC_USAGE_PROTECTED sense.
*/
@@ -518,8 +523,8 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- virtual Region latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
- const sp<Fence>& /*releaseFence*/) {
+ virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
+ const sp<Fence>& /*releaseFence*/) {
return {};
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 52abe9c..5d9cfde 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -69,24 +69,28 @@
std::string toString(const DisplayEventReceiver::Event& event) {
switch (event.header.type) {
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
- return StringPrintf("Hotplug{displayId=%u, %s}", event.header.id,
+ return StringPrintf("Hotplug{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", %s}",
+ event.header.displayId,
event.hotplug.connected ? "connected" : "disconnected");
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- return StringPrintf("VSync{displayId=%u, count=%u}", event.header.id,
- event.vsync.count);
+ return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+ ", count=%u}",
+ event.header.displayId, event.vsync.count);
default:
return "Event{}";
}
}
-DisplayEventReceiver::Event makeHotplug(uint32_t displayId, nsecs_t timestamp, bool connected) {
+DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t timestamp,
+ bool connected) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, displayId, timestamp};
event.hotplug.connected = connected;
return event;
}
-DisplayEventReceiver::Event makeVSync(uint32_t displayId, nsecs_t timestamp, uint32_t count) {
+DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
+ uint32_t count) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
event.vsync.count = count;
@@ -96,8 +100,10 @@
} // namespace
EventThreadConnection::EventThreadConnection(EventThread* eventThread,
- ResyncCallback resyncCallback)
+ ResyncCallback resyncCallback,
+ ResetIdleTimerCallback resetIdleTimerCallback)
: resyncCallback(std::move(resyncCallback)),
+ resetIdleTimerCallback(std::move(resetIdleTimerCallback)),
mEventThread(eventThread),
mChannel(gui::BitTube::DefaultSize) {}
@@ -143,22 +149,18 @@
namespace impl {
EventThread::EventThread(std::unique_ptr<VSyncSource> src,
- const InterceptVSyncsCallback& interceptVSyncsCallback,
- const ResetIdleTimerCallback& resetIdleTimerCallback,
- const char* threadName)
- : EventThread(nullptr, std::move(src), interceptVSyncsCallback, threadName) {
- mResetIdleTimer = resetIdleTimerCallback;
-}
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
+ : EventThread(nullptr, std::move(src), std::move(interceptVSyncsCallback), threadName) {}
EventThread::EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
const char* threadName)
- : EventThread(src, nullptr, interceptVSyncsCallback, threadName) {}
+ : EventThread(src, nullptr, std::move(interceptVSyncsCallback), threadName) {}
EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
: mVSyncSource(src),
mVSyncSourceUnique(std::move(uniqueSrc)),
- mInterceptVSyncsCallback(interceptVSyncsCallback),
+ mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
mThreadName(threadName) {
if (src == nullptr) {
mVSyncSource = mVSyncSourceUnique.get();
@@ -201,8 +203,10 @@
mVSyncSource->setPhaseOffset(phaseOffset);
}
-sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
- return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
+sp<EventThreadConnection> EventThread::createEventConnection(
+ ResyncCallback resyncCallback, ResetIdleTimerCallback resetIdleTimerCallback) const {
+ return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
+ std::move(resetIdleTimerCallback));
}
status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -245,9 +249,9 @@
}
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
- if (mResetIdleTimer && reset) {
+ if (connection->resetIdleTimerCallback && reset) {
ATRACE_NAME("resetIdleTimer");
- mResetIdleTimer();
+ connection->resetIdleTimerCallback();
}
if (connection->resyncCallback) {
@@ -290,10 +294,9 @@
mCondition.notify_all();
}
-void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
+void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) {
std::lock_guard<std::mutex> lock(mMutex);
- const uint32_t displayId = displayType == DisplayType::Primary ? 0 : 1;
mPendingEvents.push_back(makeHotplug(displayId, systemTime(), connected));
mCondition.notify_all();
}
@@ -312,9 +315,9 @@
switch (event->header.type) {
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
if (event->hotplug.connected && !mVSyncState) {
- mVSyncState.emplace(event->header.id);
+ mVSyncState.emplace(event->header.displayId);
} else if (!event->hotplug.connected && mVSyncState &&
- mVSyncState->displayId == event->header.id) {
+ mVSyncState->displayId == event->header.displayId) {
mVSyncState.reset();
}
break;
@@ -440,8 +443,9 @@
StringAppendF(&result, "%s: state=%s VSyncState=", mThreadName, toCString(mState));
if (mVSyncState) {
- StringAppendF(&result, "{displayId=%u, count=%u%s}\n", mVSyncState->displayId,
- mVSyncState->count, mVSyncState->synthetic ? ", synthetic" : "");
+ StringAppendF(&result, "{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%u%s}\n",
+ mVSyncState->displayId, mVSyncState->count,
+ mVSyncState->synthetic ? ", synthetic" : "");
} else {
StringAppendF(&result, "none\n");
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 89b799e..b275183 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -45,6 +45,7 @@
// ---------------------------------------------------------------------------
using ResyncCallback = std::function<void()>;
+using ResetIdleTimerCallback = std::function<void()>;
enum class VSyncRequest {
None = -1,
@@ -69,7 +70,7 @@
class EventThreadConnection : public BnDisplayEventConnection {
public:
- EventThreadConnection(EventThread* eventThread, ResyncCallback resyncCallback);
+ EventThreadConnection(EventThread*, ResyncCallback, ResetIdleTimerCallback);
virtual ~EventThreadConnection();
virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -83,6 +84,7 @@
// Called in response to requestNextVsync.
const ResyncCallback resyncCallback;
+ const ResetIdleTimerCallback resetIdleTimerCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
@@ -94,13 +96,10 @@
class EventThread {
public:
- // TODO: Remove once stable display IDs are plumbed through SF/WM interface.
- enum class DisplayType { Primary, External };
-
virtual ~EventThread();
- virtual sp<EventThreadConnection> createEventConnection(
- ResyncCallback resyncCallback) const = 0;
+ virtual sp<EventThreadConnection> createEventConnection(ResyncCallback,
+ ResetIdleTimerCallback) const = 0;
// called before the screen is turned off from main thread
virtual void onScreenReleased() = 0;
@@ -108,8 +107,7 @@
// called after the screen is turned on from main thread
virtual void onScreenAcquired() = 0;
- // called when receiving a hotplug event
- virtual void onHotplugReceived(DisplayType displayType, bool connected) = 0;
+ virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
virtual void dump(std::string& result) const = 0;
@@ -128,17 +126,14 @@
class EventThread : public android::EventThread, private VSyncSource::Callback {
public:
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
- using ResetIdleTimerCallback = std::function<void()>;
// TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
- EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
- const char* threadName);
- EventThread(std::unique_ptr<VSyncSource> src,
- const InterceptVSyncsCallback& interceptVSyncsCallback,
- const ResetIdleTimerCallback& resetIdleTimerCallback, const char* threadName);
+ EventThread(VSyncSource*, InterceptVSyncsCallback, const char* threadName);
+ EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName);
~EventThread();
- sp<EventThreadConnection> createEventConnection(ResyncCallback resyncCallback) const override;
+ sp<EventThreadConnection> createEventConnection(ResyncCallback,
+ ResetIdleTimerCallback) const override;
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
@@ -151,8 +146,7 @@
// called after the screen is turned on from main thread
void onScreenAcquired() override;
- // called when receiving a hotplug event
- void onHotplugReceived(DisplayType displayType, bool connected) override;
+ void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
void dump(std::string& result) const override;
@@ -199,9 +193,9 @@
// VSYNC state of connected display.
struct VSyncState {
- explicit VSyncState(uint32_t displayId) : displayId(displayId) {}
+ explicit VSyncState(PhysicalDisplayId displayId) : displayId(displayId) {}
- const uint32_t displayId;
+ const PhysicalDisplayId displayId;
// Number of VSYNC events since display was connected.
uint32_t count = 0;
@@ -225,9 +219,6 @@
State mState GUARDED_BY(mMutex) = State::Idle;
static const char* toCString(State);
-
- // Callback that resets the idle timer when the next vsync is received.
- ResetIdleTimerCallback mResetIdleTimer;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/IdleTimer.cpp
index 5a76dbc..e975e65 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.cpp
+++ b/services/surfaceflinger/Scheduler/IdleTimer.cpp
@@ -54,18 +54,24 @@
if (mState == TimerState::IDLE) {
mCondition.wait(mMutex);
} else if (mState == TimerState::RESET) {
+ auto triggerTime = std::chrono::steady_clock::now() + mInterval;
mState = TimerState::WAITING;
- if (mCondition.wait_for(mMutex, mInterval) == std::cv_status::timeout) {
- if (mTimeoutCallback) {
- mTimeoutCallback();
+ while (mState == TimerState::WAITING) {
+ constexpr auto zero = std::chrono::steady_clock::duration::zero();
+ auto waitTime = triggerTime - std::chrono::steady_clock::now();
+ if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
+ if (mState == TimerState::WAITING &&
+ (triggerTime - std::chrono::steady_clock::now()) <= zero) {
+ if (mTimeoutCallback) {
+ mTimeoutCallback();
+ }
+
+ mState = TimerState::IDLE;
}
}
- if (mState == TimerState::WAITING) {
- mState = TimerState::IDLE;
- }
}
}
-}
+} // namespace scheduler
void IdleTimer::reset() {
{
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 75a410b..1f18ead 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -96,7 +96,8 @@
}
mEventThread = eventThread;
- mEvents = eventThread->createEventConnection(std::move(resyncCallback));
+ mEvents =
+ eventThread->createEventConnection(std::move(resyncCallback), ResetIdleTimerCallback());
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
this);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index bfe5da5..026f7c7 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -47,6 +47,8 @@
int configId;
// Human readable name of the refresh rate.
std::string name;
+ // Refresh rate in frames per second, rounded to the nearest integer.
+ uint32_t fps = 0;
};
// TODO(b/122916473): Get this information from configs prepared by vendors, instead of
@@ -63,7 +65,7 @@
void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
// This is the rate that HWC encapsulates right now when the device is in DOZE mode.
mRefreshRates.push_back(
- RefreshRate{RefreshRateType::POWER_SAVING, SCREEN_OFF_CONFIG_ID, "ScreenOff"});
+ RefreshRate{RefreshRateType::POWER_SAVING, SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
if (configs.size() < 1) {
ALOGE("Device does not have valid configs. Config size is 0.");
@@ -86,10 +88,11 @@
nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
- mRefreshRates.push_back(RefreshRate{RefreshRateType::DEFAULT,
- configIdToVsyncPeriod[0].first,
- base::StringPrintf("%2.ffps", fps)});
+ mRefreshRates.push_back(
+ RefreshRate{RefreshRateType::DEFAULT, configIdToVsyncPeriod[0].first,
+ base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
}
+
if (configs.size() < 2) {
return;
}
@@ -99,9 +102,9 @@
vsyncPeriod = configIdToVsyncPeriod[1].second;
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
- mRefreshRates.push_back(RefreshRate{RefreshRateType::PERFORMANCE,
- configIdToVsyncPeriod[1].first,
- base::StringPrintf("%2.ffps", fps)});
+ mRefreshRates.push_back(
+ RefreshRate{RefreshRateType::PERFORMANCE, configIdToVsyncPeriod[1].first,
+ base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
}
}
@@ -109,4 +112,4 @@
};
} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 7e22232..dcb2988 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -20,6 +20,7 @@
#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/SchedulerUtils.h"
+#include "TimeStats/TimeStats.h"
#include "android-base/stringprintf.h"
#include "utils/Timers.h"
@@ -41,8 +42,10 @@
public:
explicit RefreshRateStats(
- const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs)
+ const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+ const std::shared_ptr<TimeStats>& timeStats)
: mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)),
+ mTimeStats(timeStats),
mPreviousRecordedTime(systemTime()) {}
~RefreshRateStats() = default;
@@ -116,10 +119,16 @@
// this method was called.
void flushTimeForMode(int mode) {
nsecs_t currentTime = systemTime();
- int64_t timeElapsedMs = ns2ms(currentTime - mPreviousRecordedTime);
+ nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
+ int64_t timeElapsedMs = ns2ms(timeElapsed);
mPreviousRecordedTime = currentTime;
mConfigModesTotalTime[mode] += timeElapsedMs;
+ for (const auto& config : mRefreshRateConfigs->getRefreshRates()) {
+ if (config.configId == mode) {
+ mTimeStats->recordRefreshRate(config.fps, timeElapsed);
+ }
+ }
}
// Formats the time in milliseconds into easy to read format.
@@ -136,6 +145,9 @@
// Keeps information about refresh rate configs that device has.
std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+ // Aggregate refresh rate statistics for telemetry.
+ std::shared_ptr<TimeStats> mTimeStats;
+
int64_t mCurrentConfigMode = 0;
int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
@@ -145,4 +157,4 @@
};
} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 00820f1..2f581d2 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -29,7 +29,6 @@
#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
-#include <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -81,10 +80,14 @@
}
}
-Scheduler::~Scheduler() = default;
+Scheduler::~Scheduler() {
+ // Ensure the IdleTimer thread is joined before we start destroying state.
+ mIdleTimer.reset();
+}
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
+ ResetIdleTimerCallback resetIdleTimerCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
@@ -92,12 +95,14 @@
std::unique_ptr<EventThread> eventThread =
makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
std::move(interceptCallback));
- auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
- eventThread->createEventConnection(
- std::move(resyncCallback)),
- std::move(eventThread));
- mConnections.insert(std::make_pair(id, std::move(connection)));
+ auto eventThreadConnection =
+ createConnectionInternal(eventThread.get(), std::move(resyncCallback),
+ std::move(resetIdleTimerCallback));
+ mConnections.emplace(id,
+ std::make_unique<Connection>(new ConnectionHandle(id),
+ eventThreadConnection,
+ std::move(eventThread)));
return mConnections[id]->handle;
}
@@ -107,14 +112,29 @@
std::unique_ptr<VSyncSource> eventThreadSource =
std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
- std::move(interceptCallback),
- [this] { resetIdleTimer(); }, connectionName);
+ std::move(interceptCallback), connectionName);
+}
+
+sp<EventThreadConnection> Scheduler::createConnectionInternal(
+ EventThread* eventThread, ResyncCallback&& resyncCallback,
+ ResetIdleTimerCallback&& resetIdleTimerCallback) {
+ return eventThread->createEventConnection(std::move(resyncCallback),
+ [this,
+ resetIdleTimerCallback =
+ std::move(resetIdleTimerCallback)] {
+ resetIdleTimer();
+ if (resetIdleTimerCallback) {
+ resetIdleTimerCallback();
+ }
+ });
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
+ const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
+ ResetIdleTimerCallback resetIdleTimerCallback) {
RETURN_VALUE_IF_INVALID(nullptr);
- return mConnections[handle->id]->thread->createEventConnection(std::move(resyncCallback));
+ return createConnectionInternal(mConnections[handle->id]->thread.get(),
+ std::move(resyncCallback), std::move(resetIdleTimerCallback));
}
EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -128,9 +148,9 @@
}
void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
- EventThread::DisplayType displayType, bool connected) {
+ PhysicalDisplayId displayId, bool connected) {
RETURN_IF_INVALID();
- mConnections[handle->id]->thread->onHotplugReceived(displayType, connected);
+ mConnections[handle->id]->thread->onHotplugReceived(displayId, connected);
}
void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -239,11 +259,6 @@
mExpiredTimerCallback = expiredTimerCallback;
}
-void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- mResetTimerCallback = resetTimerCallback;
-}
-
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
ATRACE_INT("FrameSkipCount", skipCount);
if (mSkipCount != skipCount) {
@@ -334,11 +349,6 @@
mIdleTimer->reset();
ATRACE_INT("ExpiredIdleTimer", 0);
}
-
- std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mResetTimerCallback) {
- mResetTimerCallback();
- }
}
void Scheduler::expiredTimerCallback() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index b717605..4abf027 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -19,8 +19,8 @@
#include <cstdint>
#include <memory>
-#include <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
+#include <ui/GraphicTypes.h>
#include "DispSync.h"
#include "EventControlThread.h"
@@ -37,7 +37,6 @@
class Scheduler {
public:
using ExpiredIdleTimerCallback = std::function<void()>;
- using ResetIdleTimerCallback = std::function<void()>;
// Enum to indicate whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
@@ -72,12 +71,13 @@
virtual ~Scheduler();
/** Creates an EventThread connection. */
- sp<ConnectionHandle> createConnection(
- const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
- impl::EventThread::InterceptVSyncsCallback interceptCallback);
+ sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
+ ResyncCallback, ResetIdleTimerCallback,
+ impl::EventThread::InterceptVSyncsCallback);
sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
- ResyncCallback resyncCallback);
+ ResyncCallback,
+ ResetIdleTimerCallback);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -85,7 +85,7 @@
sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle);
// Should be called when receiving a hotplug event.
- void hotplugReceived(const sp<ConnectionHandle>& handle, EventThread::DisplayType displayType,
+ void hotplugReceived(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
bool connected);
// Should be called after the screen is turned on.
@@ -116,8 +116,6 @@
void incrementFrameCounter();
// Callback that gets invoked once the idle timer expires.
void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
- // Callback that gets invoked once the idle timer is reset.
- void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
// Returns relevant information about Scheduler for dumpsys purposes.
std::string doDump();
@@ -127,6 +125,10 @@
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
+ // Creates a connection on the given EventThread and forwards the given callbacks.
+ sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
+ ResetIdleTimerCallback&&);
+
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
// Collects the statistical mean (average) and median between timestamp
@@ -184,7 +186,6 @@
std::mutex mCallbackLock;
ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
- ResetIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2fea060..5f8de83 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -78,7 +78,6 @@
#include "ColorLayer.h"
#include "Colorizer.h"
#include "ContainerLayer.h"
-#include "DdmConnection.h"
#include "DisplayDevice.h"
#include "Layer.h"
#include "LayerVector.h"
@@ -121,6 +120,7 @@
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
using namespace android::sysprop;
+
using base::StringAppendF;
using ui::ColorMode;
using ui::Dataspace;
@@ -128,6 +128,8 @@
using ui::Hdr;
using ui::RenderIntent;
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
namespace {
#pragma clang diagnostic push
@@ -212,6 +214,9 @@
constexpr float kSrgbWhiteY = 1.0000f;
constexpr float kSrgbWhiteZ = 1.0891f;
+constexpr float kDefaultRefreshRate = 60.f;
+constexpr float kPerformanceRefreshRate = 90.f;
+
// ---------------------------------------------------------------------------
int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
bool SurfaceFlinger::useHwcForRgbToYuv;
@@ -279,7 +284,6 @@
mAnimCompositionPending(false),
mBootStage(BootStage::BOOTLOADER),
mDebugRegion(0),
- mDebugDDMS(0),
mDebugDisableHWC(0),
mDebugDisableTransformHint(0),
mDebugInTransaction(0),
@@ -370,16 +374,12 @@
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
- property_get("debug.sf.ddms", value, "0");
- mDebugDDMS = atoi(value);
- if (mDebugDDMS) {
- if (!startDdmConnection()) {
- // start failed, and DDMS debugging not enabled
- mDebugDDMS = 0;
- }
- }
ALOGI_IF(mDebugRegion, "showupdates enabled");
- ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
+
+ // DDMS debugging deprecated (b/120782499)
+ property_get("debug.sf.ddms", value, "0");
+ int debugDdms = atoi(value);
+ ALOGI_IF(debugDdms, "DDMS debugging not supported");
property_get("debug.sf.disable_backpressure", value, "0");
mPropagateBackpressure = !atoi(value);
@@ -498,21 +498,30 @@
setTransactionFlags(eDisplayTransactionNeeded);
}
-sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
- std::optional<DisplayId> displayId;
+std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const {
+ Mutex::Autolock lock(mStateLock);
- if (id == HWC_DISPLAY_PRIMARY) {
- displayId = getInternalDisplayId();
- } else if (id == HWC_DISPLAY_EXTERNAL) {
- displayId = getExternalDisplayId();
+ const auto internalDisplayId = getInternalDisplayIdLocked();
+ if (!internalDisplayId) {
+ return {};
}
- if (!displayId) {
- ALOGE("%s: Invalid display %d", __FUNCTION__, id);
- return nullptr;
+ std::vector<PhysicalDisplayId> displayIds;
+ displayIds.reserve(mPhysicalDisplayTokens.size());
+ displayIds.push_back(internalDisplayId->value);
+
+ for (const auto& [id, token] : mPhysicalDisplayTokens) {
+ if (id != *internalDisplayId) {
+ displayIds.push_back(id.value);
+ }
}
- return getPhysicalDisplayToken(*displayId);
+ return displayIds;
+}
+
+sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
+ Mutex::Autolock lock(mStateLock);
+ return getPhysicalDisplayTokenLocked(DisplayId{displayId});
}
status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const {
@@ -616,21 +625,25 @@
// start the EventThread
if (mUseScheduler) {
- mScheduler = getFactory().createScheduler([this](bool enabled) {
- setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
- });
+ mScheduler = getFactory().createScheduler(
+ [this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
+
// TODO(b/113612090): Currently we assume that if scheduler is turned on, then the refresh
// rate is 90. Once b/122905403 is completed, this should be updated accordingly.
mPhaseOffsets->setRefreshRateType(
scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
+ auto resetIdleTimerCallback =
+ std::bind(&SurfaceFlinger::setRefreshRateTo, this, RefreshRateType::PERFORMANCE);
+
mAppConnectionHandle =
mScheduler->createConnection("appConnection", mPhaseOffsets->getCurrentAppOffset(),
- resyncCallback,
+ resyncCallback, resetIdleTimerCallback,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
mScheduler->createConnection("sfConnection", mPhaseOffsets->getCurrentSfOffset(),
- resyncCallback, [this](nsecs_t timestamp) {
+ resyncCallback, resetIdleTimerCallback,
+ [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
@@ -707,7 +720,7 @@
}
mEventControlThread = getFactory().createEventControlThread(
- [this](bool enabled) { setVsyncEnabled(EventThread::DisplayType::Primary, enabled); });
+ [this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -728,22 +741,15 @@
}
if (mUseScheduler) {
- mScheduler->setExpiredIdleTimerCallback([this]() {
- mPhaseOffsets->setRefreshRateType(
- scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
- setRefreshRateTo(60.f /* fps */);
+ mScheduler->setExpiredIdleTimerCallback([this] {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(RefreshRateType::DEFAULT);
});
- mScheduler->setResetIdleTimerCallback([this]() {
- mPhaseOffsets->setRefreshRateType(
- scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
- setRefreshRateTo(90.f /* fps */);
- });
- mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(
- getHwComposer().getConfigs(*display->getId()));
+
+ mRefreshRateStats =
+ std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
+ *display->getId()),
+ mTimeStats);
}
ALOGV("Done initializing");
@@ -822,7 +828,9 @@
return BAD_VALUE;
}
- const auto displayId = getPhysicalDisplayId(displayToken);
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
if (!displayId) {
return NAME_NOT_FOUND;
}
@@ -846,8 +854,6 @@
configs->clear();
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
DisplayInfo info = DisplayInfo();
@@ -860,7 +866,7 @@
info.viewportW = info.w;
info.viewportH = info.h;
- if (displayId == getInternalDisplayId()) {
+ if (displayId == getInternalDisplayIdLocked()) {
// The density of the device is provided by a build property
float density = Density::getBuildDensity() / 160.0f;
if (density == 0) {
@@ -916,7 +922,7 @@
// All non-virtual displays are currently considered secure.
info.secure = true;
- if (displayId == getInternalDisplayId() &&
+ if (displayId == getInternalDisplayIdLocked() &&
primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
std::swap(info.w, info.h);
}
@@ -951,13 +957,6 @@
return display->getActiveConfig();
}
-status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) {
- ATRACE_NAME("setActiveConfigAsync");
- postMessageAsync(new LambdaMessage(
- [=]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
- return NO_ERROR;
-}
-
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
ATRACE_NAME("setActiveConfigSync");
postMessageSync(new LambdaMessage(
@@ -1014,15 +1013,15 @@
return BAD_VALUE;
}
- const auto displayId = getPhysicalDisplayId(displayToken);
- if (!displayId) {
- return NAME_NOT_FOUND;
- }
-
std::vector<ColorMode> modes;
{
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
+ }
+
modes = getHwComposer().getColorModes(*displayId);
}
outColorModes->clear();
@@ -1163,20 +1162,6 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
- int32_t* outBufferId) {
- if (!outBufferId) {
- return BAD_VALUE;
- }
- *outBufferId = mBufferStateLayerCache.add(token, buffer);
- return NO_ERROR;
-}
-
-status_t SurfaceFlinger::uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
- mBufferStateLayerCache.release(token, bufferId);
- return NO_ERROR;
-}
-
status_t SurfaceFlinger::isWideColorDisplay(const sp<IBinder>& displayToken,
bool* outIsWideColorDisplay) const {
if (!displayToken || !outIsWideColorDisplay) {
@@ -1278,16 +1263,21 @@
});
if (mUseScheduler) {
- if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mScheduler->createDisplayEventConnection(mSfConnectionHandle, resyncCallback);
- } else {
- return mScheduler->createDisplayEventConnection(mAppConnectionHandle, resyncCallback);
- }
+ auto resetIdleTimerCallback = [this] {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(RefreshRateType::PERFORMANCE);
+ };
+
+ const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle
+ : mAppConnectionHandle;
+
+ return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback),
+ std::move(resetIdleTimerCallback));
} else {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mSFEventThread->createEventConnection(resyncCallback);
+ return mSFEventThread->createEventConnection(resyncCallback, ResetIdleTimerCallback());
} else {
- return mEventThread->createEventConnection(resyncCallback);
+ return mEventThread->createEventConnection(resyncCallback, ResetIdleTimerCallback());
}
}
}
@@ -1332,7 +1322,7 @@
}
nsecs_t SurfaceFlinger::getVsyncPeriod() const {
- const auto displayId = getInternalDisplayId();
+ const auto displayId = getInternalDisplayIdLocked();
if (!displayId || !getHwComposer().isConnected(*displayId)) {
return 0;
}
@@ -1449,29 +1439,39 @@
*compositorTiming = getBE().mCompositorTiming;
}
-void SurfaceFlinger::setRefreshRateTo(float newFps) {
- const auto displayId = getInternalDisplayId();
- if (!displayId || mBootStage != BootStage::FINISHED) {
+void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) {
+ mPhaseOffsets->setRefreshRateType(refreshRate);
+
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
+
+ if (mBootStage != BootStage::FINISHED) {
return;
}
+
// TODO(b/113612090): There should be a message queue flush here. Because this esentially
// runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
// manner, once the setActiveConfig is synchronous, and is executed at a known time in a
// refresh cycle.
// Don't do any updating if the current fps is the same as the new one.
- const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
- const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod();
+ const nsecs_t currentVsyncPeriod = getVsyncPeriod();
if (currentVsyncPeriod == 0) {
return;
}
+
// TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
// floating numbers.
const float currentFps = 1e9 / currentVsyncPeriod;
+ const float newFps = refreshRate == RefreshRateType::PERFORMANCE ? kPerformanceRefreshRate
+ : kDefaultRefreshRate;
if (std::abs(currentFps - newFps) <= 1) {
return;
}
+ const auto displayId = getInternalDisplayIdLocked();
+ LOG_ALWAYS_FATAL_IF(!displayId);
+
auto configs = getHwComposer().getConfigs(*displayId);
for (int i = 0; i < configs.size(); i++) {
const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
@@ -1482,11 +1482,7 @@
// TODO(b/113612090): There should be a better way at determining which config
// has the right refresh rate.
if (std::abs(fps - newFps) <= 1) {
- const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY);
- if (!display) return;
- // This is posted in async function to avoid deadlock when getDisplayDevice
- // requires mStateLock.
- setActiveConfigAsync(display, i);
+ setActiveConfigInternal(getInternalDisplayTokenLocked(), i);
ATRACE_INT("FPS", newFps);
}
}
@@ -1526,10 +1522,10 @@
repaintEverythingForHWC();
}
-void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
+void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
ATRACE_CALL();
Mutex::Autolock lock(mStateLock);
- if (const auto displayId = getInternalDisplayId()) {
+ if (const auto displayId = getInternalDisplayIdLocked()) {
getHwComposer().setVsyncEnabled(*displayId,
enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
}
@@ -1656,6 +1652,10 @@
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
+
+ updateCursorAsync();
+ updateInputFlinger();
+
refreshNeeded |= mRepaintEverything;
if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
// Signal a refresh if a transaction modified the window state,
@@ -1750,7 +1750,15 @@
bool SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
- return handlePageFlip();
+ bool refreshNeeded = handlePageFlip();
+
+ for (auto& layer : mLayersPendingRefresh) {
+ Region visibleReg;
+ visibleReg.set(layer->computeScreenBounds());
+ invalidateLayerStack(layer, visibleReg);
+ }
+ mLayersPendingRefresh.clear();
+ return refreshNeeded;
}
void SurfaceFlinger::calculateWorkingSet() {
@@ -2351,10 +2359,12 @@
break;
case Dataspace::BT2020_PQ:
case Dataspace::BT2020_ITU_PQ:
+ bestDataSpace = Dataspace::DISPLAY_P3;
*outHdrDataSpace = Dataspace::BT2020_PQ;
break;
case Dataspace::BT2020_HLG:
case Dataspace::BT2020_ITU_HLG:
+ bestDataSpace = Dataspace::DISPLAY_P3;
// When there's mixed PQ content and HLG content, we set the HDR
// data space to be BT2020_PQ and convert HLG to PQ.
if (*outHdrDataSpace == Dataspace::UNKNOWN) {
@@ -2611,14 +2621,13 @@
mPendingHotplugEvents.clear();
}
-void SurfaceFlinger::dispatchDisplayHotplugEvent(EventThread::DisplayType displayType,
- bool connected) {
+void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle, displayType, connected);
- mScheduler->hotplugReceived(mSfConnectionHandle, displayType, connected);
+ mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected);
+ mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected);
} else {
- mEventThread->onHotplugReceived(displayType, connected);
- mSFEventThread->onHotplugReceived(displayType, connected);
+ mEventThread->onHotplugReceived(displayId, connected);
+ mSFEventThread->onHotplugReceived(displayId, connected);
}
}
@@ -2634,7 +2643,7 @@
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
- const bool isInternalDisplay = displayId && displayId == getInternalDisplayId();
+ const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
creationArgs.isPrimary = isInternalDisplay;
if (useColorManagement && displayId) {
@@ -2717,19 +2726,18 @@
for (size_t i = 0; i < dc;) {
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
if (j < 0) {
- // Save display IDs before disconnecting.
- const auto internalDisplayId = getInternalDisplayId();
- const auto externalDisplayId = getExternalDisplayId();
-
// in drawing state but not in current state
if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
+ // Save display ID before disconnecting.
+ const auto displayId = display->getId();
display->disconnect();
+
+ if (!display->isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispatchDisplayHotplugEvent(displayId->value, false);
+ }
}
- if (internalDisplayId && internalDisplayId == draw[i].displayId) {
- dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, false);
- } else if (externalDisplayId && externalDisplayId == draw[i].displayId) {
- dispatchDisplayHotplugEvent(EventThread::DisplayType::External, false);
- }
+
mDisplays.erase(draw.keyAt(i));
} else {
// this display is in both lists. see if something changed.
@@ -2832,12 +2840,7 @@
dispSurface, producer));
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
-
- if (displayId == getInternalDisplayId()) {
- dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, true);
- } else if (displayId == getExternalDisplayId()) {
- dispatchDisplayHotplugEvent(EventThread::DisplayType::External, true);
- }
+ dispatchDisplayHotplugEvent(displayId->value, true);
}
}
}
@@ -2859,7 +2862,6 @@
* (perform the transaction for each of them if needed)
*/
- bool inputChanged = false;
if (transactionFlags & eTraversalNeeded) {
mCurrentState.traverseInZOrder([&](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
@@ -2870,7 +2872,7 @@
mVisibleRegionsDirty = true;
if (flags & Layer::eInputInfoChanged) {
- inputChanged = true;
+ mInputInfoChanged = true;
}
});
}
@@ -2982,22 +2984,23 @@
}
commitTransaction();
-
- if (inputChanged || mVisibleRegionsDirty) {
- updateInputWindows();
- }
- executeInputWindowCommands();
-
- updateCursorAsync();
}
-void SurfaceFlinger::updateInputWindows() {
+void SurfaceFlinger::updateInputFlinger() {
ATRACE_CALL();
-
- if (mInputFlinger == nullptr) {
+ if (!mInputFlinger) {
return;
}
+ if (mVisibleRegionsDirty || mInputInfoChanged) {
+ mInputInfoChanged = false;
+ updateInputWindowInfo();
+ }
+
+ executeInputWindowCommands();
+}
+
+void SurfaceFlinger::updateInputWindowInfo() {
Vector<InputWindowInfo> inputHandles;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3011,10 +3014,6 @@
}
void SurfaceFlinger::executeInputWindowCommands() {
- if (!mInputFlinger) {
- return;
- }
-
for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) {
if (transferTouchFocusCommand.fromToken != nullptr &&
transferTouchFocusCommand.toToken != nullptr &&
@@ -3291,9 +3290,10 @@
Mutex::Autolock lock(mStateLock);
for (auto& layer : mLayersWithQueuedFrames) {
- const Region dirty(layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence));
+ if (layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence)) {
+ mLayersPendingRefresh.push_back(layer);
+ }
layer->useSurfaceDamage();
- invalidateLayerStack(layer, dirty);
if (layer->isBufferLatched()) {
newDataLatched = true;
}
@@ -3307,11 +3307,6 @@
mVisibleRegionsDirty |= visibleRegions;
- if (visibleRegions) {
- // Update input window info if the layer receives its first buffer.
- updateInputWindows();
- }
-
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
@@ -3337,7 +3332,6 @@
void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
const Region& inDirtyRegion) {
auto display = displayDevice->getCompositionDisplay();
-
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
@@ -3357,6 +3351,7 @@
bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
const Region& debugRegion, base::unique_fd* readyFence) {
+ ATRACE_CALL();
ALOGV("doComposeSurfaces");
auto display = displayDevice->getCompositionDisplay();
@@ -3483,6 +3478,7 @@
firstLayer = false;
}
+ // Perform some cleanup steps if we used client composition.
if (hasClientComposition) {
clientCompositionDisplay.clearRegion = clearRegion;
if (!debugRegion.isEmpty()) {
@@ -3988,9 +3984,6 @@
if (what & layer_state_t::eFrameChanged) {
if (layer->setFrame(s.frame)) flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eBufferChanged) {
- if (layer->setBuffer(s.buffer)) flags |= eTraversalNeeded;
- }
if (what & layer_state_t::eAcquireFenceChanged) {
if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
}
@@ -4027,9 +4020,16 @@
callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
}
}
+
+ if (what & layer_state_t::eBufferChanged) {
+ // Add the new buffer to the cache. This should always come before eCachedBufferChanged.
+ BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.bufferId,
+ s.buffer);
+ }
if (what & layer_state_t::eCachedBufferChanged) {
sp<GraphicBuffer> buffer =
- mBufferStateLayerCache.get(s.cachedBuffer.token, s.cachedBuffer.bufferId);
+ BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
+ s.cachedBuffer.bufferId);
if (layer->setBuffer(buffer)) flags |= eTraversalNeeded;
}
if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
@@ -4846,7 +4846,7 @@
" gpu_to_cpu_unsupported : %d\n",
mTransactionFlags.load(), !mGpuToCpuSupported);
- if (const auto displayId = getInternalDisplayId();
+ if (const auto displayId = getInternalDisplayIdLocked();
displayId && getHwComposer().isConnected(*displayId)) {
const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
StringAppendF(&result,
@@ -4928,24 +4928,6 @@
return empty;
}
-bool SurfaceFlinger::startDdmConnection()
-{
- void* libddmconnection_dso =
- dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW);
- if (!libddmconnection_dso) {
- return false;
- }
- void (*DdmConnection_start)(const char* name);
- DdmConnection_start =
- (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start");
- if (!DdmConnection_start) {
- dlclose(libddmconnection_dso);
- return false;
- }
- (*DdmConnection_start)(getServiceName());
- return true;
-}
-
void SurfaceFlinger::updateColorMatrixLocked() {
mat4 colorMatrix;
if (mGlobalSaturationFactor != 1.0f) {
@@ -5016,7 +4998,8 @@
// information, so it is OK to pass them.
case AUTHENTICATE_SURFACE:
case GET_ACTIVE_CONFIG:
- case GET_BUILT_IN_DISPLAY:
+ case GET_PHYSICAL_DISPLAY_IDS:
+ case GET_PHYSICAL_DISPLAY_TOKEN:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_NATIVE_PRIMARIES:
case GET_DISPLAY_CONFIGS:
@@ -5029,8 +5012,6 @@
case GET_COLOR_MANAGEMENT:
case GET_COMPOSITION_PREFERENCE:
case GET_PROTECTED_CONTENT_SUPPORT:
- case CACHE_BUFFER:
- case UNCACHE_BUFFER:
case IS_WIDE_COLOR_DISPLAY: {
return OK;
}
@@ -5409,8 +5390,8 @@
DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
renderAreaRotation);
- auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
- display, std::placeholders::_1);
+ auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
+ std::placeholders::_1);
return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat,
useIdentityTransform);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a48e811..6546973 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -60,6 +60,7 @@
#include "Scheduler/EventThread.h"
#include "Scheduler/MessageQueue.h"
#include "Scheduler/PhaseOffsets.h"
+#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/RefreshRateStats.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/VSyncModulator.h"
@@ -313,7 +314,7 @@
compositionengine::CompositionEngine& getCompositionEngine() const;
// returns the default Display
- sp<const DisplayDevice> getDefaultDisplayDevice() const {
+ sp<const DisplayDevice> getDefaultDisplayDevice() {
Mutex::Autolock _l(mStateLock);
return getDefaultDisplayDeviceLocked();
}
@@ -327,7 +328,7 @@
// enable/disable h/w composer event
// TODO: this should be made accessible only to EventThread
- void setVsyncEnabled(EventThread::DisplayType displayType, bool enabled);
+ void setPrimaryVsyncEnabled(bool enabled);
// called on the main thread by MessageQueue when an internal message
// is received
@@ -414,7 +415,8 @@
sp<ISurfaceComposerClient> createConnection() override;
sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
void destroyDisplay(const sp<IBinder>& displayToken) override;
- sp<IBinder> getBuiltInDisplay(int32_t id) override;
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override;
+ sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
@@ -467,9 +469,6 @@
uint64_t timestamp,
DisplayedFrameStats* outStats) const override;
status_t getProtectedContentSupport(bool* outSupported) const override;
- status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
- int32_t* outBufferId) override;
- status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) override;
status_t isWideColorDisplay(const sp<IBinder>& displayToken,
bool* outIsWideColorDisplay) const override;
@@ -504,8 +503,6 @@
// called on the main thread in response to initializeDisplays()
void onInitializeDisplays() REQUIRES(mStateLock);
- // setActiveConfigInternal() posted on a main thread for async execution
- status_t setActiveConfigAsync(const sp<IBinder>& displayToken, int mode);
// called on the main thread in response to setActiveConfig()
void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
// called on the main thread in response to setPowerMode()
@@ -522,7 +519,8 @@
void handleTransaction(uint32_t transactionFlags);
void handleTransactionLocked(uint32_t transactionFlags);
- void updateInputWindows();
+ void updateInputFlinger();
+ void updateInputWindowInfo();
void executeInputWindowCommands();
void updateCursorAsync();
@@ -657,7 +655,7 @@
}
sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
- if (const auto token = getInternalDisplayToken()) {
+ if (const auto token = getInternalDisplayTokenLocked()) {
return getDisplayDeviceLocked(token);
}
return nullptr;
@@ -761,7 +759,7 @@
void processDisplayChangesLocked();
void processDisplayHotplugEventsLocked();
- void dispatchDisplayHotplugEvent(EventThread::DisplayType displayType, bool connected);
+ void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
/* ------------------------------------------------------------------------
* VSync
@@ -771,9 +769,9 @@
void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
void disableHardwareVsync(bool makeUnavailable);
- // Sets the refresh rate to newFps by switching active configs, if they are available for
+ // Sets the refresh rate by switching active configs, if they are available for
// the desired refresh rate.
- void setRefreshRateTo(float newFps);
+ void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType) REQUIRES(mStateLock);
using GetVsyncPeriod = std::function<nsecs_t()>;
@@ -801,12 +799,12 @@
/*
* Display identification
*/
- sp<IBinder> getPhysicalDisplayToken(DisplayId displayId) const {
+ sp<IBinder> getPhysicalDisplayTokenLocked(DisplayId displayId) const {
const auto it = mPhysicalDisplayTokens.find(displayId);
return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
}
- std::optional<DisplayId> getPhysicalDisplayId(const sp<IBinder>& displayToken) const {
+ std::optional<DisplayId> getPhysicalDisplayIdLocked(const sp<IBinder>& displayToken) const {
for (const auto& [id, token] : mPhysicalDisplayTokens) {
if (token == displayToken) {
return id;
@@ -816,27 +814,19 @@
}
// TODO(b/74619554): Remove special cases for primary display.
- sp<IBinder> getInternalDisplayToken() const {
- const auto displayId = getInternalDisplayId();
- return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+ sp<IBinder> getInternalDisplayTokenLocked() const {
+ const auto displayId = getInternalDisplayIdLocked();
+ return displayId ? getPhysicalDisplayTokenLocked(*displayId) : nullptr;
}
- std::optional<DisplayId> getInternalDisplayId() const {
+ std::optional<DisplayId> getInternalDisplayIdLocked() const {
const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
}
- // TODO(b/74619554): Remove special cases for external display.
- std::optional<DisplayId> getExternalDisplayId() const {
- const auto hwcDisplayId = getHwComposer().getExternalHwcDisplayId();
- return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
- }
-
/*
* Debugging & dumpsys
*/
- bool startDdmConnection();
-
using DumpArgs = Vector<String16>;
using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>;
@@ -951,7 +941,6 @@
std::unique_ptr<VSyncSource> mSfEventThreadSource;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
std::unique_ptr<EventControlThread> mEventControlThread;
- std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
// Calculates correct offsets.
VSyncModulator mVsyncModulator;
@@ -962,9 +951,13 @@
// don't need synchronization
State mDrawingState{LayerVector::StateSet::Drawing};
bool mVisibleRegionsDirty;
+ // Set during transaction commit stage to track if the input info for a layer has changed.
+ bool mInputInfoChanged{false};
bool mGeometryInvalid;
bool mAnimCompositionPending;
std::vector<sp<Layer>> mLayersWithQueuedFrames;
+ // Tracks layers that need to update a display's dirty region.
+ std::vector<sp<Layer>> mLayersPendingRefresh;
sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
bool mHadClientComposition = false;
@@ -985,10 +978,10 @@
// this may only be written from the main thread with mStateLock held
// it may be read from other threads with mStateLock held
std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays;
+ std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
// don't use a lock for these, we don't care
int mDebugRegion;
- int mDebugDDMS;
int mDebugDisableHWC;
int mDebugDisableTransformHint;
volatile nsecs_t mDebugInSwapBuffers;
@@ -1000,7 +993,7 @@
std::unique_ptr<SurfaceInterceptor> mInterceptor{mFactory.createSurfaceInterceptor(this)};
SurfaceTracing mTracing;
LayerStats mLayerStats;
- std::unique_ptr<TimeStats> mTimeStats;
+ std::shared_ptr<TimeStats> mTimeStats;
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount{0};
@@ -1096,8 +1089,6 @@
InputWindowCommands mInputWindowCommands;
- BufferStateLayerCache mBufferStateLayerCache;
-
ui::DisplayPrimaries mInternalDisplayPrimaries;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 773a5d1..26d2c21 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -128,8 +128,8 @@
return new ColorLayer(args);
}
- std::unique_ptr<TimeStats> createTimeStats() override {
- return std::make_unique<TimeStats>();
+ std::shared_ptr<TimeStats> createTimeStats() override {
+ return std::make_shared<android::impl::TimeStats>();
}
};
static Factory factory;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index ac99e2a..fc1d0f8 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -93,7 +93,7 @@
virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0;
virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
- virtual std::unique_ptr<TimeStats> createTimeStats() = 0;
+ virtual std::shared_ptr<TimeStats> createTimeStats() = 0;
protected:
~Factory() = default;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 8d3776b..78c6e74 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -32,6 +32,8 @@
namespace android {
+namespace impl {
+
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
ATRACE_CALL();
@@ -450,6 +452,15 @@
mPowerTime.powerMode = powerMode;
}
+void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mTimeStats.refreshRateStats.count(fps)) {
+ mTimeStats.refreshRateStats[fps] += duration;
+ } else {
+ mTimeStats.refreshRateStats.insert({fps, duration});
+ }
+}
+
void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
ATRACE_CALL();
@@ -547,6 +558,7 @@
mTimeStats.clientCompositionFrames = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
+ mTimeStats.refreshRateStats.clear();
mPowerTime.prevTime = systemTime();
mGlobalRecord.prevPresentTime = 0;
mGlobalRecord.presentFences.clear();
@@ -580,4 +592,6 @@
}
}
+} // namespace impl
+
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index e8fbcab..d8c0786 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -36,6 +36,40 @@
namespace android {
class TimeStats {
+public:
+ virtual ~TimeStats() = default;
+
+ virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
+ virtual bool isEnabled() = 0;
+
+ virtual void incrementTotalFrames() = 0;
+ virtual void incrementMissedFrames() = 0;
+ virtual void incrementClientCompositionFrames() = 0;
+
+ virtual void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+ nsecs_t postTime) = 0;
+ virtual void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) = 0;
+ virtual void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) = 0;
+ virtual void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) = 0;
+ virtual void setAcquireFence(int32_t layerID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& acquireFence) = 0;
+ virtual void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) = 0;
+ virtual void setPresentFence(int32_t layerID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& presentFence) = 0;
+ // Clean up the layer record
+ virtual void onDestroy(int32_t layerID) = 0;
+ // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
+ virtual void removeTimeRecord(int32_t layerID, uint64_t frameNumber) = 0;
+
+ virtual void setPowerMode(int32_t powerMode) = 0;
+ // Source of truth is RefrehRateStats.
+ virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
+ virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
+};
+
+namespace impl {
+
+class TimeStats : public android::TimeStats {
struct FrameTime {
uint64_t frameNumber = 0;
nsecs_t postTime = 0;
@@ -75,32 +109,33 @@
public:
TimeStats() = default;
- ~TimeStats() = default;
- void parseArgs(bool asProto, const Vector<String16>& args, std::string& result);
- bool isEnabled();
+ void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
+ bool isEnabled() override;
- void incrementTotalFrames();
- void incrementMissedFrames();
- void incrementClientCompositionFrames();
+ void incrementTotalFrames() override;
+ void incrementMissedFrames() override;
+ void incrementClientCompositionFrames() override;
void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
- nsecs_t postTime);
- void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
- void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
- void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
+ nsecs_t postTime) override;
+ void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) override;
+ void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) override;
+ void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) override;
void setAcquireFence(int32_t layerID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& acquireFence);
- void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime);
+ const std::shared_ptr<FenceTime>& acquireFence) override;
+ void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) override;
void setPresentFence(int32_t layerID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence);
+ const std::shared_ptr<FenceTime>& presentFence) override;
// Clean up the layer record
- void onDestroy(int32_t layerID);
+ void onDestroy(int32_t layerID) override;
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
- void removeTimeRecord(int32_t layerID, uint64_t frameNumber);
+ void removeTimeRecord(int32_t layerID, uint64_t frameNumber) override;
- void setPowerMode(int32_t powerMode);
- void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence);
+ void setPowerMode(int32_t powerMode) override;
+ // Source of truth is RefrehRateStats.
+ void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
+ void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
// TODO(zzyiwei): Bound the timeStatsTracker with weighted LRU
// static const size_t MAX_NUM_LAYER_RECORDS = 200;
@@ -126,4 +161,6 @@
GlobalRecord mGlobalRecord;
};
+} // namespace impl
+
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 75ce4be..16d2da0 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -103,6 +103,11 @@
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
+ StringAppendF(&result, "displayConfigStats is as below:\n");
+ for (const auto& [fps, duration] : refreshRateStats) {
+ StringAppendF(&result, "%dfps=%ldms ", fps, ns2ms(duration));
+ }
+ result.back() = '\n';
StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
result.append(presentToPresent.toString());
@@ -141,6 +146,13 @@
globalProto.set_missed_frames(missedFrames);
globalProto.set_client_composition_frames(clientCompositionFrames);
globalProto.set_display_on_time(displayOnTime);
+ for (const auto& ele : refreshRateStats) {
+ SFTimeStatsDisplayConfigBucketProto* configBucketProto =
+ globalProto.add_display_config_stats();
+ SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config();
+ configProto->set_fps(ele.first);
+ configBucketProto->set_duration_millis(ns2ms(ele.second));
+ }
for (const auto& histEle : presentToPresent.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
histProto->set_time_millis(histEle.first);
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 5f40a1a..f2ac7ff 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -16,6 +16,7 @@
#pragma once
#include <timestatsproto/TimeStatsProtoHeader.h>
+#include <utils/Timers.h>
#include <optional>
#include <string>
@@ -61,6 +62,7 @@
int64_t displayOnTime = 0;
Histogram presentToPresent;
std::unordered_map<std::string, TimeStatsLayer> stats;
+ std::unordered_map<uint32_t, nsecs_t> refreshRateStats;
std::string toString(std::optional<uint32_t> maxLayers) const;
SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index 377612a..0dacbeb 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -25,7 +25,7 @@
// changes to these messages, and keep google3 side proto messages in sync if
// the end to end pipeline needs to be updated.
-// Next tag: 9
+// Next tag: 10
message SFTimeStatsGlobalProto {
// The stats start time in UTC as seconds since January 1, 1970
optional int64 stats_start = 1;
@@ -39,6 +39,8 @@
optional int32 client_composition_frames = 5;
// Primary display on time in milliseconds.
optional int64 display_on_time = 7;
+ // Stats per display configuration.
+ repeated SFTimeStatsDisplayConfigBucketProto display_config_stats = 9;
// Present to present histogram.
repeated SFTimeStatsHistogramBucketProto present_to_present = 8;
// Stats per layer. Apps could have multiple layers.
@@ -80,3 +82,18 @@
// Number of frames in the bucket.
optional int32 frame_count = 2;
}
+
+// Next tag: 3
+message SFTimeStatsDisplayConfigBucketProto {
+ // Metadata desribing a display config.
+ optional SFTimeStatsDisplayConfigProto config = 1;
+ // Duration in milliseconds for how long the display was in this
+ // configuration.
+ optional int64 duration_millis = 2;
+}
+
+// Next tag: 2
+message SFTimeStatsDisplayConfigProto {
+ // Frames per second, rounded to the nearest integer.
+ optional int32 fps = 1;
+}
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index f021d3d..61d09da 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -62,9 +62,11 @@
}
void setupBackgroundSurface() {
- mDisplay = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ mDisplay = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(mDisplay == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
const ssize_t displayWidth = info.w;
const ssize_t displayHeight = info.h;
@@ -170,10 +172,8 @@
}
TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) {
- std::function<bool()> condition = [=]() {
- sp<IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
- return (display != nullptr);
+ std::function<bool()> condition = [] {
+ return SurfaceComposerClient::getInternalDisplayToken() != nullptr;
};
// Anyone can access display information.
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true));
@@ -183,7 +183,7 @@
// The following methods are tested with a UID that is not root, graphics,
// or system, to show that anyone can access them.
setBinUID();
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_TRUE(display != nullptr);
DisplayInfo info;
@@ -199,7 +199,7 @@
}
TEST_F(CredentialsTest, GetDisplayColorModesTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
Vector<ui::ColorMode> outColorModes;
return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes);
@@ -208,7 +208,7 @@
}
TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
ui::DisplayPrimaries primaries;
return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries);
@@ -217,7 +217,7 @@
}
TEST_F(CredentialsTest, SetActiveConfigTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
return SurfaceComposerClient::setActiveConfig(display, 0);
};
@@ -225,7 +225,7 @@
}
TEST_F(CredentialsTest, SetActiveColorModeTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE);
};
@@ -258,7 +258,7 @@
}
TEST_F(CredentialsTest, CaptureTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
sp<GraphicBuffer> outBuffer;
return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
@@ -324,7 +324,8 @@
}
TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
bool result = false;
status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result);
ASSERT_EQ(NO_ERROR, error);
@@ -346,7 +347,8 @@
}
TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
std::function<status_t()> condition = [=]() {
bool result = false;
return SurfaceComposerClient::isWideColorDisplay(display, &result);
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index 89c26f4..ee857b0 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -34,7 +34,7 @@
auto surf = client->createSurface(String8("t"), 100, 100,
PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(surf != nullptr);
- surf->clear();
+ surf.clear();
}
};
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 8ec3e15..5cc946a 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -240,10 +240,12 @@
}
void SurfaceInterceptorTest::setupBackgroundSurface() {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+
ssize_t displayWidth = info.w;
ssize_t displayHeight = info.h;
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4f0ded3..7b21dbc 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -195,13 +195,12 @@
class ScreenCapture : public RefBase {
public:
static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto sf = ComposerService::getComposerService();
+ const auto token = sf->getInternalDisplayToken();
SurfaceComposerClient::Transaction().apply(true);
sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR,
- sf->captureScreen(display, &outBuffer, Rect(), 0, 0, false));
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(token, &outBuffer, Rect(), 0, 0, false));
*sc = std::make_unique<ScreenCapture>(outBuffer);
}
@@ -324,7 +323,6 @@
ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
}
@@ -502,12 +500,12 @@
private:
void SetUpDisplay() {
- mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
- ASSERT_NE(nullptr, mDisplay.get()) << "failed to get built-in display";
+ mDisplay = mClient->getInternalDisplayToken();
+ ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
// get display width/height
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
mDisplayWidth = info.w;
mDisplayHeight = info.h;
mDisplayRect =
@@ -558,8 +556,7 @@
return mDelegate->screenshot();
case RenderPath::VIRTUAL_DISPLAY:
- sp<IBinder> mainDisplay =
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken();
DisplayInfo mainDisplayInfo;
SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
@@ -1137,7 +1134,7 @@
.setRelativeLayer(layerG, layerR->getHandle(), 1)
.apply();
- layerG->clear();
+ layerG.clear();
// layerG should have been removed
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
@@ -1540,7 +1537,6 @@
SCOPED_TRACE("default before setting background color layer");
screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
}
-
Transaction()
.setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
.apply();
@@ -1625,7 +1621,7 @@
bool bufferFill = true;
float alpha = 1.0f;
Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
priorColor, bufferFill, alpha, finalColor));
}
@@ -1635,7 +1631,7 @@
bool bufferFill = false;
float alpha = 1.0f;
Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
priorColor, bufferFill, alpha, finalColor));
}
@@ -1645,7 +1641,7 @@
bool bufferFill = false;
float alpha = 1.0f;
Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
priorColor, bufferFill, alpha, finalColor));
}
@@ -1655,7 +1651,7 @@
bool bufferFill = false;
float alpha = 0;
Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
priorColor, bufferFill, alpha, finalColor));
}
@@ -1665,7 +1661,7 @@
bool bufferFill = false;
float alpha = 0;
Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
priorColor, bufferFill, alpha, finalColor));
}
@@ -2405,6 +2401,117 @@
}
}
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 10> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 70> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 65> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+ if (idx == 0) {
+ buffers[0].clear();
+ }
+ idx++;
+ }
+}
+
TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
@@ -2623,143 +2730,6 @@
Transaction().setSidebandStream(layer, nullptr).apply();
}
-TEST_F(LayerTransactionTest, CacheBuffer_BufferState) {
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
-
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- ASSERT_GE(bufferId, 0);
-
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-}
-
-TEST_F(LayerTransactionTest, CacheBuffers_BufferState) {
- std::vector<int32_t> bufferIds;
- int32_t bufferCount = 20;
-
- for (int i = 0; i < bufferCount; i++) {
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- if (bufferId < 0) {
- EXPECT_GE(bufferId, 0);
- break;
- }
- bufferIds.push_back(bufferId);
- }
-
- for (int32_t bufferId : bufferIds) {
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
- }
-}
-
-TEST_F(LayerTransactionTest, CacheBufferInvalid_BufferState) {
- sp<GraphicBuffer> buffer = nullptr;
-
- int32_t bufferId = -1;
- ASSERT_NE(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- ASSERT_LT(bufferId, 0);
-}
-
-TEST_F(LayerTransactionTest, UncacheBufferTwice_BufferState) {
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
-
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- ASSERT_GE(bufferId, 0);
-
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
- mClient->uncacheBuffer(bufferId);
-}
-
-TEST_F(LayerTransactionTest, UncacheBufferInvalidId_BufferState) {
- mClient->uncacheBuffer(-1);
- mClient->uncacheBuffer(0);
- mClient->uncacheBuffer(1);
- mClient->uncacheBuffer(5);
- mClient->uncacheBuffer(1000);
-}
-
-TEST_F(LayerTransactionTest, SetCachedBuffer_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
-
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
- ASSERT_GE(bufferId, 0);
-
- Transaction().setCachedBuffer(layer, bufferId).apply();
-
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-}
-
-TEST_F(LayerTransactionTest, SetCachedBufferDelayed_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> cachedBuffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- int32_t bufferId = -1;
- ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(cachedBuffer, &bufferId));
- ASSERT_GE(bufferId, 0);
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::BLUE);
- Transaction().setBuffer(layer, buffer).apply();
- {
- SCOPED_TRACE("Uncached buffer");
-
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- fillGraphicBufferColor(cachedBuffer, Rect(0, 0, 32, 32), Color::RED);
- Transaction().setCachedBuffer(layer, bufferId).apply();
- {
- SCOPED_TRACE("Cached buffer");
-
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-}
-
TEST_F(LayerTransactionTest, ReparentToSelf) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
@@ -3155,16 +3125,25 @@
}
static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
- const sp<SurfaceControl>& layer = nullptr) {
+ const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
+ bool setBackgroundColor = false) {
if (layer) {
sp<GraphicBuffer> buffer;
sp<Fence> fence;
- int err = getBuffer(&buffer, &fence);
- if (err != NO_ERROR) {
- return err;
+ if (setBuffer) {
+ int err = getBuffer(&buffer, &fence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ transaction.setBuffer(layer, buffer);
+ transaction.setAcquireFence(layer, fence);
}
- transaction.setBuffer(layer, buffer).setAcquireFence(layer, fence);
+ if (setBackgroundColor) {
+ transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
+ ui::Dataspace::UNKNOWN);
+ }
}
transaction.addTransactionCompletedCallback(callbackHelper->function,
@@ -3195,13 +3174,13 @@
}
};
-TEST_F(LayerCallbackTest, Basic) {
+TEST_F(LayerCallbackTest, BufferColor) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
Transaction transaction;
CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
+ int err = fillTransaction(transaction, &callback, layer, true, true);
if (err) {
GTEST_SUCCEED() << "test not supported";
return;
@@ -3214,13 +3193,13 @@
EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
}
-TEST_F(LayerCallbackTest, NoBuffer) {
+TEST_F(LayerCallbackTest, NoBufferNoColor) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
Transaction transaction;
CallbackHelper callback;
- int err = fillTransaction(transaction, &callback);
+ int err = fillTransaction(transaction, &callback, layer, false, false);
if (err) {
GTEST_SUCCEED() << "test not supported";
return;
@@ -3234,6 +3213,45 @@
EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
}
+TEST_F(LayerCallbackTest, BufferNoColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, true, false);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBufferColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
TEST_F(LayerCallbackTest, NoStateChange) {
Transaction transaction;
CallbackHelper callback;
@@ -3268,7 +3286,7 @@
EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
}
-TEST_F(LayerCallbackTest, Merge) {
+TEST_F(LayerCallbackTest, MergeBufferNoColor) {
sp<SurfaceControl> layer1, layer2;
ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
@@ -3295,6 +3313,62 @@
EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
}
+TEST_F(LayerCallbackTest, MergeNoBufferColor) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeOneBufferOneColor) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer2,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
TEST_F(LayerCallbackTest, Merge_SameCallback) {
sp<SurfaceControl> layer1, layer2;
ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
@@ -3896,10 +3970,11 @@
LayerTransactionTest::SetUp();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
- sp<IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
ssize_t displayWidth = info.w;
ssize_t displayHeight = info.h;
@@ -4360,7 +4435,7 @@
mCapture->checkPixel(64, 64, 111, 111, 111);
}
- mChild->clear();
+ mChild.clear();
{
SCOPED_TRACE("After destroying child");
@@ -5232,7 +5307,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
auto redLayerHandle = redLayer->getHandle();
- redLayer->clear();
+ redLayer.clear();
SurfaceComposerClient::Transaction().apply(true);
sp<GraphicBuffer> outBuffer;
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 16e0891..f9e0b64 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -145,7 +145,7 @@
void TearDown() override;
void waitForDisplayTransaction();
- bool waitForHotplugEvent(uint32_t id, bool connected);
+ bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected);
sp<IComposer> mFakeService;
sp<SurfaceComposerClient> mComposerClient;
@@ -242,7 +242,7 @@
mMockComposer->runVSyncAndWait();
}
-bool DisplayTest::waitForHotplugEvent(uint32_t id, bool connected) {
+bool DisplayTest::waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
int waitCount = 20;
while (waitCount--) {
while (!mReceivedDisplayEvents.empty()) {
@@ -250,11 +250,12 @@
mReceivedDisplayEvents.pop_front();
ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
- "event hotplug: id %d, connected %d\t", event.header.id,
- event.hotplug.connected);
+ "event hotplug: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+ ", connected %d\t",
+ event.header.displayId, event.hotplug.connected);
if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
- event.header.id == id && event.hotplug.connected == connected) {
+ event.header.displayId == displayId && event.hotplug.connected == connected) {
return true;
}
}
@@ -294,13 +295,14 @@
waitForDisplayTransaction();
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
{
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
ASSERT_EQ(400u, info.w);
ASSERT_EQ(200u, info.h);
@@ -328,14 +330,15 @@
waitForDisplayTransaction();
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, false));
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
{
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
ASSERT_EQ(400u, info.w);
ASSERT_EQ(200u, info.h);
@@ -364,11 +367,12 @@
waitForDisplayTransaction();
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, false));
+ EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
{
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+ EXPECT_FALSE(display == nullptr);
+
DisplayInfo info;
auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
EXPECT_NE(NO_ERROR, result);
@@ -402,11 +406,12 @@
waitForDisplayTransaction();
- EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, true));
+ EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
{
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+ EXPECT_FALSE(display == nullptr);
+
DisplayInfo info;
auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
EXPECT_EQ(NO_ERROR, result);
@@ -473,10 +478,11 @@
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
ALOGI("TransactionTest::SetUp - display");
- sp<android::IBinder> display(
- SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+ ASSERT_FALSE(display == nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
mDisplayWidth = info.w;
mDisplayHeight = info.h;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index b2bcb45..b1d45f39 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -58,6 +58,7 @@
"mock/MockMessageQueue.cpp",
"mock/MockNativeWindowSurface.cpp",
"mock/MockSurfaceInterceptor.cpp",
+ "mock/MockTimeStats.cpp",
"mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h b/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
index 2245ee1..8bed766 100644
--- a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
+++ b/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
@@ -75,14 +75,16 @@
template <typename... Args>
class AsyncCallRecorder<void (*)(Args...)> {
public:
- // For the tests, we expect the wait for an expected change to be signaled
- // to be much shorter than this.
- static constexpr std::chrono::milliseconds DEFAULT_CALL_EXPECTED_TIMEOUT{10};
+ // This wait value needs to be large enough to avoid flakes caused by delays
+ // scheduling threads, but small enough that tests don't take forever if
+ // something really is wrong. Based on some empirical evidence, 100ms should
+ // be enough to avoid the former.
+ static constexpr std::chrono::milliseconds DEFAULT_CALL_EXPECTED_TIMEOUT{100};
- // The wait here is tricky. We don't expect a change, but we don't want to
- // wait forever (or for longer than the typical test function runtime). As
- // even the simplest Google Test can take 1ms (1000us) to run, we wait for
- // half that time.
+ // The wait here is tricky. It's for when We don't expect to record a call,
+ // but we don't want to wait forever (or for longer than the typical test
+ // function runtime). As even the simplest Google Test can take 1ms (1000us)
+ // to run, we wait for half that time.
static constexpr std::chrono::microseconds UNEXPECTED_CALL_TIMEOUT{500};
using ArgTuple = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 1c4a661..ee79c18 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -97,6 +97,7 @@
EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
EXPECT_CALL(*mPrimaryDispSync, getPeriod())
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
@@ -239,16 +240,23 @@
static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
static void setupPreconditions(CompositionTest* test) {
- EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
- EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ Return(Error::NONE)));
FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, HWC2::DisplayType::Physical,
true /* isPrimary */)
.setCapabilities(&test->mDefaultCapabilities)
.inject(&test->mFlinger, test->mComposer);
+ Mock::VerifyAndClear(test->mComposer);
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
false /* isVirtual */, true /* isPrimary */)
.setDisplaySurface(test->mDisplaySurface)
@@ -256,6 +264,7 @@
.setSecure(Derived::IS_SECURE)
.setPowerMode(Derived::INIT_POWER_MODE)
.inject();
+ Mock::VerifyAndClear(test->mNativeWindow);
test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
}
@@ -372,6 +381,8 @@
template <typename Case>
static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+
// TODO: This seems like an unnecessary call if display is powered off.
EXPECT_CALL(*test->mComposer,
setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
@@ -384,6 +395,8 @@
static void setupHwcCompositionCallExpectations(CompositionTest*) {}
static void setupRECompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+
// TODO: This seems like an unnecessary call if display is powered off.
EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
.WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
@@ -541,7 +554,6 @@
setLayerColor(HWC_DISPLAY, HWC_LAYER,
IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
.Times(1);
-
}
static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 4cb79ab..6659d4a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -45,9 +45,9 @@
namespace {
using testing::_;
-using testing::ByMove;
using testing::DoAll;
using testing::Mock;
+using testing::ResultOf;
using testing::Return;
using testing::SetArgPointee;
@@ -321,11 +321,6 @@
// Whether the display is primary
static constexpr Primary PRIMARY = primary;
- static constexpr auto displayType() {
- return static_cast<bool>(PRIMARY) ? EventThread::DisplayType::Primary
- : EventThread::DisplayType::External;
- }
-
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto injector =
FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
@@ -335,11 +330,17 @@
injector.setNativeWindow(test->mNativeWindow);
// Creating a DisplayDevice requires getting default dimensions from the
- // native window.
+ // native window along with some other initial setup.
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
+ .WillRepeatedly(Return(0));
return injector;
}
@@ -352,6 +353,12 @@
.WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
+ .WillRepeatedly(Return(0));
}
static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
@@ -389,7 +396,7 @@
}
// Called by tests to inject a HWC display setup
- static void injectHwcDisplay(DisplayTransactionTest* test) {
+ static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) {
const auto displayId = DisplayVariant::DISPLAY_ID::get();
ASSERT_TRUE(displayId);
FakeHwcDisplayInjector(*displayId, HWC_DISPLAY_TYPE,
@@ -401,6 +408,14 @@
.inject(&test->mFlinger, test->mComposer);
}
+ // Called by tests to inject a HWC display setup
+ static void injectHwcDisplay(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ Return(Error::NONE)));
+ injectHwcDisplayWithNoDefaultCapabilities(test);
+ }
+
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getDisplayType(HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(static_cast<IComposerClient::DisplayType>(
@@ -430,6 +445,9 @@
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::DPI_Y, _))
.WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ Return(Error::NONE)));
if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
@@ -482,6 +500,8 @@
struct TertiaryDisplay {
static constexpr Primary PRIMARY = Primary::FALSE;
+ static constexpr uint8_t PORT = 253;
+ static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
};
// A primary display is a physical display that is critical
@@ -577,6 +597,8 @@
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_DATASPACE)).Times(1);
+
EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})),
Return(Error::NONE)));
@@ -1156,9 +1178,9 @@
.WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0)));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0)));
- EXPECT_CALL(*mNativeWindow, perform(9)).Times(1);
- EXPECT_CALL(*mNativeWindow, perform(13)).Times(1);
- EXPECT_CALL(*mNativeWindow, perform(30)).Times(1);
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
auto displayDevice = mInjector.inject();
displayDevice->getCompositionDisplay()
@@ -1470,6 +1492,9 @@
template <typename Case>
void setupCommonPreconditions();
+ template <typename Case, bool connected>
+ static void expectHotplugReceived(mock::EventThread*);
+
template <typename Case>
void setupCommonCallExpectationsForConnectProcessing();
@@ -1507,6 +1532,17 @@
injectFakeNativeWindowSurfaceFactory();
}
+template <typename Case, bool connected>
+void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
+ const auto convert = [](auto physicalDisplayId) {
+ return std::make_optional(DisplayId{physicalDisplayId});
+ };
+
+ EXPECT_CALL(*eventThread,
+ onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected))
+ .Times(1);
+}
+
template <typename Case>
void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
Case::Display::setupHwcHotplugCallExpectations(this);
@@ -1522,16 +1558,16 @@
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
- EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
- EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
+ expectHotplugReceived<Case, true>(mEventThread);
+ expectHotplugReceived<Case, true>(mSFEventThread);
}
template <typename Case>
void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
- EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
- EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
+ expectHotplugReceived<Case, false>(mEventThread);
+ expectHotplugReceived<Case, false>(mSFEventThread);
}
template <typename Case>
@@ -1705,6 +1741,13 @@
PrimaryDisplayVariant::injectHwcDisplay(this);
ExternalDisplayVariant::injectHwcDisplay(this);
+ // TODO: This is an unnecessary call.
+ EXPECT_CALL(*mComposer,
+ getDisplayIdentificationData(TertiaryDisplayVariant::HWC_DISPLAY_ID, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(TertiaryDisplay::PORT),
+ SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()),
+ Return(Error::NONE)));
+
EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
@@ -1852,6 +1895,10 @@
Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+ EXPECT_CALL(*mComposer, getDisplayCapabilities(Case::Display::HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ Return(Error::NONE)));
+
EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR)));
EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _))
@@ -1864,6 +1911,7 @@
EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
+ EXPECT_CALL(*mProducer, connect(_, NATIVE_WINDOW_API_EGL, false, _)).Times(1);
EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
@@ -2096,9 +2144,9 @@
.WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
- EXPECT_CALL(*nativeWindow, perform(9)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(30)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
display.inject();
// There is a change to the viewport state
@@ -2140,9 +2188,9 @@
.WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
- EXPECT_CALL(*nativeWindow, perform(9)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(30)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
display.inject();
// There is a change to the viewport state
@@ -2656,6 +2704,8 @@
// processing.
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+
// --------------------------------------------------------------------
// Invocation
@@ -2950,7 +3000,7 @@
using Transition = TransitionVariant;
static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, int mode) {
- Display::injectHwcDisplay(test);
+ Display::injectHwcDisplayWithNoDefaultCapabilities(test);
auto display = Display::makeFakeExistingDisplayInjector(test);
display.inject();
display.mutableDisplayDevice()->setPowerMode(mode);
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index dd90063..3a7cfba 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -36,6 +36,9 @@
namespace android {
namespace {
+constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111;
+constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID = 222;
+
class MockVSyncSource : public VSyncSource {
public:
MOCK_METHOD1(setVSyncEnabled, void(bool));
@@ -50,8 +53,10 @@
class MockEventThreadConnection : public EventThreadConnection {
public:
MockEventThreadConnection(android::impl::EventThread* eventThread,
- ResyncCallback&& resyncCallback)
- : EventThreadConnection(eventThread, std::move(resyncCallback)) {}
+ ResyncCallback&& resyncCallback,
+ ResetIdleTimerCallback&& resetIdleTimerCallback)
+ : EventThreadConnection(eventThread, std::move(resyncCallback),
+ std::move(resetIdleTimerCallback)) {}
MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
};
@@ -72,13 +77,14 @@
ConnectionEventRecorder& connectionEventRecorder,
nsecs_t expectedTimestamp, unsigned expectedCount);
void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
- void expectHotplugEventReceivedByConnection(EventThread::DisplayType expectedDisplayType,
+ void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
AsyncCallRecorder<void (*)(nsecs_t)> mVSyncSetPhaseOffsetCallRecorder;
AsyncCallRecorder<void (*)()> mResyncCallRecorder;
+ AsyncCallRecorder<void (*)()> mResetIdleTimerCallRecorder;
AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
ConnectionEventRecorder mConnectionEventCallRecorder{0};
@@ -106,8 +112,8 @@
mConnection = createConnection(mConnectionEventCallRecorder);
// A display must be connected for VSYNC events to be delivered.
- mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
+ mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
+ expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, true);
}
EventThreadTest::~EventThreadTest() {
@@ -116,7 +122,7 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
// EventThread should unregister itself as VSyncSource callback.
- EXPECT_FALSE(expectVSyncSetCallbackCallReceived());
+ EXPECT_TRUE(!mVSyncSetCallbackCallRecorder.waitForUnexpectedCall().has_value());
}
void EventThreadTest::createThread() {
@@ -133,7 +139,8 @@
sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
ConnectionEventRecorder& recorder) {
sp<MockEventThreadConnection> connection =
- new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable());
+ new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable(),
+ mResetIdleTimerCallRecorder.getInvocable());
EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
return connection;
}
@@ -183,16 +190,13 @@
expectedCount);
}
-void EventThreadTest::expectHotplugEventReceivedByConnection(
- EventThread::DisplayType expectedDisplayType, bool expectedConnected) {
- const uint32_t expectedDisplayId =
- expectedDisplayType == EventThread::DisplayType::Primary ? 0 : 1;
-
+void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
+ bool expectedConnected) {
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
- EXPECT_EQ(expectedDisplayId, event.header.id);
+ EXPECT_EQ(expectedDisplayId, event.header.displayId);
EXPECT_EQ(expectedConnected, event.hotplug.connected);
}
@@ -207,13 +211,14 @@
EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mVSyncSetPhaseOffsetCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mResyncCallRecorder.waitForCall(0us).has_value());
+ EXPECT_FALSE(mResetIdleTimerCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
}
TEST_F(EventThreadTest, vsyncRequestIsIgnoredIfDisplayIsDisconnected) {
- mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
+ mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false);
+ expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false);
// Signal that we want the next vsync event to be posted to the connection.
mThread->requestNextVsync(mConnection, false);
@@ -224,9 +229,10 @@
TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
// Signal that we want the next vsync event to be posted to the connection
- mThread->requestNextVsync(mConnection, false);
+ mThread->requestNextVsync(mConnection, true);
- // EventThread should immediately request a resync.
+ // EventThread should immediately reset the idle timer and request a resync.
+ EXPECT_TRUE(mResetIdleTimerCallRecorder.waitForCall().has_value());
EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
// EventThread should enable vsync callbacks.
@@ -400,24 +406,24 @@
expectVSyncSetPhaseOffsetCallReceived(321);
}
-TEST_F(EventThreadTest, postHotplugPrimaryDisconnect) {
- mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
+TEST_F(EventThreadTest, postHotplugInternalDisconnect) {
+ mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false);
+ expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false);
}
-TEST_F(EventThreadTest, postHotplugPrimaryConnect) {
- mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
+TEST_F(EventThreadTest, postHotplugInternalConnect) {
+ mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
+ expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, true);
}
TEST_F(EventThreadTest, postHotplugExternalDisconnect) {
- mThread->onHotplugReceived(EventThread::DisplayType::External, false);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, false);
+ mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, false);
+ expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, false);
}
TEST_F(EventThreadTest, postHotplugExternalConnect) {
- mThread->onHotplugReceived(EventThread::DisplayType::External, true);
- expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, true);
+ mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, true);
+ expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, true);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
index 9fe9a18..dc63260 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
@@ -34,91 +34,117 @@
IdleTimerTest() = default;
~IdleTimerTest() 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 (*)()> mExpiredTimerCallback;
std::unique_ptr<IdleTimer> mIdleTimer;
+
+ void clearPendingCallbacks() {
+ while (mExpiredTimerCallback.waitForCall(0us).has_value()) {
+ }
+ }
};
namespace {
TEST_F(IdleTimerTest, createAndDestroyTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, [] {});
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {});
}
TEST_F(IdleTimerTest, startStopTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mExpiredTimerCallback.getInvocable());
+ auto startTime = std::chrono::steady_clock::now();
mIdleTimer->start();
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- // The timer expires after 30 ms, so the call to the callback should not happen.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall().has_value());
+ // The idle timer fires after 30ms, so there should be no callback within
+ // 25ms (waiting for a ballback 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 IdleTimer
+ // thread was started as a sanity check to not have a flakey test.
+ EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms);
mIdleTimer->stop();
}
TEST_F(IdleTimerTest, resetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mExpiredTimerCallback.getInvocable());
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- // The timer expires after 30 ms, so the call to the callback should not happen.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).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();
mIdleTimer->reset();
- // The timer was reset, so the call to the callback should not happen.
- std::this_thread::sleep_for(std::chrono::milliseconds(15));
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).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());
}
TEST_F(IdleTimerTest, startNotCalledTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
- std::this_thread::sleep_for(6ms);
// The start hasn't happened, so the callback does not happen.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
mIdleTimer->stop();
+ // Final quick check that no more callback were observed.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
}
TEST_F(IdleTimerTest, idleTimerIdlesTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(6ms);
- // The timer expires after 3 ms, so the call to the callback happens.
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
- std::this_thread::sleep_for(6ms);
- // Timer can be idle.
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
- // Timer can be reset.
+ // A callback should be generated after 3ms
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
+ // After one event, it should be idle, and not generate another.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+ // Once reset, it should generate another
mIdleTimer->reset();
- std::this_thread::sleep_for(6ms);
- // Timer fires again.
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
+ // Final quick check that no more callback were observed.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
}
TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(6ms);
- // The timer expires after 3 ms, so the call to the callback should happen.
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
}
TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(6ms);
- EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
+ clearPendingCallbacks();
mIdleTimer->reset();
- std::this_thread::sleep_for(6ms);
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
}
TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- std::this_thread::sleep_for(1ms);
mIdleTimer->stop();
- std::this_thread::sleep_for(3ms);
- EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+ clearPendingCallbacks();
+ mIdleTimer->reset();
+ // No more idle events should be observed
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 0384d9d..3d887ea 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -23,8 +23,10 @@
#include "Scheduler/RefreshRateStats.h"
#include "mock/DisplayHardware/MockDisplay.h"
+#include "mock/MockTimeStats.h"
using namespace std::chrono_literals;
+using testing::_;
namespace android {
namespace scheduler {
@@ -42,6 +44,7 @@
void init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs);
std::unique_ptr<RefreshRateStats> mRefreshRateStats;
+ std::shared_ptr<android::mock::TimeStats> mTimeStats;
};
RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -57,7 +60,8 @@
}
void RefreshRateStatsTest::init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs) {
- mRefreshRateStats = std::make_unique<RefreshRateStats>(configs);
+ mTimeStats = std::make_shared<android::mock::TimeStats>();
+ mRefreshRateStats = std::make_unique<RefreshRateStats>(configs, mTimeStats);
}
namespace {
@@ -82,6 +86,9 @@
init(configs);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(4);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(2);
+
std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
ASSERT_EQ(2, times.size());
ASSERT_EQ(0, times["ScreenOff"]);
@@ -136,6 +143,10 @@
init(configs);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(6);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(4);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(4);
+
std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
ASSERT_EQ(3, times.size());
ASSERT_EQ(0, times["ScreenOff"]);
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 4d9aec6..26b6d0c 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -18,12 +18,14 @@
namespace android {
+constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = 999;
+
class SchedulerTest : public testing::Test {
protected:
class MockEventThreadConnection : public android::EventThreadConnection {
public:
explicit MockEventThreadConnection(EventThread* eventThread)
- : EventThreadConnection(eventThread, ResyncCallback()) {}
+ : EventThreadConnection(eventThread, ResyncCallback(), ResetIdleTimerCallback()) {}
~MockEventThreadConnection() = default;
MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
@@ -76,10 +78,11 @@
// createConnection call to scheduler makes a createEventConnection call to EventThread. Make
// sure that call gets executed and returns an EventThread::Connection object.
- EXPECT_CALL(*mEventThread, createEventConnection(_))
+ EXPECT_CALL(*mEventThread, createEventConnection(_, _))
.WillRepeatedly(Return(mEventThreadConnection));
mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
+ ResetIdleTimerCallback(),
impl::EventThread::InterceptVSyncsCallback());
EXPECT_TRUE(mConnectionHandle != nullptr);
}
@@ -100,12 +103,12 @@
// exceptions, just gracefully continues.
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
- returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback()));
+ returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(),
+ ResetIdleTimerCallback()));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
- ASSERT_NO_FATAL_FAILURE(
- mScheduler->hotplugReceived(nullptr, EventThread::DisplayType::Primary, false));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(nullptr, PHYSICAL_DISPLAY_ID, false));
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr));
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr));
std::string testString;
@@ -122,15 +125,16 @@
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback()));
+ mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(),
+ ResetIdleTimerCallback()));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
// The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads.
EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(connectionHandle,
- EventThread::DisplayType::Primary, false));
+ ASSERT_NO_FATAL_FAILURE(
+ mScheduler->hotplugReceived(connectionHandle, PHYSICAL_DISPLAY_ID, false));
EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle));
@@ -151,17 +155,17 @@
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback()));
+ mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(),
+ ResetIdleTimerCallback()));
EXPECT_TRUE(returnedValue != nullptr);
ASSERT_EQ(returnedValue, mEventThreadConnection);
EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr);
- EXPECT_CALL(*mEventThread, onHotplugReceived(EventThread::DisplayType::Primary, false))
- .Times(1);
- ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(mConnectionHandle,
- EventThread::DisplayType::Primary, false));
+ EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1);
+ ASSERT_NO_FATAL_FAILURE(
+ mScheduler->hotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false));
EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle));
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 3a62c40..e639b4d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -144,9 +144,9 @@
return nullptr;
}
- std::unique_ptr<TimeStats> createTimeStats() override {
+ std::shared_ptr<TimeStats> createTimeStats() override {
// TODO: Use test-fixture controlled factory
- return std::make_unique<TimeStats>();
+ return std::make_shared<android::impl::TimeStats>();
}
using CreateBufferQueueFunction =
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 0f95cf9..f35758d 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -24,6 +25,7 @@
#include <utils/Vector.h>
#include <random>
+#include <unordered_set>
#include "TimeStats/TimeStats.h"
@@ -35,6 +37,10 @@
namespace android {
namespace {
+using testing::Contains;
+using testing::SizeIs;
+using testing::UnorderedElementsAre;
+
// clang-format off
#define FMT_PROTO true
#define FMT_STRING false
@@ -127,7 +133,7 @@
}
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
- std::unique_ptr<TimeStats> mTimeStats = std::make_unique<TimeStats>();
+ std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -371,6 +377,63 @@
}
}
+TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ uint32_t fpsOne = 30;
+ uint32_t fpsTwo = 90;
+ uint64_t millisOne = 5000;
+ uint64_t millisTwo = 7000;
+
+ mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
+ mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
+ SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
+ expectedConfigOne->set_fps(fpsOne);
+ expectedBucketOne.set_duration_millis(millisOne);
+
+ SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
+ SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
+ expectedConfigTwo->set_fps(fpsTwo);
+ expectedBucketTwo.set_duration_millis(millisTwo);
+
+ EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
+
+ std::unordered_set<uint32_t> seen_fps;
+ for (const auto& bucket : globalProto.display_config_stats()) {
+ seen_fps.emplace(bucket.config().fps());
+ if (fpsOne == bucket.config().fps()) {
+ EXPECT_EQ(millisOne, bucket.duration_millis());
+ } else if (fpsTwo == bucket.config().fps()) {
+ EXPECT_EQ(millisTwo, bucket.duration_millis());
+ } else {
+ FAIL() << "Unknown fps: " << bucket.config().fps();
+ }
+ }
+ EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
+}
+
+TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ uint32_t fps = 30;
+ uint64_t millisOne = 5000;
+ uint64_t millisTwo = 7000;
+
+ mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
+ mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+ EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
+ EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
+ EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
+}
+
TEST_F(TimeStatsTest, canRemoveTimeRecord) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -394,7 +457,7 @@
uint64_t frameNumber = 1;
nsecs_t ts = 1000000;
insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
- for (size_t i = 0; i < TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
+ for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
frameNumber++;
ts += 1000000;
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);
diff --git a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
index bc1f00d..ed628b8 100644
--- a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
+++ b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
@@ -16,6 +16,11 @@
#include <gtest/gtest.h>
+#include <sched.h>
+
+#include <processgroup/sched_policy.h>
+#include <system/graphics.h>
+
#include "libsurfaceflinger_unittest_main.h"
// ------------------------------------------------------------------------
@@ -39,6 +44,12 @@
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
+ // The SurfaceFlinger implementation assumes that threads resume
+ // execution as quickly as possible once they become unblocked.
+ // (These same calls are made in main_surfaceflinger.cpp)
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+ set_sched_policy(0, SP_FOREGROUND);
+
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--no-slow") == 0) {
g_noSlowTests = true;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 3242ef1..589237d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,10 +28,11 @@
EventThread();
~EventThread() override;
- MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback));
+ MOCK_CONST_METHOD2(createEventConnection,
+ sp<EventThreadConnection>(ResyncCallback, ResetIdleTimerCallback));
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
- MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
+ MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
MOCK_METHOD1(registerDisplayEventConnection,
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp
new file mode 100644
index 0000000..d686939
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mock/MockTimeStats.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+TimeStats::TimeStats() = default;
+TimeStats::~TimeStats() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
new file mode 100644
index 0000000..08fdb9d
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "TimeStats/TimeStats.h"
+
+namespace android {
+namespace mock {
+
+class TimeStats : public android::TimeStats {
+public:
+ TimeStats();
+ ~TimeStats() override;
+
+ MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
+ MOCK_METHOD0(isEnabled, bool());
+ MOCK_METHOD0(incrementTotalFrames, void());
+ MOCK_METHOD0(incrementMissedFrames, void());
+ MOCK_METHOD0(incrementClientCompositionFrames, void());
+ MOCK_METHOD4(setPostTime, void(int32_t, uint64_t, const std::string&, nsecs_t));
+ MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t));
+ MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t));
+ MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t));
+ MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD3(setPresentTime, void(int32_t, uint64_t, nsecs_t));
+ MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD1(onDestroy, void(int32_t));
+ MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
+ MOCK_METHOD1(setPowerMode, void(int32_t));
+ MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
+ MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 673a066..71048db 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -21,6 +21,8 @@
// There are a few of them requiring manual code for things such as layer
// discovery or chaining. They call into functions defined in this file.
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <stdlib.h>
#include <string.h>
@@ -32,6 +34,7 @@
#include <android-base/strings.h>
#include <cutils/properties.h>
#include <log/log.h>
+#include <utils/Trace.h>
#include <vulkan/vk_layer_interface.h>
#include <graphicsenv/GraphicsEnv.h>
@@ -1176,6 +1179,8 @@
VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance) {
+ ATRACE_CALL();
+
if (!EnsureInitialized())
return VK_ERROR_INITIALIZATION_FAILED;
@@ -1184,6 +1189,8 @@
void DestroyInstance(VkInstance instance,
const VkAllocationCallbacks* pAllocator) {
+ ATRACE_CALL();
+
if (instance != VK_NULL_HANDLE)
LayerChain::DestroyInstance(instance, pAllocator);
}
@@ -1192,17 +1199,23 @@
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice) {
+ ATRACE_CALL();
+
return LayerChain::CreateDevice(physicalDevice, pCreateInfo, pAllocator,
pDevice);
}
void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
+ ATRACE_CALL();
+
if (device != VK_NULL_HANDLE)
LayerChain::DestroyDevice(device, pAllocator);
}
VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount,
VkLayerProperties* pProperties) {
+ ATRACE_CALL();
+
if (!EnsureInitialized())
return VK_ERROR_INITIALIZATION_FAILED;
@@ -1225,6 +1238,8 @@
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
+ ATRACE_CALL();
+
if (!EnsureInitialized())
return VK_ERROR_INITIALIZATION_FAILED;
@@ -1253,6 +1268,8 @@
VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
uint32_t* pPropertyCount,
VkLayerProperties* pProperties) {
+ ATRACE_CALL();
+
uint32_t count;
const LayerChain::ActiveLayer* layers =
LayerChain::GetActiveLayers(physicalDevice, count);
@@ -1275,6 +1292,8 @@
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
+ ATRACE_CALL();
+
if (pLayerName) {
// EnumerateDeviceLayerProperties enumerates active layers for
// backward compatibility. The extension query here should work for
@@ -1302,6 +1321,8 @@
}
VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) {
+ ATRACE_CALL();
+
*pApiVersion = VK_API_VERSION_1_1;
return VK_SUCCESS;
}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a607a5d..421f727 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
@@ -31,6 +33,7 @@
#include <configstore/Utils.h>
#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
+#include <utils/Trace.h>
#include <utils/Vector.h>
#include "android-base/properties.h"
@@ -150,6 +153,8 @@
void* LoadLibrary(const android_dlextinfo& dlextinfo,
const char* subname,
int subname_len) {
+ ATRACE_CALL();
+
const char kLibFormat[] = "vulkan.%*s.so";
char* name = static_cast<char*>(
alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len)));
@@ -164,6 +169,8 @@
int LoadDriver(android_namespace_t* library_namespace,
const hwvulkan_module_t** module) {
+ ATRACE_CALL();
+
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = library_namespace,
@@ -198,6 +205,8 @@
}
int LoadBuiltinDriver(const hwvulkan_module_t** module) {
+ ATRACE_CALL();
+
auto ns = android_get_exported_namespace("sphal");
if (!ns)
return -ENOENT;
@@ -205,6 +214,8 @@
}
int LoadUpdatedDriver(const hwvulkan_module_t** module) {
+ ATRACE_CALL();
+
auto ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (!ns)
return -ENOENT;
@@ -212,6 +223,8 @@
}
bool Hal::Open() {
+ ATRACE_CALL();
+
ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once");
// Use a stub device unless we successfully open a real HAL device.
@@ -242,9 +255,11 @@
}
hwvulkan_device_t* device;
+ ATRACE_BEGIN("hwvulkan module open");
result =
module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
reinterpret_cast<hw_device_t**>(&device));
+ ATRACE_END();
if (result != 0) {
// Any device with a Vulkan HAL should be able to open the device.
ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result),
@@ -260,6 +275,8 @@
}
bool Hal::InitDebugReportIndex() {
+ ATRACE_CALL();
+
uint32_t count;
if (dev_->EnumerateInstanceExtensionProperties(nullptr, &count, nullptr) !=
VK_SUCCESS) {
@@ -821,8 +838,10 @@
}
}
+ ATRACE_BEGIN("driver.EnumerateInstanceExtensionProperties");
VkResult result = Hal::Device().EnumerateInstanceExtensionProperties(
pLayerName, pPropertyCount, pProperties);
+ ATRACE_END();
if (!pLayerName && (result == VK_SUCCESS || result == VK_INCOMPLETE)) {
int idx = Hal::Get().GetDebugReportIndex();
@@ -931,8 +950,10 @@
*pPropertyCount -= count;
}
+ ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
VkResult result = data.driver.EnumerateDeviceExtensionProperties(
physicalDevice, pLayerName, pPropertyCount, pProperties);
+ ATRACE_END();
if (pProperties) {
// map VK_ANDROID_native_buffer to VK_KHR_swapchain
@@ -968,12 +989,15 @@
if (result != VK_SUCCESS)
return result;
+ ATRACE_BEGIN("AllocateInstanceData");
InstanceData* data = AllocateInstanceData(data_allocator);
+ ATRACE_END();
if (!data)
return VK_ERROR_OUT_OF_HOST_MEMORY;
data->hook_extensions |= wrapper.GetHookExtensions();
+ ATRACE_BEGIN("autoDowngradeApiVersion");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
uint32_t api_version = ((pCreateInfo->pApplicationInfo)
@@ -989,7 +1013,9 @@
if (!pfn_enumerate_instance_version) {
icd_api_version = VK_API_VERSION_1_0;
} else {
+ ATRACE_BEGIN("pfn_enumerate_instance_version");
result = (*pfn_enumerate_instance_version)(&icd_api_version);
+ ATRACE_END();
}
uint32_t icd_api_major_version = VK_VERSION_MAJOR(icd_api_version);
uint32_t icd_api_minor_version = VK_VERSION_MINOR(icd_api_version);
@@ -1000,12 +1026,15 @@
wrapper.DowngradeApiVersion();
}
#pragma clang diagnostic pop
+ ATRACE_END();
// call into the driver
VkInstance instance;
+ ATRACE_BEGIN("driver.CreateInstance");
result = Hal::Device().CreateInstance(
static_cast<const VkInstanceCreateInfo*>(wrapper), pAllocator,
&instance);
+ ATRACE_END();
if (result != VK_SUCCESS) {
FreeInstanceData(data, data_allocator);
return result;
@@ -1066,8 +1095,10 @@
if (result != VK_SUCCESS)
return result;
+ ATRACE_BEGIN("AllocateDeviceData");
DeviceData* data = AllocateDeviceData(data_allocator,
instance_data.debug_report_callbacks);
+ ATRACE_END();
if (!data)
return VK_ERROR_OUT_OF_HOST_MEMORY;
@@ -1075,9 +1106,11 @@
// call into the driver
VkDevice dev;
+ ATRACE_BEGIN("driver.CreateDevice");
result = instance_data.driver.CreateDevice(
physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
pAllocator, &dev);
+ ATRACE_END();
if (result != VK_SUCCESS) {
FreeDeviceData(data, data_allocator);
return result;
@@ -1114,8 +1147,10 @@
}
VkPhysicalDeviceProperties properties;
+ ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
&properties);
+ ATRACE_END();
data->driver_device = dev;
data->driver_version = properties.driverVersion;
@@ -1141,6 +1176,8 @@
VkResult EnumeratePhysicalDevices(VkInstance instance,
uint32_t* pPhysicalDeviceCount,
VkPhysicalDevice* pPhysicalDevices) {
+ ATRACE_CALL();
+
const auto& data = GetData(instance);
VkResult result = data.driver.EnumeratePhysicalDevices(
@@ -1157,6 +1194,8 @@
VkInstance instance,
uint32_t* pPhysicalDeviceGroupCount,
VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ ATRACE_CALL();
+
VkResult result = VK_SUCCESS;
const auto& data = GetData(instance);
@@ -1217,6 +1256,8 @@
uint32_t queueFamilyIndex,
uint32_t queueIndex,
VkQueue* pQueue) {
+ ATRACE_CALL();
+
const auto& data = GetData(device);
data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
@@ -1226,6 +1267,8 @@
void GetDeviceQueue2(VkDevice device,
const VkDeviceQueueInfo2* pQueueInfo,
VkQueue* pQueue) {
+ ATRACE_CALL();
+
const auto& data = GetData(device);
data.driver.GetDeviceQueue2(device, pQueueInfo, pQueue);
@@ -1236,6 +1279,8 @@
AllocateCommandBuffers(VkDevice device,
const VkCommandBufferAllocateInfo* pAllocateInfo,
VkCommandBuffer* pCommandBuffers) {
+ ATRACE_CALL();
+
const auto& data = GetData(device);
VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo,
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index ba4cf00..af1adcf 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "layers_extensions.h"
#include <alloca.h>
@@ -33,6 +35,7 @@
#include <log/log.h>
#include <nativebridge/native_bridge.h>
#include <nativeloader/native_loader.h>
+#include <utils/Trace.h>
#include <ziparchive/zip_archive.h>
// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
@@ -428,6 +431,8 @@
}
void DiscoverLayersInPathList(const std::string& pathstr) {
+ ATRACE_CALL();
+
std::vector<std::string> paths = android::base::Split(pathstr, ":");
for (const auto& path : paths) {
ForEachFileInPath(path, [&](const std::string& filename) {
@@ -477,6 +482,8 @@
} // anonymous namespace
void DiscoverLayers() {
+ ATRACE_CALL();
+
if (property_get_bool("ro.debuggable", false) &&
prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
DiscoverLayersInPathList(kSystemLayerLibraryDir);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 8601373..32e19f7 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <algorithm>
#include <grallocusage/GrallocUsageConversion.h>
@@ -21,6 +23,7 @@
#include <ui/BufferQueueDefs.h>
#include <sync/sync.h>
#include <utils/StrongPointer.h>
+#include <utils/Trace.h>
#include <utils/Vector.h>
#include <system/window.h>
#include <android/hardware/graphics/common/1.0/types.h>
@@ -416,7 +419,7 @@
case VK_FORMAT_R16G16B16A16_SFLOAT:
native_format = HAL_PIXEL_FORMAT_RGBA_FP16;
break;
- case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+ case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
native_format = HAL_PIXEL_FORMAT_RGBA_1010102;
break;
default:
@@ -486,6 +489,8 @@
const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* out_surface) {
+ ATRACE_CALL();
+
if (!allocator)
allocator = &GetData(instance).allocator;
void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
@@ -528,6 +533,8 @@
void DestroySurfaceKHR(VkInstance instance,
VkSurfaceKHR surface_handle,
const VkAllocationCallbacks* allocator) {
+ ATRACE_CALL();
+
Surface* surface = SurfaceFromHandle(surface_handle);
if (!surface)
return;
@@ -548,6 +555,8 @@
uint32_t /*queue_family*/,
VkSurfaceKHR surface_handle,
VkBool32* supported) {
+ ATRACE_CALL();
+
const Surface* surface = SurfaceFromHandle(surface_handle);
if (!surface) {
return VK_ERROR_SURFACE_LOST_KHR;
@@ -570,6 +579,7 @@
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
format_supported = true;
break;
default:
@@ -589,6 +599,8 @@
VkPhysicalDevice /*pdev*/,
VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR* capabilities) {
+ ATRACE_CALL();
+
int err;
ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
@@ -662,6 +674,8 @@
VkSurfaceKHR surface_handle,
uint32_t* count,
VkSurfaceFormatKHR* formats) {
+ ATRACE_CALL();
+
const InstanceData& instance_data = GetData(pdev);
// TODO(jessehall): Fill out the set of supported formats. Longer term, add
@@ -700,6 +714,8 @@
VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
{VK_FORMAT_R16G16B16A16_SFLOAT,
VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
+ {VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
};
const uint32_t kNumWideColorFormats =
sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]);
@@ -734,6 +750,8 @@
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
VkSurfaceCapabilities2KHR* pSurfaceCapabilities) {
+ ATRACE_CALL();
+
VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR(
physicalDevice, pSurfaceInfo->surface,
&pSurfaceCapabilities->surfaceCapabilities);
@@ -769,6 +787,8 @@
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
uint32_t* pSurfaceFormatCount,
VkSurfaceFormat2KHR* pSurfaceFormats) {
+ ATRACE_CALL();
+
if (!pSurfaceFormats) {
return GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,
pSurfaceInfo->surface,
@@ -800,6 +820,8 @@
VkSurfaceKHR surface,
uint32_t* count,
VkPresentModeKHR* modes) {
+ ATRACE_CALL();
+
int err;
int query_value;
ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
@@ -851,6 +873,8 @@
VkResult GetDeviceGroupPresentCapabilitiesKHR(
VkDevice,
VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+ ATRACE_CALL();
+
ALOGV_IF(pDeviceGroupPresentCapabilities->sType !=
VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR,
"vkGetDeviceGroupPresentCapabilitiesKHR: invalid "
@@ -873,6 +897,8 @@
VkDevice,
VkSurfaceKHR,
VkDeviceGroupPresentModeFlagsKHR* pModes) {
+ ATRACE_CALL();
+
*pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
return VK_SUCCESS;
}
@@ -882,6 +908,8 @@
VkSurfaceKHR surface,
uint32_t* pRectCount,
VkRect2D* pRects) {
+ ATRACE_CALL();
+
if (!pRects) {
*pRectCount = 1;
} else {
@@ -923,6 +951,8 @@
const VkSwapchainCreateInfoKHR* create_info,
const VkAllocationCallbacks* allocator,
VkSwapchainKHR* swapchain_handle) {
+ ATRACE_CALL();
+
int err;
VkResult result = VK_SUCCESS;
@@ -1147,9 +1177,11 @@
int32_t legacy_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;
+ ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsage2ANDROID");
result = dispatch.GetSwapchainGrallocUsage2ANDROID(
device, create_info->imageFormat, create_info->imageUsage,
swapchain_image_usage, &consumer_usage, &producer_usage);
+ ATRACE_END();
if (result != VK_SUCCESS) {
ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1157,9 +1189,11 @@
legacy_usage =
android_convertGralloc1To0Usage(producer_usage, consumer_usage);
} else if (dispatch.GetSwapchainGrallocUsageANDROID) {
+ ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsageANDROID");
result = dispatch.GetSwapchainGrallocUsageANDROID(
device, create_info->imageFormat, create_info->imageUsage,
&legacy_usage);
+ ATRACE_END();
if (result != VK_SUCCESS) {
ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1254,8 +1288,10 @@
&image_native_buffer.usage2.producer,
&image_native_buffer.usage2.consumer);
+ ATRACE_BEGIN("dispatch.CreateImage");
result =
dispatch.CreateImage(device, &image_create, nullptr, &img.image);
+ ATRACE_END();
if (result != VK_SUCCESS) {
ALOGD("vkCreateImage w/ native buffer failed: %u", result);
break;
@@ -1279,8 +1315,11 @@
}
}
if (result != VK_SUCCESS) {
- if (img.image)
+ if (img.image) {
+ ATRACE_BEGIN("dispatch.DestroyImage");
dispatch.DestroyImage(device, img.image, nullptr);
+ ATRACE_END();
+ }
}
}
@@ -1299,6 +1338,8 @@
void DestroySwapchainKHR(VkDevice device,
VkSwapchainKHR swapchain_handle,
const VkAllocationCallbacks* allocator) {
+ ATRACE_CALL();
+
const auto& dispatch = GetData(device).driver;
Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
if (!swapchain)
@@ -1324,6 +1365,8 @@
VkSwapchainKHR swapchain_handle,
uint32_t* count,
VkImage* images) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle,
"getting images for non-active swapchain 0x%" PRIx64
@@ -1352,6 +1395,8 @@
VkSemaphore semaphore,
VkFence vk_fence,
uint32_t* image_index) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
ANativeWindow* window = swapchain.surface.window.get();
VkResult result;
@@ -1432,6 +1477,8 @@
VkResult AcquireNextImage2KHR(VkDevice device,
const VkAcquireNextImageInfoKHR* pAcquireInfo,
uint32_t* pImageIndex) {
+ ATRACE_CALL();
+
// TODO: this should actually be the other way around and this function
// should handle any additional structures that get passed in
return AcquireNextImageKHR(device, pAcquireInfo->swapchain,
@@ -1461,6 +1508,8 @@
VKAPI_ATTR
VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
+ ATRACE_CALL();
+
ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
"vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
present_info->sType);
@@ -1672,6 +1721,8 @@
VkDevice,
VkSwapchainKHR swapchain_handle,
VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
VkResult result = VK_SUCCESS;
@@ -1687,6 +1738,8 @@
VkSwapchainKHR swapchain_handle,
uint32_t* count,
VkPastPresentationTimingGOOGLE* timings) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
ANativeWindow* window = swapchain.surface.window.get();
VkResult result = VK_SUCCESS;
@@ -1711,6 +1764,8 @@
VkResult GetSwapchainStatusKHR(
VkDevice,
VkSwapchainKHR swapchain_handle) {
+ ATRACE_CALL();
+
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
VkResult result = VK_SUCCESS;
@@ -1728,6 +1783,7 @@
uint32_t swapchainCount,
const VkSwapchainKHR* pSwapchains,
const VkHdrMetadataEXT* pHdrMetadataEXTs) {
+ ATRACE_CALL();
for (uint32_t idx = 0; idx < swapchainCount; idx++) {
Swapchain* swapchain = SwapchainFromHandle(pSwapchains[idx]);