Merge "SF: Fix feedback loop with refresh rate overlay" into tm-dev
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 1c3a4f2..32ffe14 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -63,6 +63,8 @@
chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_pause/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_work_period/enable
+ chmod 0666 /sys/kernel/tracing/events/power/gpu_work_period/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/suspend_resume/enable
chmod 0666 /sys/kernel/tracing/events/power/suspend_resume/enable
chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 4e12579..397d432 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -473,7 +473,8 @@
StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
sUsingProjectIdsFlag = access(using_project_ids.c_str(), F_OK) == 0;
});
- return sUsingProjectIdsFlag;
+ // return sUsingProjectIdsFlag;
+ return false;
}
static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
@@ -632,8 +633,9 @@
}
static binder::Status createAppDataDirs(const std::string& path, int32_t uid, int32_t gid,
- int32_t* previousUid, int32_t cacheGid,
- const std::string& seInfo, mode_t targetMode) {
+ int32_t previousUid, int32_t cacheGid,
+ const std::string& seInfo, mode_t targetMode,
+ long projectIdApp, long projectIdCache) {
struct stat st{};
bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
@@ -643,25 +645,17 @@
bool code_cache_exists = (access(code_cache_path.c_str(), F_OK) == 0);
if (parent_dir_exists) {
- if (*previousUid < 0) {
- // If previousAppId is -1 in CreateAppDataArgs, we will assume the current owner
- // of the directory as previousUid. This is required because it is not always possible
- // to chown app data during app upgrade (e.g. secondary users' CE storage not unlocked)
- *previousUid = st.st_uid;
- }
- if (*previousUid != uid) {
- if (!chown_app_dir(path, uid, *previousUid, cacheGid)) {
+ if (previousUid > 0 && previousUid != uid) {
+ if (!chown_app_dir(path, uid, previousUid, cacheGid)) {
return error("Failed to chown " + path);
}
}
}
// Prepare only the parent app directory
- long project_id_app = get_project_id(uid, PROJECT_ID_APP_START);
- long project_id_cache_app = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
- if (prepare_app_dir(path, targetMode, uid, gid, project_id_app) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, project_id_cache_app) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, project_id_cache_app)) {
+ if (prepare_app_dir(path, targetMode, uid, gid, projectIdApp) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, projectIdCache) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, projectIdCache)) {
return error("Failed to prepare " + path);
}
@@ -702,12 +696,9 @@
int32_t uid = multiuser_get_uid(userId, appId);
- // If previousAppId < 0, we will use the existing app data owner as previousAppUid
- // If previousAppId == 0, we use uid as previousUid (no data migration will happen)
- // if previousAppId > 0, an app is upgrading and changing its app ID
- int32_t previousUid = previousAppId > 0
- ? (int32_t) multiuser_get_uid(userId, previousAppId)
- : (previousAppId == 0 ? uid : -1);
+ // If previousAppId > 0, an app is changing its app ID
+ int32_t previousUid =
+ previousAppId > 0 ? (int32_t)multiuser_get_uid(userId, previousAppId) : -1;
int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
@@ -717,10 +708,14 @@
cacheGid = uid;
}
+ long projectIdApp = get_project_id(uid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
if (!status.isOk()) {
return status;
}
@@ -745,11 +740,12 @@
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode);
+ auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
if (!status.isOk()) {
return status;
}
- if (previousUid != uid) {
+ if (previousUid > 0 && previousUid != uid) {
chown_app_profile_dir(packageName, appId, userId);
}
@@ -945,8 +941,12 @@
}
const int32_t sandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
int32_t previousSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
- auto status = createAppDataDirs(path, sandboxUid, AID_NOBODY, &previousSandboxUid,
- cacheGid, seInfo, 0700 | S_ISGID);
+ int32_t appUid = multiuser_get_uid(userId, appId);
+ long projectIdApp = get_project_id(appUid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(appUid, PROJECT_ID_APP_CACHE_START);
+ auto status =
+ createAppDataDirs(path, sandboxUid, AID_NOBODY, previousSandboxUid, cacheGid,
+ seInfo, 0700 | S_ISGID, projectIdApp, projectIdCache);
if (!status.isOk()) {
res = status;
continue;
@@ -3429,7 +3429,7 @@
auto temp_path = StringPrintf("%smisc/installd/ioctl_check", android_data_dir.c_str());
if (access(temp_path.c_str(), F_OK) != 0) {
int fd = open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
- result = set_quota_project_id(temp_path, 0, true) == 0;
+ result = set_quota_project_id(temp_path, 0, false) == 0;
close(fd);
// delete the temp file
remove(temp_path.c_str());
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 38cb370..f86f1d5 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -465,7 +465,7 @@
EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}
-TEST_F(ServiceTest, GetAppSize) {
+TEST_F(ServiceTest, GetAppSizeManualForMedia) {
struct stat s;
std::string externalPicDir =
@@ -509,6 +509,7 @@
system(removeCommand.c_str());
}
}
+
TEST_F(ServiceTest, GetAppSizeWrongSizes) {
int32_t externalStorageAppId = -1;
std::vector<int64_t> externalStorageSize;
diff --git a/include/android/sensor.h b/include/android/sensor.h
index c714b05..6112d5f 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -213,6 +213,13 @@
*/
ASENSOR_TYPE_HEART_BEAT = 31,
/**
+ * A constant describing a dynamic sensor meta event sensor.
+ *
+ * A sensor event of this type is received when a dynamic sensor is added to or removed from
+ * the system. This sensor type should always use special trigger report mode.
+ */
+ ASENSOR_TYPE_DYNAMIC_SENSOR_META = 32,
+ /**
* This sensor type is for delivering additional sensor information aside
* from sensor event data.
*
@@ -761,6 +768,10 @@
* Each time this is called, the previously returned list is deallocated and
* must no longer be used.
*
+ * Clients should call this if they receive a sensor update from
+ * {@link ASENSOR_TYPE_DYNAMIC_SENSOR_META} indicating the sensors have changed.
+ * If this happens, previously received lists from this method will be stale.
+ *
* Available since API level 33.
*
* \param manager the {@link ASensorManager} instance obtained from
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 01b25d3..39befbe 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -582,6 +582,10 @@
BBinder::~BBinder()
{
+ if (!wasParceled() && getExtension()) {
+ ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+ }
+
Extras* e = mExtras.load(std::memory_order_relaxed);
if (e) delete e;
}
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index f113ba8..d0cd11f 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -97,6 +97,10 @@
*
* This interface has system<->vendor stability
*/
+// b/227835797 - can't use __INTRODUCED_IN(30) because old targets load this code
+#if __ANDROID_MIN_SDK_VERSION__ < 30
+__attribute__((weak))
+#endif // __ANDROID_MIN_SDK_VERSION__ < 30
void AIBinder_markVintfStability(AIBinder* binder);
__END_DECLS
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index e3e4730..4df557b 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -575,6 +575,20 @@
cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
}
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Send for DeathRecipient {}
+
+/// # Safety
+///
+/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
+/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
+unsafe impl Sync for DeathRecipient {}
+
impl DeathRecipient {
/// Create a new death recipient that will call the given callback when its
/// associated object dies.
diff --git a/libs/binder/tests/binderBinderUnitTest.cpp b/libs/binder/tests/binderBinderUnitTest.cpp
index 1be0c59..ce2770f 100644
--- a/libs/binder/tests/binderBinderUnitTest.cpp
+++ b/libs/binder/tests/binderBinderUnitTest.cpp
@@ -41,3 +41,10 @@
EXPECT_EQ(kObject1, binder->detachObject(kObjectId1));
EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject2, nullptr, nullptr));
}
+
+TEST(Binder, AttachExtension) {
+ auto binder = sp<BBinder>::make();
+ auto ext = sp<BBinder>::make();
+ binder->setExtension(ext);
+ EXPECT_EQ(ext, binder->getExtension());
+}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 5532c6e..24d39fe 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -226,101 +226,6 @@
return result;
}
- sp<IBinder> createDisplay(const String8& displayName, bool secure) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- status_t status = data.writeString8(displayName);
- if (status) {
- return nullptr;
- }
- status = data.writeBool(secure);
- if (status) {
- return nullptr;
- }
-
- status = remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
- if (status) {
- return nullptr;
- }
- sp<IBinder> display;
- status = reply.readNullableStrongBinder(&display);
- if (status) {
- return nullptr;
- }
- return display;
- }
-
- void destroyDisplay(const sp<IBinder>& display) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
- }
-
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
- NO_ERROR) {
- std::vector<uint64_t> rawIds;
- if (reply.readUint64Vector(&rawIds) == NO_ERROR) {
- std::vector<PhysicalDisplayId> displayIds;
- displayIds.reserve(rawIds.size());
-
- for (const uint64_t rawId : rawIds) {
- if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
- displayIds.push_back(*id);
- }
- }
- return displayIds;
- }
- }
-
- return {};
- }
-
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId* displayId) const override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(remote()->transact, BnSurfaceComposer::GET_PRIMARY_PHYSICAL_DISPLAY_ID, data,
- &reply);
- uint64_t rawId;
- SAFE_PARCEL(reply.readUint64, &rawId);
- if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
- *displayId = *id;
- return NO_ERROR;
- }
- return NAME_NOT_FOUND;
- }
-
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeUint64(displayId.value);
- remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply);
- return reply.readStrongBinder();
- }
-
- void setPowerMode(const sp<IBinder>& display, int mode) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- data.writeInt32(mode);
- remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply);
- }
-
- status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATE, data, &reply);
- const status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- memcpy(state, reply.readInplace(sizeof(ui::DisplayState)), sizeof(ui::DisplayState));
- }
- return result;
- }
-
status_t getStaticDisplayInfo(const sp<IBinder>& display,
ui::StaticDisplayInfo* info) override {
Parcel data, reply;
@@ -343,20 +248,6 @@
return reply.read(*info);
}
- status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) override {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATS, data, &reply);
- status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- memcpy(stats,
- reply.readInplace(sizeof(DisplayStatInfo)),
- sizeof(DisplayStatInfo));
- }
- return result;
- }
-
status_t getDisplayNativePrimaries(const sp<IBinder>& display,
ui::DisplayPrimaries& primaries) override {
Parcel data, reply;
@@ -408,29 +299,6 @@
return static_cast<status_t>(reply.readInt32());
}
- // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
- status_t getBootDisplayModeSupport(bool* outSupport) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to write interface token: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::GET_BOOT_DISPLAY_MODE_SUPPORT, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to transact: %d", error);
- return error;
- }
- bool support;
- error = reply.readBool(&support);
- if (error != NO_ERROR) {
- ALOGE("getBootDisplayModeSupport: failed to read support: %d", error);
- return error;
- }
- *outSupport = support;
- return NO_ERROR;
- }
-
status_t setBootDisplayMode(const sp<IBinder>& display,
ui::DisplayModeId displayModeId) override {
Parcel data, reply;
@@ -456,73 +324,6 @@
return result;
}
- status_t clearBootDisplayMode(const sp<IBinder>& display) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to writeInterfaceToken: %d", result);
- return result;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to writeStrongBinder: %d", result);
- return result;
- }
- result = remote()->transact(BnSurfaceComposer::CLEAR_BOOT_DISPLAY_MODE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to transact: %d", result);
- }
- return result;
- }
-
- void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeInterfaceToken: %d", result);
- return;
- }
-
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeStrongBinder: %d", result);
- return;
- }
- result = data.writeBool(on);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to writeBool: %d", result);
- return;
- }
- result = remote()->transact(BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to transact: %d", result);
- return;
- }
- }
-
- void setGameContentType(const sp<IBinder>& display, bool on) override {
- Parcel data, reply;
- status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeInterfaceToken: %d", result);
- return;
- }
- result = data.writeStrongBinder(display);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeStrongBinder: %d", result);
- return;
- }
- result = data.writeBool(on);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to writeBool: %d", result);
- return;
- }
- result = remote()->transact(BnSurfaceComposer::SET_GAME_CONTENT_TYPE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to transact: %d", result);
- }
- }
-
status_t clearAnimationFrameStats() override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -797,26 +598,6 @@
return error;
}
- status_t isWideColorDisplay(const sp<IBinder>& token,
- bool* outIsWideColorDisplay) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- return error;
- }
- error = data.writeStrongBinder(token);
- if (error != NO_ERROR) {
- return error;
- }
-
- error = remote()->transact(BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY, data, &reply);
- if (error != NO_ERROR) {
- return error;
- }
- error = reply.readBool(outIsWideColorDisplay);
- return error;
- }
-
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override {
Parcel data, reply;
@@ -1049,109 +830,6 @@
return reply.readInt32();
}
- status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeStrongBinder(displayToken);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to write display token: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to transact: %d", error);
- return error;
- }
- bool support;
- error = reply.readBool(&support);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to read support: %d", error);
- return error;
- }
- *outSupport = support;
- return NO_ERROR;
- }
-
- status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeStrongBinder(displayToken);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write display token: %d", error);
- return error;
- }
- error = data.writeParcelable(brightness);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to write brightness: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS, data, &reply);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to transact: %d", error);
- return error;
- }
- return NO_ERROR;
- }
-
- status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeStrongBinder, displayToken);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
- const status_t error =
- remote()->transact(BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER, data, &reply);
- if (error != OK) {
- ALOGE("addHdrLayerInfoListener: Failed to transact; error = %d", error);
- }
- return error;
- }
-
- status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override {
- Parcel data, reply;
- SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeStrongBinder, displayToken);
- SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
- const status_t error =
- remote()->transact(BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER, data, &reply);
- if (error != OK) {
- ALOGE("removeHdrLayerInfoListener: Failed to transact; error = %d", error);
- }
- return error;
- }
-
- status_t notifyPowerBoost(int32_t boostId) override {
- Parcel data, reply;
- status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to write interface token: %d", error);
- return error;
- }
- error = data.writeInt32(boostId);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to write boostId: %d", error);
- return error;
- }
- error = remote()->transact(BnSurfaceComposer::NOTIFY_POWER_BOOST, data, &reply,
- IBinder::FLAG_ONEWAY);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to transact: %d", error);
- return error;
- }
- return NO_ERROR;
- }
-
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override {
Parcel data, reply;
@@ -1467,41 +1145,6 @@
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
- case CREATE_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- String8 displayName;
- SAFE_PARCEL(data.readString8, &displayName);
- bool secure = false;
- SAFE_PARCEL(data.readBool, &secure);
- sp<IBinder> display = createDisplay(displayName, secure);
- SAFE_PARCEL(reply->writeStrongBinder, display);
- return NO_ERROR;
- }
- case DESTROY_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- destroyDisplay(display);
- return NO_ERROR;
- }
- case GET_PHYSICAL_DISPLAY_TOKEN: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- const auto id = DisplayId::fromValue<PhysicalDisplayId>(data.readUint64());
- if (!id) return BAD_VALUE;
- reply->writeStrongBinder(getPhysicalDisplayToken(*id));
- return NO_ERROR;
- }
- case GET_DISPLAY_STATE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- ui::DisplayState state;
- const sp<IBinder> display = data.readStrongBinder();
- const status_t result = getDisplayState(display, &state);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- memcpy(reply->writeInplace(sizeof(ui::DisplayState)), &state,
- sizeof(ui::DisplayState));
- }
- return NO_ERROR;
- }
case GET_STATIC_DISPLAY_INFO: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
ui::StaticDisplayInfo info;
@@ -1522,18 +1165,6 @@
SAFE_PARCEL(reply->write, info);
return NO_ERROR;
}
- case GET_DISPLAY_STATS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- DisplayStatInfo stats;
- sp<IBinder> display = data.readStrongBinder();
- status_t result = getDisplayStats(display, &stats);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- memcpy(reply->writeInplace(sizeof(DisplayStatInfo)),
- &stats, sizeof(DisplayStatInfo));
- }
- return NO_ERROR;
- }
case GET_DISPLAY_NATIVE_PRIMARIES: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
ui::DisplayPrimaries primaries;
@@ -1573,15 +1204,6 @@
result = reply->writeInt32(result);
return result;
}
- case GET_BOOT_DISPLAY_MODE_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- bool support = false;
- status_t result = getBootDisplayModeSupport(&support);
- if (result == NO_ERROR) {
- reply->writeBool(support);
- }
- return result;
- }
case SET_BOOT_DISPLAY_MODE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -1598,50 +1220,6 @@
}
return setBootDisplayMode(display, displayModeId);
}
- case CLEAR_BOOT_DISPLAY_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("clearBootDisplayMode failed to readStrongBinder: %d", result);
- return result;
- }
- return clearBootDisplayMode(display);
- }
- case SET_AUTO_LOW_LATENCY_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to readStrongBinder: %d", result);
- return result;
- }
- bool setAllm = false;
- result = data.readBool(&setAllm);
- if (result != NO_ERROR) {
- ALOGE("setAutoLowLatencyMode failed to readBool: %d", result);
- return result;
- }
- setAutoLowLatencyMode(display, setAllm);
- return result;
- }
- case SET_GAME_CONTENT_TYPE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t result = data.readStrongBinder(&display);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to readStrongBinder: %d", result);
- return result;
- }
- bool setGameContentTypeOn = false;
- result = data.readBool(&setGameContentTypeOn);
- if (result != NO_ERROR) {
- ALOGE("setGameContentType failed to readBool: %d", result);
- return result;
- }
- setGameContentType(display, setGameContentTypeOn);
- return result;
- }
case CLEAR_ANIMATION_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
status_t result = clearAnimationFrameStats();
@@ -1656,13 +1234,6 @@
reply->writeInt32(result);
return NO_ERROR;
}
- case SET_POWER_MODE: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- int32_t mode = data.readInt32();
- setPowerMode(display, mode);
- return NO_ERROR;
- }
case ENABLE_VSYNC_INJECTIONS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bool enable = false;
@@ -1812,38 +1383,6 @@
}
return error;
}
- case IS_WIDE_COLOR_DISPLAY: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = nullptr;
- status_t error = data.readStrongBinder(&display);
- if (error != NO_ERROR) {
- return error;
- }
- bool result;
- error = isWideColorDisplay(display, &result);
- if (error == NO_ERROR) {
- reply->writeBool(result);
- }
- return error;
- }
- case GET_PHYSICAL_DISPLAY_IDS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- std::vector<PhysicalDisplayId> ids = getPhysicalDisplayIds();
- std::vector<uint64_t> rawIds(ids.size());
- std::transform(ids.begin(), ids.end(), rawIds.begin(),
- [](PhysicalDisplayId id) { return id.value; });
- return reply->writeUint64Vector(rawIds);
- }
- case GET_PRIMARY_PHYSICAL_DISPLAY_ID: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- PhysicalDisplayId id;
- status_t result = getPrimaryPhysicalDisplayId(&id);
- if (result != NO_ERROR) {
- ALOGE("getPrimaryPhysicalDisplayId: Failed to get id");
- return result;
- }
- return reply->writeUint64(id.value);
- }
case ADD_REGION_SAMPLING_LISTENER: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
Rect samplingArea;
@@ -2041,77 +1580,6 @@
reply->writeInt32(result);
return result;
}
- case GET_DISPLAY_BRIGHTNESS_SUPPORT: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("getDisplayBrightnessSupport: failed to read display token: %d", error);
- return error;
- }
- bool support = false;
- error = getDisplayBrightnessSupport(displayToken, &support);
- reply->writeBool(support);
- return error;
- }
- case SET_DISPLAY_BRIGHTNESS: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to read display token: %d", error);
- return error;
- }
- gui::DisplayBrightness brightness;
- error = data.readParcelable(&brightness);
- if (error != NO_ERROR) {
- ALOGE("setDisplayBrightness: failed to read brightness: %d", error);
- return error;
- }
- return setDisplayBrightness(displayToken, brightness);
- }
- case ADD_HDR_LAYER_INFO_LISTENER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("addHdrLayerInfoListener: Failed to read display token");
- return error;
- }
- sp<gui::IHdrLayerInfoListener> listener;
- error = data.readNullableStrongBinder(&listener);
- if (error != NO_ERROR) {
- ALOGE("addHdrLayerInfoListener: Failed to read listener");
- return error;
- }
- return addHdrLayerInfoListener(displayToken, listener);
- }
- case REMOVE_HDR_LAYER_INFO_LISTENER: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> displayToken;
- status_t error = data.readNullableStrongBinder(&displayToken);
- if (error != NO_ERROR) {
- ALOGE("removeHdrLayerInfoListener: Failed to read display token");
- return error;
- }
- sp<gui::IHdrLayerInfoListener> listener;
- error = data.readNullableStrongBinder(&listener);
- if (error != NO_ERROR) {
- ALOGE("removeHdrLayerInfoListener: Failed to read listener");
- return error;
- }
- return removeHdrLayerInfoListener(displayToken, listener);
- }
- case NOTIFY_POWER_BOOST: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int32_t boostId;
- status_t error = data.readInt32(&boostId);
- if (error != NO_ERROR) {
- ALOGE("notifyPowerBoost: failed to read boostId: %d", error);
- return error;
- }
- return notifyPowerBoost(boostId);
- }
case SET_GLOBAL_SHADOW_SETTINGS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1fb11e0..54b6d6a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -27,13 +27,13 @@
#include <inttypes.h>
+#include <android/gui/DisplayStatInfo.h>
#include <android/native_window.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <utils/NativeHandle.h>
-#include <ui/DisplayStatInfo.h>
#include <ui/DynamicDisplayInfo.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
@@ -45,6 +45,7 @@
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
namespace android {
@@ -125,6 +126,10 @@
return ComposerService::getComposerService();
}
+sp<gui::ISurfaceComposer> Surface::composerServiceAIDL() const {
+ return ComposerServiceAIDL::getComposerService();
+}
+
nsecs_t Surface::now() const {
return systemTime();
}
@@ -174,10 +179,10 @@
status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
ATRACE_CALL();
- DisplayStatInfo stats;
- status_t result = composerService()->getDisplayStats(nullptr, &stats);
- if (result != NO_ERROR) {
- return result;
+ gui::DisplayStatInfo stats;
+ binder::Status status = composerServiceAIDL()->getDisplayStats(nullptr, &stats);
+ if (!status.isOk()) {
+ return status.transactionError();
}
*outRefreshDuration = stats.vsyncPeriod;
@@ -343,20 +348,20 @@
status_t Surface::getWideColorSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
if (display == nullptr) {
return NAME_NOT_FOUND;
}
*supported = false;
- status_t error = composerService()->isWideColorDisplay(display, supported);
- return error;
+ binder::Status status = composerServiceAIDL()->isWideColorDisplay(display, supported);
+ return status.transactionError();
}
status_t Surface::getHdrSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = composerService()->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
if (display == nullptr) {
return NAME_NOT_FOUND;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6c197c4..7a63af0 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/gui/DisplayState.h>
#include <android/gui/IWindowInfosListener.h>
#include <utils/Errors.h>
#include <utils/Log.h>
@@ -43,6 +44,7 @@
#include <gui/WindowInfo.h>
#include <private/gui/ParcelUtils.h>
#include <ui/DisplayMode.h>
+#include <ui/DisplayState.h>
#include <ui/DynamicDisplayInfo.h>
#include <private/gui/ComposerService.h>
@@ -206,12 +208,14 @@
}
sp<TransactionCompletedListener> TransactionCompletedListener::sInstance = nullptr;
+static std::mutex sListenerInstanceMutex;
void TransactionCompletedListener::setInstance(const sp<TransactionCompletedListener>& listener) {
sInstance = listener;
}
sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
+ std::lock_guard<std::mutex> lock(sListenerInstanceMutex);
if (sInstance == nullptr) {
sInstance = new TransactionCompletedListener;
}
@@ -1022,32 +1026,59 @@
// ---------------------------------------------------------------------------
sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
- return ComposerService::getComposerService()->createDisplay(displayName,
- secure);
+ sp<IBinder> display = nullptr;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->createDisplay(std::string(
+ displayName.string()),
+ secure, &display);
+ return status.isOk() ? display : nullptr;
}
void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->destroyDisplay(display);
+ ComposerServiceAIDL::getComposerService()->destroyDisplay(display);
}
std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() {
- return ComposerService::getComposerService()->getPhysicalDisplayIds();
+ std::vector<int64_t> displayIds;
+ std::vector<PhysicalDisplayId> physicalDisplayIds;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPhysicalDisplayIds(&displayIds);
+ if (status.isOk()) {
+ physicalDisplayIds.reserve(displayIds.size());
+ for (auto item : displayIds) {
+ auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(item));
+ physicalDisplayIds.push_back(*id);
+ }
+ }
+ return physicalDisplayIds;
}
status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) {
- return ComposerService::getComposerService()->getPrimaryPhysicalDisplayId(id);
+ int64_t displayId;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPrimaryPhysicalDisplayId(&displayId);
+ if (status.isOk()) {
+ *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+ }
+ return status.transactionError();
}
std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
- return ComposerService::getComposerService()->getInternalDisplayId();
+ ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+ return instance.getInternalDisplayId();
}
sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
- return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId);
+ sp<IBinder> display = nullptr;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getPhysicalDisplayToken(displayId.value,
+ &display);
+ return status.isOk() ? display : nullptr;
}
sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
- return ComposerService::getComposerService()->getInternalDisplayToken();
+ ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+ return instance.getInternalDisplayToken();
}
void SurfaceComposerClient::Transaction::setAnimationTransaction() {
@@ -2100,7 +2131,16 @@
status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
ui::DisplayState* state) {
- return ComposerService::getComposerService()->getDisplayState(display, state);
+ gui::DisplayState ds;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getDisplayState(display, &ds);
+ if (status.isOk()) {
+ state->layerStack = ui::LayerStack::fromValue(ds.layerStack);
+ state->orientation = static_cast<ui::Rotation>(ds.orientation);
+ state->layerStackSpaceRect =
+ ui::Size(ds.layerStackSpaceRect.width, ds.layerStackSpaceRect.height);
+ }
+ return status.transactionError();
}
status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display,
@@ -2164,7 +2204,9 @@
}
status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) {
- return ComposerService::getComposerService()->getBootDisplayModeSupport(support);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getBootDisplayModeSupport(support);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display,
@@ -2173,7 +2215,9 @@
}
status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) {
- return ComposerService::getComposerService()->clearBootDisplayMode(display);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->clearBootDisplayMode(display);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) {
@@ -2181,16 +2225,16 @@
}
void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
- ComposerService::getComposerService()->setAutoLowLatencyMode(display, on);
+ ComposerServiceAIDL::getComposerService()->setAutoLowLatencyMode(display, on);
}
void SurfaceComposerClient::setGameContentType(const sp<IBinder>& display, bool on) {
- ComposerService::getComposerService()->setGameContentType(display, on);
+ ComposerServiceAIDL::getComposerService()->setGameContentType(display, on);
}
void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token,
int mode) {
- ComposerService::getComposerService()->setPowerMode(token, mode);
+ ComposerServiceAIDL::getComposerService()->setPowerMode(token, mode);
}
status_t SurfaceComposerClient::getCompositionPreference(
@@ -2251,8 +2295,10 @@
status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display,
bool* outIsWideColorDisplay) {
- return ComposerService::getComposerService()->isWideColorDisplay(display,
- outIsWideColorDisplay);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->isWideColorDisplay(display,
+ outIsWideColorDisplay);
+ return status.transactionError();
}
status_t SurfaceComposerClient::addRegionSamplingListener(
@@ -2289,28 +2335,39 @@
bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) {
bool support = false;
- ComposerService::getComposerService()->getDisplayBrightnessSupport(displayToken, &support);
- return support;
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->getDisplayBrightnessSupport(displayToken,
+ &support);
+ return status.isOk() ? support : false;
}
status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness) {
- return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->setDisplayBrightness(displayToken,
+ brightness);
+ return status.transactionError();
}
status_t SurfaceComposerClient::addHdrLayerInfoListener(
const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
- return ComposerService::getComposerService()->addHdrLayerInfoListener(displayToken, listener);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->addHdrLayerInfoListener(displayToken,
+ listener);
+ return status.transactionError();
}
status_t SurfaceComposerClient::removeHdrLayerInfoListener(
const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
- return ComposerService::getComposerService()->removeHdrLayerInfoListener(displayToken,
- listener);
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->removeHdrLayerInfoListener(displayToken,
+ listener);
+ return status.transactionError();
}
status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) {
- return ComposerService::getComposerService()->notifyPowerBoost(boostId);
+ binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId);
+ return status.transactionError();
}
status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor,
diff --git a/libs/gui/aidl/android/gui/DisplayStatInfo.aidl b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
new file mode 100644
index 0000000..68f3942
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+/** @hide */
+parcelable DisplayStatInfo {
+ long vsyncTime;
+ long vsyncPeriod;
+}
diff --git a/libs/gui/aidl/android/gui/DisplayState.aidl b/libs/gui/aidl/android/gui/DisplayState.aidl
new file mode 100644
index 0000000..9589ab6
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DisplayState.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+import android.gui.Rotation;
+import android.gui.Size;
+
+/** @hide */
+parcelable DisplayState {
+ int layerStack;
+ Rotation orientation = Rotation.Rotation0;
+ Size layerStackSpaceRect;
+}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 07921a5..a9977b0 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -17,11 +17,88 @@
package android.gui;
import android.gui.DisplayCaptureArgs;
+import android.gui.DisplayBrightness;
+import android.gui.DisplayState;
+import android.gui.DisplayStatInfo;
+import android.gui.IHdrLayerInfoListener;
import android.gui.LayerCaptureArgs;
import android.gui.IScreenCaptureListener;
/** @hide */
interface ISurfaceComposer {
+
+ /* create a virtual display
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ @nullable IBinder createDisplay(@utf8InCpp String displayName, boolean secure);
+
+ /* destroy a virtual display
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ void destroyDisplay(IBinder display);
+
+ /* get stable IDs for connected physical displays.
+ */
+ long[] getPhysicalDisplayIds();
+
+ long getPrimaryPhysicalDisplayId();
+
+ /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
+ * DisplayEventReceiver hotplug event.
+ */
+ @nullable IBinder getPhysicalDisplayToken(long displayId);
+
+ /* set display power mode. depending on the mode, it can either trigger
+ * screen on, off or low power mode and wait for it to complete.
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
+ void setPowerMode(IBinder display, int mode);
+
+ /* returns display statistics for a given display
+ * intended to be used by the media framework to properly schedule
+ * video frames */
+ DisplayStatInfo getDisplayStats(IBinder display);
+
+ /**
+ * Get transactional state of given display.
+ */
+ DisplayState getDisplayState(IBinder display);
+
+ /**
+ * Clears the user-preferred display mode. The device should now boot in system preferred
+ * display mode.
+ */
+ void clearBootDisplayMode(IBinder display);
+
+ /**
+ * Gets whether boot time display mode operations are supported on the device.
+ *
+ * outSupport
+ * An output parameter for whether boot time display mode operations are supported.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
+ boolean getBootDisplayModeSupport();
+
+ /**
+ * Switches Auto Low Latency Mode on/off on the connected display, if it is
+ * available. This should only be called if the display supports Auto Low
+ * Latency Mode as reported in #getDynamicDisplayInfo.
+ * For more information, see the HDMI 2.1 specification.
+ */
+ void setAutoLowLatencyMode(IBinder display, boolean on);
+
+ /**
+ * This will start sending infoframes to the connected display with
+ * ContentType=Game (if on=true). This should only be called if the display
+ * Game Content Type as reported in #getDynamicDisplayInfo.
+ * For more information, see the HDMI 1.4 specification.
+ */
+ void setGameContentType(IBinder display, boolean on);
+
/**
* Capture the specified screen. This requires READ_FRAME_BUFFER
* permission. This function will fail if there is a secure window on
@@ -39,4 +116,67 @@
* is a secure window on screen
*/
void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
+
+ /*
+ * Queries whether the given display is a wide color display.
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ boolean isWideColorDisplay(IBinder token);
+
+ /*
+ * Gets whether brightness operations are supported on a display.
+ *
+ * displayToken
+ * The token of the display.
+ * outSupport
+ * An output parameter for whether brightness operations are supported.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ boolean getDisplayBrightnessSupport(IBinder displayToken);
+
+ /*
+ * Sets the brightness of a display.
+ *
+ * displayToken
+ * The token of the display whose brightness is set.
+ * brightness
+ * The DisplayBrightness info to set on the desired display.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the brightness is invalid, or
+ * INVALID_OPERATION if brightness operations are not supported.
+ */
+ void setDisplayBrightness(IBinder displayToken, in DisplayBrightness brightness);
+
+ /*
+ * Adds a listener that receives HDR layer information. This is used in combination
+ * with setDisplayBrightness to adjust the display brightness depending on factors such
+ * as whether or not HDR is in use.
+ *
+ * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
+ */
+ void addHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+ /*
+ * Removes a listener that was added with addHdrLayerInfoListener.
+ *
+ * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
+ * the listener wasn't registered.
+ *
+ */
+ void removeHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+ /*
+ * Sends a power boost to the composer. This function is asynchronous.
+ *
+ * boostId
+ * boost id according to android::hardware::power::Boost
+ *
+ * Returns NO_ERROR upon success.
+ */
+ void notifyPowerBoost(int boostId);
}
diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/Rect.aidl
new file mode 100644
index 0000000..1b13761
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Rect.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+// copied from libs/arect/include/android/rect.h
+// TODO(b/221473398):
+// use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
+/** @hide */
+parcelable Rect {
+ /// Minimum X coordinate of the rectangle.
+ int left;
+
+ /// Minimum Y coordinate of the rectangle.
+ int top;
+
+ /// Maximum X coordinate of the rectangle.
+ int right;
+
+ /// Maximum Y coordinate of the rectangle.
+ int bottom;
+}
diff --git a/libs/gui/aidl/android/gui/Rotation.aidl b/libs/gui/aidl/android/gui/Rotation.aidl
new file mode 100644
index 0000000..451ff45
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Rotation.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+/** @hide */
+@Backing(type="int")
+enum Rotation {
+ Rotation0 = 0,
+ Rotation90 = 1,
+ Rotation180 = 2,
+ Rotation270 = 3
+}
diff --git a/libs/gui/aidl/android/gui/Size.aidl b/libs/gui/aidl/android/gui/Size.aidl
new file mode 100644
index 0000000..415fa36
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Size.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+/** @hide */
+parcelable Size {
+ int width = -1;
+ int height = -1;
+}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index b11e674..a610e94 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -138,40 +138,6 @@
VsyncSource vsyncSource = eVsyncSourceApp,
EventRegistrationFlags eventRegistration = {}) = 0;
- /* create a virtual display
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual sp<IBinder> createDisplay(const String8& displayName,
- bool secure) = 0;
-
- /* destroy a virtual display
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual void destroyDisplay(const sp<IBinder>& display) = 0;
-
- /* get stable IDs for connected physical displays.
- */
- virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
-
- virtual status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) 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 status_t setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state,
@@ -195,24 +161,6 @@
virtual status_t getSupportedFrameTimestamps(
std::vector<FrameEvent>* outSupported) const = 0;
- /* set display power mode. depending on the mode, it can either trigger
- * screen on, off or low power mode and wait for it to complete.
- * requires ACCESS_SURFACE_FLINGER permission.
- */
- virtual void setPowerMode(const sp<IBinder>& display, int mode) = 0;
-
-
- /* returns display statistics for a given display
- * intended to be used by the media framework to properly schedule
- * video frames */
- virtual status_t getDisplayStats(const sp<IBinder>& display,
- DisplayStatInfo* stats) = 0;
-
- /**
- * Get transactional state of given display.
- */
- virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0;
-
/**
* Gets immutable information about given physical display.
*/
@@ -233,40 +181,6 @@
*/
virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0;
- /**
- * Clears the user-preferred display mode. The device should now boot in system preferred
- * display mode.
- */
- virtual status_t clearBootDisplayMode(const sp<IBinder>& display) = 0;
-
- /**
- * Gets whether boot time display mode operations are supported on the device.
- *
- * outSupport
- * An output parameter for whether boot time display mode operations are supported.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the output parameter is invalid.
- */
- virtual status_t getBootDisplayModeSupport(bool* outSupport) const = 0;
-
- /**
- * Switches Auto Low Latency Mode on/off on the connected display, if it is
- * available. This should only be called if the display supports Auto Low
- * Latency Mode as reported in #getDynamicDisplayInfo.
- * For more information, see the HDMI 2.1 specification.
- */
- virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) = 0;
-
- /**
- * This will start sending infoframes to the connected display with
- * ContentType=Game (if on=true). This should only be called if the display
- * Game Content Type as reported in #getDynamicDisplayInfo.
- * For more information, see the HDMI 1.4 specification.
- */
- virtual void setGameContentType(const sp<IBinder>& display, bool on) = 0;
-
/* Clears the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.
@@ -345,13 +259,6 @@
*/
virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
- /*
- * Queries whether the given display is a wide color display.
- * Requires the ACCESS_SURFACE_FLINGER permission.
- */
- virtual status_t isWideColorDisplay(const sp<IBinder>& token,
- bool* outIsWideColorDisplay) const = 0;
-
/* Registers a listener to stream median luma updates from SurfaceFlinger.
*
* The sampling area is bounded by both samplingArea and the given stopLayerHandle
@@ -432,65 +339,6 @@
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) = 0;
- /*
- * Gets whether brightness operations are supported on a display.
- *
- * displayToken
- * The token of the display.
- * outSupport
- * An output parameter for whether brightness operations are supported.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the output parameter is invalid.
- */
- virtual status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const = 0;
-
- /*
- * Sets the brightness of a display.
- *
- * displayToken
- * The token of the display whose brightness is set.
- * brightness
- * The DisplayBrightness info to set on the desired display.
- *
- * Returns NO_ERROR upon success. Otherwise,
- * NAME_NOT_FOUND if the display is invalid, or
- * BAD_VALUE if the brightness is invalid, or
- * INVALID_OPERATION if brightness operations are not supported.
- */
- virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) = 0;
-
- /*
- * Adds a listener that receives HDR layer information. This is used in combination
- * with setDisplayBrightness to adjust the display brightness depending on factors such
- * as whether or not HDR is in use.
- *
- * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
- */
- virtual status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) = 0;
- /*
- * Removes a listener that was added with addHdrLayerInfoListener.
- *
- * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
- * the listener wasn't registered.
- *
- */
- virtual status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) = 0;
-
- /*
- * Sends a power boost to the composer. This function is asynchronous.
- *
- * boostId
- * boost id according to android::hardware::power::Boost
- *
- * Returns NO_ERROR upon success.
- */
- virtual status_t notifyPowerBoost(int32_t boostId) = 0;
/*
* Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
@@ -597,9 +445,9 @@
CREATE_CONNECTION,
GET_STATIC_DISPLAY_INFO,
CREATE_DISPLAY_EVENT_CONNECTION,
- CREATE_DISPLAY,
- DESTROY_DISPLAY,
- GET_PHYSICAL_DISPLAY_TOKEN,
+ CREATE_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+ DESTROY_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+ GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now.
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
GET_SUPPORTED_FRAME_TIMESTAMPS,
@@ -610,7 +458,7 @@
CAPTURE_LAYERS, // Deprecated. Autogenerated by .aidl now.
CLEAR_ANIMATION_FRAME_STATS,
GET_ANIMATION_FRAME_STATS,
- SET_POWER_MODE,
+ SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_STATS,
GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
@@ -625,22 +473,22 @@
SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
GET_DISPLAYED_CONTENT_SAMPLE,
GET_PROTECTED_CONTENT_SUPPORT,
- IS_WIDE_COLOR_DISPLAY,
+ IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_NATIVE_PRIMARIES,
- GET_PHYSICAL_DISPLAY_IDS,
+ GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now.
ADD_REGION_SAMPLING_LISTENER,
REMOVE_REGION_SAMPLING_LISTENER,
SET_DESIRED_DISPLAY_MODE_SPECS,
GET_DESIRED_DISPLAY_MODE_SPECS,
- GET_DISPLAY_BRIGHTNESS_SUPPORT,
- SET_DISPLAY_BRIGHTNESS,
- CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now.
- NOTIFY_POWER_BOOST,
+ GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now.
+ SET_DISPLAY_BRIGHTNESS, // Deprecated. Autogenerated by .aidl now.
+ CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now.
+ NOTIFY_POWER_BOOST, // Deprecated. Autogenerated by .aidl now.
SET_GLOBAL_SHADOW_SETTINGS,
GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
- SET_AUTO_LOW_LATENCY_MODE,
- GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
- SET_GAME_CONTENT_TYPE,
+ SET_AUTO_LOW_LATENCY_MODE, // Deprecated. Autogenerated by .aidl now.
+ GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+ SET_GAME_CONTENT_TYPE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
SET_FRAME_RATE,
// Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
@@ -652,18 +500,18 @@
ADD_FPS_LISTENER,
REMOVE_FPS_LISTENER,
OVERRIDE_HDR_TYPES,
- ADD_HDR_LAYER_INFO_LISTENER,
- REMOVE_HDR_LAYER_INFO_LISTENER,
+ ADD_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
+ REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
ON_PULL_ATOM,
ADD_TUNNEL_MODE_ENABLED_LISTENER,
REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
ADD_WINDOW_INFOS_LISTENER,
REMOVE_WINDOW_INFOS_LISTENER,
- GET_PRIMARY_PHYSICAL_DISPLAY_ID,
+ GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now.
GET_DISPLAY_DECORATION_SUPPORT,
- GET_BOOT_DISPLAY_MODE_SUPPORT,
+ GET_BOOT_DISPLAY_MODE_SUPPORT, // Deprecated. Autogenerated by .aidl now.
SET_BOOT_DISPLAY_MODE,
- CLEAR_BOOT_DISPLAY_MODE,
+ CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now.
SET_OVERRIDE_FRAME_RATE,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 5fe308c..ab9ebaa 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -35,6 +35,10 @@
namespace android {
+namespace gui {
+class ISurfaceComposer;
+} // namespace gui
+
class ISurfaceComposer;
/* This is the same as ProducerListener except that onBuffersDiscarded is
@@ -196,6 +200,7 @@
// Virtual for testing.
virtual sp<ISurfaceComposer> composerService() const;
+ virtual sp<gui::ISurfaceComposer> composerServiceAIDL() const;
virtual nsecs_t now() const;
private:
diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h
index fee37ee..9a96976 100644
--- a/libs/gui/include/private/gui/ComposerServiceAIDL.h
+++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h
@@ -50,6 +50,28 @@
// Get a connection to the Composer Service. This will block until
// a connection is established. Returns null if permission is denied.
static sp<gui::ISurfaceComposer> getComposerService();
+
+ // the following two methods are moved from ISurfaceComposer.h
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+ std::vector<int64_t> displayIds;
+ binder::Status status = mComposerService->getPhysicalDisplayIds(&displayIds);
+ return (!status.isOk() || displayIds.empty())
+ ? std::nullopt
+ : DisplayId::fromValue<PhysicalDisplayId>(
+ static_cast<uint64_t>(displayIds.front()));
+ }
+
+ // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId) return nullptr;
+ sp<IBinder> display;
+ binder::Status status =
+ mComposerService->getPhysicalDisplayToken(static_cast<int64_t>(displayId->value),
+ &display);
+ return status.isOk() ? display : nullptr;
+ }
};
// ---------------------------------------------------------------------------
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index a885e92..065cd7a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -20,6 +20,7 @@
#include <SurfaceFlingerProperties.h>
#include <android/gui/IDisplayEventConnection.h>
+#include <android/gui/ISurfaceComposer.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <binder/ProcessState.h>
#include <configstore/Utils.h>
@@ -260,9 +261,7 @@
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
- const sp<IBinder> display = sf->getInternalDisplayToken();
+ const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
DisplayCaptureArgs captureArgs;
@@ -696,12 +695,6 @@
ISurfaceComposer::VsyncSource, ISurfaceComposer::EventRegistrationFlags) override {
return nullptr;
}
- sp<IBinder> createDisplay(const String8& /*displayName*/,
- bool /*secure*/) override { return nullptr; }
- void destroyDisplay(const sp<IBinder>& /*display */) override {}
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override { return NO_ERROR; }
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
const Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
@@ -740,7 +733,6 @@
return NO_ERROR;
}
- void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override {
return NO_ERROR;
}
@@ -748,24 +740,16 @@
ui::DynamicDisplayInfo*) override {
return NO_ERROR;
}
- status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
- return NO_ERROR;
- }
- status_t getDisplayStats(const sp<IBinder>& /*display*/,
- DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
ui::DisplayPrimaries& /*primaries*/) override {
return NO_ERROR;
}
- status_t setActiveColorMode(const sp<IBinder>& /*display*/,
- ColorMode /*colorMode*/) override { return NO_ERROR; }
- status_t getBootDisplayModeSupport(bool* /*outSupport*/) const override { return NO_ERROR; }
+ status_t setActiveColorMode(const sp<IBinder>& /*display*/, ColorMode /*colorMode*/) override {
+ return NO_ERROR;
+ }
status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override {
return NO_ERROR;
}
- status_t clearBootDisplayMode(const sp<IBinder>& /*display*/) override { return NO_ERROR; }
- void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
- void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
status_t clearAnimationFrameStats() override { return NO_ERROR; }
status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
@@ -812,26 +796,6 @@
status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
- status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
- status_t getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
- bool* /*outSupport*/) const override {
- return NO_ERROR;
- }
- status_t setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
- const gui::DisplayBrightness& /*brightness*/) override {
- return NO_ERROR;
- }
-
- status_t addHdrLayerInfoListener(const sp<IBinder>&,
- const sp<gui::IHdrLayerInfoListener>&) override {
- return NO_ERROR;
- }
-
- status_t removeHdrLayerInfoListener(const sp<IBinder>&,
- const sp<gui::IHdrLayerInfoListener>&) override {
- return NO_ERROR;
- }
-
status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
const sp<IBinder>& /*stopLayerHandle*/,
const sp<IRegionSamplingListener>& /*listener*/) override {
@@ -873,7 +837,6 @@
float* /*outAppRequestRefreshRateMax*/) override {
return NO_ERROR;
};
- status_t notifyPowerBoost(int32_t /*boostId*/) override { return NO_ERROR; }
status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/,
float /*lightPosY*/, float /*lightPosZ*/,
@@ -925,6 +888,114 @@
bool mSupportsPresent{true};
};
+class FakeSurfaceComposerAIDL : public gui::ISurfaceComposer {
+public:
+ ~FakeSurfaceComposerAIDL() override {}
+
+ void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; }
+
+ binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/,
+ sp<IBinder>* /*outDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status destroyDisplay(const sp<IBinder>& /*display*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPhysicalDisplayIds(std::vector<int64_t>* /*outDisplayIds*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getPhysicalDisplayToken(int64_t /*displayId*/,
+ sp<IBinder>* /*outDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayStats(const sp<IBinder>& /*display*/,
+ gui::DisplayStatInfo* /*outStatInfo*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayState(const sp<IBinder>& /*display*/,
+ gui::DisplayState* /*outState*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getBootDisplayModeSupport(bool* /*outMode*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureDisplay(const DisplayCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status captureLayers(const LayerCaptureArgs&,
+ const sp<IScreenCaptureListener>&) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/,
+ bool* /*outIsWideColorDisplay*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
+ bool* /*outSupport*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
+ const gui::DisplayBrightness& /*brightness*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status addHdrLayerInfoListener(
+ const sp<IBinder>& /*displayToken*/,
+ const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status removeHdrLayerInfoListener(
+ const sp<IBinder>& /*displayToken*/,
+ const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status notifyPowerBoost(int /*boostId*/) override { return binder::Status::ok(); }
+
+protected:
+ IBinder* onAsBinder() override { return nullptr; }
+
+private:
+ bool mSupportsPresent{true};
+};
+
class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
public:
explicit FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap) : mFenceMap(fenceMap) {}
diff --git a/libs/input/android/os/InputEventInjectionResult.aidl b/libs/input/android/os/InputEventInjectionResult.aidl
index 34f10ec..3bc7068 100644
--- a/libs/input/android/os/InputEventInjectionResult.aidl
+++ b/libs/input/android/os/InputEventInjectionResult.aidl
@@ -29,9 +29,8 @@
/* Injection succeeded. */
SUCCEEDED = 0,
- /* Injection failed because the injector did not have permission to inject
- * into the application with input focus. */
- PERMISSION_DENIED = 1,
+ /* Injection failed because the injected event did not target the appropriate window. */
+ TARGET_MISMATCH = 1,
/* Injection failed because there were no available input targets. */
FAILED = 2,
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 84e84dd..cb92df3 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -27,6 +27,7 @@
"-DEGL_EGLEXT_PROTOTYPES",
],
shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libEGL",
diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp
index 471159f..249fec5 100644
--- a/libs/renderengine/benchmark/Android.bp
+++ b/libs/renderengine/benchmark/Android.bp
@@ -43,6 +43,7 @@
],
shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libjnigraphics",
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 40ba5ad..bf50644 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -16,6 +16,7 @@
#pragma once
+#include <aidl/android/hardware/graphics/composer3/DimmingStage.h>
#include <iosfwd>
#include <math/mat4.h>
@@ -68,6 +69,10 @@
// All layers will be dimmed by (max(layer white points) / targetLuminanceNits).
// If the target luminance is unknown, then no display-level dimming occurs.
float targetLuminanceNits = -1.f;
+
+ // Configures when dimming should be applied for each layer.
+ aidl::android::hardware::graphics::composer3::DimmingStage dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::NONE;
};
static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index df9f8ab..a77a798 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -737,7 +737,9 @@
return roundedRect;
}
-static bool equalsWithinMargin(float expected, float value, float margin) {
+// Arbitrary default margin which should be close enough to zero.
+constexpr float kDefaultMargin = 0.0001f;
+static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) {
LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
return std::abs(expected - value) < margin;
}
@@ -995,10 +997,13 @@
? displayDimmingRatio
: (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
+ const bool dimInLinearSpace = display.dimmingStage !=
+ aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
+
const bool requiresLinearEffect = layer.colorTransform != mat4() ||
(mUseColorManagement &&
needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
- !equalsWithinMargin(1.f, layerDimmingRatio, 0.001f);
+ (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio));
// quick abort from drawing the remaining portion of the layer
if (layer.skipContentDraw ||
@@ -1104,7 +1109,9 @@
.undoPremultipliedAlpha = !item.isOpaque &&
item.usePremultipliedAlpha,
.requiresLinearEffect = requiresLinearEffect,
- .layerDimmingRatio = layerDimmingRatio}));
+ .layerDimmingRatio = dimInLinearSpace
+ ? layerDimmingRatio
+ : 1.f}));
// Turn on dithering when dimming beyond this (arbitrary) threshold...
static constexpr float kDimmingThreshold = 0.2f;
@@ -1177,7 +1184,20 @@
// An A8 buffer will already have the proper color filter attached to
// its paint, including the displayColorTransform as needed.
if (!paint.getColorFilter()) {
- paint.setColorFilter(displayColorTransform);
+ if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) {
+ // If we don't dim in linear space, then when we gamma correct the dimming ratio we
+ // can assume a gamma 2.2 transfer function.
+ static constexpr float kInverseGamma22 = 1.f / 2.2f;
+ const auto gammaCorrectedDimmingRatio =
+ std::pow(layerDimmingRatio, kInverseGamma22);
+ const auto dimmingMatrix =
+ mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio,
+ gammaCorrectedDimmingRatio, 1.f));
+ paint.setColorFilter(SkColorFilters::Matrix(
+ toSkColorMatrix(display.colorTransform * dimmingMatrix)));
+ } else {
+ paint.setColorFilter(displayColorTransform);
+ }
}
if (!roundRectClip.isEmpty()) {
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index d91af1e..e66fee1 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -47,6 +47,7 @@
],
shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libEGL",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 38ae2fd..2493242 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -2405,15 +2405,18 @@
TEST_P(RenderEngineTest, testDimming) {
if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
- return;
+ GTEST_SKIP();
}
+
initializeRenderEngine();
+ const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB_LINEAR;
+
const auto displayRect = Rect(3, 1);
const renderengine::DisplaySettings display{
.physicalDisplay = displayRect,
.clip = displayRect,
- .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .outputDataspace = dataspace,
.targetLuminanceNits = 1000.f,
};
@@ -2432,7 +2435,7 @@
},
},
.alpha = 1.0f,
- .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .sourceDataspace = dataspace,
.whitePointNits = 200.f,
};
@@ -2447,7 +2450,7 @@
},
},
.alpha = 1.0f,
- .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .sourceDataspace = dataspace,
.whitePointNits = 1000.f / 51.f,
};
@@ -2462,7 +2465,7 @@
},
},
.alpha = 1.0f,
- .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .sourceDataspace = dataspace,
// When the white point is not set for a layer, just ignore it and treat it as the same
// as the max layer
.whitePointNits = -1.f,
@@ -2476,6 +2479,84 @@
expectBufferColor(Rect(2, 0, 3, 1), 51, 0, 0, 255, 1);
}
+TEST_P(RenderEngineTest, testDimming_inGammaSpace) {
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ GTEST_SKIP();
+ }
+ initializeRenderEngine();
+
+ const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
+ ui::Dataspace::TRANSFER_GAMMA2_2 |
+ ui::Dataspace::RANGE_FULL);
+
+ const auto displayRect = Rect(3, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .outputDataspace = dataspace,
+ .targetLuminanceNits = 1000.f,
+ .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ };
+
+ const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+ const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+ const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255));
+
+ const renderengine::LayerSettings greenLayer{
+ .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = greenBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ .whitePointNits = 200.f,
+ };
+
+ const renderengine::LayerSettings blueLayer{
+ .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = blueBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ .whitePointNits = 1000.f / 51.f,
+ };
+
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = FloatRect(2.f, 0.f, 3.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = redBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ // When the white point is not set for a layer, just ignore it and treat it as the same
+ // as the max layer
+ .whitePointNits = -1.f,
+ };
+
+ std::vector<renderengine::LayerSettings> layers{greenLayer, blueLayer, redLayer};
+ invokeDraw(display, layers);
+
+ expectBufferColor(Rect(1, 1), 0, 122, 0, 255, 1);
+ expectBufferColor(Rect(1, 0, 2, 1), 0, 0, 42, 255, 1);
+ expectBufferColor(Rect(2, 0, 3, 1), 122, 0, 0, 255, 1);
+}
+
TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
initializeRenderEngine();
if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 32eec29..a2e60c4 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -31,11 +31,11 @@
namespace android::inputdispatcher {
// An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
+constexpr int32_t DEVICE_ID = 1;
-// An arbitrary injector pid / uid pair that has permission to inject events.
-static const int32_t INJECTOR_PID = 999;
-static const int32_t INJECTOR_UID = 1001;
+// The default pid and uid for windows created by the test.
+constexpr int32_t WINDOW_PID = 999;
+constexpr int32_t WINDOW_UID = 1001;
static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s;
static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms;
@@ -108,8 +108,6 @@
void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
- bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; }
-
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
void setPointerCapture(const PointerCaptureRequest&) override {}
@@ -196,8 +194,8 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(mFrame);
- mInfo.ownerPid = INJECTOR_PID;
- mInfo.ownerUid = INJECTOR_UID;
+ mInfo.ownerPid = WINDOW_PID;
+ mInfo.ownerUid = WINDOW_UID;
mInfo.displayId = ADISPLAY_ID_DEFAULT;
}
@@ -310,14 +308,14 @@
for (auto _ : state) {
MotionEvent event = generateMotionEvent();
// Send ACTION_DOWN
- dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+ dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ INJECT_EVENT_TIMEOUT,
POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
// Send ACTION_UP
event.setAction(AMOTION_EVENT_ACTION_UP);
- dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+ dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ INJECT_EVENT_TIMEOUT,
POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
window->consumeEvent();
diff --git a/services/inputflinger/dispatcher/InjectionState.cpp b/services/inputflinger/dispatcher/InjectionState.cpp
index c8024a6..c2d3ad6 100644
--- a/services/inputflinger/dispatcher/InjectionState.cpp
+++ b/services/inputflinger/dispatcher/InjectionState.cpp
@@ -20,10 +20,9 @@
namespace android::inputdispatcher {
-InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid)
+InjectionState::InjectionState(const std::optional<int32_t>& targetUid)
: refCount(1),
- injectorPid(injectorPid),
- injectorUid(injectorUid),
+ targetUid(targetUid),
injectionResult(android::os::InputEventInjectionResult::PENDING),
injectionIsAsync(false),
pendingForegroundDispatches(0) {}
diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h
index 0bfafb1..90cf150 100644
--- a/services/inputflinger/dispatcher/InjectionState.h
+++ b/services/inputflinger/dispatcher/InjectionState.h
@@ -27,13 +27,12 @@
struct InjectionState {
mutable int32_t refCount;
- int32_t injectorPid;
- int32_t injectorUid;
+ std::optional<int32_t> targetUid;
android::os::InputEventInjectionResult injectionResult; // initially PENDING
bool injectionIsAsync; // set to true if injection is not waiting for the result
int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
- InjectionState(int32_t injectorPid, int32_t injectorUid);
+ explicit InjectionState(const std::optional<int32_t>& targetUid);
void release();
private:
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6bab349..f3d0b65 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -567,6 +567,38 @@
return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy();
}
+bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int32_t uid) {
+ if (windowHandle == nullptr) {
+ return false;
+ }
+ const WindowInfo* windowInfo = windowHandle->getInfo();
+ if (pid == windowInfo->ownerPid && uid == windowInfo->ownerUid) {
+ return true;
+ }
+ return false;
+}
+
+// Checks targeted injection using the window's owner's uid.
+// Returns an empty string if an entry can be sent to the given window, or an error message if the
+// entry is a targeted injection whose uid target doesn't match the window owner.
+std::optional<std::string> verifyTargetedInjection(const sp<WindowInfoHandle>& window,
+ const EventEntry& entry) {
+ if (entry.injectionState == nullptr || !entry.injectionState->targetUid) {
+ // The event was not injected, or the injected event does not target a window.
+ return {};
+ }
+ const int32_t uid = *entry.injectionState->targetUid;
+ if (window == nullptr) {
+ return StringPrintf("No valid window target for injection into uid %d.", uid);
+ }
+ if (entry.injectionState->targetUid != window->getInfo()->ownerUid) {
+ return StringPrintf("Injected event targeted at uid %d would be dispatched to window '%s' "
+ "owned by uid %d.",
+ uid, window->getName().c_str(), window->getInfo()->ownerUid);
+ }
+ return {};
+}
+
} // namespace
// --- InputDispatcher ---
@@ -1025,6 +1057,8 @@
switch (entry.type) {
case EventEntry::Type::KEY: {
+ LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
+ "Unexpected untrusted event.");
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
@@ -1062,6 +1096,8 @@
}
case EventEntry::Type::MOTION: {
+ LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
+ "Unexpected untrusted event.");
if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) {
mNextUnblockedEvent = mInboundQueue.back();
needWake = true;
@@ -1707,8 +1743,7 @@
}
setInjectionResult(*entry, injectionResult);
- if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
- ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
+ if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) {
return true;
}
if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
@@ -1965,9 +2000,10 @@
// we have a valid, non-null focused window
resetNoFocusedWindowTimeoutLocked();
- // Check permissions.
- if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
- return InputEventInjectionResult::PERMISSION_DENIED;
+ // Verify targeted injection.
+ if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) {
+ ALOGW("Dropping injected event: %s", (*err).c_str());
+ return InputEventInjectionResult::TARGET_MISMATCH;
}
if (focusedWindowHandle->getInfo()->inputConfig.test(
@@ -2033,11 +2069,6 @@
nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
ATRACE_CALL();
- enum InjectionPermission {
- INJECTION_PERMISSION_UNKNOWN,
- INJECTION_PERMISSION_GRANTED,
- INJECTION_PERMISSION_DENIED
- };
// For security reasons, we defer updating the touch state until we are sure that
// event injection will be allowed.
@@ -2047,7 +2078,6 @@
// Update the touch state as needed based on the properties of the touch event.
InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING;
- InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
sp<WindowInfoHandle> newHoverWindowHandle(mLastHoverWindowHandle);
sp<WindowInfoHandle> newTouchedWindowHandle;
@@ -2096,7 +2126,7 @@
"in display %" PRId32,
displayId);
// TODO: test multiple simultaneous input streams.
- injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
+ injectionResult = InputEventInjectionResult::FAILED;
switchedDevice = false;
wrongDevice = true;
goto Failed;
@@ -2129,6 +2159,14 @@
newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
}
+ // Verify targeted injection.
+ if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
+ ALOGW("Dropping injected touch event: %s", (*err).c_str());
+ injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
+ newTouchedWindowHandle = nullptr;
+ goto Failed;
+ }
+
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr) {
if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2172,6 +2210,11 @@
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
const WindowInfo& info = *windowHandle->getInfo();
+ // Skip spy window targets that are not valid for targeted injection.
+ if (const auto err = verifyTargetedInjection(windowHandle, entry); err) {
+ continue;
+ }
+
if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Not sending touch event to %s because it is paused",
windowHandle->getName().c_str());
@@ -2265,6 +2308,14 @@
newTouchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus);
+ // Verify targeted injection.
+ if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
+ ALOGW("Dropping injected event: %s", (*err).c_str());
+ injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
+ newTouchedWindowHandle = nullptr;
+ goto Failed;
+ }
+
// Drop touch events if requested by input feature
if (newTouchedWindowHandle != nullptr &&
shouldDropInput(entry, newTouchedWindowHandle)) {
@@ -2356,19 +2407,26 @@
goto Failed;
}
- // Check permission to inject into all touched foreground windows.
- if (std::any_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
- [this, &entry](const TouchedWindow& touchedWindow) {
- return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 &&
- !checkInjectionPermission(touchedWindow.windowHandle,
- entry.injectionState);
- })) {
- injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
- injectionPermission = INJECTION_PERMISSION_DENIED;
- goto Failed;
+ // Ensure that all touched windows are valid for injection.
+ if (entry.injectionState != nullptr) {
+ std::string errs;
+ for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
+ if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+ // Allow ACTION_OUTSIDE events generated by targeted injection to be
+ // dispatched to any uid, since the coords will be zeroed out later.
+ continue;
+ }
+ const auto err = verifyTargetedInjection(touchedWindow.windowHandle, entry);
+ if (err) errs += "\n - " + *err;
+ }
+ if (!errs.empty()) {
+ ALOGW("Dropping targeted injection: At least one touched window is not owned by uid "
+ "%d:%s",
+ *entry.injectionState->targetUid, errs.c_str());
+ injectionResult = InputEventInjectionResult::TARGET_MISMATCH;
+ goto Failed;
+ }
}
- // Permission granted to inject into all touched foreground windows.
- injectionPermission = INJECTION_PERMISSION_GRANTED;
// Check whether windows listening for outside touches are owned by the same UID. If it is
// set the policy flag that we will not reveal coordinate information to this window.
@@ -2434,19 +2492,6 @@
tempTouchState.filterNonAsIsTouchWindows();
Failed:
- // Check injection permission once and for all.
- if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
- if (checkInjectionPermission(nullptr, entry.injectionState)) {
- injectionPermission = INJECTION_PERMISSION_GRANTED;
- } else {
- injectionPermission = INJECTION_PERMISSION_DENIED;
- }
- }
-
- if (injectionPermission != INJECTION_PERMISSION_GRANTED) {
- return injectionResult;
- }
-
// Update final pieces of touch state if the injector had permission.
if (!wrongDevice) {
if (switchedDevice) {
@@ -2644,26 +2689,6 @@
}
}
-bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle,
- const InjectionState* injectionState) {
- if (injectionState &&
- (windowHandle == nullptr ||
- windowHandle->getInfo()->ownerUid != injectionState->injectorUid) &&
- !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
- if (windowHandle != nullptr) {
- ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
- "owned by uid %d",
- injectionState->injectorPid, injectionState->injectorUid,
- windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid);
- } else {
- ALOGW("Permission denied: injecting event from pid %d uid %d",
- injectionState->injectorPid, injectionState->injectorUid);
- }
- return false;
- }
- return true;
-}
-
/**
* Indicate whether one window handle should be considered as obscuring
* another window handle. We only check a few preconditions. Actually
@@ -4182,20 +4207,20 @@
}
}
-InputEventInjectionResult InputDispatcher::injectInputEvent(
- const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
- InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
+InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event,
+ std::optional<int32_t> targetUid,
+ InputEventInjectionSync syncMode,
+ std::chrono::milliseconds timeout,
+ uint32_t policyFlags) {
if (DEBUG_INBOUND_EVENT_DETAILS) {
- ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
- event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
+ ALOGD("injectInputEvent - eventType=%d, targetUid=%s, syncMode=%d, timeout=%lld, "
+ "policyFlags=0x%08x",
+ event->getType(), targetUid ? std::to_string(*targetUid).c_str() : "none", syncMode,
+ timeout.count(), policyFlags);
}
nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
- policyFlags |= POLICY_FLAG_INJECTED;
- if (hasInjectionPermission(injectorPid, injectorUid)) {
- policyFlags |= POLICY_FLAG_TRUSTED;
- }
+ policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED;
// For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events
// that have gone through the InputFilter. If the event passed through the InputFilter, assign
@@ -4336,7 +4361,7 @@
return InputEventInjectionResult::FAILED;
}
- InjectionState* injectionState = new InjectionState(injectorPid, injectorUid);
+ InjectionState* injectionState = new InjectionState(targetUid);
if (syncMode == InputEventInjectionSync::NONE) {
injectionState->injectionIsAsync = true;
}
@@ -4408,8 +4433,7 @@
} // release lock
if (DEBUG_INJECTION) {
- ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
- injectionResult, injectorPid, injectorUid);
+ ALOGD("injectInputEvent - Finished with result %d.", injectionResult);
}
return injectionResult;
@@ -4448,19 +4472,12 @@
return result;
}
-bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
- return injectorUid == 0 ||
- mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
-}
-
void InputDispatcher::setInjectionResult(EventEntry& entry,
InputEventInjectionResult injectionResult) {
InjectionState* injectionState = entry.injectionState;
if (injectionState) {
if (DEBUG_INJECTION) {
- ALOGD("Setting input event injection result to %d. "
- "injectorPid=%d, injectorUid=%d",
- injectionResult, injectionState->injectorPid, injectionState->injectorUid);
+ ALOGD("Setting input event injection result to %d.", injectionResult);
}
if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
@@ -4469,12 +4486,12 @@
case InputEventInjectionResult::SUCCEEDED:
ALOGV("Asynchronous input event injection succeeded.");
break;
+ case InputEventInjectionResult::TARGET_MISMATCH:
+ ALOGV("Asynchronous input event injection target mismatch.");
+ break;
case InputEventInjectionResult::FAILED:
ALOGW("Asynchronous input event injection failed.");
break;
- case InputEventInjectionResult::PERMISSION_DENIED:
- ALOGW("Asynchronous input event injection permission denied.");
- break;
case InputEventInjectionResult::TIMED_OUT:
ALOGW("Asynchronous input event injection timed out.");
break;
@@ -4990,21 +5007,11 @@
toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission));
}
if (!hasPermission) {
- const sp<IBinder> focusedToken =
- mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
-
- // TODO(b/218541064): if no window is currently focused, then we need to check the last
- // interacted window (within 1 second timeout). We should allow touch mode change
- // if the last interacted window owner's pid/uid match the calling ones.
- if (focusedToken == nullptr) {
- return false;
- }
- const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
- if (windowHandle == nullptr) {
- return false;
- }
- const WindowInfo* windowInfo = windowHandle->getInfo();
- if (pid != windowInfo->ownerPid || uid != windowInfo->ownerUid) {
+ if (!focusedWindowIsOwnedByLocked(pid, uid) &&
+ !recentWindowsAreOwnedByLocked(pid, uid)) {
+ ALOGD("Touch mode switch rejected, caller (pid=%d, uid=%d) doesn't own the focused "
+ "window nor none of the previously interacted window",
+ pid, uid);
return false;
}
}
@@ -5022,6 +5029,24 @@
return true;
}
+bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) {
+ const sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
+ if (focusedToken == nullptr) {
+ return false;
+ }
+ sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
+ return isWindowOwnedBy(windowHandle, pid, uid);
+}
+
+bool InputDispatcher::recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) {
+ return std::find_if(mInteractionConnectionTokens.begin(), mInteractionConnectionTokens.end(),
+ [&](const sp<IBinder>& connectionToken) REQUIRES(mLock) {
+ const sp<WindowInfoHandle> windowHandle =
+ getWindowHandleLocked(connectionToken);
+ return isWindowOwnedBy(windowHandle, pid, uid);
+ }) != mInteractionConnectionTokens.end();
+}
+
void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
if (opacity < 0 || opacity > 1) {
LOG_ALWAYS_FATAL("Maximum obscuring opacity for touch should be >= 0 and <= 1");
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 3c79c98..a9fb5c6 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -104,7 +104,7 @@
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+ const InputEvent* event, std::optional<int32_t> targetUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) override;
@@ -275,7 +275,6 @@
// Event injection and synchronization.
std::condition_variable mInjectionResultAvailable;
- bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
void setInjectionResult(EventEntry& entry,
android::os::InputEventInjectionResult injectionResult);
void transformMotionEntryForInjectionLocked(MotionEntry&,
@@ -433,7 +432,8 @@
// Dispatcher state at time of last ANR.
std::string mLastAnrState GUARDED_BY(mLock);
- // The connection tokens of the channels that the user last interacted, for debugging
+ // The connection tokens of the channels that the user last interacted (used for debugging and
+ // when switching touch mode state).
std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> mInteractionConnectionTokens
GUARDED_BY(mLock);
void updateInteractionTokensLocked(const EventEntry& entry,
@@ -550,8 +550,6 @@
void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId)
REQUIRES(mLock);
void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
- bool checkInjectionPermission(const sp<android::gui::WindowInfoHandle>& windowHandle,
- const InjectionState* injectionState);
// Enqueue a drag event if needed, and update the touch state.
// Uses findTouchedWindowTargetsLocked to make the decision
void addDragEventLocked(const MotionEntry& entry) REQUIRES(mLock);
@@ -677,6 +675,10 @@
void traceOutboundQueueLength(const Connection& connection);
void traceWaitQueueLength(const Connection& connection);
+ // Check window ownership
+ bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
+ bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
+
sp<InputReporterInterface> mReporter;
};
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 67e1b6f..100bd18 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -68,10 +68,16 @@
* input injection to proceed.
* Returns one of the INPUT_EVENT_INJECTION_XXX constants.
*
- * This method may be called on any thread (usually by the input manager).
+ * If a targetUid is provided, InputDispatcher will only consider injecting the input event into
+ * windows owned by the provided uid. If the input event is targeted at a window that is not
+ * owned by the provided uid, input injection will fail. If no targetUid is provided, the input
+ * event will be dispatched as-is.
+ *
+ * This method may be called on any thread (usually by the input manager). The caller must
+ * perform all necessary permission checks prior to injecting events.
*/
virtual android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+ const InputEvent* event, std::optional<int32_t> targetUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) = 0;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index de0b6da..575b3d7 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -125,15 +125,6 @@
/* Poke user activity for an event dispatched to a window. */
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) = 0;
- /* Checks whether a given application pid/uid has permission to inject input events
- * into other applications.
- *
- * This method is special in that its implementation promises to be non-reentrant and
- * is safe to call while holding other locks. (Most other methods make no such guarantees!)
- */
- virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
- int32_t injectorUid) = 0;
-
/* Notifies the policy that a pointer down event has occurred outside the current focused
* window.
*
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 8641287..f15ed9e 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -45,10 +45,10 @@
using namespace ftl::flag_operators;
// An arbitrary time value.
-static const nsecs_t ARBITRARY_TIME = 1234;
+static constexpr nsecs_t ARBITRARY_TIME = 1234;
// An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
+static constexpr int32_t DEVICE_ID = 1;
// An arbitrary display id.
static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
@@ -56,12 +56,17 @@
static constexpr int32_t POINTER_1_DOWN =
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t POINTER_2_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
-// An arbitrary injector pid / uid pair that has permission to inject events.
-static const int32_t INJECTOR_PID = 999;
-static const int32_t INJECTOR_UID = 1001;
+// The default pid and uid for windows created by the test.
+static constexpr int32_t WINDOW_PID = 999;
+static constexpr int32_t WINDOW_UID = 1001;
+
+// The default policy flags to use for event injection by tests.
+static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
// An arbitrary pid of the gesture monitor window
static constexpr int32_t MONITOR_PID = 2001;
@@ -470,10 +475,6 @@
void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
- bool checkInjectEventsPermissionNonReentrant(int32_t pid, int32_t uid) override {
- return pid == INJECTOR_PID && uid == INJECTOR_UID;
- }
-
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
std::scoped_lock lock(mLock);
mOnPointerDownToken = newToken;
@@ -558,8 +559,8 @@
/*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
ARBITRARY_TIME);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject key events with undefined action.";
// Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
@@ -567,8 +568,8 @@
INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
ARBITRARY_TIME, ARBITRARY_TIME);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject key events with ACTION_MULTIPLE.";
}
@@ -597,8 +598,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with undefined action.";
// Rejects pointer down with invalid index.
@@ -609,8 +610,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer down index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -621,8 +622,8 @@
identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer down index too small.";
// Rejects pointer up with invalid index.
@@ -633,8 +634,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer up index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -645,8 +646,8 @@
identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer up index too small.";
// Rejects motion events with invalid number of pointers.
@@ -657,8 +658,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with 0 pointers.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -668,8 +669,8 @@
ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with more than MAX_POINTERS pointers.";
// Rejects motion events with invalid pointer ids.
@@ -681,8 +682,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer ids less than 0.";
pointerProperties[0].id = MAX_POINTER_ID + 1;
@@ -693,8 +694,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
// Rejects motion events with duplicate pointer ids.
@@ -707,8 +708,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with duplicate pointer ids.";
}
@@ -1011,8 +1012,8 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo.ownerPid = INJECTOR_PID;
- mInfo.ownerUid = INJECTOR_UID;
+ mInfo.ownerPid = WINDOW_PID;
+ mInfo.ownerUid = WINDOW_UID;
mInfo.displayId = displayId;
mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT;
}
@@ -1294,7 +1295,8 @@
int32_t displayId = ADISPLAY_ID_NONE,
InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
- bool allowKeyRepeat = true) {
+ bool allowKeyRepeat = true, std::optional<int32_t> targetUid = {},
+ uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
KeyEvent event;
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -1303,13 +1305,11 @@
INVALID_HMAC, action, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE,
repeatCount, currentTime, currentTime);
- int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
if (!allowKeyRepeat) {
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
// Inject event until dispatch out.
- return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, syncMode,
- injectionTimeout, policyFlags);
+ return dispatcher->injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
}
static InputEventInjectionResult injectKeyDown(const std::unique_ptr<InputDispatcher>& dispatcher,
@@ -1452,10 +1452,10 @@
static InputEventInjectionResult injectMotionEvent(
const std::unique_ptr<InputDispatcher>& dispatcher, const MotionEvent& event,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT) {
- return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, injectionMode,
- injectionTimeout,
- POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+ InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
+ std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
+ return dispatcher->injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
+ policyFlags);
}
static InputEventInjectionResult injectMotionEvent(
@@ -1465,7 +1465,8 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION},
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
- nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC)) {
+ nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
+ std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
MotionEvent event = MotionEventBuilder(action, source)
.displayId(displayId)
.eventTime(eventTime)
@@ -1477,7 +1478,8 @@
.build();
// Inject event until dispatch out.
- return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode);
+ return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode, targetUid,
+ policyFlags);
}
static InputEventInjectionResult injectMotionDown(
@@ -2245,6 +2247,53 @@
}
/**
+ * This test documents the behavior of WATCH_OUTSIDE_TOUCH. The window will get ACTION_OUTSIDE when
+ * a another pointer causes ACTION_DOWN to be sent to another window for the first time. Only one
+ * ACTION_OUTSIDE event is sent per gesture.
+ */
+TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
+ // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ window->setWatchOutsideTouch(true);
+ window->setFrame(Rect{0, 0, 100, 100});
+ sp<FakeWindowHandle> secondWindow =
+ new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ secondWindow->setFrame(Rect{100, 100, 200, 200});
+ sp<FakeWindowHandle> thirdWindow =
+ new FakeWindowHandle(application, mDispatcher, "Third Window", ADISPLAY_ID_DEFAULT);
+ thirdWindow->setFrame(Rect{200, 200, 300, 300});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, secondWindow, thirdWindow}}});
+
+ // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE.
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {PointF{-10, -10}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+ secondWindow->assertNoEvents();
+
+ // The second pointer lands inside `secondWindow`, which should receive a DOWN event.
+ // Now, `window` should get ACTION_OUTSIDE.
+ motionArgs = generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {PointF{-10, -10}, PointF{105, 105}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionOutside();
+ secondWindow->consumeMotionDown();
+ thirdWindow->assertNoEvents();
+
+ // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is
+ // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture.
+ motionArgs = generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}});
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+ secondWindow->consumeMotionMove();
+ thirdWindow->consumeMotionDown();
+}
+
+/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
* InputDispatcher works in the display space, so its coordinate system is relative to the display
@@ -3466,8 +3515,8 @@
* FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
*/
TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
- constexpr int32_t SLIPPERY_PID = INJECTOR_PID + 1;
- constexpr int32_t SLIPPERY_UID = INJECTOR_UID + 1;
+ constexpr int32_t SLIPPERY_PID = WINDOW_PID + 1;
+ constexpr int32_t SLIPPERY_UID = WINDOW_UID + 1;
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -3994,7 +4043,7 @@
const int32_t additionalPolicyFlags =
POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
policyFlags | additionalPolicyFlags));
@@ -4029,7 +4078,7 @@
const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
policyFlags | additionalPolicyFlags));
@@ -4536,7 +4585,7 @@
const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
InputEventInjectionResult result =
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ mDispatcher->injectInputEvent(&event, {} /* targetUid */,
InputEventInjectionSync::WAIT_FOR_RESULT,
INJECT_EVENT_TIMEOUT, policyFlags);
ASSERT_EQ(InputEventInjectionResult::FAILED, result)
@@ -6336,8 +6385,11 @@
mWindow->consumeFocusEvent(true);
// Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
- mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
- INJECTOR_UID, /* hasPermission */ true);
+ if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
+ WINDOW_UID, /* hasPermission */ true)) {
+ mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
+ mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
+ }
}
void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
@@ -6382,6 +6434,23 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
+ // Interact with the window first.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+
+ // Then remove focus.
+ mWindow->setFocusable(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
+
+ // Assert that caller can switch touch mode by owning one of the last interacted window.
+ const WindowInfo& windowInfo = *mWindow->getInfo();
+ ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
+ windowInfo.ownerPid, windowInfo.ownerUid,
+ /* hasPermission= */ false));
+}
+
class InputDispatcherSpyWindowTest : public InputDispatcherTest {
public:
sp<FakeWindowHandle> createSpy() {
@@ -6666,9 +6735,7 @@
// Third finger goes down outside all windows, so injection should fail.
const MotionEvent thirdFingerDownEvent =
- MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
- (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- AINPUT_SOURCE_TOUCHSCREEN)
+ MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
.displayId(ADISPLAY_ID_DEFAULT)
.eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
.pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
@@ -6950,4 +7017,149 @@
window->assertNoEvents();
}
+struct User {
+ int32_t mPid;
+ int32_t mUid;
+ uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
+ std::unique_ptr<InputDispatcher>& mDispatcher;
+
+ User(std::unique_ptr<InputDispatcher>& dispatcher, int32_t pid, int32_t uid)
+ : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
+
+ InputEventInjectionResult injectTargetedMotion(int32_t action) const {
+ return injectMotionEvent(mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {100, 200},
+ {AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION},
+ INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
+ systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
+ }
+
+ InputEventInjectionResult injectTargetedKey(int32_t action) const {
+ return inputdispatcher::injectKey(mDispatcher, action, 0 /* repeatCount*/, ADISPLAY_ID_NONE,
+ InputEventInjectionSync::WAIT_FOR_RESULT,
+ INJECT_EVENT_TIMEOUT, false /*allowKeyRepeat*/, {mUid},
+ mPolicyFlags);
+ }
+
+ sp<FakeWindowHandle> createWindow() const {
+ std::shared_ptr<FakeApplicationHandle> overlayApplication =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = new FakeWindowHandle(overlayApplication, mDispatcher,
+ "Owned Window", ADISPLAY_ID_DEFAULT);
+ window->setOwnerInfo(mPid, mUid);
+ return window;
+ }
+};
+
+using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ window->consumeMotionDown();
+
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true);
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+ window->consumeKeyDown(ADISPLAY_ID_NONE);
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ auto rando = User(mDispatcher, 20, 21);
+ EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+ rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true);
+
+ EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+ rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+ auto spy = owner.createWindow();
+ spy->setSpy(true);
+ spy->setTrustedOverlay(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ spy->consumeMotionDown();
+ window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+
+ auto rando = User(mDispatcher, 20, 21);
+ auto randosSpy = rando.createWindow();
+ randosSpy->setSpy(true);
+ randosSpy->setTrustedOverlay(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+ // The event is targeted at owner's window, so injection should succeed, but the spy should
+ // not receive the event.
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ randosSpy->assertNoEvents();
+ window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+
+ auto rando = User(mDispatcher, 20, 21);
+ auto randosSpy = rando.createWindow();
+ randosSpy->setSpy(true);
+ randosSpy->setTrustedOverlay(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+ // A user that has injection permission can inject into any window.
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT));
+ randosSpy->consumeMotionDown();
+ window->consumeMotionDown();
+
+ setFocusedWindow(randosSpy);
+ randosSpy->consumeFocusEvent(true);
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
+ randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanGenerateActionOutsideToOtherUids) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+
+ auto rando = User(mDispatcher, 20, 21);
+ auto randosWindow = rando.createWindow();
+ randosWindow->setFrame(Rect{-10, -10, -5, -5});
+ randosWindow->setWatchOutsideTouch(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosWindow, window}}});
+
+ // We allow generation of ACTION_OUTSIDE events into windows owned by different uids.
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ window->consumeMotionDown();
+ randosWindow->consumeMotionOutside();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 516c3ef..11a9e19 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -42,6 +42,10 @@
"libtonemap",
"libtrace_proto",
"libaidlcommonsupport",
+ "libprocessgroup",
+ "libcgrouprc",
+ "libjsoncpp",
+ "libcgrouprc_format",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
@@ -69,6 +73,7 @@
"src/DisplayColorProfile.cpp",
"src/DisplaySurface.cpp",
"src/DumpHelpers.cpp",
+ "src/HwcAsyncWorker.cpp",
"src/HwcBufferCache.cpp",
"src/LayerFECompositionState.cpp",
"src/Output.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index c553fce..ca86f4c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -72,6 +72,9 @@
virtual void resizeBuffers(const ui::Size&) = 0;
virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
+
+ // Returns true if the render surface supports client composition prediction.
+ virtual bool supportsCompositionStrategyPrediction() const;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index d8644a4..5846e67 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -35,6 +35,7 @@
#include <utils/Vector.h>
#include <ui/DisplayIdentification.h>
+#include "DisplayHardware/HWComposer.h"
namespace android {
@@ -54,6 +55,7 @@
namespace impl {
struct OutputCompositionState;
+struct GpuCompositionResult;
} // namespace impl
/**
@@ -262,6 +264,9 @@
// Latches the front-end layer state for each output layer
virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0;
+ // Enables predicting composition strategy to run client composition earlier
+ virtual void setPredictCompositionStrategy(bool) = 0;
+
protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
@@ -278,13 +283,22 @@
virtual void updateColorProfile(const CompositionRefreshArgs&) = 0;
virtual void beginFrame() = 0;
virtual void prepareFrame() = 0;
+
+ using GpuCompositionResult = compositionengine::impl::GpuCompositionResult;
+ // Runs prepare frame in another thread while running client composition using
+ // the previous frame's composition strategy.
+ virtual GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) = 0;
virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0;
- virtual void finishFrame(const CompositionRefreshArgs&) = 0;
+ virtual void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) = 0;
virtual std::optional<base::unique_fd> composeSurfaces(
- const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) = 0;
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&) = 0;
virtual void postFramebuffer() = 0;
virtual void renderCachedSets(const CompositionRefreshArgs&) = 0;
- virtual void chooseCompositionStrategy() = 0;
+ virtual bool chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*) = 0;
+ virtual void applyCompositionStrategy(
+ const std::optional<android::HWComposer::DeviceRequestedChanges>& changes) = 0;
virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
virtual std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
@@ -295,6 +309,7 @@
std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
virtual void setExpensiveRenderingExpected(bool enabled) = 0;
virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
+ virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index daee83b..9ee779c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -100,6 +100,9 @@
// Debugging - gets the page flip count for the RenderSurface
virtual std::uint32_t getPageFlipCount() const = 0;
+
+ // Returns true if the render surface supports client composition prediction.
+ virtual bool supportsCompositionStrategyPrediction() const = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index e12d1b4..61a0e6a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -22,6 +22,7 @@
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/GpuCompositionResult.h>
#include <compositionengine/impl/Output.h>
#include <ui/PixelFormat.h>
#include <ui/Size.h>
@@ -51,11 +52,16 @@
void setReleasedLayers(const CompositionRefreshArgs&) override;
void setColorTransform(const CompositionRefreshArgs&) override;
void setColorProfile(const ColorProfile&) override;
- void chooseCompositionStrategy() override;
+
+ void beginFrame() override;
+ using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges;
+ bool chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*) override;
+ void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
void setExpensiveRenderingExpected(bool) override;
- void finishFrame(const CompositionRefreshArgs&) override;
+ void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override;
// compositionengine::Display overrides
DisplayId getId() const override;
@@ -72,12 +78,11 @@
using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests;
using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests;
using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty;
- virtual bool anyLayersRequireClientComposition() const;
virtual bool allLayersRequireClientComposition() const;
virtual void applyChangedTypesToLayers(const ChangedTypes&);
virtual void applyDisplayRequests(const DisplayRequests&);
virtual void applyLayerRequestsToLayers(const LayerRequests&);
- virtual void applyClientTargetRequests(const ClientTargetProperty&, float brightness);
+ virtual void applyClientTargetRequests(const ClientTargetProperty&);
// Internal
virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h
new file mode 100644
index 0000000..2b1f50f
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android::compositionengine::impl {
+
+struct GpuCompositionResult {
+ // Composition ready fence.
+ base::unique_fd fence{};
+
+ // Buffer to be used for gpu composition. If gpu composition was not successful,
+ // then we want to reuse the buffer instead of dequeuing another buffer.
+ std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
+
+ bool bufferAvailable() const { return buffer != nullptr; };
+};
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h
new file mode 100644
index 0000000..0c7da6c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <future>
+#include <optional>
+#include <thread>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine::impl {
+
+// HWC Validate call may take multiple milliseconds to complete and can account for
+// a signification amount of time in the display hotpath. This helper class allows
+// us to run the hwc validate function on a real time thread if we can predict what
+// the composition strategy will be and if composition includes client composition.
+// While the hwc validate runs, client composition is kicked off with the prediction.
+// When the worker returns with a value, the composition continues if the prediction
+// was successful otherwise the client composition is re-executed.
+//
+// Note: This does not alter the sequence between HWC and surfaceflinger.
+class HwcAsyncWorker final {
+public:
+ HwcAsyncWorker();
+ ~HwcAsyncWorker();
+ // Runs the provided function which calls hwc validate and returns the requested
+ // device changes as a future.
+ std::future<bool> send(std::function<bool()>);
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mCv GUARDED_BY(mMutex);
+ bool mDone GUARDED_BY(mMutex) = false;
+ bool mTaskRequested GUARDED_BY(mMutex) = false;
+ std::packaged_task<bool()> mTask GUARDED_BY(mMutex);
+ std::thread mThread;
+ void run();
+};
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index a7a8e97..0feb9f7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -17,9 +17,13 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/Output.h>
#include <compositionengine/impl/ClientCompositionRequestCache.h>
+#include <compositionengine/impl/GpuCompositionResult.h>
+#include <compositionengine/impl/HwcAsyncWorker.h>
#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/impl/planner/Planner.h>
#include <renderengine/DisplaySettings.h>
#include <renderengine/LayerSettings.h>
@@ -92,25 +96,42 @@
void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
void beginFrame() override;
void prepareFrame() override;
+ GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) override;
void devOptRepaintFlash(const CompositionRefreshArgs&) override;
- void finishFrame(const CompositionRefreshArgs&) override;
- std::optional<base::unique_fd> composeSurfaces(
- const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) override;
+ void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override;
+ std::optional<base::unique_fd> composeSurfaces(const Region&,
+ const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>,
+ base::unique_fd&) override;
void postFramebuffer() override;
void renderCachedSets(const CompositionRefreshArgs&) override;
void cacheClientCompositionRequests(uint32_t) override;
+ bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override;
+ void setPredictCompositionStrategy(bool) override;
// Testing
const ReleasedLayers& getReleasedLayersForTest() const;
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
bool plannerEnabled() const { return mPlanner != nullptr; }
+ virtual bool anyLayersRequireClientComposition() const;
+ virtual void updateProtectedContentState();
+ virtual bool dequeueRenderBuffer(base::unique_fd*,
+ std::shared_ptr<renderengine::ExternalTexture>*);
+ virtual std::future<bool> chooseCompositionStrategyAsync(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*);
+ virtual void resetCompositionStrategy();
protected:
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
std::optional<size_t> findCurrentOutputLayerForLayer(
const sp<compositionengine::LayerFE>&) const;
- void chooseCompositionStrategy() override;
+ using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges;
+ bool chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>*) override {
+ return true;
+ };
+ void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override{};
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
@@ -131,6 +152,7 @@
private:
void dirtyEntireOutput();
compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const;
+ void finishPrepareFrame();
ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
compositionengine::Output::ColorProfile pickColorProfile(
const compositionengine::CompositionRefreshArgs&) const;
@@ -144,6 +166,7 @@
OutputLayer* mLayerRequestingBackgroundBlur = nullptr;
std::unique_ptr<ClientCompositionRequestCache> mClientCompositionRequestCache;
std::unique_ptr<planner::Planner> mPlanner;
+ std::unique_ptr<HwcAsyncWorker> mHwComposerAsyncWorker;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 66dd825..5fa0d67 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include "aidl/android/hardware/graphics/composer3/DimmingStage.h"
#include <math/mat4.h>
#include <ui/FenceTime.h>
@@ -37,6 +38,8 @@
#include <ui/Region.h>
#include <ui/Transform.h>
+#include "DisplayHardware/HWComposer.h"
+
namespace android {
namespace compositionengine::impl {
@@ -114,6 +117,10 @@
// Current target dataspace
ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
+ std::optional<android::HWComposer::DeviceRequestedChanges> previousDeviceRequestedChanges{};
+
+ bool previousDeviceRequestedSuccess = false;
+
// The earliest time to send the present command to the HAL
std::chrono::steady_clock::time_point earliestPresentTime;
@@ -133,10 +140,26 @@
// Brightness of the client target, normalized to display brightness
float clientTargetBrightness{1.f};
+ // Stage in which the client target should apply dimming
+ aidl::android::hardware::graphics::composer3::DimmingStage clientTargetDimmingStage{
+ aidl::android::hardware::graphics::composer3::DimmingStage::NONE};
+
// Display brightness that will take effect this frame.
// This is slightly distinct from nits, in that nits cannot be passed to hw composer.
std::optional<float> displayBrightness = std::nullopt;
+ enum class CompositionStrategyPredictionState : uint32_t {
+ // Composition strategy prediction did not run for this frame.
+ DISABLED = 0,
+ // Composition strategy predicted successfully for this frame.
+ SUCCESS = 1,
+ // Composition strategy prediction failed for this frame.
+ FAIL = 2,
+ };
+
+ CompositionStrategyPredictionState strategyPrediction =
+ CompositionStrategyPredictionState::DISABLED;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index a8a5380..e4cb113 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -63,6 +63,7 @@
void queueBuffer(base::unique_fd readyFence) override;
void onPresentDisplayCompleted() override;
void flip() override;
+ bool supportsCompositionStrategyPrediction() const override;
// Debugging
void dump(std::string& result) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index d90cc90..72e6f3b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -41,6 +41,7 @@
MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
+ MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index b68b95d..fa86076 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -22,6 +22,7 @@
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/GpuCompositionResult.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <gmock/gmock.h>
@@ -99,16 +100,24 @@
MOCK_METHOD0(beginFrame, void());
MOCK_METHOD0(prepareFrame, void());
- MOCK_METHOD0(chooseCompositionStrategy, void());
+ MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&));
+ MOCK_METHOD1(chooseCompositionStrategy,
+ bool(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD1(chooseCompositionStrategyAsync,
+ std::future<bool>(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD1(applyCompositionStrategy,
+ void(const std::optional<android::HWComposer::DeviceRequestedChanges>&));
MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD2(finishFrame,
+ void(const compositionengine::CompositionRefreshArgs&, GpuCompositionResult&&));
- MOCK_METHOD2(composeSurfaces,
+ MOCK_METHOD4(composeSurfaces,
std::optional<base::unique_fd>(
const Region&,
- const compositionengine::CompositionRefreshArgs& refreshArgs));
+ const compositionengine::CompositionRefreshArgs& refreshArgs,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
MOCK_CONST_METHOD0(getSkipColorTransform, bool());
MOCK_METHOD0(postFramebuffer, void());
@@ -121,6 +130,8 @@
void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t));
+ MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
+ MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index fe858c2..e12aebb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -45,6 +45,7 @@
MOCK_METHOD0(flip, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
+ MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 2165e1d..84c22cf 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -207,16 +207,8 @@
setReleasedLayers(std::move(releasedLayers));
}
-void Display::chooseCompositionStrategy() {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
- if (mIsDisconnected) {
- return;
- }
-
- // Default to the base settings -- client composition only.
- Output::chooseCompositionStrategy();
+void Display::beginFrame() {
+ Output::beginFrame();
// If we don't have a HWC display, then we are done.
const auto halDisplayId = HalDisplayId::tryCast(mId);
@@ -224,8 +216,6 @@
return;
}
- // Get any composition changes requested by the HWC device, and apply them.
- std::optional<android::HWComposer::DeviceRequestedChanges> changes;
auto& hwc = getCompositionEngine().getHwComposer();
if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
physicalDisplayId && getState().displayBrightness) {
@@ -237,30 +227,54 @@
ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
getName().c_str(), result, strerror(-result));
}
+ // Clear out the display brightness now that it's been communicated to composer.
+ editState().displayBrightness.reset();
+}
+bool Display::chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (mIsDisconnected) {
+ return false;
+ }
+
+ // If we don't have a HWC display, then we are done.
+ const auto halDisplayId = HalDisplayId::tryCast(mId);
+ if (!halDisplayId) {
+ return false;
+ }
+
+ // Get any composition changes requested by the HWC device, and apply them.
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ auto& hwc = getCompositionEngine().getHwComposer();
if (status_t result =
hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
getState().earliestPresentTime,
getState().previousPresentFence,
- getState().expectedPresentTime, &changes);
+ getState().expectedPresentTime, outChanges);
result != NO_ERROR) {
ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
strerror(-result));
- return;
+ return false;
}
+
+ return true;
+}
+
+void Display::applyCompositionStrategy(const std::optional<DeviceRequestedChanges>& changes) {
if (changes) {
applyChangedTypesToLayers(changes->changedTypes);
applyDisplayRequests(changes->displayRequests);
applyLayerRequestsToLayers(changes->layerRequests);
- applyClientTargetRequests(changes->clientTargetProperty, changes->clientTargetBrightness);
+ applyClientTargetRequests(changes->clientTargetProperty);
}
// Determine what type of composition we are doing from the final state
auto& state = editState();
state.usesClientComposition = anyLayersRequireClientComposition();
state.usesDeviceComposition = !allLayersRequireClientComposition();
- // Clear out the display brightness now that it's been communicated to composer.
- state.displayBrightness.reset();
}
bool Display::getSkipColorTransform() const {
@@ -273,12 +287,6 @@
return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM);
}
-bool Display::anyLayersRequireClientComposition() const {
- const auto layers = getOutputLayersOrderedByZ();
- return std::any_of(layers.begin(), layers.end(),
- [](const auto& layer) { return layer->requiresClientComposition(); });
-}
-
bool Display::allLayersRequireClientComposition() const {
const auto layers = getOutputLayersOrderedByZ();
return std::all_of(layers.begin(), layers.end(),
@@ -327,16 +335,19 @@
}
}
-void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty,
- float brightness) {
- if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
+void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty) {
+ if (static_cast<ui::Dataspace>(clientTargetProperty.clientTargetProperty.dataspace) ==
+ ui::Dataspace::UNKNOWN) {
return;
}
- editState().dataspace = clientTargetProperty.dataspace;
- editState().clientTargetBrightness = brightness;
- getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
- getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
+ editState().dataspace =
+ static_cast<ui::Dataspace>(clientTargetProperty.clientTargetProperty.dataspace);
+ editState().clientTargetBrightness = clientTargetProperty.brightness;
+ editState().clientTargetDimmingStage = clientTargetProperty.dimmingStage;
+ getRenderSurface()->setBufferDataspace(editState().dataspace);
+ getRenderSurface()->setBufferPixelFormat(
+ static_cast<ui::PixelFormat>(clientTargetProperty.clientTargetProperty.pixelFormat));
}
compositionengine::Output::FrameFences Display::presentAndGetFrameFences() {
@@ -376,7 +387,8 @@
}
}
-void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ GpuCompositionResult&& result) {
// 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
@@ -386,7 +398,7 @@
return;
}
- impl::Output::finishFrame(refreshArgs);
+ impl::Output::finishFrame(refreshArgs, std::move(result));
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
index db6d4f2..28900af 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
@@ -20,4 +20,8 @@
DisplaySurface::~DisplaySurface() = default;
+bool DisplaySurface::supportsCompositionStrategyPrediction() const {
+ return true;
+}
+
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
new file mode 100644
index 0000000..6086f0b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 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 <compositionengine/impl/HwcAsyncWorker.h>
+#include <processgroup/sched_policy.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <system/thread_defs.h>
+
+#include <android-base/thread_annotations.h>
+#include <cutils/sched_policy.h>
+
+namespace android::compositionengine::impl {
+
+HwcAsyncWorker::HwcAsyncWorker() {
+ mThread = std::thread(&HwcAsyncWorker::run, this);
+ pthread_setname_np(mThread.native_handle(), "HwcAsyncWorker");
+}
+
+HwcAsyncWorker::~HwcAsyncWorker() {
+ {
+ std::scoped_lock lock(mMutex);
+ mDone = true;
+ mCv.notify_all();
+ }
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+std::future<bool> HwcAsyncWorker::send(std::function<bool()> task) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ android::base::ScopedLockAssertion assumeLock(mMutex);
+ mTask = std::packaged_task<bool()>([task = std::move(task)]() { return task(); });
+ mTaskRequested = true;
+ mCv.notify_one();
+ return mTask.get_future();
+}
+
+void HwcAsyncWorker::run() {
+ set_sched_policy(0, SP_FOREGROUND);
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ sched_setscheduler(gettid(), SCHED_FIFO, ¶m);
+
+ std::unique_lock<std::mutex> lock(mMutex);
+ android::base::ScopedLockAssertion assumeLock(mMutex);
+ while (!mDone) {
+ mCv.wait(lock);
+ if (mTaskRequested && mTask.valid()) {
+ mTask();
+ mTaskRequested = false;
+ }
+ }
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 4e67a63..e99b70f 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -22,6 +22,7 @@
#include <compositionengine/LayerFE.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/HwcAsyncWorker.h>
#include <compositionengine/impl/Output.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayer.h>
@@ -57,7 +58,8 @@
Output::~Output() = default;
namespace impl {
-
+using CompositionStrategyPredictionState =
+ OutputCompositionState::CompositionStrategyPredictionState;
namespace {
template <typename T>
@@ -434,9 +436,17 @@
writeCompositionState(refreshArgs);
setColorTransform(refreshArgs);
beginFrame();
- prepareFrame();
+
+ GpuCompositionResult result;
+ const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs);
+ if (predictCompositionStrategy) {
+ result = prepareFrameAsync(refreshArgs);
+ } else {
+ prepareFrame();
+ }
+
devOptRepaintFlash(refreshArgs);
- finishFrame(refreshArgs);
+ finishFrame(refreshArgs, std::move(result));
postFramebuffer();
renderCachedSets(refreshArgs);
}
@@ -953,19 +963,74 @@
ATRACE_CALL();
ALOGV(__FUNCTION__);
- const auto& outputState = getState();
+ auto& outputState = editState();
if (!outputState.isEnabled) {
return;
}
- chooseCompositionStrategy();
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ bool success = chooseCompositionStrategy(&changes);
+ resetCompositionStrategy();
+ outputState.strategyPrediction = CompositionStrategyPredictionState::DISABLED;
+ outputState.previousDeviceRequestedChanges = changes;
+ outputState.previousDeviceRequestedSuccess = success;
+ if (success) {
+ applyCompositionStrategy(changes);
+ }
+ finishPrepareFrame();
+}
- if (mPlanner) {
- mPlanner->reportFinalPlan(getOutputLayersOrderedByZ());
+std::future<bool> Output::chooseCompositionStrategyAsync(
+ std::optional<android::HWComposer::DeviceRequestedChanges>* changes) {
+ return mHwComposerAsyncWorker->send(
+ [&, changes]() { return chooseCompositionStrategy(changes); });
+}
+
+GpuCompositionResult Output::prepareFrameAsync(const CompositionRefreshArgs& refreshArgs) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+ auto& state = editState();
+ const auto& previousChanges = state.previousDeviceRequestedChanges;
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ resetCompositionStrategy();
+ auto hwcResult = chooseCompositionStrategyAsync(&changes);
+ if (state.previousDeviceRequestedSuccess) {
+ applyCompositionStrategy(previousChanges);
+ }
+ finishPrepareFrame();
+
+ base::unique_fd bufferFence;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ updateProtectedContentState();
+ const bool dequeueSucceeded = dequeueRenderBuffer(&bufferFence, &buffer);
+ GpuCompositionResult compositionResult;
+ if (dequeueSucceeded) {
+ std::optional<base::unique_fd> optFd =
+ composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence);
+ if (optFd) {
+ compositionResult.fence = std::move(*optFd);
+ }
}
- mRenderSurface->prepareFrame(outputState.usesClientComposition,
- outputState.usesDeviceComposition);
+ auto chooseCompositionSuccess = hwcResult.get();
+ const bool predictionSucceeded = dequeueSucceeded && changes == previousChanges;
+ state.strategyPrediction = predictionSucceeded ? CompositionStrategyPredictionState::SUCCESS
+ : CompositionStrategyPredictionState::FAIL;
+ if (!predictionSucceeded) {
+ ATRACE_NAME("CompositionStrategyPredictionMiss");
+ resetCompositionStrategy();
+ if (chooseCompositionSuccess) {
+ applyCompositionStrategy(changes);
+ }
+ finishPrepareFrame();
+ // Track the dequeued buffer to reuse so we don't need to dequeue another one.
+ compositionResult.buffer = buffer;
+ } else {
+ ATRACE_NAME("CompositionStrategyPredictionHit");
+ }
+ state.previousDeviceRequestedChanges = std::move(changes);
+ state.previousDeviceRequestedSuccess = chooseCompositionSuccess;
+ return compositionResult;
}
void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) {
@@ -975,7 +1040,11 @@
if (getState().isEnabled) {
if (const auto dirtyRegion = getDirtyRegion(); !dirtyRegion.isEmpty()) {
- static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs));
+ base::unique_fd bufferFence;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ updateProtectedContentState();
+ dequeueRenderBuffer(&bufferFence, &buffer);
+ static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs, buffer, bufferFence));
mRenderSurface->queueBuffer(base::unique_fd());
}
}
@@ -987,17 +1056,33 @@
prepareFrame();
}
-void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositionResult&& result) {
ATRACE_CALL();
ALOGV(__FUNCTION__);
-
- if (!getState().isEnabled) {
+ const auto& outputState = getState();
+ if (!outputState.isEnabled) {
return;
}
- // Repaint the framebuffer (if needed), getting the optional fence for when
- // the composition completes.
- auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs);
+ std::optional<base::unique_fd> optReadyFence;
+ std::shared_ptr<renderengine::ExternalTexture> buffer;
+ base::unique_fd bufferFence;
+ if (outputState.strategyPrediction == CompositionStrategyPredictionState::SUCCESS) {
+ optReadyFence = std::move(result.fence);
+ } else {
+ if (result.bufferAvailable()) {
+ buffer = std::move(result.buffer);
+ bufferFence = std::move(result.fence);
+ } else {
+ updateProtectedContentState();
+ if (!dequeueRenderBuffer(&bufferFence, &buffer)) {
+ return;
+ }
+ }
+ // Repaint the framebuffer (if needed), getting the optional fence for when
+ // the composition completes.
+ optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence);
+ }
if (!optReadyFence) {
return;
}
@@ -1006,16 +1091,8 @@
mRenderSurface->queueBuffer(std::move(*optReadyFence));
}
-std::optional<base::unique_fd> Output::composeSurfaces(
- const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs) {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
+void Output::updateProtectedContentState() {
const auto& outputState = getState();
- OutputCompositionState& outputCompositionState = editState();
- const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
- outputState.usesClientComposition};
-
auto& renderEngine = getCompositionEngine().getRenderEngine();
const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
@@ -1037,29 +1114,48 @@
} else if (!outputState.isSecure && renderEngine.isProtected()) {
renderEngine.useProtectedContext(false);
}
+}
- base::unique_fd fd;
-
- std::shared_ptr<renderengine::ExternalTexture> tex;
+bool Output::dequeueRenderBuffer(base::unique_fd* bufferFence,
+ std::shared_ptr<renderengine::ExternalTexture>* tex) {
+ const auto& outputState = getState();
// If we aren't doing client composition on this output, but do have a
// flipClientTarget request for this frame on this output, we still need to
// dequeue a buffer.
- if (hasClientComposition || outputState.flipClientTarget) {
- tex = mRenderSurface->dequeueBuffer(&fd);
- if (tex == nullptr) {
+ if (outputState.usesClientComposition || outputState.flipClientTarget) {
+ *tex = mRenderSurface->dequeueBuffer(bufferFence);
+ if (*tex == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
mName.c_str());
- return {};
+ return false;
}
}
+ return true;
+}
+std::optional<base::unique_fd> Output::composeSurfaces(
+ const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs,
+ std::shared_ptr<renderengine::ExternalTexture> tex, base::unique_fd& fd) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ const auto& outputState = getState();
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ outputState.usesClientComposition};
if (!hasClientComposition) {
setExpensiveRenderingExpected(false);
return base::unique_fd();
}
+ if (tex == nullptr) {
+ ALOGW("Buffer not valid for display [%s], bailing out of "
+ "client composition for this frame",
+ mName.c_str());
+ return {};
+ }
+
ALOGV("hasClientComposition");
renderengine::DisplaySettings clientCompositionDisplay;
@@ -1080,6 +1176,7 @@
mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
clientCompositionDisplay.targetLuminanceNits =
outputState.clientTargetBrightness * outputState.displayBrightnessNits;
+ clientCompositionDisplay.dimmingStage = outputState.clientTargetDimmingStage;
// Compute the global color transform matrix.
clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
@@ -1087,6 +1184,8 @@
outputState.usesDeviceComposition || getSkipColorTransform();
// Generate the client composition requests for the layers on this output.
+ auto& renderEngine = getCompositionEngine().getRenderEngine();
+ const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
std::vector<LayerFE*> clientCompositionLayersFE;
std::vector<LayerFE::LayerSettings> clientCompositionLayers =
generateClientCompositionRequests(supportsProtectedContent,
@@ -1094,16 +1193,19 @@
clientCompositionLayersFE);
appendRegionFlashRequests(debugRegion, clientCompositionLayers);
+ OutputCompositionState& outputCompositionState = editState();
// Check if the client composition requests were rendered into the provided graphic buffer. If
// so, we can reuse the buffer and avoid client composition.
if (mClientCompositionRequestCache) {
if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(),
clientCompositionDisplay,
clientCompositionLayers)) {
+ ATRACE_NAME("ClientCompositionCacheHit");
outputCompositionState.reusedClientComposition = true;
setExpensiveRenderingExpected(false);
return base::unique_fd();
}
+ ATRACE_NAME("ClientCompositionCacheMiss");
mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
clientCompositionLayers);
}
@@ -1355,7 +1457,7 @@
outputState.dirtyRegion.set(outputState.displaySpace.getBoundsAsRect());
}
-void Output::chooseCompositionStrategy() {
+void Output::resetCompositionStrategy() {
// The base output implementation can only do client composition
auto& outputState = editState();
outputState.usesClientComposition = true;
@@ -1375,5 +1477,63 @@
return result;
}
+void Output::setPredictCompositionStrategy(bool predict) {
+ if (predict) {
+ mHwComposerAsyncWorker = std::make_unique<HwcAsyncWorker>();
+ } else {
+ mHwComposerAsyncWorker.reset(nullptr);
+ }
+}
+
+bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
+ if (!getState().isEnabled || !mHwComposerAsyncWorker) {
+ ALOGV("canPredictCompositionStrategy disabled");
+ return false;
+ }
+
+ if (!getState().previousDeviceRequestedChanges) {
+ ALOGV("canPredictCompositionStrategy previous changes not available");
+ return false;
+ }
+
+ if (!mRenderSurface->supportsCompositionStrategyPrediction()) {
+ ALOGV("canPredictCompositionStrategy surface does not support");
+ return false;
+ }
+
+ if (refreshArgs.devOptFlashDirtyRegionsDelay) {
+ ALOGV("canPredictCompositionStrategy devOptFlashDirtyRegionsDelay");
+ return false;
+ }
+
+ // If no layer uses clientComposition, then don't predict composition strategy
+ // because we have less work to do in parallel.
+ if (!anyLayersRequireClientComposition()) {
+ ALOGV("canPredictCompositionStrategy no layer uses clientComposition");
+ return false;
+ }
+
+ if (!refreshArgs.updatingOutputGeometryThisFrame) {
+ return true;
+ }
+
+ ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame");
+ return false;
+}
+
+bool Output::anyLayersRequireClientComposition() const {
+ const auto layers = getOutputLayersOrderedByZ();
+ return std::any_of(layers.begin(), layers.end(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+void Output::finishPrepareFrame() {
+ const auto& state = getState();
+ if (mPlanner) {
+ mPlanner->reportFinalPlan(getOutputLayersOrderedByZ());
+ }
+ mRenderSurface->prepareFrame(state.usesClientComposition, state.usesDeviceComposition);
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 482250a..7188281 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -18,6 +18,19 @@
#include <compositionengine/impl/OutputCompositionState.h>
namespace android::compositionengine::impl {
+using CompositionStrategyPredictionState =
+ OutputCompositionState::CompositionStrategyPredictionState;
+
+std::string toString(CompositionStrategyPredictionState state) {
+ switch (state) {
+ case CompositionStrategyPredictionState::DISABLED:
+ return "Disabled";
+ case CompositionStrategyPredictionState::SUCCESS:
+ return "Success";
+ case CompositionStrategyPredictionState::FAIL:
+ return "Fail";
+ }
+}
void OutputCompositionState::dump(std::string& out) const {
out.append(" ");
@@ -56,6 +69,7 @@
dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
dumpVal(out, "displayBrightness", displayBrightness);
+ dumpVal(out, "compositionStrategyPredictionState", toString(strategyPrediction));
out.append("\n");
}
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 12c2c8e..5a3af7b 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -289,5 +289,9 @@
return mTexture;
}
+bool RenderSurface::supportsCompositionStrategyPrediction() const {
+ return mDisplaySurface->supportsCompositionStrategyPrediction();
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 5cc0f97..9a61667 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -30,7 +30,9 @@
#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
+
#include <ui/Rect.h>
#include <ui/StaticDisplayInfo.h>
@@ -43,6 +45,7 @@
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::Composition;
+using aidl::android::hardware::graphics::composer3::DimmingStage;
namespace android::compositionengine {
namespace {
@@ -113,8 +116,9 @@
return mCompositionEngine;
};
+ size_t getOutputLayerCount() const override { return 1u; }
+
// Mock implementation overrides
- MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex,
compositionengine::OutputLayer*(size_t));
MOCK_METHOD2(ensureOutputLayer,
@@ -197,6 +201,26 @@
std::shared_ptr<Display> mDisplay =
createPartialMockDisplay<Display>(mCompositionEngine,
getDisplayCreationArgsForPhysicalDisplay());
+
+ android::HWComposer::DeviceRequestedChanges mDeviceRequestedChanges{
+ {{nullptr, Composition::CLIENT}},
+ hal::DisplayRequest::FLIP_CLIENT_TARGET,
+ {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
+ {DEFAULT_DISPLAY_ID.value,
+ {aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888,
+ aidl::android::hardware::graphics::common::Dataspace::UNKNOWN},
+ -1.f,
+ DimmingStage::NONE},
+ };
+
+ void chooseCompositionStrategy(Display* display) {
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ bool success = display->chooseCompositionStrategy(&changes);
+ display->resetCompositionStrategy();
+ if (success) {
+ display->applyCompositionStrategy(changes);
+ }
+ }
};
struct FullDisplayImplTestCommon : public DisplayTestCommon {
@@ -213,6 +237,11 @@
std::unique_ptr<compositionengine::OutputLayer>(mLayer2.outputLayer));
mDisplay->injectOutputLayerForTest(
std::unique_ptr<compositionengine::OutputLayer>(mLayer3.outputLayer));
+ mResultWithBuffer.buffer = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
}
Layer mLayer1;
@@ -221,6 +250,8 @@
StrictMock<HWC2::mock::Layer> hwc2LayerUnknown;
std::shared_ptr<Display> mDisplay =
createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
+ impl::GpuCompositionResult mResultWithBuffer;
+ impl::GpuCompositionResult mResultWithoutBuffer;
};
/*
@@ -553,7 +584,7 @@
createPartialMockDisplay<Display>(mCompositionEngine, args);
EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId()));
- gpuDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(gpuDisplay.get());
auto& state = gpuDisplay->getState();
EXPECT_TRUE(state.usesClientComposition);
@@ -566,11 +597,12 @@
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _, _))
.WillOnce(Return(INVALID_OPERATION));
- mDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(mDisplay.get());
auto& state = mDisplay->getState();
EXPECT_TRUE(state.usesClientComposition);
EXPECT_FALSE(state.usesDeviceComposition);
+ EXPECT_FALSE(state.previousDeviceRequestedChanges.has_value());
}
TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
@@ -587,10 +619,16 @@
EXPECT_CALL(mHwComposer,
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(Return(NO_ERROR));
+ .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges),
+ Return(NO_ERROR)));
+ EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
+ .Times(1);
+ EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
+ EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
+ .Times(1);
EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
- mDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(mDisplay.get());
auto& state = mDisplay->getState();
EXPECT_FALSE(state.usesClientComposition);
@@ -602,42 +640,23 @@
// values, use a Sequence to control the matching so the values are returned in a known
// order.
constexpr float kDisplayBrightness = 0.5f;
- Sequence s;
- EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
- .InSequence(s)
- .WillOnce(Return(true));
- EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
- .InSequence(s)
- .WillOnce(Return(false));
EXPECT_CALL(mHwComposer,
setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness,
Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately =
false}))
.WillOnce(Return(ByMove(ftl::yield<status_t>(NO_ERROR))));
- EXPECT_CALL(mHwComposer,
- getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
-
mDisplay->setNextBrightness(kDisplayBrightness);
- mDisplay->chooseCompositionStrategy();
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ EXPECT_CALL(*renderSurface, beginFrame(_)).Times(1);
+ mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+ mDisplay->beginFrame();
auto& state = mDisplay->getState();
- EXPECT_FALSE(state.usesClientComposition);
- EXPECT_TRUE(state.usesDeviceComposition);
EXPECT_FALSE(state.displayBrightness.has_value());
}
TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
- android::HWComposer::DeviceRequestedChanges changes{
- {{nullptr, Composition::CLIENT}},
- hal::DisplayRequest::FLIP_CLIENT_TARGET,
- {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
- {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
- -1.f,
- };
-
// Since two calls are made to anyLayersRequireClientComposition with different return
// values, use a Sequence to control the matching so the values are returned in a known
// order.
@@ -651,13 +670,15 @@
EXPECT_CALL(mHwComposer,
getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
- .WillOnce(DoAll(SetArgPointee<5>(changes), Return(NO_ERROR)));
- EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1);
- EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1);
- EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1);
+ .WillOnce(DoAll(SetArgPointee<5>(mDeviceRequestedChanges), Return(NO_ERROR)));
+ EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes))
+ .Times(1);
+ EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1);
+ EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests))
+ .Times(1);
EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
- mDisplay->chooseCompositionStrategy();
+ chooseCompositionStrategy(mDisplay.get());
auto& state = mDisplay->getState();
EXPECT_FALSE(state.usesClientComposition);
@@ -822,23 +843,37 @@
using DisplayApplyClientTargetRequests = DisplayWithLayersTestCommon;
TEST_F(DisplayApplyLayerRequestsToLayersTest, applyClientTargetRequests) {
- Display::ClientTargetProperty clientTargetProperty = {
- .pixelFormat = hal::PixelFormat::RGB_565,
- .dataspace = hal::Dataspace::STANDARD_BT470M,
- };
-
static constexpr float kWhitePointNits = 800.f;
+ Display::ClientTargetProperty clientTargetProperty = {
+ .clientTargetProperty =
+ {
+ .pixelFormat =
+ aidl::android::hardware::graphics::common::PixelFormat::RGB_565,
+ .dataspace = aidl::android::hardware::graphics::common::Dataspace::
+ STANDARD_BT470M,
+ },
+ .brightness = kWhitePointNits,
+ .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ };
+
mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
- EXPECT_CALL(*renderSurface, setBufferPixelFormat(clientTargetProperty.pixelFormat));
- EXPECT_CALL(*renderSurface, setBufferDataspace(clientTargetProperty.dataspace));
- mDisplay->applyClientTargetRequests(clientTargetProperty, kWhitePointNits);
+ EXPECT_CALL(*renderSurface,
+ setBufferPixelFormat(static_cast<ui::PixelFormat>(
+ clientTargetProperty.clientTargetProperty.pixelFormat)));
+ EXPECT_CALL(*renderSurface,
+ setBufferDataspace(static_cast<ui::Dataspace>(
+ clientTargetProperty.clientTargetProperty.dataspace)));
+ mDisplay->applyClientTargetRequests(clientTargetProperty);
auto& state = mDisplay->getState();
- EXPECT_EQ(clientTargetProperty.dataspace, state.dataspace);
+ EXPECT_EQ(clientTargetProperty.clientTargetProperty.dataspace,
+ static_cast<aidl::android::hardware::graphics::common::Dataspace>(state.dataspace));
EXPECT_EQ(kWhitePointNits, state.clientTargetBrightness);
+ EXPECT_EQ(aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ state.clientTargetDimmingStage);
}
/*
@@ -921,7 +956,7 @@
mDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
mDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- mDisplay->finishFrame({});
+ mDisplay->finishFrame({}, std::move(mResultWithBuffer));
}
TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) {
@@ -939,7 +974,7 @@
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- gpuDisplay->finishFrame({});
+ gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer));
}
TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) {
@@ -956,7 +991,7 @@
gpuDisplay->editState().usesClientComposition = false;
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
- gpuDisplay->finishFrame({});
+ gpuDisplay->finishFrame({}, std::move(mResultWithBuffer));
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index dd3858b..31a89af 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -28,6 +28,7 @@
#include <gtest/gtest.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/impl/ExternalTexture.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -73,6 +74,9 @@
constexpr OutputColorSetting kVendorSpecifiedOutputColorSetting =
static_cast<OutputColorSetting>(0x100);
+using CompositionStrategyPredictionState = android::compositionengine::impl::
+ OutputCompositionState::CompositionStrategyPredictionState;
+
struct OutputPartialMockBase : public impl::Output {
// compositionengine::Output overrides
const OutputCompositionState& getState() const override { return mState; }
@@ -989,7 +993,9 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_METHOD0(chooseCompositionStrategy, void());
+ MOCK_METHOD1(chooseCompositionStrategy,
+ bool(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD0(resetCompositionStrategy, void());
};
OutputPrepareFrameTest() {
@@ -1015,11 +1021,13 @@
mOutput.editState().usesClientComposition = false;
mOutput.editState().usesDeviceComposition = true;
- EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
+ EXPECT_CALL(mOutput, chooseCompositionStrategy(_)).WillRepeatedly(Return(true));
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(1);
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
mOutput.prepareFrame();
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED);
}
// Note: Use OutputTest and not OutputPrepareFrameTest, so the real
@@ -1035,6 +1043,148 @@
EXPECT_TRUE(mOutput->getState().usesClientComposition);
EXPECT_FALSE(mOutput->getState().usesDeviceComposition);
+ EXPECT_EQ(mOutput->getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED);
+}
+
+struct OutputPrepareFrameAsyncTest : public testing::Test {
+ struct OutputPartialMock : public OutputPartialMockBase {
+ // Sets up the helper functions called by the function under test to use
+ // mock implementations.
+ MOCK_METHOD1(chooseCompositionStrategy,
+ bool(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD0(updateProtectedContentState, void());
+ MOCK_METHOD2(dequeueRenderBuffer,
+ bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
+ MOCK_METHOD1(
+ chooseCompositionStrategyAsync,
+ std::future<bool>(std::optional<android::HWComposer::DeviceRequestedChanges>*));
+ MOCK_METHOD4(composeSurfaces,
+ std::optional<base::unique_fd>(
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
+ MOCK_METHOD0(resetCompositionStrategy, void());
+ };
+
+ OutputPrepareFrameAsyncTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ }
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<OutputPartialMock> mOutput;
+ CompositionRefreshArgs mRefreshArgs;
+};
+
+TEST_F(OutputPrepareFrameAsyncTest, delegatesToChooseCompositionStrategyAndRenderSurface) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ std::promise<bool> p;
+ p.set_value(true);
+
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(1);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(1);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_))
+ .WillOnce(DoAll(SetArgPointee<0>(mOutput.editState().previousDeviceRequestedChanges),
+ Return(ByMove(p.get_future()))));
+ EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::SUCCESS);
+ EXPECT_FALSE(result.bufferAvailable());
+}
+
+TEST_F(OutputPrepareFrameAsyncTest, skipCompositionOnDequeueFailure) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ std::promise<bool> p;
+ p.set_value(true);
+
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(false));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_))
+ .WillOnce(DoAll(SetArgPointee<0>(mOutput.editState().previousDeviceRequestedChanges),
+ Return(ByMove(p.get_future()))));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
+ EXPECT_FALSE(result.bufferAvailable());
+}
+
+// Tests that in the event of hwc error when choosing composition strategy, we would fall back
+// client composition
+TEST_F(OutputPrepareFrameAsyncTest, chooseCompositionStrategyFailureCallsPrepareFrame) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ std::promise<bool> p;
+ p.set_value(false);
+ std::shared_ptr<renderengine::ExternalTexture> tex =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 2);
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true)));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)).WillOnce([&] {
+ return p.get_future();
+ });
+ EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
+ EXPECT_TRUE(result.bufferAvailable());
+}
+
+TEST_F(OutputPrepareFrameAsyncTest, predictionMiss) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+ mOutput.editState().previousDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ auto newDeviceRequestedChanges =
+ std::make_optional<android::HWComposer::DeviceRequestedChanges>({});
+ newDeviceRequestedChanges->displayRequests = static_cast<hal::DisplayRequest>(0);
+ std::promise<bool> p;
+ p.set_value(false);
+ std::shared_ptr<renderengine::ExternalTexture> tex =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 2);
+
+ EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2);
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true)));
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2);
+ EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)).WillOnce([&] {
+ return p.get_future();
+ });
+ EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _));
+
+ impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs);
+ EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL);
+ EXPECT_TRUE(result.bufferAvailable());
}
/*
@@ -1820,10 +1970,14 @@
MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD0(beginFrame, void());
MOCK_METHOD0(prepareFrame, void());
+ MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&));
MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD2(finishFrame,
+ void(const compositionengine::CompositionRefreshArgs&,
+ GpuCompositionResult&&));
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD1(renderCachedSets, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
};
StrictMock<OutputPartialMock> mOutput;
@@ -1839,9 +1993,30 @@
EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
EXPECT_CALL(mOutput, beginFrame());
+ EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(false));
EXPECT_CALL(mOutput, prepareFrame());
EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
- EXPECT_CALL(mOutput, finishFrame(Ref(args)));
+ EXPECT_CALL(mOutput, finishFrame(Ref(args), _));
+ EXPECT_CALL(mOutput, postFramebuffer());
+ EXPECT_CALL(mOutput, renderCachedSets(Ref(args)));
+
+ mOutput.present(args);
+}
+
+TEST_F(OutputPresentTest, predictingCompositionStrategyInvokesPrepareFrameAsync) {
+ CompositionRefreshArgs args;
+
+ InSequence seq;
+ EXPECT_CALL(mOutput, updateColorProfile(Ref(args)));
+ EXPECT_CALL(mOutput, updateCompositionState(Ref(args)));
+ EXPECT_CALL(mOutput, planComposition());
+ EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
+ EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
+ EXPECT_CALL(mOutput, beginFrame());
+ EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, prepareFrameAsync(Ref(args)));
+ EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
+ EXPECT_CALL(mOutput, finishFrame(Ref(args), _));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, renderCachedSets(Ref(args)));
@@ -2739,11 +2914,15 @@
// Sets up the helper functions called by the function under test to use
// mock implementations.
MOCK_METHOD(Region, getDirtyRegion, (), (const));
- MOCK_METHOD2(composeSurfaces,
+ MOCK_METHOD4(composeSurfaces,
std::optional<base::unique_fd>(
- const Region&, const compositionengine::CompositionRefreshArgs&));
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD0(prepareFrame, void());
+ MOCK_METHOD0(updateProtectedContentState, void());
+ MOCK_METHOD2(dequeueRenderBuffer,
+ bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
};
OutputDevOptRepaintFlashTest() {
@@ -2800,7 +2979,9 @@
InSequence seq;
EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kNotEmptyRegion));
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs)));
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs), _, _));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, prepareFrame());
@@ -2816,10 +2997,14 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_METHOD2(composeSurfaces,
+ MOCK_METHOD4(composeSurfaces,
std::optional<base::unique_fd>(
- const Region&, const compositionengine::CompositionRefreshArgs&));
+ const Region&, const compositionengine::CompositionRefreshArgs&,
+ std::shared_ptr<renderengine::ExternalTexture>, base::unique_fd&));
MOCK_METHOD0(postFramebuffer, void());
+ MOCK_METHOD0(updateProtectedContentState, void());
+ MOCK_METHOD2(dequeueRenderBuffer,
+ bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
};
OutputFinishFrameTest() {
@@ -2837,27 +3022,62 @@
TEST_F(OutputFinishFrameTest, ifNotEnabledDoesNothing) {
mOutput.mState.isEnabled = false;
- mOutput.finishFrame(mRefreshArgs);
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
}
TEST_F(OutputFinishFrameTest, takesEarlyOutifComposeSurfacesReturnsNoFence) {
mOutput.mState.isEnabled = true;
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _));
- InSequence seq;
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _));
-
- mOutput.finishFrame(mRefreshArgs);
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
}
TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) {
mOutput.mState.isEnabled = true;
InSequence seq;
- EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _))
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _))
.WillOnce(Return(ByMove(base::unique_fd())));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
- mOutput.finishFrame(mRefreshArgs);
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
+}
+
+TEST_F(OutputFinishFrameTest, predictionSucceeded) {
+ mOutput.mState.isEnabled = true;
+ mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::SUCCESS;
+ InSequence seq;
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
+}
+
+TEST_F(OutputFinishFrameTest, predictionFailedAndBufferIsReused) {
+ mOutput.mState.isEnabled = true;
+ mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::FAIL;
+
+ InSequence seq;
+
+ impl::GpuCompositionResult result;
+ result.buffer =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ 2);
+
+ EXPECT_CALL(mOutput,
+ composeSurfaces(RegionEq(Region::INVALID_REGION), _, result.buffer,
+ Eq(ByRef(result.fence))))
+ .WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+ mOutput.finishFrame(mRefreshArgs, std::move(result));
}
/*
@@ -3104,8 +3324,15 @@
struct ExecuteState : public CallOrderStateMachineHelper<TestType, ExecuteState> {
auto execute() {
- getInstance()->mReadyFence =
- getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fence;
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+ const bool success =
+ getInstance()->mOutput.dequeueRenderBuffer(&fence, &externalTexture);
+ if (success) {
+ getInstance()->mReadyFence =
+ getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs,
+ externalTexture, fence);
+ }
return nextState<FenceCheckState>();
}
};
@@ -3475,6 +3702,15 @@
: public CallOrderStateMachineHelper<TestType, OutputWithDisplayBrightnessNits> {
auto withDisplayBrightnessNits(float nits) {
getInstance()->mOutput.mState.displayBrightnessNits = nits;
+ return nextState<OutputWithDimmingStage>();
+ }
+ };
+
+ struct OutputWithDimmingStage
+ : public CallOrderStateMachineHelper<TestType, OutputWithDimmingStage> {
+ auto withDimmingStage(
+ aidl::android::hardware::graphics::composer3::DimmingStage dimmingStage) {
+ getInstance()->mOutput.mState.clientTargetDimmingStage = dimmingStage;
return nextState<SkipColorTransformState>();
}
};
@@ -3507,16 +3743,20 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3526,16 +3766,45 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
+ .andIfSkipColorTransform(false)
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
+ .execute()
+ .expectAFenceWasReturned();
+}
+
+TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings,
+ forHdrMixedCompositionWithDimmingStage) {
+ verify().ifMixedCompositionIs(true)
+ .andIfUsesHdr(true)
+ .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(
+ aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF)
+
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDisplayLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
.orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage = aidl::android::hardware::graphics::
+ composer3::DimmingStage::GAMMA_OETF})
.execute()
.expectAFenceWasReturned();
}
@@ -3544,16 +3813,21 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(false)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3562,16 +3836,21 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = false,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = false,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3580,16 +3859,21 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = false,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = false,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3599,16 +3883,21 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kUnknownLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+
.andIfSkipColorTransform(true)
- .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
- .clip = kDefaultOutputViewport,
- .maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
- .outputDataspace = kDefaultOutputDataspace,
- .colorTransform = kDefaultColorTransformMat,
- .deviceHandlesColorTransform = true,
- .orientation = kDefaultOutputOrientationFlags,
- .targetLuminanceNits = kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR})
.execute()
.expectAFenceWasReturned();
}
@@ -3666,7 +3955,11 @@
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
EXPECT_CALL(mRenderEngine, useProtectedContext(false));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotSupportIt) {
@@ -3674,7 +3967,11 @@
mLayer2.mLayerFEState.hasProtectedContent = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) {
@@ -3686,7 +3983,11 @@
EXPECT_CALL(mRenderEngine, useProtectedContext(false));
EXPECT_CALL(*mRenderSurface, setProtected(false));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) {
@@ -3708,7 +4009,11 @@
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) {
@@ -3718,7 +4023,11 @@
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRenderEngine) {
@@ -3729,7 +4038,11 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
EXPECT_CALL(mRenderEngine, useProtectedContext(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderEngine) {
@@ -3740,7 +4053,11 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false));
EXPECT_CALL(*mRenderSurface, setProtected(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) {
@@ -3751,7 +4068,11 @@
EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true));
EXPECT_CALL(mRenderEngine, useProtectedContext(true));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
struct OutputComposeSurfacesTest_SetsExpensiveRendering : public OutputComposeSurfacesTest {
@@ -3781,7 +4102,11 @@
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd);
}
struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur
@@ -3816,7 +4141,12 @@
mOutput.writeCompositionState(mRefreshArgs);
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
- mOutput.composeSurfaces(kDebugRegion, mRefreshArgs);
+
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd);
}
TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotExpensive) {
@@ -3826,7 +4156,12 @@
mOutput.writeCompositionState(mRefreshArgs);
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(0);
- mOutput.composeSurfaces(kDebugRegion, mRefreshArgs);
+
+ base::unique_fd fd;
+ std::shared_ptr<renderengine::ExternalTexture> tex;
+ mOutput.updateProtectedContentState();
+ mOutput.dequeueRenderBuffer(&fd, &tex);
+ mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd);
}
/*
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 9116fd3..3651c8b 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -91,6 +91,7 @@
static_cast<uint32_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers));
}
+ mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy);
mCompositionDisplay->createDisplayColorProfile(
compositionengine::DisplayColorProfileCreationArgsBuilder()
.setHasWideColorGamut(args.hasWideColorGamut)
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 297a776..117540d 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -41,6 +41,7 @@
using aidl::android::hardware::graphics::composer3::BnComposerCallback;
using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
using aidl::android::hardware::graphics::composer3::PowerMode;
using aidl::android::hardware::graphics::composer3::VirtualDisplay;
@@ -155,15 +156,6 @@
.refreshTimeNanos = x.refreshTimeNanos,
};
}
-
-template <>
-IComposerClient::ClientTargetProperty translate(ClientTargetProperty x) {
- return IComposerClient::ClientTargetProperty{
- .pixelFormat = translate<PixelFormat>(x.pixelFormat),
- .dataspace = translate<Dataspace>(x.dataspace),
- };
-}
-
mat4 makeMat4(std::vector<float> in) {
return mat4(static_cast<const float*>(in.data()));
}
@@ -1082,12 +1074,8 @@
}
Error AidlComposer::getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) {
- const auto property = mReader.takeClientTargetProperty(translate<int64_t>(display));
- *outClientTargetProperty =
- translate<IComposerClient::ClientTargetProperty>(property.clientTargetProperty);
- *outBrightness = property.brightness;
+ Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) {
+ *outClientTargetProperty = mReader.takeClientTargetProperty(translate<int64_t>(display));
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 28ff167..0099024 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -208,9 +208,10 @@
bool mandatory, const std::vector<uint8_t>& value) override;
V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
- Error getClientTargetProperty(Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) override;
+ Error getClientTargetProperty(
+ Display display,
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) override;
// AIDL Composer HAL
Error setLayerBrightness(Display display, Layer layer, float brightness) override;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 2dc0830..fd26e0b 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -33,6 +33,7 @@
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -264,8 +265,7 @@
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
virtual Error getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) = 0;
+ Display display, V3_0::ClientTargetPropertyWithBrightness* outClientTargetProperty) = 0;
// AIDL Composer
virtual Error setLayerBrightness(Display display, Layer layer, float brightness) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c0432bf..d8f2334 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -585,10 +585,10 @@
return static_cast<Error>(intError);
}
-Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty,
- float* outWhitePointNits) {
- const auto error =
- mComposer.getClientTargetProperty(mId, outClientTargetProperty, outWhitePointNits);
+Error Display::getClientTargetProperty(
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) {
+ const auto error = mComposer.getClientTargetProperty(mId, outClientTargetProperty);
return static_cast<Error>(error);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index a805566..2154553 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -39,6 +39,7 @@
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -160,7 +161,8 @@
std::vector<hal::ContentType>*) const = 0;
[[nodiscard]] virtual hal::Error setContentType(hal::ContentType) = 0;
[[nodiscard]] virtual hal::Error getClientTargetProperty(
- hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0;
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) = 0;
[[nodiscard]] virtual hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) = 0;
@@ -238,8 +240,9 @@
hal::Error getSupportedContentTypes(
std::vector<hal::ContentType>* outSupportedContentTypes) const override;
hal::Error setContentType(hal::ContentType) override;
- hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty,
- float* outWhitePointNits) override;
+ hal::Error getClientTargetProperty(
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) override;
hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) override;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 459291a..9580964 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -479,12 +479,11 @@
RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
- float brightness = 1.f;
- error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &brightness);
+ error = hwcDisplay->getClientTargetProperty(&clientTargetProperty);
outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
std::move(layerRequests),
- std::move(clientTargetProperty), brightness});
+ std::move(clientTargetProperty)});
error = hwcDisplay->acceptChanges();
RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 0e15a7c..5e2ab78 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -45,6 +45,7 @@
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -78,7 +79,8 @@
using ChangedTypes =
std::unordered_map<HWC2::Layer*,
aidl::android::hardware::graphics::composer3::Composition>;
- using ClientTargetProperty = hal::ClientTargetProperty;
+ using ClientTargetProperty =
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
using DisplayRequests = hal::DisplayRequest;
using LayerRequests = std::unordered_map<HWC2::Layer*, hal::LayerRequest>;
@@ -86,7 +88,6 @@
DisplayRequests displayRequests;
LayerRequests layerRequests;
ClientTargetProperty clientTargetProperty;
- float clientTargetBrightness;
};
struct HWCDisplayMode {
@@ -279,6 +280,13 @@
virtual Hwc2::AidlTransform getPhysicalDisplayOrientation(PhysicalDisplayId) const = 0;
};
+static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs,
+ const android::HWComposer::DeviceRequestedChanges& rhs) {
+ return lhs.changedTypes == rhs.changedTypes && lhs.displayRequests == rhs.displayRequests &&
+ lhs.layerRequests == rhs.layerRequests &&
+ lhs.clientTargetProperty == rhs.clientTargetProperty;
+}
+
namespace impl {
class HWComposer final : public android::HWComposer {
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index d9af553..fd456ff 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -37,6 +37,8 @@
#include <cinttypes>
using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
+using aidl::android::hardware::graphics::composer3::DimmingStage;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace android {
@@ -1302,10 +1304,17 @@
}
Error HidlComposer::getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) {
- mReader.takeClientTargetProperty(display, outClientTargetProperty);
- *outBrightness = 1.f;
+ Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) {
+ IComposerClient::ClientTargetProperty property;
+ mReader.takeClientTargetProperty(display, &property);
+ outClientTargetProperty->display = display;
+ outClientTargetProperty->clientTargetProperty.dataspace =
+ static_cast<::aidl::android::hardware::graphics::common::Dataspace>(property.dataspace);
+ outClientTargetProperty->clientTargetProperty.pixelFormat =
+ static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(
+ property.pixelFormat);
+ outClientTargetProperty->brightness = 1.f;
+ outClientTargetProperty->dimmingStage = DimmingStage::NONE;
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 5869ae5..68c1c15 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -317,9 +317,10 @@
bool mandatory, const std::vector<uint8_t>& value) override;
V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
- Error getClientTargetProperty(Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty,
- float* outBrightness) override;
+ Error getClientTargetProperty(
+ Display display,
+ aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
+ outClientTargetProperty) override;
// AIDL Composer HAL
Error setLayerBrightness(Display display, Layer layer, float brightness) override;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 307da41..e21095a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -89,6 +89,9 @@
virtual void dumpAsString(String8& result) const;
virtual void resizeBuffers(const ui::Size&) override;
virtual const sp<Fence>& getClientTargetAcquireFence() const override;
+ // Virtual display surface needs to prepare the frame based on composition type. Skip
+ // any client composition prediction.
+ virtual bool supportsCompositionStrategyPrediction() const override { return false; };
private:
enum Source : size_t {
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 5ba8a1b..cbea77e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -346,6 +346,12 @@
VsyncEventData EventThread::getLatestVsyncEventData(
const sp<EventThreadConnection>& connection) const {
+ // Resync so that the vsync is accurate with hardware. getLatestVsyncEventData is an alternate
+ // way to get vsync data (instead of posting callbacks to Choreographer).
+ if (connection->resyncCallback) {
+ connection->resyncCallback();
+ }
+
VsyncEventData vsyncEventData;
nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
vsyncEventData.frameInterval = frameInterval;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 64ba280..7ec8e6f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -162,6 +162,8 @@
using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
+using CompositionStrategyPredictionState = android::compositionengine::impl::
+ OutputCompositionState::CompositionStrategyPredictionState;
using base::StringAppendF;
using gui::DisplayInfo;
@@ -411,6 +413,9 @@
property_get("debug.sf.disable_client_composition_cache", value, "0");
mDisableClientCompositionCache = atoi(value);
+ property_get("debug.sf.predict_hwc_composition_strategy", value, "0");
+ mPredictCompositionStrategy = atoi(value);
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -2219,24 +2224,24 @@
const bool prevFrameHadClientComposition = mHadClientComposition;
- mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
- const auto& state = pair.second->getCompositionDisplay()->getState();
- return state.usesClientComposition && !state.reusedClientComposition;
- });
- mHadDeviceComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
- const auto& state = pair.second->getCompositionDisplay()->getState();
- return state.usesDeviceComposition;
- });
- mReusedClientComposition =
- std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
- const auto& state = pair.second->getCompositionDisplay()->getState();
- return state.reusedClientComposition;
- });
- // Only report a strategy change if we move in and out of client composition
- if (prevFrameHadClientComposition != mHadClientComposition) {
- mTimeStats->incrementCompositionStrategyChanges();
+ mHadClientComposition = mHadDeviceComposition = mReusedClientComposition = false;
+ TimeStats::ClientCompositionRecord clientCompositionRecord;
+ for (const auto& [_, display] : displays) {
+ const auto& state = display->getCompositionDisplay()->getState();
+ mHadClientComposition |= state.usesClientComposition && !state.reusedClientComposition;
+ mHadDeviceComposition |= state.usesDeviceComposition;
+ mReusedClientComposition |= state.reusedClientComposition;
+ clientCompositionRecord.predicted |=
+ (state.strategyPrediction != CompositionStrategyPredictionState::DISABLED);
+ clientCompositionRecord.predictionSucceeded |=
+ (state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS);
}
+ clientCompositionRecord.hadClientComposition = mHadClientComposition;
+ clientCompositionRecord.reused = mReusedClientComposition;
+ clientCompositionRecord.changed = prevFrameHadClientComposition != mHadClientComposition;
+ mTimeStats->pushCompositionStrategyState(clientCompositionRecord);
+
// TODO: b/160583065 Enable skip validation when SF caches all client composition layers
const bool usedGpuComposition = mHadClientComposition || mReusedClientComposition;
modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
@@ -2527,13 +2532,6 @@
}
mTimeStats->incrementTotalFrames();
- if (mHadClientComposition) {
- mTimeStats->incrementClientCompositionFrames();
- }
-
- if (mReusedClientComposition) {
- mTimeStats->incrementClientCompositionReusedFrames();
- }
mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime);
@@ -5469,30 +5467,21 @@
// access to SF.
case BOOT_FINISHED:
case CLEAR_ANIMATION_FRAME_STATS:
- case CREATE_DISPLAY:
- case DESTROY_DISPLAY:
case GET_ANIMATION_FRAME_STATS:
case OVERRIDE_HDR_TYPES:
case GET_HDR_CAPABILITIES:
case SET_DESIRED_DISPLAY_MODE_SPECS:
case GET_DESIRED_DISPLAY_MODE_SPECS:
case SET_ACTIVE_COLOR_MODE:
- case GET_BOOT_DISPLAY_MODE_SUPPORT:
case SET_BOOT_DISPLAY_MODE:
- case CLEAR_BOOT_DISPLAY_MODE:
case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
- case SET_AUTO_LOW_LATENCY_MODE:
case GET_GAME_CONTENT_TYPE_SUPPORT:
- case SET_GAME_CONTENT_TYPE:
- case SET_POWER_MODE:
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
case GET_DISPLAYED_CONTENT_SAMPLE:
case ADD_TUNNEL_MODE_ENABLED_LISTENER:
case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
- case NOTIFY_POWER_BOOST:
case SET_GLOBAL_SHADOW_SETTINGS:
- case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
// OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary
// permission dynamically. Don't use the permission cache for this check.
@@ -5523,15 +5512,11 @@
case AUTHENTICATE_SURFACE:
case GET_ACTIVE_COLOR_MODE:
case GET_ACTIVE_DISPLAY_MODE:
- case GET_PHYSICAL_DISPLAY_IDS:
- case GET_PHYSICAL_DISPLAY_TOKEN:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_NATIVE_PRIMARIES:
case GET_STATIC_DISPLAY_INFO:
case GET_DYNAMIC_DISPLAY_INFO:
case GET_DISPLAY_MODES:
- case GET_DISPLAY_STATE:
- case GET_DISPLAY_STATS:
case GET_SUPPORTED_FRAME_TIMESTAMPS:
// Calling setTransactionState is safe, because you need to have been
// granted a reference to Client* and Handle* to do anything with it.
@@ -5540,11 +5525,9 @@
case GET_COLOR_MANAGEMENT:
case GET_COMPOSITION_PREFERENCE:
case GET_PROTECTED_CONTENT_SUPPORT:
- case IS_WIDE_COLOR_DISPLAY:
// setFrameRate() is deliberately available for apps to call without any
// special permissions.
case SET_FRAME_RATE:
- case GET_DISPLAY_BRIGHTNESS_SUPPORT:
case GET_DISPLAY_DECORATION_SUPPORT:
case SET_FRAME_TIMELINE_INFO:
case GET_GPU_CONTEXT_PRIORITY:
@@ -5552,19 +5535,6 @@
// This is not sensitive information, so should not require permission control.
return OK;
}
- case SET_DISPLAY_BRIGHTNESS:
- case ADD_HDR_LAYER_INFO_LISTENER:
- case REMOVE_HDR_LAYER_INFO_LISTENER: {
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
- !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
- ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- return OK;
- }
case ADD_FPS_LISTENER:
case REMOVE_FPS_LISTENER:
case ADD_REGION_SAMPLING_LISTENER:
@@ -5610,10 +5580,28 @@
}
return PERMISSION_DENIED;
}
+ case CREATE_DISPLAY:
+ case DESTROY_DISPLAY:
+ case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
+ case GET_PHYSICAL_DISPLAY_IDS:
+ case GET_PHYSICAL_DISPLAY_TOKEN:
+ case SET_POWER_MODE:
+ case GET_DISPLAY_STATE:
+ case GET_DISPLAY_STATS:
+ case CLEAR_BOOT_DISPLAY_MODE:
+ case GET_BOOT_DISPLAY_MODE_SUPPORT:
+ case SET_AUTO_LOW_LATENCY_MODE:
+ case SET_GAME_CONTENT_TYPE:
case CAPTURE_LAYERS:
case CAPTURE_DISPLAY:
case CAPTURE_DISPLAY_BY_ID:
- LOG_FATAL("Deprecated opcode: %d", code);
+ case IS_WIDE_COLOR_DISPLAY:
+ case GET_DISPLAY_BRIGHTNESS_SUPPORT:
+ case SET_DISPLAY_BRIGHTNESS:
+ case ADD_HDR_LAYER_INFO_LISTENER:
+ case REMOVE_HDR_LAYER_INFO_LISTENER:
+ case NOTIFY_POWER_BOOST:
+ LOG_FATAL("Deprecated opcode: %d, migrated to AIDL", code);
return PERMISSION_DENIED;
}
@@ -7309,6 +7297,123 @@
}
// gui::ISurfaceComposer
+
+binder::Status SurfaceComposerAIDL::createDisplay(const std::string& displayName, bool secure,
+ sp<IBinder>* outDisplay) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ String8 displayName8 = String8::format("%s", displayName.c_str());
+ *outDisplay = mFlinger->createDisplay(displayName8, secure);
+ return binder::Status::ok();
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::destroyDisplay(const sp<IBinder>& display) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ mFlinger->destroyDisplay(display);
+ return binder::Status::ok();
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) {
+ std::vector<PhysicalDisplayId> physicalDisplayIds = mFlinger->getPhysicalDisplayIds();
+ std::vector<int64_t> displayIds;
+ displayIds.reserve(physicalDisplayIds.size());
+ for (auto item : physicalDisplayIds) {
+ displayIds.push_back(static_cast<int64_t>(item.value));
+ }
+ *outDisplayIds = displayIds;
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) {
+ status_t status = checkAccessPermission();
+ if (status != OK) {
+ return binder::Status::fromStatusT(status);
+ }
+
+ PhysicalDisplayId id;
+ status = mFlinger->getPrimaryPhysicalDisplayId(&id);
+ if (status == NO_ERROR) {
+ *outDisplayId = id.value;
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId,
+ sp<IBinder>* outDisplay) {
+ const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+ *outDisplay = mFlinger->getPhysicalDisplayToken(*id);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setPowerMode(const sp<IBinder>& display, int mode) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ mFlinger->setPowerMode(display, mode);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display,
+ gui::DisplayStatInfo* outStatInfo) {
+ DisplayStatInfo statInfo;
+ status_t status = mFlinger->getDisplayStats(display, &statInfo);
+ if (status == NO_ERROR) {
+ outStatInfo->vsyncTime = static_cast<long>(statInfo.vsyncTime);
+ outStatInfo->vsyncPeriod = static_cast<long>(statInfo.vsyncPeriod);
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display,
+ gui::DisplayState* outState) {
+ ui::DisplayState state;
+ status_t status = mFlinger->getDisplayState(display, &state);
+ if (status == NO_ERROR) {
+ outState->layerStack = state.layerStack.id;
+ outState->orientation = static_cast<gui::Rotation>(state.orientation);
+ outState->layerStackSpaceRect.width = state.layerStackSpaceRect.width;
+ outState->layerStackSpaceRect.height = state.layerStackSpaceRect.height;
+ }
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->clearBootDisplayMode(display);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->getBootDisplayModeSupport(outMode);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ mFlinger->setAutoLowLatencyMode(display, on);
+ return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& display, bool on) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ mFlinger->setGameContentType(display, on);
+ return binder::Status::ok();
+}
+
binder::Status SurfaceComposerAIDL::captureDisplay(
const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
status_t status = mFlinger->captureDisplay(args, captureListener);
@@ -7335,6 +7440,75 @@
return binder::Status::fromStatusT(status);
}
+binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) {
+ status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) {
+ status_t status = mFlinger->getDisplayBrightnessSupport(displayToken, outSupport);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->setDisplayBrightness(displayToken, brightness);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->addHdrLayerInfoListener(displayToken, listener);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ status_t status = checkControlDisplayBrightnessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->removeHdrLayerInfoListener(displayToken, listener);
+ return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) {
+ status_t status = checkAccessPermission();
+ if (status != OK) return binder::Status::fromStatusT(status);
+
+ status = mFlinger->notifyPowerBoost(boostId);
+ return binder::Status::fromStatusT(status);
+}
+
+status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) {
+ if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(),
+ ipc->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+ return OK;
+}
+
+status_t SurfaceComposerAIDL::checkControlDisplayBrightnessPermission() {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS) &&
+ !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
+ ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ return OK;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3c7facf..910c5bb 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -7,7 +7,6 @@
*
* 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
@@ -24,6 +23,8 @@
#include <android-base/thread_annotations.h>
#include <android/gui/BnSurfaceComposer.h>
+#include <android/gui/DisplayStatInfo.h>
+#include <android/gui/DisplayState.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <gui/BufferQueue.h>
@@ -342,6 +343,11 @@
void disableExpensiveRendering();
FloatRect getMaxDisplayBounds();
+ // If set, composition engine tries to predict the composition strategy provided by HWC
+ // based on the previous frame. If the strategy can be predicted, gpu composition will
+ // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect.
+ bool mPredictCompositionStrategy = false;
+
protected:
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -518,17 +524,30 @@
bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true)
EXCLUDES(mStateLock);
+ // the following two methods are moved from ISurfaceComposer.h
+ // 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());
+ }
+
+ // 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;
+ }
+
// Implements ISurfaceComposer
sp<ISurfaceComposerClient> createConnection() override;
- sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
- void destroyDisplay(const sp<IBinder>& displayToken) override;
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override EXCLUDES(mStateLock) {
+ sp<IBinder> createDisplay(const String8& displayName, bool secure);
+ void destroyDisplay(const sp<IBinder>& displayToken);
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const EXCLUDES(mStateLock) {
Mutex::Autolock lock(mStateLock);
return getPhysicalDisplayIdsLocked();
}
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override EXCLUDES(mStateLock);
+ status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const EXCLUDES(mStateLock);
- sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
+ sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
@@ -550,9 +569,9 @@
status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
- status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
+ status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
- EXCLUDES(mStateLock) override;
+ EXCLUDES(mStateLock);
status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*)
EXCLUDES(mStateLock) override;
status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*)
@@ -560,12 +579,12 @@
status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
ui::DisplayPrimaries&) override;
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
- status_t getBootDisplayModeSupport(bool* outSupport) const override;
+ status_t getBootDisplayModeSupport(bool* outSupport) const;
status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override;
- status_t clearBootDisplayMode(const sp<IBinder>& displayToken) override;
- void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) override;
- void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
- void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
+ status_t clearBootDisplayMode(const sp<IBinder>& displayToken);
+ void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
+ void setGameContentType(const sp<IBinder>& displayToken, bool on);
+ void setPowerMode(const sp<IBinder>& displayToken, int mode);
status_t clearAnimationFrameStats() override;
status_t getAnimationFrameStats(FrameStats* outStats) const override;
status_t overrideHdrTypes(const sp<IBinder>& displayToken,
@@ -588,8 +607,7 @@
uint64_t timestamp,
DisplayedFrameStats* outStats) const override;
status_t getProtectedContentSupport(bool* outSupported) const override;
- status_t isWideColorDisplay(const sp<IBinder>& displayToken,
- bool* outIsWideColorDisplay) const override;
+ status_t isWideColorDisplay(const sp<IBinder>& displayToken, bool* outIsWideColorDisplay) const;
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
@@ -611,15 +629,14 @@
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) override;
- status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
- bool* outSupport) const override;
+ status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const;
status_t setDisplayBrightness(const sp<IBinder>& displayToken,
- const gui::DisplayBrightness& brightness) override;
+ const gui::DisplayBrightness& brightness);
status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override;
+ const sp<gui::IHdrLayerInfoListener>& listener);
status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
- const sp<gui::IHdrLayerInfoListener>& listener) override;
- status_t notifyPowerBoost(int32_t boostId) override;
+ const sp<gui::IHdrLayerInfoListener>& listener);
+ status_t notifyPowerBoost(int32_t boostId);
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
status_t getDisplayDecorationSupport(
@@ -1439,11 +1456,43 @@
public:
SurfaceComposerAIDL(sp<SurfaceFlinger> sf) { mFlinger = sf; }
+ binder::Status createDisplay(const std::string& displayName, bool secure,
+ sp<IBinder>* outDisplay) override;
+ binder::Status destroyDisplay(const sp<IBinder>& display) override;
+ binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override;
+ binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override;
+ binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
+ binder::Status setPowerMode(const sp<IBinder>& display, int mode) override;
+ binder::Status getDisplayStats(const sp<IBinder>& display,
+ gui::DisplayStatInfo* outStatInfo) override;
+ binder::Status getDisplayState(const sp<IBinder>& display,
+ gui::DisplayState* outState) override;
+ binder::Status clearBootDisplayMode(const sp<IBinder>& display) override;
+ binder::Status getBootDisplayModeSupport(bool* outMode) override;
+ binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override;
+ binder::Status setGameContentType(const sp<IBinder>& display, bool on) override;
binder::Status captureDisplay(const DisplayCaptureArgs&,
const sp<IScreenCaptureListener>&) override;
binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override;
binder::Status captureLayers(const LayerCaptureArgs&,
const sp<IScreenCaptureListener>&) override;
+ binder::Status isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) override;
+ binder::Status getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) override;
+ binder::Status setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) override;
+ binder::Status addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
+ binder::Status removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
+ binder::Status notifyPowerBoost(int boostId) override;
+
+private:
+ static const constexpr bool kUsePermissionCache = true;
+ status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache);
+ status_t checkControlDisplayBrightnessPermission();
private:
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index b1a2bda..e5a9dd4 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -321,22 +321,19 @@
mTimeStats.missedFramesLegacy++;
}
-void TimeStats::incrementClientCompositionFrames() {
- if (!mEnabled.load()) return;
+void TimeStats::pushCompositionStrategyState(const TimeStats::ClientCompositionRecord& record) {
+ if (!mEnabled.load() || !record.hasInterestingData()) {
+ return;
+ }
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionFramesLegacy++;
-}
-
-void TimeStats::incrementClientCompositionReusedFrames() {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
-
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.clientCompositionReusedFramesLegacy++;
+ if (record.changed) mTimeStats.compositionStrategyChangesLegacy++;
+ if (record.hadClientComposition) mTimeStats.clientCompositionFramesLegacy++;
+ if (record.reused) mTimeStats.clientCompositionReusedFramesLegacy++;
+ if (record.predicted) mTimeStats.compositionStrategyPredictedLegacy++;
+ if (record.predictionSucceeded) mTimeStats.compositionStrategyPredictionSucceededLegacy++;
}
void TimeStats::incrementRefreshRateSwitches() {
@@ -348,15 +345,6 @@
mTimeStats.refreshRateSwitchesLegacy++;
}
-void TimeStats::incrementCompositionStrategyChanges() {
- if (!mEnabled.load()) return;
-
- ATRACE_CALL();
-
- std::lock_guard<std::mutex> lock(mMutex);
- mTimeStats.compositionStrategyChangesLegacy++;
-}
-
void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
if (!mEnabled.load()) return;
@@ -1062,8 +1050,10 @@
mTimeStats.missedFramesLegacy = 0;
mTimeStats.clientCompositionFramesLegacy = 0;
mTimeStats.clientCompositionReusedFramesLegacy = 0;
- mTimeStats.refreshRateSwitchesLegacy = 0;
mTimeStats.compositionStrategyChangesLegacy = 0;
+ mTimeStats.compositionStrategyPredictedLegacy = 0;
+ mTimeStats.compositionStrategyPredictionSucceededLegacy = 0;
+ mTimeStats.refreshRateSwitchesLegacy = 0;
mTimeStats.displayEventConnectionsCountLegacy = 0;
mTimeStats.displayOnTimeLegacy = 0;
mTimeStats.presentToPresentLegacy.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 77c7973..7a159b8 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -45,7 +45,7 @@
virtual ~TimeStats() = default;
// Process a pull request from statsd.
- virtual bool onPullAtom(const int atomId, std::string* pulledData);
+ virtual bool onPullAtom(const int atomId, std::string* pulledData) = 0;
virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
virtual bool isEnabled() = 0;
@@ -53,14 +53,8 @@
virtual void incrementTotalFrames() = 0;
virtual void incrementMissedFrames() = 0;
- virtual void incrementClientCompositionFrames() = 0;
- virtual void incrementClientCompositionReusedFrames() = 0;
// Increments the number of times the display refresh rate changed.
virtual void incrementRefreshRateSwitches() = 0;
- // Increments the number of changes in composition strategy
- // The intention is to reflect the number of changes between hwc and gpu
- // composition, where "gpu composition" may also include mixed composition.
- virtual void incrementCompositionStrategyChanges() = 0;
// Records the most up-to-date count of display event connections.
// The stored count will be the maximum ever recoded.
virtual void recordDisplayEventConnectionCount(int32_t count) = 0;
@@ -158,6 +152,24 @@
}
};
+ struct ClientCompositionRecord {
+ // Frame had client composition or mixed composition
+ bool hadClientComposition = false;
+ // Composition changed between hw composition and mixed/client composition
+ bool changed = false;
+ // Frame reused the client composition result from a previous frame
+ bool reused = false;
+ // Composition strategy predicted for frame
+ bool predicted = false;
+ // Composition strategy prediction succeeded
+ bool predictionSucceeded = false;
+
+ // Whether there is data we want to record.
+ bool hasInterestingData() const {
+ return hadClientComposition || changed || reused || predicted;
+ }
+ };
+
virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0;
// Clean up the layer record
virtual void onDestroy(int32_t layerId) = 0;
@@ -169,6 +181,7 @@
// 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;
+ virtual void pushCompositionStrategyState(const ClientCompositionRecord&) = 0;
};
namespace impl {
@@ -236,10 +249,7 @@
void incrementTotalFrames() override;
void incrementMissedFrames() override;
- void incrementClientCompositionFrames() override;
- void incrementClientCompositionReusedFrames() override;
void incrementRefreshRateSwitches() override;
- void incrementCompositionStrategyChanges() override;
void recordDisplayEventConnectionCount(int32_t count) override;
void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
@@ -275,6 +285,8 @@
void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
+ void pushCompositionStrategyState(const ClientCompositionRecord&) override;
+
static const size_t MAX_NUM_TIME_RECORDS = 64;
private:
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 69afa2a..cf1ca65 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -143,6 +143,14 @@
clientCompositionReusedFramesLegacy);
StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
+ StringAppendF(&result, "compositionStrategyPredicted = %d\n",
+ compositionStrategyPredictedLegacy);
+ StringAppendF(&result, "compositionStrategyPredictionSucceeded = %d\n",
+ compositionStrategyPredictionSucceededLegacy);
+ StringAppendF(&result, "compositionStrategyPredictionFailed = %d\n",
+ compositionStrategyPredictedLegacy -
+ compositionStrategyPredictionSucceededLegacy);
+
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
StringAppendF(&result, "displayConfigStats is as below:\n");
for (const auto& [fps, duration] : refreshRateStatsLegacy) {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 438561c..237ae8d 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -178,6 +178,8 @@
Histogram frameDurationLegacy;
Histogram renderEngineTimingLegacy;
std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
+ int32_t compositionStrategyPredictedLegacy = 0;
+ int32_t compositionStrategyPredictionSucceededLegacy = 0;
std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;
diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
index abdb16d..d70908e 100644
--- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp
+++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
@@ -20,28 +20,33 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
#include <chrono>
namespace android {
TEST(BootDisplayModeTest, setBootDisplayMode) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> sf_aidl(ComposerServiceAIDL::getComposerService());
auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
bool bootModeSupport = false;
- ASSERT_NO_FATAL_FAILURE(sf->getBootDisplayModeSupport(&bootModeSupport));
+ binder::Status status = sf_aidl->getBootDisplayModeSupport(&bootModeSupport);
+ ASSERT_NO_FATAL_FAILURE(status.transactionError());
if (bootModeSupport) {
ASSERT_EQ(NO_ERROR, sf->setBootDisplayMode(displayToken, 0));
}
}
TEST(BootDisplayModeTest, clearBootDisplayMode) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
bool bootModeSupport = false;
- ASSERT_NO_FATAL_FAILURE(sf->getBootDisplayModeSupport(&bootModeSupport));
+ binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
+ ASSERT_NO_FATAL_FAILURE(status.transactionError());
if (bootModeSupport) {
- ASSERT_EQ(NO_ERROR, sf->clearBootDisplayMode(displayToken));
+ status = sf->clearBootDisplayMode(displayToken);
+ ASSERT_EQ(NO_ERROR, status.transactionError());
}
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index fa36d9c..c033af8 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -415,6 +415,10 @@
EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData));
VsyncEventData vsyncEventData = mThread->getLatestVsyncEventData(mConnection);
+
+ // Check EventThread immediately requested a resync.
+ EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
+
EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
<< "Deadline timestamp should be greater than frame time";
for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 0ef8456..6ffc039 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -268,8 +268,11 @@
for (size_t i = 0; i < MISSED_FRAMES; i++) {
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
}
+ TimeStats::ClientCompositionRecord record;
+ record.hadClientComposition = true;
+
for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState(record));
}
SFTimeStatsGlobalProto globalProto;
@@ -459,19 +462,49 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
-TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
+TEST_F(TimeStatsTest, canIncreaseClientCompositionStats) {
// this stat is not in the proto so verify by checking the string dump
- constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
+ constexpr size_t COMPOSITION_STRATEGY_CHANGED_FRAMES = 1;
+ constexpr size_t HAD_CLIENT_COMPOSITION_FRAMES = 2;
+ constexpr size_t REUSED_CLIENT_COMPOSITION_FRAMES = 3;
+ constexpr size_t COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES = 4;
+ constexpr size_t COMPOSITION_STRATEGY_PREDICTED_FRAMES = 5;
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ for (size_t i = 0; i <= COMPOSITION_STRATEGY_PREDICTED_FRAMES; i++) {
+ TimeStats::ClientCompositionRecord record;
+ record.hadClientComposition = i < HAD_CLIENT_COMPOSITION_FRAMES;
+ record.changed = i < COMPOSITION_STRATEGY_CHANGED_FRAMES;
+ record.reused = i < REUSED_CLIENT_COMPOSITION_FRAMES;
+ record.predicted = i < COMPOSITION_STRATEGY_PREDICTED_FRAMES;
+ record.predictionSucceeded = i < COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES;
+ mTimeStats->pushCompositionStrategyState(record);
}
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- const std::string expectedResult =
- "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
- EXPECT_THAT(result, HasSubstr(expectedResult));
+ std::string expected =
+ "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "clientCompositionFrames = " + std::to_string(HAD_CLIENT_COMPOSITION_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected =
+ "clientCompositionReusedFrames = " + std::to_string(REUSED_CLIENT_COMPOSITION_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "compositionStrategyPredicted = " +
+ std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "compositionStrategyPredictionSucceeded = " +
+ std::to_string(COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
+
+ expected = "compositionStrategyPredictionFailed = " +
+ std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES -
+ COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expected));
}
TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) {
@@ -489,21 +522,6 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
-TEST_F(TimeStatsTest, canIncreaseCompositionStrategyChanges) {
- // this stat is not in the proto so verify by checking the string dump
- constexpr size_t COMPOSITION_STRATEGY_CHANGES = 2;
-
- EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- for (size_t i = 0; i < COMPOSITION_STRATEGY_CHANGES; i++) {
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
- }
-
- const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
- const std::string expectedResult =
- "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGES);
- EXPECT_THAT(result, HasSubstr(expectedResult));
-}
-
TEST_F(TimeStatsTest, canAverageFrameDuration) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
mTimeStats->setPowerMode(PowerMode::ON);
@@ -836,7 +854,7 @@
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({}));
ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
@@ -867,9 +885,8 @@
TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
// These stats are not in the proto so verify by checking the string dump.
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({}));
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
mTimeStats->setPowerMode(PowerMode::ON);
mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
std::chrono::nanoseconds(5ms).count());
@@ -1032,8 +1049,10 @@
for (size_t i = 0; i < MISSED_FRAMES; i++) {
mTimeStats->incrementMissedFrames();
}
+ TimeStats::ClientCompositionRecord record;
+ record.hadClientComposition = true;
for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- mTimeStats->incrementClientCompositionFrames();
+ mTimeStats->pushCompositionStrategyState(record);
}
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index c1d41bb..e215550 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -151,8 +151,10 @@
const std::vector<uint8_t>&));
MOCK_METHOD1(getLayerGenericMetadataKeys,
V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
- MOCK_METHOD3(getClientTargetProperty,
- Error(Display, IComposerClient::ClientTargetProperty*, float*));
+ MOCK_METHOD2(getClientTargetProperty,
+ Error(Display,
+ aidl::android::hardware::graphics::composer3::
+ ClientTargetPropertyWithBrightness*));
MOCK_METHOD3(setLayerBrightness, Error(Display, Layer, float));
MOCK_METHOD3(setLayerBlockingRegion,
Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index ac2ab199c..4c2aa34 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -93,8 +93,10 @@
MOCK_METHOD(hal::Error, getSupportedContentTypes, (std::vector<hal::ContentType> *),
(const, override));
MOCK_METHOD(hal::Error, setContentType, (hal::ContentType), (override));
- MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *, float *),
- (override));
+ MOCK_METHOD(
+ hal::Error, getClientTargetProperty,
+ (aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness *),
+ (override));
MOCK_METHOD(
hal::Error, getDisplayDecorationSupport,
(std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport> *),
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 0a69b56..0dee800 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -33,10 +33,7 @@
MOCK_METHOD0(miniDump, std::string());
MOCK_METHOD0(incrementTotalFrames, void());
MOCK_METHOD0(incrementMissedFrames, void());
- MOCK_METHOD0(incrementClientCompositionFrames, void());
- MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
MOCK_METHOD0(incrementRefreshRateSwitches, void());
- MOCK_METHOD0(incrementCompositionStrategyChanges, void());
MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
@@ -63,6 +60,8 @@
void(hardware::graphics::composer::V2_4::IComposerClient::PowerMode));
MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD(void, pushCompositionStrategyState,
+ (const android::TimeStats::ClientCompositionRecord&), (override));
};
} // namespace android::mock